Planning bug: MOTIR-4093 was sealed on two unverified preconditions — a credential that is not a configured secret, and a read path (`GET …/acceptance-evidence`) that has never existed
Opened by Zhu Yue ·
Filed by a halted motir run MOTIR-4093 (2026-09-01), under run.md guard #4. The correction is already submitted as plan cmtj5ngqi00ybhvphc9yqzu0v; this card is the telemetry.
What the plan asserted, and what was true
MOTIR-4093 diagnosed a real defect correctly — the lane-membership guard's credential is absent from the Vitest job — and then wrote three acceptance criteria on top of two premises nobody checked.
Premise 1: "the same secret/vars the publish step used" is a working credential.
It is not. gh secret list --repo moooon-B-V/motir-core returns ten secrets; MOTIR_UPLOAD_TOKEN is not one of them. The publish step's own comment says what it actually authenticates with: "the moooon repo is App-connected, so no secret is needed; MOTIR_UPLOAD_TOKEN is the PAT fallback" (keyless OIDC, MOTIR-1650). The card read the env: block and took the NAMES in it for a configured credential.
Premise 2: the guard's read path resolves.
fetchApprovedStories calls GET {base}/api/work-items/{key}/acceptance-evidence. That route exports POST only; git log --all -S'export async function GET' on it returns nothing, and the deployed product answers HTTP 405. Nothing in the card, in MOTIR-2770 that shipped the guard, or in the tests of that guard has ever asked whether the URL it builds resolves — every existing test hands fetchApprovedStories a fetchImpl stub.
Why it got through
Both premises are of the shape the precondition-verification rule exists for, and both were checkable in one command. What made them invisible is that the card's evidence was unusually good everywhere else: the mechanism was quoted from source, the cost was measured off a real run with per-shard timings, and the sequencing hazard was thought through. A card that verifies four things carefully reads as a card that verified everything.
The second premise is the more interesting failure, because the guard's own design hides it. fetchApprovedStories fails OPEN by policy — "a story the read cannot resolve is treated as NOT approved" — which is correct for a flaky hop and silently absorbs there is no route here as though it were a fact about a story. So the missing endpoint produces no error, no log line and no degraded-mode notice: just a well-formed empty answer computed from nothing.
Acceptance criteria
- The
plan-rulesprecondition-verification rule (plan-rules/phase-deepen.md) gains the limb this missed: when a card's premise is that an environment variable, secret or credential is available, the check is against the PROVIDER (gh secret list, the platform's own console) — not against a workflowenv:block naming it. Anenv:block is a claim about what a job would pass, never evidence that a value exists behind the name. - And its twin: when a card is about a check that queries a remote endpoint, verify the ENDPOINT ANSWERS — one authenticated call, and read the status code — before writing criteria about the credential it would use. A read path that returns 404/405 into a fail-open error branch is indistinguishable from a negative answer.
- Both limbs cite this card and MOTIR-4093 as the fixture, and are ADDED beside the existing rule rather than re-wording it.
Context refs
- MOTIR-4093 — the card, now Blocked, with the full evidence in its halt comment.
- Plan
cmtj5ngqi00ybhvphc9yqzu0v— the submitted correction. - MOTIR-2770 — the card that shipped the guard whose read path never resolved.
tests/e2e-acceptance-lane-membership.test.ts(motir-core) —fetchApprovedStoriesand its fail-open comment.
Discussion
No comments yet.
Adding to this discussion signs you in on app.motir.co and brings you back to this request.