Wave 5 addendum appended below — original audit covered FIN Central vault and DB-side projections only. Wave 5 closes the gap on nathel-intranet tenant vault, Central↔Tenant taproot sync, tenant vault webhook, tenant projector, and end-to-end cross-taproot propagation. All Wave 5 verdicts: FAIL or DEGRADED. The tenant content layer has no producer and no transport. See “Wave 5 Addendum” section at the end of this doc.

FIN Projection System Audit — 2026-05-17

Scope: Both JSONB and MD format projections, across both FIN Central and Nathel tenants, including the vault → DB ingestion pipeline, the agent runtime’s tool access, the human UI’s drill-through experience, the closed-loop refresh + self-improvement mechanism, and the supporting registers/indexes.

Method: 15 work streams in 4 parallel waves, dispatched as general-purpose subagents with self-contained briefs. Each WS produced an evidence-backed report under .audit-2026-05-17/waveN/ws-NN-*.md. This document consolidates findings and the remediation backlog.

Master HEAD at audit time: dc2e36a2 (after PR #793 + #794 + #798 squash-merges).


TL;DR — Executive Summary

The “agentic ERP with closed-loop self-improving MD projection system that fuses universal + tenant intelligence” is architecturally sound but operationally cold. Schema is in place, RLS hardened, dispatch loop runs, ~544 tools registered, vault has 487 well-formed entity profiles. But the runtime never actually executes end-to-end:

  • 6.4% of the expected 4D projection matrix is operational (3 cells of 47 non-N/A; per WS-13).
  • The MD renderer worker (fin-central-renderer) is not deployed — entry-point file missing, Hyperdrive ID is placeholder; the 331 entity_doc rows are one-shot hand-seeds from 2026-05-17 02:02-03:34 UTC (per WS-03, WS-05).
  • The agent never uses the MD tools — 0 real-agent activations in 30 days; system prompt steers to legacy get_commodity_profile (per WS-08).
  • The UI strips what little exists — drill buttons are dead clicks (EntityRoute.tsx:282 calls CardRenderer with NO onAction prop); linked_entities never make it into tool envelopes (per WS-14).
  • fin-central staging is 21 migrations behind nathel — federation has nowhere to land (per WS-01, WS-12).
  • The self-improvement signal substrate IS in place — 19,198 system.scenario_eval_result events + 45 knowledge.domain_stale + 100%-populated knowledge.confidence/knowledge.version — but zero consumers wire them back into projections (per WS-15).

The audit’s framing: This is a deployment + back-fill + system-prompt-rewrite + ~5 small wiring patches problem, not a redesign. PR #798 shipped components; integration of those components into a working pipeline did not happen. The fixes are bounded.

Health summary table

WSDomainVerdictCritical finding
WS-01DB inventoryDEGRADEDnathel 18/20 projections present, 10+ empty; fin-central 5/20 (21 mig behind); mig 053+054 missing
WS-02Vault MD inventoryPASS547 .md / 98.9% frontmatter / 487 entity_profiles; 50/52 wikilinks broken (type-prefix resolver missing)
WS-03CF assetsDEGRADEDfin-central-renderer Worker NOT deployed (placeholder Hyperdrive ID); 5 parity crons broken on pnpm v10/9.15.4; phantom out-of-band staging deploy
WS-04JSONB freshnessDEGRADED7 fresh / 11 empty / 3 missing updater; doc_backlink dispatch wiring missing; intel_inbox rejects 100% of 1,400+/day events; 360s are attribute-key-mismatch stubs
WS-05MD completenessFAILdoc_backlink=0 rows; 4/5 entity domains 0 rows; body_md empty across all 331 rows; 70% DB commodities have no vault MD source; fin-central missing entity_doc table entirely
WS-06Universal+overlayDEGRADED0 tenant overlay rows; composition is override-not-merge; nathel HAS 708 price_observation + 33 vendor_quote events in 30d but no consumer materializes them
WS-07Tool accessDEGRADED8 JSONB projections have NO MCP reader; pulse_admin reachable only via Hono; 5 brief tools fail INVALID_EVENT_PAYLOAD; 5 MD tools in SPRINT_TOOLS but not in any role catalog
WS-08Agent usageFAIL0 real-agent activations of MD tools in 30 days; system prompt teaches legacy get_commodity_profile as authoritative; jargon-heavy descriptions
WS-09KF contentDEGRADED386 of 487 vault profiles never ingested (variety+vendor); vault STALER than DB on commodities; wikilink resolver bug (1-line fix); 8 READMEs collide on doc_id
WS-10Drill-throughDEGRADED1 PASS + 2 PARTIAL + 2 FAIL on 5 paths; walk_provenance never reaches events; 0 vendor actors break vendor drill; graph data EXISTS (2,620 links) but adapter drops it
WS-11Closed-loopFAIL16/19 dispatcher-wired; renderer cron not in wrangler triggers; no staleness listener; 4 feedback event types defined but 0 events; watchdog has 0 runs ever
WS-12RegistersDEGRADEDapproved-projection-tables.json has unresolved git merge conflict (lines 167/196/207); schema bifurcation on slots 050/053/054; fin-central 21 mig behind; 4 phantom SPRINT_TOOLS
WS-13Parity matrixDEGRADED6.4% operational (3 of 47 non-N/A cells); central column uniformly missing; MD shared/commodity-only; federation publisher mature but intentionally frozen
WS-14Human UIDEGRADED4/5 routes load; drill buttons are dead clicks (CardRenderer no onAction); explore_vendor returns vendor_not_found for vendors visible via other tools; no tool envelope carries linked_entities
WS-15Perf + self-improvementDEGRADED8/14 tools meet <2s p95; median projection age 12h; 19,198 eval events archived without consumer; knowledge.confidence+.version 100% populated but never updated from feedback

Convergent themes

Theme 1 — “Shipped schema + tools, not integration”

PR #798 (137/137 task ship) landed schema (mig 051..068), tools (14 new SPRINT_TOOLS), and dispatcher wiring (15 updaters). Wave 1+2 confirm those components exist on master. But three integration steps never happened:

  1. Deploymentfin-central-renderer Worker config exists at packages/mcp-server/wrangler.fin-central.jsonc but references a non-existent entry-point file + a placeholder Hyperdrive ID. ZERO renderer.* or entity_doc.* events ever in events table (WS-03).
  2. Cron registrationentity-doc-renderer-worker.ts exports RECOMMENDED_CRON_SCHEDULES but wrangler.jsonc triggers.crons doesn’t include them, and packages/mcp-server/src/index.ts:3480-3760 scheduled() handler has no runRendererLoopIteration call (WS-11).
  3. Workflow auth — the 5 parity cron workflows (PR #794) are present but broken on pnpm/action-setup@v4 version: 10 vs repo packageManager: pnpm@9.15.4 (WS-03).

Theme 2 — “Producer dead, composition shallow, consumer ignoring”

Even granting the substrate works, the three layers of the pipeline each have an independent failure:

LayerFailureConcrete evidence
ProducerRenderer worker dead; body_md empty across all 331 rows; commodity-only domain coverageWS-03, WS-05
Composition0 tenant overlay rows; SQL is LIMIT 1 tenant-prefer (override, not merge); nathel signal substrate (708+33/30d) never materialized into knowledgeWS-06
Consumer0 real-agent MD-tool activations in 30 days; system prompt at reasoning.ts:232-305 + exploration-context.ts:707 steers to get_commodity_profile as authoritative; MD tool descriptions are jargon-heavy (“Plane 3 / TZ-5 §5.1”)WS-08

Theme 3 — “Self-improvement substrate exists, no closer”

The richest discovery of the audit (WS-15) — the system already produces the signals it would need to self-improve:

  • 19,198 system.scenario_eval_result events on nathel (last 30d) with score/latency/category payloads
  • 45 knowledge.domain_stale events, 81 knowledge.freshness_check_completed events
  • knowledge.confidence 100% populated across 14,885 rows
  • knowledge.version 100% populated, max=330

None of these have a consumer that closes the loop into entity_doc re-renders or trust_score updates. ~30 LOC of glue per loop, not a redesign.

Theme 4 — “Graph data exists, transport layer drops it”

The drill-through experience is broken NOT because the graph is missing but because two adapters drop it:

  1. get_entity_profile returns the profile with linked_entities arrays present in knowledge.content (2,620 cross-entity links across 330 commodities). But EntityRoute.tsx:124-249 commodityProfileToEnvelope hand-extracts only s01_identity — drops 28 of 29 KF sections AND the linked_entities array (WS-10, WS-14).
  2. Even if linked_entities reached the renderer, EntityRoute.tsx:282 calls <CardRenderer> with NO onAction prop, so every drill button across every entity URL is a dead click (WS-14).

doc_backlink_projection has 0 rows but the data to reconstruct it lives in knowledge.content.linked_entities — a one-time back-fill query could populate it (WS-09, WS-10).

Theme 5 — “Vault is staler than DB”

Counter-intuitive but well-evidenced (WS-09):

  • For the 98 overlapping commodities, DB content is more comprehensive than vault (apricot vault = 4-section stub, DB = 3142-attribute profile; apple vault = 3735 attrs, DB = 3647).
  • 233 of 331 DB commodity rows have NO vault MD source (bulk-render scripts wrote richer content than the vault holds).
  • 386 of 487 vault profiles (varieties + vendors) NEVER reached DB at all.

This inverts the assumption that vault = source of truth. Reality: vault is one input, the bulk-render machinery is another, and the DB has accumulated content from both — but without source_row_version provenance (95.5% of rows have 'unknown', per WS-05), no one knows which is which.

Theme 6 — “fin-central is uninhabited”

WS-01, WS-12, WS-13 all converge:

  • fin-central staging Neon: 0 events, 1 knowledge row, 3 actors, 5/20 projection tables, 21 migrations behind (last applied 047_fts_hybrid_search).
  • entity_doc_projection table doesn’t even exist on fin-central.
  • Federation publisher code is mature (EIF-RM-026/027 — k≥5 anonymization, HMAC-hashed vendor IDs, customer fields dropped, gated behind FEDERATION_PUBLISH_ENABLED='true') but ZERO federation.* events ever fired — and per memory feedback_federation_publisher_frozen.md this freeze is intentional (single-tenant reality).

So fin-central is structurally an empty branch waiting for the day federation activates. The audit’s federation-readiness verdict is “intentionally not ready” — not a bug.


Prioritized remediation backlog

Listed in recommended fix order. Each item names file path(s) where applicable.

P0 — System-correctness blockers (15 items, mostly small)

#TitleLocationEstimated effort
P0-01Resolve git merge conflict in audit/card-window-system/approved-projection-tables.json (lines 167, 196, 207) — runtime parses this; invalid JSON breaks projection registryaudit/card-window-system/approved-projection-tables.json5 min
P0-02Fix pnpm/action-setup@v4 version: 10 conflict in 5 parity cron workflows — either drop version: 10 or bump root packageManager to 10.x.github/workflows/parity-*.yml (5 files)10 min
P0-03Deploy fin-central-renderer Worker: write the entry-point file + replace placeholder Hyperdrive ID + add to deploy pipelinepackages/mcp-server/src/workers/fin-central-renderer-worker.ts (new), wrangler.fin-central.jsonc2-3 hr
P0-04Wire runRendererLoopIteration into Cloudflare scheduled() handler + add cron to wrangler.jsonc triggers.cronspackages/mcp-server/src/index.ts:3480-3760 + packages/mcp-server/wrangler.jsonc30 min
P0-05Write event-handlers/projection-doc-backlink.ts + register in dispatchProjectionUpdaters; back-fill from knowledge.content.linked_entities (2,620 existing edges)packages/mcp-server/src/event-handlers/projection-doc-backlink.ts (new) + event-handlers/index.ts:113-1312-3 hr
P0-06Write entity_doc staleness listener — consume knowledge.row_updated / knowledge.domain_stale events and flip entity_doc_projection.status='stale' (~30 LOC per WS-15)event-handlers/projection-entity-doc-staleness.ts (new)1 hr
P0-07Write system.scenario_eval_result consumer — 19,198 events being archived; consume into entity_doc_projection.trust_score + knowledge.confidence updatesevent-handlers/projection-eval-feedback.ts (new)2 hr
P0-08Fix attributeEventToInbox() upstream — propagate source_email_inbox/inbox/to_address into event data from EIF S0.5 intake classifier + S4 extractor consumerspackages/mcp-server/src/intake/intake-classifier.ts, packages/mcp-server/src/intake/extractor-consumer.ts2 hr
P0-09Fix attribute-key mismatch in commodity_360_projection + vendor_360_projection recompute — events use data.commodity/data.vendor, projection queries data.commodity_key/data.vendor_keypackages/mcp-server/src/event-handlers/projection-commodity-360.ts, projection-vendor-360.ts30 min
P0-10Fix extractWikilinkTarget to output commodity_profile_X (matching DB doc_id shape) instead of commodity_X — 1-line fixpackages/mcp-server/src/ingestion/upsert-doc.ts:342-3565 min
P0-11Wire EntityRoute to pass onAction prop to <CardRenderer> — currently all drill buttons across every entity URL are dead clickspackages/workspace/src/routes/EntityRoute.tsx:28230 min
P0-12Add linked_entities field to tool envelope schema (CardSpec) AND ensure get_entity_profile + explore_commodity etc. emit itpackages/shared/src/schemas/cardspec.ts, packages/mcp-server/src/tools/get-entity-profile.ts, explore-commodity.ts2 hr
P0-13Fix explore_vendor — returns vendor_not_found for vendor IDs that lookup_vendor + explore_commodity resolve (vendor 000876 LA MINITA FRESH LLC is a confirmed example); 0 vendor actors on nathel means vendor lookup must use party + relationship tables, not actors WHERE role='vendor'packages/mcp-server/src/tools/explore-vendor.ts, lookup-vendor.ts2-3 hr
P0-14Sync fin-central staging — apply migrations 048..068 to fin-central; create entity_doc_projection + doc_backlink_projection tables; backfill shared-tenant rowsdb/migrations/048-068 + apply via scripts/apply-staging-migrations.ts to project cool-scene-51259109 branch br-super-sky-apy08f2d1 hr
P0-15Resolve schema bifurcation on slots 050, 053, 054 — nathel has duplicate-slot applied migrations (veteran_panelist_role + inventory_current_projection at 050; materialized_views + customer_360_projection at 055); parity-integration is missing slot 050 entirely. Re-number all conflicting migs to new slots and rebase.db/migrations/*.sql2-3 hr

P1 — Quality/agent-effectiveness blockers (12 items)

#TitleLocationEstimated effort
P1-01Rewrite system prompt to teach MD tools — replace “cross-reference get_commodity_profile for authoritative data” with search_entity_profiles + get_entity_profile + walk_provenance chain; de-jargon descriptionspackages/agent/src/personas/reasoning.ts:232-305, packages/agent/src/exploration-context.ts:707, tool descriptions in packages/mcp-server/src/tools/get-entity-profile.ts etc.4 hr
P1-02Add 5 MD-projection tools (get_entity_profile, search_entity_profiles, walk_provenance, get_doc_graph, get_knowledge_health) to role catalogs — currently only admin gets *, SMS/voice agents can’t pickpackages/mcp-server/src/tools/role-tool-catalog.ts1 hr
P1-03Add get_knowledge_health to SPRINT_TOOLS (in toolRegistry but missing from allow-list → fails authz with TOOL_UNKNOWN)packages/agent/src/permissions.ts5 min
P1-04Fix 5 generate_*_brief tools failing INVALID_EVENT_PAYLOAD (brief.generated schema drift — requires shift_type + posted_to_slack)packages/mcp-server/src/tools/generate-*-brief.ts (5 files)1 hr
P1-05Wire 8 JSONB projections to MCP readers (buyer_team_dashboard, commodity_360, customer_360, daily_company_pulse, location_intel, sales_team_dashboard, supply_chain_position, vendor_360) — currently explore_* tools read raw events instead of these projections, which is why the 360s remain stubs (no read pressure to validate the projection is correct)packages/mcp-server/src/tools/get-*-360.ts (new) + update explore_*.ts to prefer projection3-4 hr
P1-06Add MCP reader for pulse_admin_active_holds (currently reachable only via Hono /api/pulse route)packages/mcp-server/src/tools/get-pulse-admin.ts (new)1 hr
P1-07Fix explore_commodity p50=7s (3.5x over CLAUDE.md ≤2s target) — bypasses commodity_360_projection and does wide KB scan; route through projection once P1-05 landspackages/mcp-server/src/tools/explore-commodity.ts2 hr
P1-08Fix walk_provenance to query doc_backlink_projection (currently only get_doc_graph does); also fix fact_citations to use event_id instead of abstract commodity:<slug> keys so provenance reaches eventspackages/mcp-server/src/tools/walk-provenance.ts + citation emitters in packages/mcp-server/src/ingestion/extract-fact-citations.ts3 hr
P1-09Implement renderer routes for vendor / customer / location / lot domains (currently routeRenderer() throws RendererNotImplementedError for all 4) — Each domain has substantial vault content (142 vendors + …) that’s strandedpackages/mcp-server/src/ingestion/renderers/route-renderer.ts + per-domain renderer files1-2 days
P1-10Resolve 24 silent render failures (19 s01_identity TypeError on acai-berry section sub-renders, 5 embedding_model NOT NULL violations on L-named commodities); raise retry cap from 1 to 3; add ops alerting on entity_doc_projection.status='failed'packages/mcp-server/src/ingestion/renderers/entity-doc-renderer-worker.ts, packages/mcp-server/src/ingestion/upsert-doc.ts2 hr
P1-11Fix renderer to populate source_row_version correctly (95.5% of 331 rows have 'unknown' → drift detection blind even after P0-06 lands)packages/mcp-server/src/ingestion/renderers/entity-doc-renderer-worker.ts30 min
P1-12Add post-deploy /health version-match gate to eval-pipeline.yml deploy-staging job — catches out-of-band wrangler deploys (today’s qc-receiving-cte-20260517T144520Z phantom deploy clobbered CI’s dc2e36a).github/workflows/eval-pipeline.yml30 min

P2 — Hygiene + smaller (8 items)

#TitleLocationEstimated effort
P2-01Add frontmatter to 3 vault audits (HISTORICAL_DATA_BACKFILL_2026-05-16, ROLE_DRILLTHROUGH_DESIGN_2026-05-16, PROJECTION_PARITY_AUDIT_2026-05-16) — won’t index without itvault docs/audits/*.md15 min
P2-02Build wikilink resolver for vault’s type-prefix shorthand ([[commodity:X]], [[vendor:X]], [[canon/people/X]]) — 50 of 52 wikilinks currently brokenvault _scripts/link-resolver.ts (new) or via Obsidian-style alias map4 hr
P2-03Fix 8 README.md files sharing doc_id: readme (collide on upsert, silently destroy 7 of 8)vault docs/**/README.md (8 files)20 min
P2-04Fix FIN_PLATFORM_DOC_INDEX.md — ~12 broken absolute links to fin-agentic paths (e.g., /AGENTS.md, /db/schema.sql); either convert to GitHub URLs or removevault FIN_PLATFORM_DOC_INDEX.md30 min
P2-05Tag vault docs with data_plane other than universal_intelligence where appropriate (currently monovalent → federation gate has no signal); especially flag avocado.md which leaks Nathel-specific operational pattern at line 124 into universal planevault docs/**/*.md author disciplineongoing
P2-06Fix variety/vendor naming mismatch — commodities link to display slugs (crimson_sweet) but variety files stored as anonymous codes (cmd_00057.md); causes 98.2% orphan rate in linked_entities graphvault rename OR build alias map2 hr
P2-07Author the 9 missing W1/W2 PROJECTION_INDEX types — kb_health_summary, tenant_readiness, region_intelligence, season_window, agent_enrichment_metrics, cohort_status, etc. have 0 vault docs despite being in the indexvaultauthor backlog
P2-08Add normalizer for docId shape inconsistency — commodity_profile_blackberry (underscored, internal) vs commodity_profile/blackberry/v1 (slashed/versioned, external API)packages/shared/src/utils/doc-id-normalize.ts (new)1 hr

Frozen / intentional (do not fix)

#ItemWhy
F-01Federation publisher (EIF Slice 7 — anonymization verifier + publisher + cron + 6 acceptance tests) gated behind FEDERATION_PUBLISH_ENABLED='true'Single-tenant reality per feedback_federation_publisher_frozen.md; system resources + rights not aligned to activate; code preserved as future-proof option for training-data scenario
F-02fin-central tenant emptyIntentional — no production tenant relies on it yet; sync to current schema only when first federation peer onboards
F-03OpenClaw integration testsUser has confirmed (this session) OpenClaw is not in scope for current phase; eval-smoke-staging timeout on openclaw/staging-http.test.ts is acceptable

Three tiers of work, each independently shippable:

Sequence A — “Turn on the pipeline” (~1 day)

Goal: Get the renderer running, the dispatcher firing, the consumers consuming. Most impact per LOC.

  1. P0-01 (registry JSON merge conflict) — 5 min
  2. P0-02 (cron pnpm fix) — 10 min
  3. P0-04 (cron+scheduled wiring) — 30 min
  4. P0-05 (doc_backlink updater + back-fill) — 2-3 hr
  5. P0-06 (staleness listener) — 1 hr
  6. P0-09 (360 attribute-key fix) — 30 min
  7. P0-10 (wikilink resolver fix) — 5 min
  8. P1-11 (source_row_version populate) — 30 min
  9. P0-03 (deploy renderer worker) — 2-3 hr — DEFERRED if Sequence A only running on existing renderer cron via P0-04

End state: Projections refresh on event; backlinks populated; 360s carry real data; renderer cron actually fires.

Sequence B — “Surface to agent” (~1 day)

Goal: Make the agent actually use the MD layer and the user able to drill through.

  1. P0-11 (EntityRoute onAction wiring) — 30 min
  2. P0-12 (linked_entities in tool envelope) — 2 hr
  3. P0-13 (explore_vendor + vendor-actor gap) — 2-3 hr
  4. P1-01 (system prompt rewrite — teach MD tools) — 4 hr
  5. P1-02 (5 MD tools into role catalogs) — 1 hr
  6. P1-08 (walk_provenance reads doc_backlink + cite event_ids) — 3 hr
  7. P1-07 (explore_commodity speed via 360) — 2 hr

End state: Drill buttons work, agent prefers MD tools, drill-through traverses actual graph, provenance reaches events.

Sequence C — “Close the self-improvement loop” (~0.5 day)

Goal: The 19,198 archived eval signals start updating content quality.

  1. P0-07 (eval-feedback consumer → trust_score + re-render trigger) — 2 hr
  2. P0-08 (inbox-lineage propagation upstream) — 2 hr
  3. P1-10 (24 silent renders + retry cap + alerting) — 2 hr
  4. P1-12 (post-deploy version-match gate) — 30 min

End state: Low-scoring profiles auto-flagged for re-render; intel inbox starts populating digest; render failures visible; phantom deploys caught.

Sequence D — “Vault hygiene + back-fill” (~0.5 day)

Goal: Bring vault back to parity with DB.

  1. P0-14 (sync fin-central staging) — 1 hr
  2. P0-15 (resolve mig slot collisions) — 2-3 hr
  3. P1-09 (vendor/customer/location/lot renderers) — 1-2 days (largest item — split into Sequence D2)
  4. P2-01..P2-08 vault hygiene — ~6 hr total

Sub-report index

Detailed evidence for each work stream:

WSReport
WS-01.audit-2026-05-17/wave1/ws-01-db-inventory.md
WS-02.audit-2026-05-17/wave1/ws-02-vault-inventory.md
WS-03.audit-2026-05-17/wave1/ws-03-cf-inventory.md
WS-04.audit-2026-05-17/wave2/ws-04-jsonb-freshness.md
WS-05.audit-2026-05-17/wave2/ws-05-md-completeness.md
WS-06.audit-2026-05-17/wave2/ws-06-overlay-composition.md
WS-07.audit-2026-05-17/wave2/ws-07-tool-access.md
WS-08.audit-2026-05-17/wave2/ws-08-agent-usage.md
WS-09.audit-2026-05-17/wave3/ws-09-kf-content.md
WS-10.audit-2026-05-17/wave3/ws-10-drill-through.md
WS-11.audit-2026-05-17/wave3/ws-11-closed-loop.md
WS-12.audit-2026-05-17/wave3/ws-12-registers.md
WS-13.audit-2026-05-17/wave3/ws-13-parity-matrix.md
WS-14.audit-2026-05-17/wave4/ws-14-ui-projections.md
WS-15.audit-2026-05-17/wave4/ws-15-perf-self-improvement.md

Methodology notes

  • Subagent contract: Each WS dispatched as general-purpose background agent with self-contained brief + structured ===WS-NN-RESULT=== return block per CLAUDE.md §Subagent Orchestration Rules.
  • Subagent state: Returns VERIFYING per §1; this audit doc’s orchestrator (Claude) is responsible for promoting to verified findings — done above.
  • Read-only: All 15 work streams were read-only audits. No DDL, no DML, no deploys, no code edits.
  • Connection info pre-resolved: Each subagent received Neon project + branch IDs, vault path (/tmp/fin-central-intranet HEAD 74cf796), staging Worker URL + bypass header.
  • Stale-worktree caveat: This worktree (heuristic-kepler-4f9104) is stale relative to parity-integration (per WS-12: duplicate 048 migrations + 049-062 gap). One WS (WS-15) appears to have searched this worktree for cron workflows — they exist on master via PR #794. The eval workflow that IS running on master is eval-baseline.yml.

Open questions for follow-up

  1. Federation activation criteria — what triggers FEDERATION_PUBLISH_ENABLED=true? Memory says “frozen, single-tenant reality; rights + resources not aligned”. Need explicit unfreeze conditions.
  2. Renderer ownership — should the renderer worker run on Cloudflare (per current design) or migrate to a long-running Node process? Cloudflare cron has limits.
  3. Vault vs DB authoring contract — given DB content is richer than vault for commodities, is the vault meant to be authoritative? Or is it a publishing/snapshot target? This needs a written decision before Sequence D2.
  4. Hot-path tools NOT going through projections — the WS-08 telemetry shows get_events, query_knowledge, get_load_context_package, list_work_threads are the production hot path, but the audit focused on projection-read tools. There may be a parallel parity audit needed for the hot-path tools (do they have JSONB projections behind them?).

Wave 5 Addendum — Tenant Intranet + Cross-Taproot Propagation (2026-05-17, 16:00 UTC)

Trigger: the original 15-WS audit covered FIN Central vault (fin-central-intranet) and the DB-side projections, but missed (a) the separate nathel-intranet tenant vault, (b) the Central → Tenant taproot sync mechanism, (c) the tenant vault webhook ingest, (d) the tenant projector write-back, and (e) end-to-end cross-taproot propagation. Wave 5 ran 5 additional parallel subagents to close that gap.

Wave 5 health summary

WSDomainVerdictCritical finding
WS-16nathel-intranet contentDEGRADEDPure skeleton: 14 .md files all scaffolding READMEs, 0 content/projected/mirrored docs; vault-webhook is .placeholder; 0 of 16 advertised projections have produced output
WS-17Central → Tenant taproot syncFAILWave 1 (poll) + Wave 4 (push) BOTH not implemented; no code skeleton, no wrangler config, no GH workflow; 0 sync events ever; design exists ONLY in _taproot_mirror/README.md — under-spec’d
WS-18Tenant vault webhook → NeonFAIL3 stacked show-stoppers: route unmounted in index.ts, handler skeleton (no upsertDoc call), no GH webhook configured on nathel-intranet; nathel knowledge.domain='doc' = 0 rows (vs 5,272 total across 27 other domains); 0 vault.* events all-time
WS-19Tenant projector → vaultFAILVapor: zero octokit usage anywhere; no tenant Cloudflare Worker; 13 promised renderers have NO source files; one renderer comment misleading (says it writes MD but actually writes to DB); naming collision with DB CQRS projection layer masks absence
WS-20Cross-taproot E2E (3 commodities × 5 stages)DEGRADED0/3 chains operational; breakpoint at Stage 2 (fin-central Neon empty) AND Stage 3 (taproot mirror dormant); agent reachability passes 6/6 but returns BYTE-IDENTICAL content per commodity; cucumber has 314 nathel price observations / 30d but data.tenant overlay returns null — federation plumbed in schema but unwired in assembly

The 3-rung stack — none implemented

The “agentic ERP with federated tenant + central intelligence” requires three stacked layers. All three are independently broken:

RungLayerWave 5 verdict
1Central MD renderer (fin-central-renderer writes to fin-central Neon + supposedly to vault)WS-03 (original): config exists with placeholder Hyperdrive ID; never deployed
2Central → Tenant sync transport (_taproot_mirror/ populated from fin-central-intranet)WS-17: does not exist (no code, no spec beyond a one-page README)
3Tenant overlay renderer (writes tenant-specific MD into nathel-intranet from tenant events)WS-19: vapor (zero code; 13 promised renderers have no source files)

Fixing rung 1 alone doesn’t unblock the chain — rungs 2 and 3 are also gone.

The critical new finding (WS-20 bonus probe)

Cucumber has 314 tenant-specific signal.price_observation events on nathel in last 30 days. get_entity_profile(commodity:cucumber, tenantId:nathel) returns data.tenant = null.

The federation overlay is plumbed in the response schema but unwired in the assembly logic. The substrate exists (314 events). The contract supports it (data.tenant field). The code that fills the field doesn’t query the substrate.

This is a single-fix gap — wire the assembly to query nathel signals and populate data.tenant. Same pattern as the system-prompt rewrite (WS-08): tools exist, agent doesn’t pick them; data exists, surface doesn’t render them.

Naming collision — architectural blind spot

WS-19 surfaced a structural confusion:

TermWhat it meansState
”Projection” in PROJECTION_CATALOG_2026-05-16.md17 DB tables, event-driven CQRS read modelsLive (16 wired updaters per WS-11)
“Projection” in nathel-intranet/PROJECTION_INDEX.md13 MD documents to be deposited in the tenant vault by an agent-projectorNone implemented; renderers don’t exist

The two unrelated systems share the word “projection”. The catalog never references the vault-deposit projector. The naming collision masks the absence — verbal confidence in the DB CQRS layer implies that the vault projector is also working, when it’s vapor.

Remediation suggestion: rename the vault-deposit layer to “tenant vault renderer outputs” or “tenant projector deposits” to distinguish from CQRS projections. Then the absence becomes obvious in any future audit.

Updated remediation backlog (Wave 5 additions)

P0 additions

#TitleLocationEstimated effort
P0-W5-01Mount vaultWebhookRoutes in packages/mcp-server/src/index.ts — currently POST /webhooks/github-vault returns 404 even though handler code existspackages/mcp-server/src/index.ts15 min
P0-W5-02Complete the tenant vault webhook handler — currently a skeleton that doesn’t invoke upsertDoc; file’s docstring marks it “next session”. Wire fetch-from-GitHub + parseDocMarkdown + upsertDoc (which is fully implemented per §11.5.3)packages/mcp-server/src/routes/github-vault-webhook.ts2-3 hr
P0-W5-03Configure GitHub webhook on fin-platform/nathel-intranet to POST to the staging Worker /webhooks/github-vault endpoint (once P0-W5-01 lands)gh api repos/fin-platform/nathel-intranet/hooks POST15 min
P0-W5-04Wire get_entity_profile assembly to populate data.tenant overlay from tenant-side signal events (cucumber has 314 ready signals; cherry/grape have similar)packages/mcp-server/src/tools/get-entity-profile.ts2-3 hr
P0-W5-05Build Central → Tenant taproot sync — choose one of: (Wave 1) Cloudflare Worker poll on 5-min cron via GitHub Commits API, OR (Wave 4) repository_dispatch from fin-central-intranet on mergeNew file packages/mcp-server/src/workers/taproot-sync-worker.ts + wrangler config1-2 days
P0-W5-06Implement at least 1 of the 13 promised tenant projectors (start with daily_arrivals since RP581 ingest is live) — establishes the pattern; remaining 12 follow same skeletonpackages/mcp-server/src/workers/tenant-projector/daily-arrivals.ts (new) + wrangler config + octokit dep1-2 days

P1 additions

#TitleLocationEstimated effort
P1-W5-01Fix misleading comment at qc-inspection-profile-renderer.ts:13 (says writes to nathel-intranet vault but actually writes to DB)packages/mcp-server/src/ingestion/renderers/qc-inspection-profile-renderer.ts:135 min
P1-W5-02Add FIN_VAULT_TENANT_MAP entry for nathel in wrangler.fin-central.jsonc (or create peer wrangler.tenant.jsonc) so the renderer worker would even know to address nathel contentpackages/mcp-server/wrangler.*.jsonc30 min
P1-W5-03Document the auth bypass tenant routing footgun — body tenantId arg returns UNAUTHORIZED while X-Fin-Tenant header silently re-binds. Harmonize the contractpackages/mcp-server/src/middleware/auth.ts + docs/engineering/AUTH_CONTRACT.md1 hr
P1-W5-04Rename “PROJECTION_INDEX” in tenant vault to “VAULT_RENDERER_OUTPUTS” or similar to disambiguate from DB CQRS PROJECTION_CATALOGnathel-intranet/PROJECTION_INDEX.md (rename) + fin-central-intranet mirror30 min
P1-W5-05Engineering Spec §11.5 currently covers alert routing, not taproot. Add a new §11.7 (or similar) covering the 3-rung architecture: renderer + sync transport + tenant overlay renderer. Without it the design lives only in _taproot_mirror/README.mddocs/engineering/ENGINEERING_SPEC.md (or wherever the canonical spec lives)2-3 hr

Frozen-intentional additions

#ItemWhy
F-W5-01Tenant authored content (decisions, runbooks, SOPs)nathel-intranet README itself says “(empty at bootstrap 2026-05-15 — content lands during Phase 2+)“. Phase 2+ author work, not a runtime gap
F-W5-02Aggregate intelligence (across-tenant rollups)fin-central-intranet’s aggregate_intelligence/ is frozen per single-tenant reality (feedback_federation_publisher_frozen.md)

Wave 5 work fits into the existing 4-sequence model from the original audit, but adds a new tier-2 priority because the tenant pipeline being completely cold means none of the agent-tool work (Sequence B) can deliver tenant-overlay value without the producer being built.

Sequence E — “Wake the tenant pipeline” (~3-4 days, new)

Goal: turn on tenant-side ingestion + at least one projector + the taproot sync. Establishes the pattern so the remaining 12 projectors are mechanical.

  1. P0-W5-01 (mount route) — 15 min
  2. P0-W5-02 (complete handler) — 2-3 hr
  3. P0-W5-03 (configure GH webhook) — 15 min
  4. P0-W5-04 (wire data.tenant overlay) — 2-3 hr (this alone gives meaningful tenant-overlay value immediately, even before the sync transport lands)
  5. P0-W5-05 (taproot sync, pick Wave 1 OR Wave 4) — 1-2 days
  6. P0-W5-06 (1st tenant projector: daily_arrivals) — 1-2 days

End state: Tenant vault accepts authored content + Central taproot mirrors into tenant + at least daily_arrivals projector deposits agent-generated MD back into tenant vault. The 3-rung stack is live for 1 deliverable; remaining 12 projectors can follow the same pattern.

Original 4 sequences still apply

A (pipeline), B (agent surface), C (self-improvement loop), D (vault back-fill) — unchanged. Sequence E should precede or run parallel to B, since the agent-surface work has no tenant content to surface without it.

Wave 5 sub-report index

WSReport
WS-16.audit-2026-05-17/wave5/ws-16-nathel-intranet.md
WS-17.audit-2026-05-17/wave5/ws-17-taproot-sync.md
WS-18.audit-2026-05-17/wave5/ws-18-tenant-webhook.md
WS-19.audit-2026-05-17/wave5/ws-19-tenant-projector.md
WS-20.audit-2026-05-17/wave5/ws-20-cross-taproot.md

Final consolidated health (20 work streams)

StatusCountWSs
PASS1WS-02
DEGRADED13WS-01, WS-03, WS-04, WS-06, WS-07, WS-09, WS-10, WS-12, WS-13, WS-14, WS-15, WS-16, WS-20
FAIL6WS-05, WS-08, WS-11, WS-17, WS-18, WS-19

Final remediation backlog count:

  • P0: 21 items (15 original + 6 Wave 5)
  • P1: 17 items (12 original + 5 Wave 5)
  • P2: 8 items (unchanged)
  • Frozen-intentional: 5 (3 original + 2 Wave 5)

Total estimated focused work to fully operational: ~7-8 days across 5 parallel sequences (A pipeline, B agent surface, C self-improvement loop, D vault back-fill, E tenant pipeline NEW). Still all bounded fixes; no redesign needed.