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:
- Entity and response tools were doing admin-client record access by ID without always enforcing
tenant_id. - 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.tsfeatures/tools/response-tools.tsfeatures/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
getEntitynow resolves records throughgetEntityByIdKeyed(tenantId, id).createEntity,updateEntity,deleteEntity, andcreateRelationnow route through the keyed entity services instead of open-coding admin-client mutations.submitResponsenow resolves the entity type usingtenant_idin addition toid.getToolRunByIdnow 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
logTenantActivityrather 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.tssopnpm typecheckis no longer blocked on that code path. - The remaining
lib/docs-source.tsfailure 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.tsand 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.tsso 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.fieldNameandstat-cards.statsshapes are standardized automatically on read and write. - Simplified
resolveDetailViewBlocks()and editor previews to assume the canonicalfields: 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()andresolveViewBlocks()exports fromfeatures/blocks/lib/from-entity-view.ts. - Tightened
resolve-view.ts, architecture docs, and block-system docs soresolveView()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 deletedfeatures/blocks/lib/from-entity-view.tsentirely. - Moved regression coverage onto
resolve-view.test.tsso the supported contract is tested at the actual public entry point. - Updated the live docs to match the flattened
viewsmodel already encoded in migrations: flatblocks,block_order,data_sources, andlayout, without regions/tabs/presets in the runtime contract.
10. Extraction review and workflow-state cleanup
approveResult()andrejectResult()now synchronize linkedentity_responsesso 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]/historyno longer rely onentity_idalone. - Deleted the dead
/api/enrichcompatibility 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.tspath toresolve-server-blocks.ts. - Renamed the helper export to
resolveServerBlocks()soresolveView()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.tsalias now that the codebase imports the canonical entity-card registry/types directly. - Removed stale docs references to
/api/enrichso 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]/historynow 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.sectionsstill 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/enrichworkflow 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.tsentry point is gone; onlyresolveView()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
- Continue narrowing record-detail customization so the optional workspace-view/editor surface stays aligned with the schema-first default.
- Retire or hard-freeze the remaining extraction audit compatibility surface behind the workflow/response runtime.
- Prune the remaining view/schema compatibility shims and historical docs that still imply write-on-read migration behavior.
- Keep route verification healthy by regenerating
.source/as part of environment setup or CI.
Sprinter Platform Package Migration
Compare Amble to the live Sprinter Platform package and registry surface, identify where Sprinter is ahead, and define a batch migration plan to consume @sprinterai packages and selective registry UI.
Unified Agent Intelligence
Consolidate feedback intake, self-improvement, admin review, and eval systems into a thin harness around two primitives — feedback inputs and shared_context outputs — that turn every agent interaction into durable workspace intelligence.