The issue comes from the task's own template¶
rig-conductor#2270. Follows the marker names its template (#2266).
What was pinned¶
CockpitTaskConfirm filed OperatorTaskIssueTemplate.Title and Body(requestId, attemptId), both v1
constants, and ignored the stored TemplateId. After #2266 the rule a PR is judged by follows the
template, but the request Dev-E is given did not. A second registered template would have filed the
Reward-E issue word for word, and Dev-E would have made the Reward-E change under the new template's marker.
MergeGate would then judge that diff against the new template, read Differs, and hold it for a human.
That is why #2266 said nothing else may be registered until this was fixed.
What the issue is made of now¶
| Part | Source | Can it drift from the diff rule? |
|---|---|---|
| Title | the template's IssueCopy.Title |
Only if its words lie. The registry test covers every entry. |
| Before and after blocks | derived from OldAnchor and NewAnchor, indented by IssueCopy.Indent |
No: they come from the same values OperatorTaskDiffPolicy compares |
| Change intro, tail, acceptance, out of scope, after merge | the template's IssueCopy |
Checked: every registered body must contain its own path, href and both anchors, and no other entry's new anchor |
| Marker | the template's own id and derived digest | No |
OperatorTaskIssueCopy is registry data that lives beside the anchors. It is not input: no marker or issue body
can supply it, because a marker only selects a registered template (#2266).
The copy is deliberately not part of CanonicalIntent. The digest binds the change (repo, path, from, to).
Hashing the prose too would turn every wording fix into a new intent, and the Cockpit Worker's frozen
TASK_INTENT_DIGEST would stop matching it.
Recovery follows the same template¶
An ambiguous create is recovered by listing the target repo's recent issues and binding the one that carries this attempt's
marker. After this change the create posted to template.Repo, but at first recovery still listed v1's repo, stamped its
evidence with v1's repo, and OperatorTaskPolicy.Reconcile rejected any other repo. Review-E caught it. All three now resolve
the task's stored template. A task whose template is no longer registered is not reconciled at all: no other template's repo
could hold its issue.
With one registered repo, the evidence stamp and the policy check behave the same either way. Only the list path can be
told apart today, through an unregistered template. The proof for the other two arrives with the first template in a second
repo, which also needs the issue creator's single-repo allowlist (repo_not_allowed) lifted.
Fail closed¶
- A template with no copy cannot file an issue.
IssueCopythrows instead of borrowing another template's words. A template that exists only to judge a diff, such as a test fixture, stays wordless. - A claim naming an unregistered template files nothing.
OperatorTaskPolicy.Validresolves the id at proposal time, so this happens only if the registry loses an entry that a live task still names. The lookup throws inside the one-POST block. That throw is treated as Ambiguous, so the attempt is recorded asOutcomeUnknownand never retried.
The parser-hazard test (no checkbox, dependency phrase, epic, closing keyword or #N) now runs over every
registered body, not only v1's. Each body goes into Dev-E's prompt verbatim, so a new entry's wording can stall
dispatch just as v1's could.
v1's prose moved into its registry entry verbatim. A byte-for-byte golden test (body length and sha256) proves it was moved, not rewritten.
Proved by mutation¶
| Mutation | Result |
|---|---|
| Confirm uses v1 regardless of the stored template | 1 fails: a claim naming an unregistered template files no issue |
Body uses v1's copy regardless of the template |
2 fail, including a second template files its own issue, not the first one's |
A second entry registered whose out-of-scope text says Depends on #12. |
1 fails: body has zero hazard hits for the rig parsers |
| Reconciliation lists v1's repo regardless of the stored template | 1 fails: a task naming an unregistered template is not reconciled against another template's repo |
| Restored | Core 2480 pass / 0 fail |
Still pinned after this¶
RefuseTemplatestill compares the signed body's id to one id (CockpitTaskRoutes.cs), andIOperatorTaskStore.ProposeAsynctakes no template.- The status route's probe, and
GitHubTaskSnapshotReader, take their template by injection with a v1 default. Until the template is passed at call time, a second template can never reach Verified. - The Cockpit Worker freezes one
TASK_TEMPLATEandTASK_INTENT_DIGEST. SiteUrland thedeploy.ymlrun URL are constants (OperatorTaskSnapshotReading.cs).