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

Planning bug: a card's second half was inferred from a MODULE PATH — `lib/ai/codeContext` was read as "calls motir-ai" while its whole import closure is Prisma

Done
Description

Filed by the run of MOTIR-3719 (PR #2403), under the planner-bug home. No fix is owed in a repo — the correction is already applied to MOTIR-3719's body and to the shipped code comment. This is the telemetry record.

What the card claimed

MOTIR-3719 was filed as "a dead arm plus a live uncaught path". Its second half:

resolveCodeContext(...) can throw a MotirAiError and is issued before the try … So the one live MotirAiError path on this page is uncaught — motir-ai being unreachable renders the server-error page rather than the degraded surface the code was written to show.

That claim also carried the card's whole priority argument, in explanationMd: "the live half is the cost".

It is false, and one command shows it

resolveCodeContext reaches no motir-ai client. On origin/main bed2bbc52:

$ grep -n "^import" lib/ai/codeContext.ts
1:import { githubInstallationRepository } from '@/lib/repositories/githubInstallationRepository';
2:import { githubRepoRepository } from '@/lib/repositories/githubRepoRepository';
3:import { withWorkspaceContext } from '@/lib/workspaces/context';

and the whole closure of those three is @/lib/db + @/generated/prisma/client. Every MotirAiError in the codebase is constructed in lib/ai/motirAiClient.ts (plus one site in projectLessonsService), which nothing on that path imports. The module's own header states it outright — "A DB read ONLY (the 891 mirror rows) — never a GitHub API round-trip on the submit path."

Not drift. git log --oneline e88d3d73..HEAD over the page, lib/ai/codeContext.ts and CodeHealthClient.tsx is EMPTY, so the three files are byte-identical between the card's base and main: the premise was false when written, not overtaken.

The mechanism, which is the part worth keeping

The claim was inferred from the module PATH, not from the module. The card's first half is exemplary — it enumerates every aiConventionService call site, walks all four paths through loadCodeHealthSurfaces, and proves the arm dead by exhaustion. The second half asserts a throw for a function under lib/ai/ whose name reads as an AI call, with no call site named and no import read.

Two properties make this hard to catch rather than careless:

  1. The two halves are stated in one voice. A reader who verifies the first half — which rewards verification richly — carries that confidence into the second, and the second is one sentence long.
  2. A directory is a plausible-looking authority. lib/ai/ holds the motir-ai client, its errors and its types; codeContext is genuinely for an AI planning job. The path is not misleading by accident, and it is still not evidence about what a function throws.

The cost, and why it is not zero

The false half is what made the card a defect rather than a cleanup: it set the priority argument and it framed the decision as a real fork (resolveCodeContext moves inside the try or the arm goes). With the premise falsified, option (a) is vacuous — moving a call that cannot raise a MotirAiError makes the arm no less dead — and the design asset had already settled the answer. The run spent its first block re-deriving a fork that had one arm.

What would have caught it

The card's own first half is the method: name the call site, or read the import closure. A claim that X throws Y is checkable in one grep for Y's construction sites plus one for X's imports — the same two commands that make the dead-arm proof convincing, applied to the sentence beside it. The authoring-side rule this belongs to is plan-rules/phase-deepen.md's precondition-verification limb: a claim about what a function CAN raise is a precondition, and a module path is not a reading of one.

Acceptance criteria

  1. Nothing to build. The correction is on MOTIR-3719 — the falsified section is struck through with its evidence rather than deleted, explanationMd's cost argument is restated, and AC 2 names the limb that discharges it.
  2. app/(authed)/code-health/page.tsx carries the finding at the resolveCodeContext call site, so the next reader meets it instead of re-deriving it (PR #2403).