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-2798

PLANNING BUG — a story titled "the tenant reads" decomposed into fixtures only, and its adjudication card was given an AC that required it to fix the class it was scoped to merely CATALOGUE

Done
Description

Two coupled planning defects, found on 2026-08-12 while running MOTIR-2789. Filed together because the second is what kept the first invisible.

Defect 1 — the story's title promised a deliverable its children did not cover

MOTIR-2755 is titled "Adopt the motir_app non-bypass role — the tenant reads, the test fixtures, and the deployed runtime". Its 25 children: 20 fixture batches, a guard, an adjudication card, two small read fixes, the flag retirement, and the deployed cutover.

Nothing in that set binds the read surface. It is now measured at 55 unbound reads across 20 servicesreportsService.ts and savedFiltersService.ts contain zero context wrappers in the entire file. The story would have gone done with its first named deliverable undelivered, and then MOTIR-2515 would have cut production over to a role under which most reporting surfaces return empty.

The tell, and it is cheap: a story title with a comma-separated LIST of deliverables is a coverage checklist. Read each item against the child set and name the child that owns it. Two of three had owners; the first had none. No existing gate reads a title as a promise — gate 12 (the journey audit) walks the verification_recipe, and this story's recipe was about the fixtures, so the audit passed while the title's first clause had no owner anywhere.

Defect 2 — an AC that made the card unclosable by construction

MOTIR-2789's scope is adjudicate the sites — write a verdict per read. But it was given this acceptance criterion:

TEST_DB_APP_ROLE=1 over every migrated batch shows no remaining failure of the unbound-read family.

That is not a property of an adjudication. It is the completion condition of the repair, which is 55 sites across 20 services — now MOTIR-2796, a 34-point story. A card scoped to CATALOGUE a defect class cannot be closed against the class's ABSENCE.

This is gate 14 (AC satisfiable inside the card's own boundary) on an axis its three limbs miss. Limb (a) asks WHO performs the crossing step — the same agent, so it passes. Limb (b) asks WHICH SURFACE — the card declares no exclusion list for it to contradict. Limb (c) asks WHEN — nothing here reads on post-merge state. The criterion is unsatisfiable on a fourth axis: SIZE. It names work two orders of magnitude larger than the card it sits on, and every existing limb is blind to that.

Why it survived: it reads as the natural verification of the card's own subject. A catalogue of a defect class and the elimination of that class use the same nouns, so an AC written in those nouns looks like it belongs — and the card's own header, which is careful and well-argued about evidence, argues for the catalogue while the criterion demands the cure.

The rule this proposes (the fix is a rule change, not a card edit)

A card whose deliverable is an ENUMERATION — a catalogue, an inventory, an audit, an adjudication, a survey — may NOT carry an acceptance criterion that asserts the ABSENCE of what it enumerates. Its criteria are properties of the LIST (complete, evidence-backed, each entry disposed); the absence of the class belongs to the card that repairs it, and if no such card exists, the enumeration card's real deliverable is FILING it.

The tell is lexical and greppable: on a card whose verb is inventory / catalogue / adjudicate / audit / enumerate / survey / measure, any criterion containing "no remaining", "shows none", "is zero", "is empty", "all … are fixed" is on the wrong card.

And for defect 1:

A story title carrying a LIST of deliverables is a coverage claim — walk each item against the child set and name the owning child, at authoring time and on every re-plan. A clause with no owner is the gap; the verification_recipe will not catch it, because a recipe written about one clause passes the journey audit while the others go unowned.

Both belong in plan-rules/core.md (gate 14 gains the SIZE axis; gate 12 or the story-slicing pack gains the title-list check) and mirrored into SHARED_PLANNING_RULES in motir-ai — the two-homes rule.

Acceptance criteria

  • prompts/plan-rules/core.md carries both rules, each with its lexical tell, landed via a branch + PR (never a direct commit to main).
  • The mirror in motir-ai's SHARED_PLANNING_RULES carries the same text — TWO PRs, one per repo, per the two-homes rule.
  • notes.html carries the numbered entry for both.
  • MOTIR-2789's offending AC is struck and re-pointed at MOTIR-2796, where it is satisfiable.

Context refs

  • MOTIR-2789 — the close-out comment records the adjudication and marks that AC unsatisfiable-as-written.
  • MOTIR-2796 / MOTIR-2797 — the two stories the discovery produced; both now block MOTIR-2755.
  • MOTIR-2791 — the sibling planning bug from the same run (the dependency arrow between the app-layer cards and the fixture batches pointed the wrong way). Same root shape: a card's stated relationship to a class of work did not survive contact with the measurement.