The marker names its template, and the diff rule follows it¶
What was pinned¶
OperatorTaskDiffPolicy.Decide took only the file list and compared it to three constants — the path from
OperatorTaskPolicy, and OperatorTaskIssueTemplate's two anchors. A PR that is exactly right for any
other template therefore read Differs, which the release hold turns into a human click.
That is a manual step on every non-forward run, in a loop whose stated requirement is that there are none. It is also the blocker named in rig-conductor#2264's own body.
Why the marker is the carrier¶
MergeGate has no request and no store access. Its only input about which change was consented to is the
issue marker — and the marker already named the template, then threw it away, because ExactMarker
hard-coded the id and the digest as regex literals rather than capturing them.
So the parse now captures both and resolves the id through the registry (OperatorTaskTemplates.ById,
rc#2257), requiring the marker's digest to equal that template's own derived digest.
The marker is a selector, never an authority. It can only select something already registered, carrying that registration's own digest. A hand-edited marker can make a PR unjudgeable — which holds it for the operator — but never judgeable against a different intent.
Fail closed, in two places¶
| Classification keeps the loose test | IsTaskIssueBody (any marker-shaped comment) still decides whether this is a task PR, so a damaged marker cannot buy a PR its way past the gate. The exact parse only supplies the template. |
| No template is not a default template | A task PR whose exact marker does not parse yields a null template, and MergeGate answers Unreadable → Hold. Decide throws on a null template rather than reaching for one. |
Proved by mutation¶
A green run proves nothing here — the suite was green before, against one template.
| Mutation | Result |
|---|---|
Decide compares to OperatorTaskIssueTemplate's anchors again |
2 fail, including "a diff is judged against its own template" |
| The marker resolves to v1 regardless of the id it names | 3 fail |
| The digest is not compared to the registry | 2 fail |
| Restored | 2474 pass / 0 fail |
The two most valuable tests are the ones that could not have been written before: the same diff is
Matches under its own template and Differs under another, and a reverse template accepts the
reverse diff — which is precisely what makes an iterable target possible.
Still pinned after this¶
This slice moves the rule, not the whole pipeline:
- The issue Title and Body are v1 constants, and
CockpitTaskConfirmignores the storedTemplateId. Nothing else may be registered until that is fixed, or a second template would file the Reward-E issue verbatim. SiteUrland thedeploy.ymlrun URL are constants (OperatorTaskSnapshotReading:54-55).RefuseTemplatestill compares the signed body's id to one id.GitHubTaskSnapshotReadertakes its template by injection, mirroring what rc#2253 did forDashecorpSiteProbe. The status route holds the request, and therefore its registered template, so a later slice should pass it at call time and delete the default.