Documentation source
Tech Debt Pass 4
Close tool-layer tenant scoping gaps, collapse duplicate entity-tool mutations onto shared services, refresh backlog priorities, and restore local verification.
## Problem Recent `dev` work kept expanding the view/block/tool surface area while some of the most sensitive tool paths drifted away from the shared entity services. The result was two immediate platform risks: 1. Entity and response tools were doing admin-client record access by ID without always enforcing `tenant_id`. 2. Entity tools reimplemented entity CRUD and relation writes instead of reusing the tenant-scoped keyed entity services, which made behavior drift and increased bug surface. The broader backlog had also gone stale: several old auth items were already fixed on current `dev`, while newer architecture debt around exploratory view/block growth and legacy extraction paths was underrepresented. ## Goals - Fail closed on tenant scoping for agent-facing tools. - Reduce duplicate mutation logic in the tool layer. - Add regression coverage for the scoped paths. - Refresh the backlog so the next cleanup pass targets real current debt. - Restore local verification by fixing the localized code-side typecheck regression. ## Scope ### In scope - `features/tools/entity-tools.ts` - `features/tools/response-tools.ts` - `features/tools/server/actions.ts` - Focused regression tests for those paths - Backlog refresh notes - Local typecheck unblock for `features/graph/hooks/use-graph-data.test.ts` ### Out of scope - Re-architecting the view/block system in this pass - Removing custom workspace views from record detail - Full extraction/runtime consolidation - Sweeping lint-warning cleanup across the repo ## Changes ### 1. Tenant-scoped tool reads and writes - `getEntity` now resolves records through `getEntityByIdKeyed(tenantId, id)`. - `createEntity`, `updateEntity`, `deleteEntity`, and `createRelation` now route through the keyed entity services instead of open-coding admin-client mutations. - `submitResponse` now resolves the entity type using `tenant_id` in addition to `id`. - `getToolRunById` now scopes by active tenant. ### 2. Shared mutation path - Entity tool CRUD now reuses the same keyed services used by API-key routes. - Activity logging for relation creation is handled through `logTenantActivity` rather than another inline insert path. - This narrows the number of places where entity-write behavior can diverge. ### 3. Regression coverage - Added tests that assert entity tools delegate to tenant-scoped keyed helpers. - Added test coverage for response-tool tenant scoping. - Added test coverage for tool-run tenant scoping. ### 4. Verification repair - Fixed the localized test typing issue in `use-graph-data.test.ts` so `pnpm typecheck` is no longer blocked on that code path. - The remaining `lib/docs-source.ts` failure is a generated-artifact issue and is handled by regenerating `.source/` locally before verification. ### 5. Legacy extraction route consolidation - Extracted shared extraction submission/sync logic into `features/entities/extraction/server/submissions.ts`. - Updated `run-extraction.ts` and the deprecated external submit route to share the same response-sync path instead of maintaining separate promotion logic. - Reduced route-layer business logic in `app/api/extraction/[entityId]/submit/route.ts` so it is now primarily auth, validation, and response mapping. ### 6. Record detail default-path simplification - Extracted detail-view selection into a tested helper so the record page no longer decides view state ad hoc in the client. - Changed entity detail back to schema-first default behavior: custom workspace views now activate only when a specific `?view=` is requested. - Reduced server work and bug surface by resolving blocks for only the selected custom detail view instead of resolving every workspace view on every record request. ### 7. Block/view canonical config cleanup - Moved legacy block-config migration to the parse/normalization boundary so older `field-card.fieldName` and `stat-cards.stats` shapes are standardized automatically on read and write. - Simplified `resolveDetailViewBlocks()` and editor previews to assume the canonical `fields: string[]` shape instead of carrying render-time compatibility branches. - Stopped the field-card config panel from writing legacy keys back into saved views. - Removed obsolete diagnostic warnings for legacy config shapes that are now auto-canonicalized. ### 8. Dead resolver-wrapper removal - Removed the unused `collectViewBlocks()` and `resolveViewBlocks()` exports from `features/blocks/lib/from-entity-view.ts`. - Tightened `resolve-view.ts`, architecture docs, and block-system docs so `resolveView()` is the documented entry point and the remaining helpers are clearly internal implementation details. ### 9. Unified entity-single resolution and flattened-view alignment - Folded the remaining entity-single resolver logic into `resolveView()` and deleted `features/blocks/lib/from-entity-view.ts` entirely. - Moved regression coverage onto `resolve-view.test.ts` so the supported contract is tested at the actual public entry point. - Updated the live docs to match the flattened `views` model already encoded in migrations: flat `blocks`, `block_order`, `data_sources`, and `layout`, without regions/tabs/presets in the runtime contract. ### 10. Extraction review and workflow-state cleanup - `approveResult()` and `rejectResult()` now synchronize linked `entity_responses` so extraction review cannot diverge from the canonical response runtime. - `/api/workflows/[entityId]` no longer fetches and returns legacy extraction rows that the workflow UI does not use. - Deleted the dead extraction-progress/history/result-row components that were no longer mounted anywhere in the app. - Updated the architecture docs to describe the workflow-first status UI and the extraction tables as compatibility/audit surfaces rather than the primary runtime. - Restored tenant scoping on the deprecated extraction-history path so `getExtractionRunHistory()` and `/api/extraction/[entityId]/history` no longer rely on `entity_id` alone. - Deleted the dead `/api/enrich` compatibility wrapper and the unused extraction barrel so fewer legacy workflow entry points remain available. ### 11. Canonical internal naming for server-resolved blocks - Renamed the remaining collection/aggregation helper from the deprecated `resolve.ts` path to `resolve-server-blocks.ts`. - Renamed the helper export to `resolveServerBlocks()` so `resolveView()` is the only documented/public block resolution entry point. - Updated tests and live docs to describe the helper as an internal implementation detail rather than another supported resolver API. ### 12. Dead compatibility-shim removal - Deleted the unused `features/entities/components/registry.ts` alias now that the codebase imports the canonical entity-card registry/types directly. - Removed stale docs references to `/api/enrich` so the documented manual workflow trigger path matches the actual runtime surface. ### 13. Workflow-route parity and non-mutating legacy view fallback - Added shared workflow API access resolution so `/api/workflows/[entityId]` and `/api/workflows/[entityId]/history` now support the same API-key tenant/scoping rules that the deprecated extraction trigger/history wrappers used. - Updated the single-field rerun dialog to call the canonical workflow trigger route directly with `triggerType: "feedback_rejected"` and field overrides. - Removed the deprecated extraction trigger/history/rerun wrappers once the workflow endpoints fully covered that functionality. - Replaced entity-type-page write-on-read migration with a deterministic synthetic legacy dashboard view so old `config.dashboard.sections` still render without creating DB rows during page load. - Stopped the record-detail client from recomputing detail-view selection; the server now passes one unified selection payload alongside resolved blocks. ## Audit outcomes ### Fixed in this pass - Tool-layer tenant scoping gaps for entity reads/writes - Duplicate entity tool mutation orchestration - Tool-run single-record scoping gap - Local graph hook test type regression - One legacy extraction-response duplication path in the external submit route - Extraction review no longer updates only legacy audit rows when a canonical response link exists - Extraction-history compatibility reads are tenant-scoped again instead of relying on entity ID alone - The dead `/api/enrich` workflow wrapper and unused extraction/entity-card compatibility barrels are removed - The default record-detail request path no longer resolves workspace views unless explicitly requested - Legacy field-card/stat-card config compatibility no longer leaks into the block render path - Dead wrapper exports around the old entity-view resolver path are removed - The old entity-detail resolver module is removed and entity-single resolution now lives behind `resolveView()` only - The deprecated `features/blocks/server/resolve.ts` entry point is gone; only `resolveView()` remains as the supported resolver contract - The record-detail client no longer runs a second custom-view selection pass on top of the server result - Workflow trigger/status/history routes now provide API-key parity, so the deprecated extraction trigger/history/rerun wrappers are removed - Legacy dashboard configs no longer create persisted views as a side effect of reading an entity-type page ### Still high priority - Record detail still carries the workspace-view/editor system as optional page surface even though the default path is now schema-first again. - Extraction audit/result compatibility APIs and tables still coexist with workflow/response execution. - Some legacy dashboard/view schema compatibility code still exists even though the resolver stack is now standardized behind `resolveView()`. - Some historical planning docs still reference removed compatibility surfaces and need occasional pruning as those surfaces are deleted. - Current backlog counts and some historical P0/P1 items needed rescoring against current `dev`. ## Follow-up queue 1. Continue narrowing record-detail customization so the optional workspace-view/editor surface stays aligned with the schema-first default. 2. Retire or hard-freeze the remaining extraction audit compatibility surface behind the workflow/response runtime. 3. Prune the remaining view/schema compatibility shims and historical docs that still imply write-on-read migration behavior. 4. Keep route verification healthy by regenerating `.source/` as part of environment setup or CI.