Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
144
planned
1,362
shipped

Motir · Work items

MOTIR-3109Done

Planning bug: a card that ENUMERATES a population measured it with `find` over the working tree, and shipped a count 4 short

⚠️ AMENDED ON THE RECORD, 2026-08-20, by the run that executed this card. Two clauses below were written under conditions that no longer hold, and both are corrected here rather than quietly edited. (1) The repo pin WORKS nowMOTIR-3078's data migration and MOTIR-3086's code have since reached production, so the parenthetical that used to open this card ("the pin is omitted — UNKNOWN_TARGET_REPO still refuses one") is stale. Tested, not inferred: update_work_item targetRepos: ['motir-meta', 'motir-ai'] succeeded at 21:17 UTC. (2) The acceptance criteria were ONE HOME SHORT. A standing planning RULE lives in plan-rules/ for the manual planner AND in SHARED_PLANNING_RULES for the shipped one; the criteria named only the first. Corrected as the fourth criterion below. Yue, declining a proposal to file that mirror as a separate subtask: "a planning bug is not a subtask, and a work item (bug included) can carry multiple repos." — so the second home is a REPOSITORY on this card, not a sibling card.

Repos · motir-meta (primary) + motir-ai. One pull request per repository, both titled with this card's key; the card completes only when BOTH have merged.

Filed about MOTIR-3069, whose table named THREE *.mock.html with no .png export. There are seven, and there were seven at the moment the card was written.

What happened

MOTIR-3069 was filed from a sweep on MOTIR-3054's branch and carried this reproduce block, which is also how it measured the population:

$ for m in $(find design -name '*.mock.html'); do [ -f "${m%.mock.html}.png" ] || echo "$m"; done
design/boards/board.mock.html
design/work-items/links.mock.html
design/work-items/list.mock.html

Run against the COMMITTED tree it returns seven, and it returns the same seven at origin/main and at b305d567 — the very merge the card was filed from:

$ git ls-tree -r --name-only b305d567 -- design | python3 -c "
import sys; files=set(sys.stdin.read().split())
print(len([m for m in files if m.endswith('.mock.html') and m[:-10]+'.png' not in files]))"
7

The four the card missed — datepicker, filter, relationships, tree-scale — were all added in June 2026 and have never had an export, so nothing changed between the filing and the run.

The mechanism

find reads the working tree. MOTIR-3054 was a 51-mock re-export sweep, so its worktree held rendered .pngs that were never committed — and every mock with one of those was invisible to the check. The measurement was taken inside the process that was perturbing the thing being measured, and the result reads as a clean, reproducible three-row table.

Why it was not caught at authoring time. Nothing about the output looks partial: three rows, each verifiable by hand, each true. notes.html #296's reproduce at the reporter's base did fire on the run — it is what produced the seven — but that rule is written for a defect that will not reproduce, i.e. a count going DOWN. A count that comes back HIGHER reads as drift since filing and gets absorbed, which is exactly what this run nearly did before checking the dates.

Why it cost something

The card's last acceptance criterion asks for a green pnpm vitest run --config vitest.design.config.ts, and the card's own deliverable is a guard over that population — so a card that renders three and guards all of them is internally contradictory and leaves the lane red. The count was load-bearing rather than descriptive, and a card that enumerates a population it also gates has no slack in it.

The correction (already applied)

  • MOTIR-3069 amended on the record: title, table and first acceptance criterion, with the amendment banner naming the date and the evidence. All seven rendered on motir-core#2147.
  • Its reproduce block replaced with a git ls-tree form, so the command in the card answers about what is COMMITTED.

What to change here

  • A limb on the authoring rule for a card that ENUMERATES: a population is measured against the committed tree (git ls-tree / git grep on the ref), never with find / ls / a bare grep -r over a working tree — and a sweep's own worktree is the worst place to take the measurement, because the sweep's uncommitted output is exactly what hides the population. The natural home is plan-rules/phase-deepen.md beside the NEGATIVE limb (a card explaining a defect by what does not exist owes the grep, not the verdict); this is its positive twin — a card COUNTING a population owes the ref the count was taken on.
  • The run-time half, beside notes.html #296's reproduce-at-the-reporter's-base: a count that comes back HIGHER than the card's is not automatically drift. Date the additions (git log --diff-filter=A) before deciding — if they predate the card, the enumeration was wrong, which is an amendment, not a re-scope.
  • A notes.html entry carrying the lesson (the corpus half; the card here is the record half — both are owed).
  • (added on amendment) The RULE's second home in motir-ai — see criterion 4.

Acceptance criteria

  • plan-rules/phase-deepen.md carries the enumeration limb, stating the committed-tree requirement and naming the sweep-worktree trap.
  • notes.html carries the matching mistake entry, with the count bumped and the .mistake markup matched.
  • A card that enumerates without naming the ref its count was taken on is identifiable from the rule text alone — i.e. the rule says what the card must SHOW, not only what its author must do.
  • (added on amendment) SHARED_PLANNING_RULES (motir-ai/src/llm/planningRulePacks.ts) carries the same limb — the rule's SECOND home — appended to VERIFY_EVERY_PRECONDITION's existing A COUNTED SET bullet, with a phrase pin in the guard suite. Deliberately NARROWER than the motir-meta wording: the sweep-worktree trap and the run-time drift-vs-wrong-enumeration procedure trigger on facts the shipped planner cannot observe (no worktree, no branch, no base), so they are EXCLUDED — and the exclusions are asserted as ABSENCES rather than merely omitted, so the next reader holding the full source cannot restore them by accident.