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

Planning bug: the totality rule (#29) cannot reach a renderer keyed on a DATABASE-defined set — a `Record<Union, …>` is total against a union that is itself the hand-authored subset, so the compiler certifies the lie

Done
Description

Type · planning mistake (RECORD card — the correction is already applied) · Parent · MOTIR-1465, the planner-bug home · Discovered in · filing MOTIR-3170, 2026-08-19 · Repo · motir-meta (the deliverable is a notes.html entry; no product code)

What the plan missed

MOTIR-3170: the planning / roadmap / plan-detail canvas draws a card at implemented or planning as To Do. Three files each keep a private six-member copy of the workflow status set and coerce anything outside it to todo.

Two cards were supposed to make a new status visible everywhere, and both enumerated their sweep correctly and incompletely:

  • MOTIR-3003 added implemented to STATUS_KEY_EL — the DOT map.
  • MOTIR-3103 added the CHIP, under the heading "The call sites — SEVEN, and every one already has the key / Verified by reading them, not remembered". Seven is the exact number of STATUS_TONE consumers, and the enumeration is correct.

The canvas is not one of the seven, because it does not consume STATUS_TONE. It has STATUS_META — a third, independent status vocabulary — and no card has ever counted it. A sweep enumerated over the callers of the symbol you are changing is structurally blind to a surface that re-implements it.

Why the existing rule did not reach it

notes.html #29 already states the Totality rule for lookup layers:

Any metadata map, switch, validator, or renderer keyed off an enum/discriminant must be total over every value that enum can actually hold in the database.

That is exactly this defect's class, it is always-injected, and it did not fire — the order-beats-density shape (the third promote test: has this check already been written as a rule and failed since?). The reason it did not fire is worth stating precisely, because it is the new limb:

#29 presumes a CLOSED enum. STATUS_META IS declared Record<WorkItemStatus, StatusMeta> and IS total — over WorkItemStatus, a six-member union hand-authored in the same file. TypeScript reports nothing, a reviewer asking "is the map total?" gets yes, and the answer is worthless, because the union is the subset. The real discriminant is workflow_status, a TABLE: a project defines its own statuses, RoadmapNodeDto.status is typed string for exactly that reason, and defaultWorkflow alone has eight rows against the union's six.

So the check #29 asks — "is the map total over the enum?" — is unanswerable by inspection at the map. It has to be asked one level up: what defines this discriminant's membership, and can the compiler see it? When the answer is "a database row set", a closed Record is not totality; it is a subset with a totality certificate.

The second half is the degrade. toStatus does not fall through to a neutral render — it returns 'todo', the name of a real, specific state the card is definitively not in. A partial map that throws or blanks announces itself; one that resolves to a plausible sibling value never will. An open discriminant needs a fallback that carries the real value through, not one that picks a default member.

Fix applied / Resolution taken

  • MOTIR-3170 filed under MOTIR-2200, motir-core, 5 pts / 100 min — with the fix scoped as the general rule (carry statusLabel + statusCategory on the roadmap DTO; resolve key → category → neutral; delete all three literals) rather than as two more map rows. Its own repeat-defect section records the five occurrences.
  • No plan structure changed: nothing was re-parented, re-scoped or archived. This is a record, not a correction.
  • Lesson: notes.html #334the totality certificate over a hand-authored union (motir-meta PR, branch docs/canvas-status-literal-lesson). #333 was taken by a sibling session's PR #270 while this was being written; the number here is the next free one and the count bump must be reconciled against whichever lands first.

The promote question — RULE tier, deliberately NOT claimed here

This card ships the LESSON only. Whether the limb belongs in the RULES tier is this record's close-out deliverable, and the evidence is assembled so it can be settled in one read rather than re-derived:

  • Same check or family resemblance? Same check. implemented (MOTIR-3003), planning (MOTIR-2425) and every custom status all fail the identical predicate in the identical three files. Not one incident in four costumes.
  • Already written and failed since? Yes — #29, verbatim, including the word renderer. That is the condition MOTIR-1886 / notes #177 used to promote on three occurrences rather than four-in-two-days.
  • Register? The limb states a situation and an action without needing the incident: when a discriminant's membership is defined by DATA rather than by a TypeScript enum, a Record<Union, …> is not totality — resolve by key with a fallback that preserves the value's own identity. Rule register, not narrative.

If the close-out answers SHARPEN it is TWO cards, not one: a motir-meta W card and its (motir-ai) Mirror W<n> into SHARED_PLANNING_RULES sibling, blocked_by it, both under MOTIR-1464. Checked 2026-08-19 so the close-out does not have to — the open W series is W6 (MOTIR-2929 / MOTIR-2930), W7 + W7b (MOTIR-2953 / MOTIR-2954), W8 (MOTIR-2962 meta, MOTIR-2963 mirror), W9 (MOTIR-2987 meta, MOTIR-2989 mirror) and MOTIR-3072, and none of them touches the totality / lookup-layer region. So this would be a NEW W number, not an amendment to an existing one; read MOTIR-1464's child list for the next free one before filing. (Re-verify the pairing by reading MOTIR-1464's children — the keys above come from a SHARED_PLANNING_RULES text search, which finds the mirror halves reliably and the meta halves only when they name the constant.)

Acceptance criteria

  • git show origin/main:notes.html | grep -c 'mistake-num">334<' returns 1, and the entry it opens is this lesson — matched by CONTENT (the phrase totality certificate), not by trusting the numeral.
  • That entry's Lesson section states the limb #29 does not carry: that a Record over a hand-authored union proves nothing when the discriminant's membership is defined by a table, and that the honest fallback preserves the value rather than picking a default member.
  • The Across the N mistakes count in notes.html matches the highest mistake-num present after the merge — reconciled against PR #270's bump rather than clobbering it.
  • The promote question above is answered ON THIS CARD (a comment naming SHARPEN or LESSON with its reason) before the card is closed, and if SHARPEN, the two W cards exist and are blocked_by-wired before it closes.
  • No product code is changed by this card; git diff --name-only origin/main in motir-meta shows notes.html and nothing else.

Context refs

  • MOTIR-3170 — the product defect this records, with the file-level diagnosis and the reproduction
  • notes.html #29Totality rule for lookup layers, the rule this incident falsifies at its edge
  • MOTIR-3003 · MOTIR-3103 — the two sweeps that were correct and incomplete; 3103's "the call sites — SEVEN" table is the artefact
  • motir-core/components/planning/WorkItemNode.tsx:59-98WorkItemStatus + STATUS_META, the closed union with the totality certificate
  • motir-core/lib/dto/workItems.ts:644RoadmapNodeDto.status: string, the open discriminant on the wire
  • motir-core/lib/workflows/defaultWorkflow.ts — eight statuses against the union's six
  • MOTIR-1464 — the W-series epic, if the close-out answers SHARPEN

Resolution

Open — lesson authored as notes.html #334; the promote question is unanswered.