MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-2686

Planning bug: an acceptance criterion was written in a metric the card's own scope forbids it from moving — and the metric was mis-attributed at source

Done
Description

Filed by the motir run of MOTIR-2569 (2026-08-11). The correction is already applied — the criterion is amended on the card and the doc's Finding 4 carries the re-measurement. This records WHY, so the shape does not recur.

What happened

MOTIR-2569 carried two clauses that cannot both hold:

  • Scope: "It does NOT migrate test fixtures (MOTIR-2528's)."
  • Acceptance criterion 4: "the ProjectNotFoundError / WorkItemNotFoundError counts from lib/ frames reach zero."

Measured on the branch before any change (four batches, TEST_DB_APP_ROLE=1): 290 ProjectNotFoundError, of which 222 are entered DIRECTLY from a test fixturetests/fixtures/workItemFixtures.ts:154 calls projectRepository.allocateWorkItemNumber inside its own bare db.$transaction, so the topmost non-node_modules frame is lib/repositories/projectRepository.ts and the classifier counts it as a lib/ frame. The remaining 68 are application paths. Only the 68 are movable by this card; the 222 are Finding 2 fixture debt, whose migration the scope excludes by name. The criterion asked for zero and forbade the work that reaches zero.

The root cause is one level up, in the measurement it inherited

docs/rls-runtime-role-inventory.md Finding 4 reported "ProjectNotFoundError (135) — projectRepository.findById on the db singleton, 94 frames in lib/repositories/projectRepository.ts." The attribution is wrong. Those frames are allocateWorkItemNumber (a raw UPDATE … RETURNING that throws on zero rows), not findById, and they are reached from fixtures rather than from a service. The classifier the inventory used — topmost non-node_modules frame — cannot tell "the application read unbound" from "a fixture reached into a repository", and the finding read the file name as if it could.

The card was then written from that sentence, which is how a measurement artefact became a shipping gate.

The lesson

A criterion stated as a NUMBER must be stated in a number the card's own scope can move. Two checks, both cheap, both skipped here:

  1. When a criterion cites a metric produced by a CLASSIFIER, state what the classifier cannot distinguish. "Frames in lib/" silently merges application defects with test debt, and the two were split across two cards on purpose.
  2. When a criterion is inherited from a prior measurement, RE-READ the raw evidence, not the finding's prose. One grep -A 3 over the stack blocks was enough to show allocateWorkItemNumber where the doc said findById — and would have been enough at plan time.

What was done

  • Criterion 4 amended on MOTIR-2569 to the achievable form (application-path count to zero; fixture-entered count reported separately and attributed to MOTIR-2528), with the evidence and the date, per run.md's amend-a-contradicted-clause rule.
  • The doc's Finding 4 attribution corrected in the same PR, as the card's own re-measurement criterion required.
  • notes.html lesson added.