Delete the core tool-name tables; rows render from persisted data and structure (WS3 layer 5) - #2232
Delete the core tool-name tables; rows render from persisted data and structure (WS3 layer 5)#2232SawyerHood wants to merge 1 commit into
Conversation
1df241b to
8f319cf
Compare
… structure (WS3 layer 5) Core no longer keys any projection on a tool name. The thread-view DELEGATION/READ/SEARCH/LIST name sets, the suppression name set, the TodoWrite-by-name todo reader and @bb/domain's claude-task-tools are gone; statusLabels leave the event, the timeline row and the daemon wire (HOST_DAEMON_PROTOCOL_VERSION 150 -> 151); the events.tool_name virtual column and its index are replaced by kind-based partial indexes (migration 0107); turn/plan/updated leaves the noise list and decodes at read time into a planSteps item so legacy codex plans still render. A persisted tool call that other rows name as their parentToolCallId becomes the delegation row structurally (same row id as before, label metadata from conventional argument keys), so old threads keep their nesting. Pi's read/grep/find/ls knowledge moves into its own translation as fileRead/search items. The corpus gate gains an identity-based row-class mode (BB_PROVIDER_CORPUS_ROW_CLASSES) because a change that adds, removes or moves rows cannot be expressed by pointer allowlist; this layer's nine classes live in allowlists/ws3-layer5-row-classes.json. Co-Authored-By: Claude <noreply@anthropic.com>
8f319cf to
03479c3
Compare
Coordinator review — WS3 stack #2207Layers 1–4 (#2192, #2206, #2208, #2209): PASS. Layer 5 (#2232): PASS WITH ONE CONDITION — a layer 6 is required before the stack is complete. Do not merge: the stack accumulates until the full migration is done. Verified
The condition: old threads must not regress Four classes are improvements and stay: Five classes are regressions on threads the user already has, because those rows were persisted before bridges sent
The owner's standing constraint is "do not regress current behavior". A core with no tool-name tables is the target for the live path; it does not require history to change. Layer 6 — legacy read-time adapter (required) In
Then Left for the owner: iOS simulator QA (no simulator on this box; Maestro flow extended in layer 3).
|
Stack #2207, layer 5 of 5 (on #2209 ← #2208 ← #2206 ← #2192). Spec: WS3 "projection + renderers + mobile", delete layer.
What was wrong
Core still knew provider tool names.
packages/thread-viewcarried the Agent/Task/spawnAgent delegation set, the Read/Grep/Glob exploration sets, the TodoWrite/ToolSearch/AskUserQuestion suppression set, and a TodoWrite-by-name todo reader;@bb/domainshippedclaude-task-tools.ts; the server copied pluginstatusLabelsinto every tool-call event; theeventstable had atool_namevirtual column with an index for name lookups; andturn/plan/updatedsat on the noise list so legacy codex plans never rendered. Layers 1–4 taught every client to read the bridge-ownedpresentationand the grammar v3 kinds beside those tables. With the tables still there, a plugin provider could not hide, label, or nest a row unless its tool happened to share a name with a first-party one.What changed
Deleted (core knows no tool names).
packages/thread-view/src/tool-call-parsing.ts: the DELEGATION/READ/SEARCH/LIST name sets, their predicates,baseToolName,stripAgentOutputMetadata. Shell wrapper handling,parseShellCommandIntents, andformatToolCallCommandstay.tool-call-suppression.tshonourspresentation.suppressonly.todo-snapshot-extraction.tsreadsplanStepsitems only.exec-lifecycle.tsprojects every tool call as a generic tool call.packages/domain/src/claude-task-tools.tsand theclaudeTaskTool*schemas in@get-bb/plugin-sdk/provider-bridge.statusLabels: off thetoolCallitem, the timeline tool row, the projection message, andapps/server/src/internal/events.ts(withPluginToolStatusLabels). The plugin-facingexperimental_statusLabelsfield still exists; the server folds it into the tool's resolved presentation, which the bridge stamps on every call (docs/api_to_audit.md entry updated).events.tool_namevirtual column and its index. Migration0107_kind_based_indexesreplaces them withevents_delegating_item_lookup_idx(item_kind IN ('toolCall','delegation'), covering) andevents_plan_steps_thread_sequence_idx(planStepscompletions orturn/plan/updated). Generated with drizzle-kit, thenIF EXISTS/IF NOT EXISTSadded so a rewound database replays.turn/plan/updatedleavestimeline-noise-events.ts.Replaced by structure or persisted data.
parentToolCallIdbecomes the delegation row (normalize-event-projection.ts). It keeps the:delegation:row id it had under the name set, so nested rows keep their ids, and takesdescription/subagentTypefrom conventional argument keys (argument shape, never a name). A v3delegationitem does not pass through this path.packages/domain/src/legacy-thread-events.tsconverts a persisted codexturn/plan/updatedinto aplanStepsitem at read time (deterministic id from turn + payload), so old codex threads show their plans and feed the todo banner.packages/db/src/data/events.ts: delegating-item and plan-snapshot queries select byitem_kind/typeliterals with the new indexes (query-plans.test.tspins both plans).packages/agent-runtime/src/pi/delta-translation.ts, which now emitsfileRead/searchitems with presentation (bridge-owned, like the other bridges).Wire.
HOST_DAEMON_PROTOCOL_VERSION150 → 151: thetoolCallitem lost its optionalstatusLabelskey and the daemon contract's guard for it, so an older daemon could still send the key. Compatibility was not tested, so the version bumps.Corpus gate. A pointer allowlist cannot describe a change that adds, removes, or moves rows.
apps/server/test/provider-corpus/row-diff-classes.tsadds an identity-based mode to the A4 gate (BB_PROVIDER_CORPUS_ROW_CLASSES=<file>): rows match bycallId/itemId/interactionId/turn id, every change must fall into a named class (added,removed,moved,resegmented,reshaped,changed+ fields), and a class that claims nothing fails the run. This PR's classes live inallowlists/ws3-layer5-row-classes.json;scripts/provider-corpus/classify-row-diff.tsruns the same engine offline over two snapshot dirs. Documented in docs/debugging-and-qa.md and the allowlists README. RelativeBB_PROVIDER_CORPUS_*file paths now resolve against the repo root as well as turbo'sapps/servercwd.Parity harness.
maskPathaccepts the root pointer (/) to empty one layer of one cell. One entry uses it (codex/user-question rows): the immutable v2 recording'sthread/startpredates the server-resolved tool presentation, so the replayedAskUserQuestioncall renders as a generic row where the old leg hid it by name; the live server sendssuppress: trueon the definition. The cell's row pin moves 1 → 2 for the same reason. Re-recording the cell drops both.How you verified
pnpm exec turbo run testfor@bb/thread-view(365),@bb/domain(150),@bb/db(406),@bb/client-core(239),@bb/cli(453),@bb/app(3209),@bb/provider-bridge-protocol(217),@bb/provider-parity(44),@bb/host-daemon-contract,@bb/agent-runtime,@bb/server; typecheck for@bb/serverand the above. New/changed tests: structural delegation (build-thread-timeline.test.ts: arbitrary tool name becomes a delegation only when referenced, keeps its id and argument metadata),todo-snapshot-extraction.test.ts(planSteps only; a TodoWrite-named call decides nothing),row-diff-classes.test.ts(5),query-plans.test.ts(both new indexes),migrate.test.tsrewind, Pi translation (read/grep/find/ls→ fileRead/search), host-daemon contract 151, parity self-suite root mask.exploration-intent-by-name4183 ·container-bounds712 ·unsuppressed-by-name567 ·legacy-plan-rows356 ·delegation-output-unstripped160 ·delegation-from-children145 ·parented-rows-surface141 ·delegation-rows-gain-v3-fields123 (Project grammar v3 items to presentation-driven rows (WS3 layer 1) #2192) ·turn-segments-rejoined24. Each class's reason is in the JSON file. Legacy threads render from persisted data: delegation rows keep their ids, nesting, description and subagent type; old codex plans appear as plan-steps rows.walk vs base0.73–1.04× (normalized min), synthetic 10k-event thread 161 ms full walk.pnpm parity --old ~/.bb/parity-old-main --new .→ 39 passed, 0 failed, 13 skipped (pi in-process, model-list), no stale entries.node scripts/check-provider-literal-ratchet.mjs148 → 148. The ratchet counts provider-ID literals and its header excludes tool-name keying, so this layer cannot move it; the remaining hits are plan-mode comments and the Claude model-fallback raw-event parser. Substitute measure, reproducible:git grep -c -E '"(Read|Grep|Glob|Edit|Write|Bash|Task|Agent|TodoWrite|TodoRead|ToolSearch|AskUserQuestion|TaskOutput|TaskStop|TaskCreate|TaskUpdate|TaskGet|TaskList|Monitor|WebFetch|WebSearch|spawnAgent|resumeAgent|update_plan|exec_command|apply_patch|read_file|list_dir|grep_search|file_search|shell)"'overpackages/thread-view/src packages/domain/src packages/db/src packages/server-contract/src apps/server/src/services/threads: main 31 → this PR 3, and the three left are the English words "Read"/"Reading" in row titles and the terminal"shell"mode.internal-skill-trees0644 vs 0664 under umask 0002 (passes in CI).Part of the WS3 stack; no issue number.