Removes the dual-write into messages.tool_calls / messages.tool_results JSON columns and drops the columns. message_parts is now the only source of truth for tool calls and tool results. 10 dual-write sites stripped (5 in tool-phase.ts, 2 in routes/skills.ts, 2 in routes/messages.ts, 1 in routes/chats.ts fork-clone). The recon-driven grep caught 2 sites beyond the original v1.13.2 roadmap inventory and an extra fixture file (tool_cost_stats.test.ts) with a direct legacy-column INSERT. messages_with_parts view rewritten to parts-only subselects (COALESCE fallbacks gone). View runs via CREATE OR REPLACE so it lands before the column DROPs in startup DDL — Postgres rejects column-drop on view-referenced cols. v1.12.1 cleanup DO block (DROP CONSTRAINT messages_status_check / messages_role_check) removed; those one-shots have done their work. Adversarial review caught a runtime bug the green test suite missed: the discard_stale endpoint (chats.ts) had a RETURNING ... tool_calls, tool_results clause that would have crashed on every 60s-no-token-activity recovery in production. Fixed by switching to two-step UPDATE returning id, then SELECT from messages_with_parts so parts-synthesized fields keep flowing on the wire. Message API type retains tool_calls? / tool_results? — the view synthesizes those keys from parts so the wire shape is unchanged; frontend reads need no update. Override on the original v1.13.2 plan, captured in the openspec proposal. 339/339 server tests passing (including 7 DB-integration tests that applied the schema migration to a live DB and ran the parts-only view end-to-end). tsc + web build clean. Pairs with v1.13.0-ai-sdk-v6 (introduced the dual-write) and v1.13.1-B (moved the read path to messages_with_parts). Umbrella v1.13 tag ships on this same commit, marking the strangler-fig closed. CLAUDE.md picks up Sam's pre-existing edits documenting tag-naming and CHANGELOG conventions — both already in use by v1.13.19 / v1.13.20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.1 KiB
5.1 KiB
v1.13.20-drop-legacy-cols tasks
B1 — Recon (STOP after this step)
- Grep
apps/server/src/**/*.tsfor everytool_callsandtool_resultsmention. Categorize each hit as:- dual-write (an UPDATE / INSERT that writes the JSON column)
- read (a SELECT that reads the JSON column, or code that destructures it from a row)
- type-only (interface / type field reference)
- test fixture (literal in a test file)
- comment / docs
- Confirm the v1.13.2 roadmap inventory is complete:
- tool-phase.ts: 3 sites
- error-handler.ts (
finalizeCompletion): 1 site - routes/skills.ts: 2 sites
- routes/messages.ts (answer flow): 1 site
- routes/chats.ts (fork): 1 site
- Any extras the grep finds: list them
- Confirm no READ sites still touching the legacy columns (everything should go through
messages_with_parts). If reads remain, flag them — they need to migrate to the view BEFORE dropping the columns. - Hand back inventory as a per-file table: file, line, kind (dual-write / read / type / fixture), action (delete / migrate-to-view / type-prune).
B2 — Backups
cp <file> <file>.bak-v1.13.20-20260523for every file in B1's action list before editing.
B3 — Remove dual-writes
- Remove the JSON-column UPDATE / INSERT at every site identified in B1 as a dual-write. Keep the paired
insertParts(...)call. - If a site only writes the JSON column with no parts pair (would indicate a bug from v1.13.0) — STOP, report as BLOCKED.
- Verify by grep: zero remaining writes to
tool_callsortool_resultsoutside ofschema.sqland test fixtures.
B4 — Simplify messages_with_parts view
- Open
schema.sql. Find the view definition. - Drop the COALESCE fallbacks that read
m.tool_calls/m.tool_resultsfrommessages. - View now reads only from
message_partsjoined tomessages. - Confirm view's output column shapes are unchanged:
tool_calls jsonb[],tool_results jsonbsingle object,reasoning_parts jsonb[].
B5 — Drop columns
ALTER TABLE messages DROP COLUMN IF EXISTS tool_calls;ALTER TABLE messages DROP COLUMN IF EXISTS tool_results;- Idempotent on re-run.
- Apply order in
schema.sql: AFTER the view is updated (view depends on the columns; can't drop a column referenced by a view). - Actually verify the order — if the view references the columns, you must drop the view first OR change it before the ALTER.
B6 — Remove v1.12.1 cleanup block
- Find the
DO $$ DROP CONSTRAINT messages_status_checkblock inschema.sql(likely near the messages CHECK constraints). - Confirm it's safe to remove (the constraint should have been dropped long ago).
- Delete the block.
B7 — Type pruning
apps/server/src/types/api.ts— removetool_calls?andtool_results?from theMessageinterface.apps/web/src/api/types.ts— mirror byte-for-byte.- Search for any other type references —
ToolCallsField,ToolResultsField, etc.
B8 — Test fixture updates
- Run
pnpm -C apps/server testto see what breaks. - For each failing test that constructs a
Messageliteral withtool_calls: null/tool_results: null— remove those fields. - For tests that exercised tool-call behavior via the legacy columns, rewrite to construct via
message_partsrows. - Confirm:
pnpm -C apps/server test— all green.
B9 — Type / build verification
npx tsc --noEmit -p apps/server— 0 errors.npx tsc -p apps/web/tsconfig.app.json --noEmit— 0 errors.pnpm -C apps/web build— green.
B10 — STOP checkpoint, hand back diff
- Hand controller the diff for backend changes + test results.
B11 — Schema deploy
docker compose up --build -drebuilds with new schema.- Boot twice in sequence — confirm idempotent (column DROP IF EXISTS is a no-op on the second boot).
docker exec boocode_db psql -U boocode -d boocode -c "\d messages"— confirm columns absent.docker logs boocode 2>&1 | tail -50— confirm no schema errors.
B12 — Smoke
- Live-smoke: send a chat that triggers at least one tool call. Confirm:
- Assistant message renders with content + tool_call ActionRow.
- Tool result renders.
- No console errors in browser or
docker logs boocode.
- Trigger a compaction-eligible turn (long context). Confirm rolling summary anchors correctly.
B13 — Docs
CHANGELOG.mdentry for v1.13.20-drop-legacy-cols.boocode_roadmap.mdretrospective bullet on the v1.13.2 section (note the slug rename and ship date).CLAUDE.md— drop the v1.13.0 dual-write notes that no longer apply. Audit the surrounding paragraphs.
B14 — Tag + push + rebuild
git addonly the v1.13.20 batch files (per CLAUDE.md convention).git commitwith HEREDOC commit message.git tag v1.13.20-drop-legacy-colsANDgit tag v1.13(umbrella, per original v1.13.2 plan).- Push:
GIT_SSH_COMMAND="ssh -i /opt/boocode/secrets/boocode_gitea -o IdentitiesOnly=yes" git push origin main - Push both tags.
docker compose up --build -d.- Curl health check.