Planning bug: MOTIR-4106 pinned motir-core owed a row in docs/contract.md, which is a motir-ai file — a repo straddle the BARE path hid from the detector
Type · planning mistake (card authoring — gate 1, the repo column, criterion by criterion)
Parent · MOTIR-1465 (Captured planning-mistake bugs) — the defect is in the PLAN, and the correction is already applied
Discovered in · motir run MOTIR-4106, 2026-09-01, before the worktree existed
Blocks · nothing. Both cards were corrected in-run; this is telemetry.
What the plan said
MOTIR-4106 is pinned targetRepo: motir-core and carried the criterion:
docs/contract.md's ai→core read-back inventory gains this route, because that document is what the consumer is written against.
with its contract-doc row listed under IN in its Scope BOUNDARY.
Why that is wrong
docs/contract.md is a motir-ai file. There is no docs/contract.md in motir-core — find . -name contract.md on origin/main returns nothing, and git show origin/main:docs/contract.md in motir-ai returns the §6 Read-back endpoints (ai → core) inventory the criterion is about.
So a card pinned to one repository owed a file in the other: one subtask, two repositories, two pull requests — the shape ONE SUBTASK = ONE REPO = ONE PR exists to refuse, and the same gate the card was itself CREATED by (motir run MOTIR-4058 halted at guard #5 and split this producer half out of a motir-ai card).
It is also not satisfiable in motir-core in some other form, which is what makes it a straddle rather than a mislocated path. motir-core's docs/ai-boundary.md records the opposite decision:
It is kept there (not here) deliberately: the contract is owned by the closed side, and a copy in the open repo would drift. … Their shapes are specified in
motir-ai/docs/contract.md§6.
The sibling card MOTIR-4107 carried the mirror of the same misconception — a Context ref reading "motir-core docs/contract.md" — so the error is about the FILE's home, not a slip on one card.
Why no mechanism caught it
validate_work_item on MOTIR-4106 returned two advisories and neither was likely-repo-straddle. The shape detector checks a criterion's path against the card's targetRepo, and docs/contract.md is bare — a plausible path in either repository — so it has nothing to key on. The detector is right; the path is what makes the card unreadable to it. (Advisories returned: a subsumption on lib/services/aiBoundaryService.ts from the merged #2501, disposed of by reading that PR — no overlap; and a plain reference advisory naming MOTIR-4058, which is provenance rather than consumption.)
The correction, already applied
- MOTIR-4106: criterion struck ON THE RECORD with the evidence,
its contract-doc rowremoved from IN and added to OUT. - MOTIR-4107 (
motir-ai,blocked_byMOTIR-4106, the consumer that document is written for): the §6 row added as an acceptance criterion and to its IN; its Context ref corrected to namemotir-ai. - Both carry a comment stating what moved and why.
What would have prevented it
An authoring-time check that a criterion naming a path RESOLVES in the card's targetRepo — git ls-tree origin/main <path> in the pinned repo — for a bare path the straddle detector cannot classify. The absence of a file is as much a repo signal as the presence of one in the wrong repo, and it is one command.
Acceptance criteria
- A
motir-corecard pinned to one repository whose criterion names a path that does not exist in that repository is caught before dispatch — either by wideningvalidate_work_item'slikely-repo-straddleto report a bare path that resolves in NO repository the project carries, or by a gate-1 authoring step that resolves each named path against the pin. - The fix names which of the two it took and why, and states what it does with a path that resolves in BOTH repositories (
CLAUDE.md,docs/decisions/…), which is the case that makes a naive existence check noisy.