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

Planning bug: run.md's branch-prefix rule still cites the `startsWith(head_ref, …)` CI gate that MOTIR-3148 replaced with a diff-based predicate — and understates which prefixes skip the Vercel preview

Done
Description

Type: planning-corpus drift (a rule citing a mechanism that was replaced) · Repo: motir-meta. ONE PR.

Discovered in

motir run MOTIR-3257 (2026-08-20), while choosing the branch prefix for a docs-only diff. The rule was READ, applied, and landed on the right prefix — and its stated mechanism turned out to be false in two places. Filed rather than absorbed (notes.html #27); MOTIR-3257 is pinned motir-core and is one PR, so it cannot carry a motir-meta edit.

The two false statements

prompts/run.md, motir run step 8 (the branch-prefix-by-DIFF paragraph):

The design/* AND docs/* prefixes both make CI skip the Playwright E2E + Vitest integration jobs (ci.yml gates them on !startsWith(head_ref, 'design/'|'docs/'|'seed/')); design/* also skips the Vercel preview deploy. lint/typecheck/build still run. So a docs PR on a subtask/* branch burns the full E2E matrix for nothing — pick the prefix from what the diff actually edits.

1 — The startsWith(head_ref, …) gate no longer exists. MOTIR-3148 replaced it with a changes job that reads the DIFF. Verified at origin/main 7de5856f:

$ grep -n 'startsWith' .github/workflows/*.yml
.github/workflows/ci.yml:55:  # NAME — a `startsWith` test against the `seed/` / `design/` / `docs/`

— one hit, and it is the comment explaining that the test was REMOVED. Every expensive lane now reads needs.changes.outputs.app (ci.yml:566, 650, 768, 964) / .images (1115, 1144), and app is false only when every changed path matches docs/*|design/*|scripts/plan-seed/*|*.md (ci.yml:133), defaulting to true on any doubt. The job's own comment names both failure directions the branch test had, including the one that mattered: "a docs/… branch that touched app code SKIPPED the entire test suite and merged unverified … a hole in the merge gate, not a cost problem."

2 — docs/* and seed/* skip the Vercel preview too, not only design/*. vercel.json:4:

"ignoreCommand": "bash -c 'case \"$VERCEL_GIT_COMMIT_REF\" in seed/*|design/*|docs/*) ;; main) … ;; *) exit 1 ;; esac'"

This half IS still branch-prefix-keyed, which is why the sentence reads as though the whole rule is — the two mechanisms diverged and the prose describes neither correctly.

Why it is worth fixing even though the ADVICE is still right

"Pick the prefix from what the diff actually edits" lands on the correct branch name either way, so this cost nothing on the run that found it. The hazard is in what a reader DERIVES from the mechanism:

  • The costly direction: "a docs PR on a subtask/* branch burns the full E2E matrix for nothing" is now false — the diff predicate classifies it as documentation whatever the branch is called. A run that re-cuts a branch to avoid a cost that no longer exists pays for the belief.
  • The dangerous direction: the inverse reading — a docs/* branch skips E2E — is the exact hole MOTIR-3148 closed, and a rule that still describes the old gate is a rule that would license it. Nothing bad happens today because the CODE is right; the corpus is what is wrong.

Class: notes.html #283 — a referrer left behind by a mechanism that moved — and notes.html #219, one tier over: the corpus's job is to make the runner READ the shipped check, not to restate it in prose that can drift.

Fix direction

Rewrite the paragraph so the prefix choice and the CI mechanism are stated separately, because they are now separate things:

  • The prefix is still chosen by DIFF CONTENT (subtask/ / design/ / docs/) — unchanged guidance, and the branch name remains what the design-result publish and the Vercel ignore key off.
  • The E2E / Vitest skip is decided by the DIFF, not the branch (ci.yml's changes job, MOTIR-3148), and it fails OPEN — cite the job, do not restate its path list, per notes.html #219.
  • The Vercel preview skip IS branch-keyed and covers seed/*, design/* and docs/* (vercel.json).
  • Drop "a docs PR on a subtask/* branch burns the full E2E matrix for nothing", which is the sentence the change falsified.

Check for the same claim elsewhere in the corpus while there (_shared.md, plan-rules/, plan-procedure.md, verify.md) rather than assuming run.md is the only carrier — that assumption is what produced this card.

Acceptance criteria

  1. grep -rn 'startsWith(head_ref' prompts/ returns nothing, and no file in prompts/ describes the E2E / Vitest skip as keyed on the branch prefix.
  2. run.md's step-8 paragraph names ci.yml's changes job as the decider for the app lanes, says it reads the DIFF and defaults to running everything, and does NOT restate its path list.
  3. The Vercel-preview sentence names all three prefixes the ignoreCommand matches (seed/, design/, docs/) and says that half IS branch-keyed.
  4. grep -rn 'burns the full E2E matrix' prompts/ returns nothing.
  5. ORDERING — every criterion reads on this card's own motir-meta branch, pre-merge. Nothing blocks it: the motir-core change it describes (MOTIR-3148) has already merged, and this card only edits prose in another repository. It is relates_to MOTIR-3257 for provenance only — that card's pull request touches no file this one does.

Context refs

  • motir-meta/prompts/run.mdmotir run step 8, the branch-prefix-by-DIFF paragraph; and the worktree-rules block near the top, whose 0a step carries the same prefix list (check whether it repeats the mechanism).
  • motir-core/.github/workflows/ci.yml:50-150 — the changes job and its two booleans; :566, 650, 768, 964, 1115, 1144 — the consumers.
  • motir-core/vercel.json:4 — the branch-keyed preview skip.
  • motir-core/tests/ci-changed-paths-gate.test.ts — the guard that keeps the image half of that predicate from going stale.