Planning bug: MOTIR-2939 attributed a count rise to two specs from what LANDED RECENTLY, not from measuring — one of the two was already inside the baseline
Filed by the motir run MOTIR-2939 of 2026-08-17. The card's headline premise was CORRECT and reproduced — main was red, the ceiling was stale, nothing had risen. This is about its supporting attribution table, which the run had to falsify before it could size the fix.
What the card claimed
MOTIR-2939 explained a rise from 454 to 457 with a two-row table:
| spec | statements | first landed |
|---|---|---|
tests/e2e/cloud-board-load.spec.ts | 4 | 22316a62 — MOTIR-2912 |
tests/e2e/cloud-orb-clearance.spec.ts | 3 | a39bd115 — MOTIR-2763 |
and concluded "Both are present in 05ac5337^. So 457 was already the true count at 2918's merge." The conclusion is right. The table is not.
What measuring returned
Running the scanner at each commit — it takes a root, so a detached worktree per commit measures directly:
a39bd115 454 MOTIR-2763 · cloud-orb-clearance.spec.ts lands
bd0584c5 454 ← the reading MOTIR-2918 shipped as its ceiling
22316a62 457 MOTIR-2912 · cloud-board-load.spec.ts lands (+3)
05ac5337 457 ← MOTIR-2918 merges carrying the stale 454. RED.
d024d863 457
cloud-orb-clearance landed BEFORE the 454 reading (21:06 vs 21:07) and contributed nothing to the rise; its statements are inside the baseline. The entire +3 is cloud-board-load. And the per-spec numbers (4 and 3) are counts of every db.<model> statement, not of the statements the ceiling actually counts — the ceiling excludes not-gated, and db.user.* is ungated, so the ratchet-relevant contributions are 3 and 2.
The mistake, and it is not the arithmetic
Both specs were new, both seeded through @/lib/db, and both were plausible. The card picked them by reading what had landed recently and checking they were present at the merge — git log --oneline, then git show 05ac5337^:<path>. Presence at the merge commit is compatible with having landed before the baseline reading too, so that check cannot separate the two candidates, and the one command that does — running the scanner at each commit — was never run, on a card whose entire subject is a number being measured at the wrong commit.
The cost was small here because the run measured before acting. It would not have been: converting only what the table named would have left the ceiling at a number the table could not predict.
The lesson
A card that attributes a MEASURED change to a set of commits owes the measurement AT those commits, not a reading of what landed near them. This is plan-rules/phase-deepen.md's NEGATIVE limb one step over: that rule says a card explaining a defect by what does not exist owes the grep rather than the verdict; this says a card explaining a NUMBER by what changed owes the count at each commit rather than the plausible cause. When the instrument is already in the tree and takes a root parameter, the measurement is minutes.
The corrected history is recorded in tests/rls/test-singleton-statement-guard.test.ts's UNCONVERTED_E2E_CEILING block, so the next reader inherits it rather than re-deriving it.
Acceptance criteria
- No build work. This is telemetry; the correction is already applied to MOTIR-2939's card and to the guard's comment block.
- Close when the lesson has been read — or promote it to
plan-rules/phase-deepen.mdif a second instance of attribute-by-adjacency arrives.
Close-out (motir run MOTIR-2942, 2026-08-17)
1 — Both premises re-verified on origin/main (rung 2), and one of the two was FALSE
| the card's claim | verdict |
|---|---|
the corrected history is in the guard's UNCONVERTED_E2E_CEILING block | ✅ origin/main 45dd9a48 — tests/rls/test-singleton-statement-guard.test.ts carries the per-commit table under "WHY THIS NUMBER MOVED", states in its own words that cloud-orb-clearance is NOT part of the rise, and the constant reads 452 = 457 − 5 |
| the lesson is written | ✅ notes.html #299 on origin/main 30ad13f (motir-meta #224), lesson + prompt hint as stated, 301 entries with no gap or duplicate at that number |
| the correction is already applied to MOTIR-2939's card | ⚠️ COMMENT ONLY. Posted at 2026-08-17T20:50:49Z; get_work_item_activity view: history returns ten changes for that card and no descriptionMd edit at all since creation. The two-row suspects table, the 4/3 per-spec counts, and the plan clauses derived from them ("the 3 statements", "7 per-line swaps", "7 statements in 2 files") all still stood in the spec. Written into the DESCRIPTION at 22:05Z as a dated amendment — the original table struck through and kept, the measured table beside it, plus a second amendment marking the option-1 counts as superseded by the 5 statements that actually shipped. |
That third row is notes.html #292's own re-verification row repeating — a description is the spec; a comment is not (MOTIR-2907's close-out found the identical shape on MOTIR-2763) — and it landed on the card this home exists to correct. The generalisable half: a telemetry card's "the correction is already applied" is a CLAIM about another card's description, discharged by reading that description, not by having written the correcting comment yourself. Both instances were made by the run that authored the correction, which is the one reader for whom the comment and the description feel like the same act.
2 — Promote question: NO. The family is ONE — the lesson stands at notes.html #299 and no plan-rules/ pack is edited
The card's condition is a second instance of attribute-by-adjacency, so what follows is the SEARCH rather than the verdict — this lesson's own bar.
- Corpus searched: all 301
notes.htmlentries atorigin/main30ad13f(every title read) + all 57 children of this home (every title read). Lexical pass/attribut|culprit|suspect|caused the|the cause was|blamed|by adjacency|plausible cause|correlat/iover each.mistakeblock → 36 matches, #299 itself included; every match whose title describes a numeric or causal claim was opened, as were the five nearest home cards by title (MOTIR-2907, MOTIR-2687, MOTIR-2707, MOTIR-2916, MOTIR-2925). - Nearest neighbours, and why each is a DIFFERENT defect:
- #292 (
phase-deepen.md's PROSPECTIVE limb, counted set) — a count whose enumerating search was scoped to one directory. The search was RUN and under-scoped; here it was never run, and the claim is causal rather than a census. - #257–#260 (gate 2's QUANTITY limb, warrant
×4) — a number written into an ACCEPTANCE CRITERION without running its measurement. Nearest by mechanism and still not this: the limb names three failure shapes — a denominator swap, an unread constant, a number the card's scope forbids it to move — none of which is an attribution, and its subject is a criterion while #299's number sat in a diagnosis table. - #249 — an instrument run correctly and misread (it measures ORDER, not extent). The measurement exists; its semantics were wrong.
- #253 / #270 / #272 — a reading taken at the wrong REF or commit. Same measured at the wrong point axis, but no candidate set is being chosen between.
- #292 (
- Verdict under
plan-rules/CORPUS-MAINTENANCE.md: the default is LESSON and promotion is earned by RECURRING. One instance, no recurrence, nothing added to the always-injected set — and the neighbouring #286 hazard (an eighth rewording of a rule that is already correct) argues the same way. - For whoever gets the second one, so the structural argument is not re-derived: the home is beside
phase-deepen.md's NEGATIVE limb, not inside gate 2. That limb's insight is that a claim class can sit in the DIAGNOSIS half — which the prospective limb warrants as "produced by reading what is there, so every sentence is a reading" — while having no reading behind it. A negative is one such class; an ATTRIBUTION is the other, and its tell is the same register change the limb already names: a table of commits and counts is the visual grammar of a measurement.
3 — What the false row produced: MOTIR-2951, and motir-meta #227
The ⚠️ row in §1 is a planning defect in its own right and a second instance, so it is filed rather than folded — MOTIR-2951 under this home, relates_to this card / MOTIR-2939 / MOTIR-2907, with notes.html #302 as its deliverable (motir-meta #227, docs/MOTIR-2951-comment-is-not-the-spec). That card's targetRepo is motir-meta, so its PR carries the id in branch and title and the merge closes it; this card's stays unset and it is closed by hand along the legal hops — nothing in it ships in a repo, and there is no PR of its own for the sync to see.
(§2's verdict is unaffected: #302 is a different family from #299. What recurred is where a correction LANDS, not how a number is attributed.)