Skip to content

simplify(todos): make work_item_approvals the only approval storage - #111

Merged
hristo2612 merged 1 commit into
mainfrom
simplify/PLA-48-drop-frozen-approval-columns
Aug 3, 2026
Merged

simplify(todos): make work_item_approvals the only approval storage#111
hristo2612 merged 1 commit into
mainfrom
simplify/PLA-48-drop-frozen-approval-columns

Conversation

@hristo2612

Copy link
Copy Markdown
Owner

Selected area

Todo approval storage in packages/jinn/src/work-items/ — the work_items table's eight
approval_* columns and the read seam in store.ts that still mapped them onto WorkItem.

Evidence of over-engineering / blended concerns

Todos v2 slice 4 moved approvals into a dedicated work_item_approvals table but left the old
columns in place behind a "dual-read window" that was never closed:

  • Two storage owners, one of them write-dead. Nothing had written the eight approval_*
    columns since slice 4; every read already resolved through work_item_approvals. The columns
    survived only as shadow state, plus a backfillWorkItemApprovals call that re-ran on every
    gateway boot
    to keep copying from a table nobody wrote.
  • A silent-wrong-answer read path. rowToWorkItem returned a full WorkItem, populating the
    eleven approval fields from those dead columns — including three knowingly-wrong hardcoded
    defaults. Any read path that forgot to call hydrateApprovals compiled fine and returned an
    all-NULL approval state that looked authoritative. The correctness of the approval surface
    rested on every call site remembering an opt-in step.
  • Prose asserting a design that no longer existed. Comments in store.ts (:28, :274-281) and
    the requestApproval doc in approvals.ts described the columns as live, frozen, or
    dual-read.

Fixed constraint budget

Field Cap
netLineDelta ≤ 0
filesTouched ≤ 8
newFiles 0
maxFileLines ≤ 1180

Qualitative locks: exactly one new public export (V2_APPROVAL_WORK_ITEMS_TABLE_DDL); only
migrate.ts may end larger than base (the frozen legacy recognizer DDL has no deletable
counterpart); no new dependencies, config options, or single-caller abstractions;
packages/web/**, approval-rows.ts, approval-authority.ts, workflow-todo-binding.ts and
all payload field names untouched.

Measured budget (verbatim output)

Command from PLAN.md, run at HEAD 764a0aa36a34d4b00950daad5bffe70ceb819396:

netLineDelta=-6
filesTouched=7
newFiles=0
maxFileLines=1168 (packages/jinn/src/work-items/migrate.ts)

Per file:

 1  1  packages/jinn/src/gateway/__tests__/control-plane-authority.test.ts
18 31  packages/jinn/src/gateway/__tests__/work-item-approval-parity.test.ts
 4 26  packages/jinn/src/work-items/__tests__/approvals.test.ts
57 57  packages/jinn/src/work-items/__tests__/migrate-v2.test.ts
 3  3  packages/jinn/src/work-items/approvals.ts
72 36  packages/jinn/src/work-items/migrate.ts
35 42  packages/jinn/src/work-items/store.ts

Every touched file ends at or below its base line count except migrate.ts (1132 → 1168), the
one file the budget explicitly allowed to grow.

What was deleted / clarified

Deleted

  • The eight approval_* columns from the canonical WORK_ITEMS_TABLE_DDL, which cascades into
    REQUIRED_TABLE_SQL / verifyCurrentWorkItemSchema automatically. Fresh databases never get
    them; existing ones drop them via ALTER TABLE work_items DROP COLUMN.
  • The every-boot backfillWorkItemApprovals call. The backfill is now a one-shot step inside
    each rebuild path, parameterized by source table (work_items pre-drop for the v2 legacy heal,
    work_items_v1_legacy for the v1 rebuild).
  • Those columns from both v1-rebuild copy lists, the column reads in rowToWorkItem, its three
    wrong hardcoded defaults, and the frozen-columns test helpers (rawColumns,
    expectColumnsFrozenNull) whose covered behaviour is deleted along with the columns.
  • The falsified prose: no surviving comment claims the columns exist, are frozen, or are
    dual-read.

Clarified

  • rowToWorkItem now returns a module-local WorkItemRowBase = Omit<WorkItem, …approval fields>.
    overlayApproval is the only producer of the eleven approval fields, so a read path that
    skips hydration is a type error rather than a silent all-NULL authority bug. No new export,
    no runtime cost, no as WorkItem cast anywhere in the diff.
  • The pre-drop shape is frozen as V2_APPROVAL_WORK_ITEMS_TABLE_DDL (the existing
    V1_WORK_ITEMS_TABLE_DDL precedent) so a legacy database is recognized and classifies
    "current" — healable at boot inside the existing single immediate transaction, so backfill
    and drops commit atomically or not at all. No new preflight state.

Compatibility. Public payload field names and values are unchanged. The golden
work-item-approval-parity FIXTURES and pinned payloads are byte-identical; only their seeding
mechanism changed.

Test results

Run in the worktree at HEAD 764a0aa3, after the final commit:

  • pnpm typecheck — 2 tasks successful (@jinn/web, jinn-cli), clean.
  • pnpm test309 test files passed, 3829 tests passed, 1 skipped, 0 failed.
  • pnpm build — 2 tasks successful; web bundle built, dist/ compiled, assets synced.
  • pnpm lint — the repo defines no lint task, so this executes zero tasks (noted by the
    verifier, not treated as a passing gate).

Independently re-verified in round 2 by jinn-verifier with the turbo cache forced off, plus a
column-death grep across packages/jinn/src and packages/web/src returning empty.

Known gap: the migration was exercised through the test suite only (fresh-database, v2-legacy
fixture, and v1 fixture upgrade paths), not against a live gateway booting on a real
pre-PLA-48 home.

Todo: PLA-48

The eight `approval_*` columns on `work_items` had been write-dead since
Todos v2 slice 4 — every read already resolved through
`work_item_approvals`, but the columns stayed, `rowToWorkItem` still
mapped them, and three of its eleven approval fields were knowingly-wrong
hardcoded defaults. Drop them.

- `migrate.ts`: freeze the pre-drop shape as `V2_APPROVAL_WORK_ITEMS_TABLE_DDL`
  (the `V1_WORK_ITEMS_TABLE_DDL` precedent) and delete the columns from the
  canonical DDL, which cascades into `verifyCurrentWorkItemSchema`. A database
  matching the frozen shape classifies "current" and heals in the existing
  boot transaction: create the additive tables, copy the columns off-row, then
  `ALTER TABLE ... DROP COLUMN` each. `backfillWorkItemApprovals` takes its
  source table so the v1 rebuild reads `work_items_v1_legacy` before the drop,
  and it stops running on every boot — it is a one-shot rebuild step now.
- `store.ts`: `rowToWorkItem` returns a module-local `WorkItemRowBase` that
  omits all eleven approval fields, so `overlayApproval` is the only producer
  of them and a read path that skips hydration no longer typechecks.
- Fix the prose the removal falsifies (frozen / dual-read / `approval_state`).

Payload field names and values are untouched; the golden parity fixtures and
pins are byte-identical, only their seeding mechanism changed.
@hristo2612
hristo2612 force-pushed the simplify/PLA-48-drop-frozen-approval-columns branch from 764a0aa to c1a1e43 Compare August 3, 2026 10:06
@hristo2612
hristo2612 merged commit 4ec1899 into main Aug 3, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant