chatTools monolith split into typed tool registry
Archibald312 broke a 3,284-line orchestration file into ten per-tool modules behind a single registry. The orchestrator shrank by roughly 70% and now handles only what genuinely belongs there.
The old chatTools.ts held four schema arrays, a monolithic dispatch chain, and all ten callable tools jammed together. The new shape: each tool gets its own file with a ToolDefinition export, a registry array collects them, and a single dispatcher routes calls. Shared helpers for document reading, docx generation, and tracked-edit persistence live alongside as separate modules.
The gating logic changed too. Previously, callers threaded tool availability in via extraTools pass-throughs. Now each tool carries an availableWhen predicate that encodes whether it needs a project ID, a tabular store, or a document index. The project-chat and tabular-review routes drop their pass-through entirely.
Behavioral surface is held stable: tool schemas reproduced verbatim, SSE event shapes unchanged, aggregated side-effect counters (docsRead, docsFound, docsCreated, docsReplicated, workflowsApplied, docsEdited) carried through.
The test picture is honest about its gaps. Unit suite was green; three of four e2e specs passed. The chat/documents/projects/tabular Playwright specs were already parked on main behind test.describe.skip() due to drifted selectors before this PR landed, so the new dispatcher hasn't been exercised end-to-end under automation. A follow-up to fix those selectors is queued. Two adjacent findings (a log-out redirect change, a missing user_profiles migration in the test Supabase project) went to TECHDEBT rather than this PR.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?