Planning bug: a card headed "One PR" carried an acceptance criterion naming a file in the OTHER repo
Found while running MOTIR-2697. Telemetry about the planner; the correction is already applied (the card shipped as two coordinated PRs, the contract flow), so this holds nothing up.
The defect
MOTIR-2697's body opens "Repo: motir-core. One PR." and its targetRepo is motir-core. Its acceptance criterion 7 reads:
This PR adds the route's entry to
docs/contract.mdalongside the other internal AI routes.
docs/contract.md does not exist in motir-core. It is motir-ai's file — deliberately, and the open repo says so in its own words: motir-core/docs/ai-boundary.md is a POINTER whose whole text is "the authoritative spec … lives on the closed side, where it is owned and versioned … a copy in the open repo would drift." So the card's own header and its own criterion 7 contradict each other, and the contradiction is only visible to someone who goes and looks for the file.
Why it did not become a replan
run.md guard #5's second check covers exactly this: a card that names the producer side, the mirror AND the consumer sink is a pinned boundary-CONTRACT card — two-PRs-one-card, run as the contract flow, not a straddle to re-plan. MOTIR-2697 names all three (the motir-core route, docs/contract.md, and motir-ai's src/core/coreClient.ts in its context refs), so the run built both halves and reported the merge order. The mechanism worked; the card was still wrong.
The cost is not zero, though: resolving "is this a straddle, a contract card, or a mislabelled file?" is a rung-2 investigation across two repos, and every future runner of a card in this shape pays it again.
The fix — a card-authoring rule, not product code
A card's repo pin and its acceptance criteria must agree, and a criterion that names a FILE is where they most easily stop agreeing, because a filename carries no repo. Concretely, at seal time: for every criterion naming a path, confirm which repo owns that path. Where the answer is "the other one", the card is either a contract card (say so in the header, and say two PRs) or it is mis-scoped — but it is never "One PR".
docs/contract.md is worth naming as the recurring instance: it is the boundary's source of truth, it is motir-ai's, and it is the file a motir-core boundary card most naturally reaches for.
Acceptance criteria
- The rule lands in
motir-metaplan-rules/where the per-card gate on the repo column lives (gate 1), phrased as the file-path corollary: a criterion naming a path is checked against the card'stargetRepo. - It names
docs/contract.mdexplicitly as the recurring instance, with the reason it lives on the closed side. - It states the two legal outcomes — declare the card a contract card carrying TWO PRs, or re-scope it — and that "One PR" plus a foreign path is neither.