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

Planning bug: a card asserted two Playwright lanes were interchangeable by RENAME, having compared their globs and never their webServer env

Done
Description

Found by motir run MOTIR-2765 (2026-08-13), executing MOTIR-2769. Split out as MOTIR-2849; MOTIR-2770's ordering was re-wired behind it.

The claim, and why it read as verified

MOTIR-2769's Context refs state:

playwright.acceptance.config.ts (testMatch: ['**/acceptance*.spec.ts']) and playwright.config.ts (testIgnore on the same pattern) — the two globs a rename moves a spec between; they are complementary, so a rename is the whole mechanism.

Both halves of that were CHECKED and both are TRUE. The globs are complementary; a rename really does move a spec from one lane to the other. The planner cited file paths, quoted the actual config keys, and got them right.

What was never opened is the webServer.env block twenty lines below the glob in the same file. Measured on origin/main @ fca2c9f3:

LaneMOTIR_CLOUDE2E_TEST_BILLINGMOTIR_AI_URLE2E_TEST_CODE_HEALTH
playwright.config.ts (main)
playwright.acceptance.config.ts

Nine of twenty-six specs assert behaviour that only exists under those flags. A rename lands them in a lane where the product they test is switched off.

The generalisable finding

A card that moves work between two environments must compare the ENVIRONMENTS, not only the SELECTORS that route work into them. The selector is what is visible when you go looking for "how does a spec get into this lane" — it is the answer to the question actually being asked, it is short, and it is adjacent in the file to the thing that would have falsified the claim. Verification stopped at the first true statement.

The second-order finding is worse, and is what makes this worth a rule rather than a correction: the failure would have been SILENT. playwright.acceptance.config.ts's own header already records why (MOTIR-2601) — off-cloud, an entitlement path short-circuits to the same inert value it returns for an exempt org, so the assertion passes because billing does not exist rather than because the rule works. A promoted spec would have gone green and been counted as coverage. The plan's own worked example points the other way and was not read: ai-callout-gate.spec.ts exists in the main lane precisely to assert that off-cloud there is no orb, which is the exact negation of what the promoted acceptance-ai-callout.spec.ts would have claimed.

Acceptance criteria

  • The notes.html lesson is appended: comparing the SELECTORS is not comparing the ENVIRONMENTS; when a card moves work between lanes/configs/deployments, diff the env blocks and name the flags.
  • Assessed whether this belongs in plan-rules/ as a standing precondition-verification clause — a "moving work between two runtimes" trigger on the existing precondition rule — or stays a lesson. Record which and why.
  • If adopted as a rule, it lands in BOTH homes (plan-rules/ pack + motir-ai SHARED_PLANNING_RULES) per the two-homes rule.

Context refs

  • MOTIR-2769 — the card carrying the claim.
  • MOTIR-2849 — the split-out card that now owns the nine gated specs.
  • playwright.config.ts / playwright.acceptance.config.ts / playwright.billing.config.ts — the three env blocks; the measurement.
  • tests/e2e/ai-callout-gate.spec.ts — the repo's own off-cloud ground truth.