(motir-core) The `@planner-bug-home` marker resolves through a mutable child row, so a single re-parent silently stops it resolving
Repo: motir-core · ONE PR. Found 2026-08-05 while verifying that re-filing the captured-mistakes story into the agent-loop epic was safe.
⚠️ Corrected 2026-08-05 — the original impact claim was WRONG
This card first said the marker path was live and "every auto-filed planner bug 404s", so the inward loop, the outward loop and log_planning_bug could no longer file. That is false, and it was asserted without reading the deployment. Read off the platform:
fly machines list -a motir-ai → MOTIR_META_BUG_PARENT_KEY = 'MOTIR-1465'
fly secrets list -a motir-ai → no MOTIR_META_BUG_PARENT_KEY (nothing overrides it)
Production sends the literal numeric key, not the marker, so isPlannerBugHomeMarker() is false and fileBug takes the getWorkItemByIdentifier branch — a direct identifier lookup that never reads parentage. Filing has worked throughout, including during the window this card called an outage. MOTIR-1466 taught motir-core to resolve the marker but motir-ai was never re-pointed to send it; fly.toml's own comment records the unfinished handoff ("after which this is re-pointed").
So there is no outage — dropped from high to medium. What remains is a real latent defect on a path nothing currently takes, which must be fixed before that re-point happens.
The defect
aiWorkItemsService.fileBug resolves @planner-bug-home in two hops:
- find the
epictitledPLANNER_BUG_HOME_EPIC_TITLE; - take its first child of kind
storyas the bug parent.
Hop 2 returns nothing today: MOTIR-1464's ~26 children were all bug/task once the home story was re-parented, so the marker raised WorkItemNotFoundError → 404. getFirstChildOfKind(epic, 'story') is a positional read of mutable structure wearing the clothes of a stable marker — the same fragility the marker was introduced to escape when it replaced the numeric key. And because the consumer swallows a failed file by design, the failure would be invisible.
The fix — resolve the home STORY by its own title
Auto-filed bugs land in MOTIR-1465 (Yue, 2026-08-05). The marker resolves in ONE hop to the story whose title is PLANNER_BUG_HOME_STORY_TITLE, looked up project-wide, so where that story sits in the tree is irrelevant — no move_to_parent anywhere can void it. The epic is no longer a resolution input; getFirstChildOfKind is deleted from the service and the repository so the positional read cannot return.
The live story was renamed to exactly Captured planning-mistake bugs, so one literal is shared by the constant, the resolver and the migration's SQL.
Acceptance criteria
- Resolving
@planner-bug-homeno longer depends on the home epic having astorychild positioned first; the mechanism it does depend on is one amove_to_parentcannot void, and the card states which mechanism was chosen and why. - The marker resolves to MOTIR-1465 — auto-filed bugs land under that story, not the epic and not project-root.
- A test drives resolution against a fixture whose home epic has only non-
storychildren and asserts it still resolves — the exact state that was live, so the regression cannot recur unobserved. - A test re-parents the home story to an unrelated epic and asserts the marker still resolves to it.
- A resolution failure is observable: it raises or logs at a level a human sees, rather than being swallowed on the background filing path. A test asserts the failure signal.
PLANNER_BUG_HOME_MARKERkeeps its current literal value, so no motir-ai config change is required (the cross-repo contract inlib/ai/plannerBugHome.tsstays intact and this stays ONE repo, ONE PR).- The existing
tests/integration/migrations/ensure-planner-bug-home.test.tsliteral-sync assertion stays green.
Out of scope — the follow-up this uncovered
Re-pointing motir-ai's MOTIR_META_BUG_PARENT_KEY from MOTIR-1465 to @planner-bug-home is MOTIR-1466's unfinished half and is NOT this card — it ships in motir-ai (one env value + a deploy) and would straddle the repo boundary. Until it happens this fix changes nothing in production; after it happens, the numeric key stops dangling on a tenant rebuild. Needs its own card.
Context refs
lib/services/aiWorkItemsService.ts—fileBug; the two-hop marker resolution.lib/ai/plannerBugHome.ts—PLANNER_BUG_HOME_MARKER, the title constants, and the header documenting the cross-repo config contract.prisma/migrations/20260701130000_ensure_planner_bug_home/migration.sql— the one-shot backfill, and its own note that it is not a per-deploy guarantee.app/api/internal/ai/work-items/route.ts— the service-auth route the marker arrives on (MOTIR-1450).- motir-ai
fly.toml[env]+src/services/lessonService.ts— the consumer, still on the numeric key; unchanged by this card.