Planning bug: MOTIR-3414/3422 assert "84 step.run call sites across 37 files, incl. services outside lib/jobs/" — measured 58 across 26, ALL inside lib/jobs/
Found by motir run MOTIR-3414, 2026-08-23, before the first line of work — the run-time
re-measure of a card's own enumeration (run.md: a card whose count carries no ref is a card to
RE-MEASURE before the first line of work).
The claim
Story MOTIR-3414 and its child MOTIR-3422 both state, as a load-bearing figure:
All 84
step.runcall sites across 37 files change by zero characters.
and MOTIR-3414's explanationMd extends it into the story's cost argument:
84
step.runcall sites live across 37 files, including services well outsidelib/jobs/. Rewriting them would be the real work of this epic and would touch code that has nothing to do with queueing.
The measurement
Taken on the ref, not on a working tree (git grep against origin/main@165f1485, the commit the
run branched from):
$ git grep -c 'step\.run(' origin/main -- '*.ts' '*.tsx'
60 occurrences across 27 files
$ git grep -c 'step\.run(' origin/main -- '*.ts' '*.tsx' ':!tests/*'
58 occurrences across 26 files
$ git grep -l 'step\.run(' origin/main -- '*.ts' '*.tsx' ':!tests/*'
lib/jobs/defineJob.ts
lib/jobs/definitions/*.ts (24 files)
lib/jobs/indexFleetSteps.ts
scripts/plan-seed/data/story-1.6.ts ← seed FIXTURE DATA, not a service
Two falsifications, and they are different in kind
-
The COUNT is ~45% high. 84/37 against a measured 58/26 (60/27 including the one test file). An overcount alone would be drift worth an amendment and little more.
-
The RATIONALE's premise is false, and this is the one that matters. "including services well outside
lib/jobs/" — 25 of the 26 files are underlib/jobs/, and the 26th is plan-seed fixture data. Zero service files outsidelib/jobs/callstep.run. The story's argument for the shim's value rests on a blast radius that does not exist: rewriting the call sites would touchlib/jobs/and nothing else, which is exactly where the seam already is.
Why this is a planning bug and not a card defect
The conclusion the numbers were recruited to support — build the shim — survives both
falsifications: 58 call sites are still 58 that should not be rewritten, and compatibility with the
existing job definitions is a good enough reason on its own. So no deliverable changes and nothing
is re-scoped. What went wrong is upstream of the deliverable: a figure was asserted with a
precision it was never measured to (84, 37 — not round numbers, which is what makes them read
as counted), and then reasoned FROM in the explanation. A reader weighing whether this epic is
worth its cost was handed a blast-radius argument that a single git grep refutes.
The likely mechanism, and it is worth recording because it is reproducible: lib/jobs/registry.ts
exports 37 job functions across 24 definition files. 37 is almost certainly the registered
FUNCTION count, re-labelled as a file count of step.run callers. Two real populations, correctly
observed, fused into one sentence about a third.
The rule this should have been caught by
plan-rules/phase-deepen.md's ENUMERATION limb already says a card counting a population owes
the ref the count was taken on. It exists and it was not applied — so the corpus gap, if there is
one, is about ENFORCEMENT at deepen time rather than a missing rule. Worth checking whether
validate_work_item can carry an advisory for a bare integer in a card body that names no ref, the
way likely-repo-straddle mechanised the repo/path check.
Disposition already taken by the run
- MOTIR-3414 and MOTIR-3422 amended on the record with the measured figures, the command, and the ref — the original sentences preserved beneath the amendment rather than silently rewritten.
- The story is not re-planned: no deliverable, edge, repo pin or estimate changes.
- The falsification is carried into the story's pull-request body.
Acceptance criteria
- MOTIR-3414 and MOTIR-3422 carry the corrected figures with the ref they were measured on.
- The
explanationMdclaim about services outsidelib/jobs/is corrected rather than deleted, and the weakened cost argument is stated as such. - A decision is recorded on whether the deepen-time enumeration rule needs a mechanised advisory, or whether the existing prose rule is sufficient and this was a one-off miss.
Evidence provenance
Every figure above was measured with git grep against origin/main@165f1485 — a ref, not a
working tree, and not the run's own branch. No number here was taken on unmerged work.
Advisory disposition (validate_work_item, at filing)
Two reference advisories fired, both likely-missing-edge: this card names MOTIR-3414 and MOTIR-3422 in its acceptance criteria with no blocked_by edge to either.
Both are DELIBERATE EXCLUSIONS, not missing edges — stated here because an absent edge and a considered exclusion are the same absent edge, and only saying so distinguishes them. This card does not CONSUME either item's output; it consumes their card text, and the amendment it asks for was applied by the same run that filed it, minutes after the measurement. A blocked_by on MOTIR-3414 would hold this card unstartable until an eight-child story merges — exactly backwards for a defect record whose corrective work is already done. No edge is owed in either direction.