ID-71 {71.3} TECH — AI tooling surface rationalisation (outcome-grouped server + headless fleet substrate)
ID-71 {71.3} TECH — AI tooling surface rationalisation
Section titled “ID-71 {71.3} TECH — AI tooling surface rationalisation”Status:
{71.3}TECH spec. Authored by a FRESH Planner instance (Q-PLANNER-2 / B4 — NOT the{71.2}PRODUCT Planner) against the ratified predecessors:{71.1}RESEARCH.md,{71.2}PRODUCT.md (B-INV-1..43 — amended 15/06/2026, B-INV-43 added), andheadless-requirement-refinement.md(HR/HC contract). Every Proposed change below maps 1:1 to a numbered B-INV invariant via the mapping table in §M; the Checker + MCP eval L4 verify that mapping. British English throughout. DD/MM/YYYY dates.Five TECH OQs resolved in §OQ. The four PRODUCT OQs are RESOLVED inputs (not re-opened): create_content_item=write-to-store (TECH-GATED → see OQ-1), renewals grouped with O2 later, fact-check-first, PI-15 retired.
This spec fixes the mechanics; it does not re-litigate behaviour. Settled context (do NOT re-open): surface = Option A outcome-grouped server + Option C headless fleet; one queue + facet (B-INV-30); headless-complete launch set = O1/O4/O6 reads + W5.6; full fleet = post-launch graduation.
Context
Section titled “Context”ID-71 rationalises KH’s AI-consumption surface (MCP tools + resources + prompts + MCP Apps
- plugin commands/skills + inline
lib/ai/touchpoints) into one outcome-grouped MCP server (Option A) with a headless-agent fleet (Option C) layered additively, and ships it with a testable headless-completeness guarantee verified against the MCP eval L4 layer + a per-agent ID-104 eval contract. The behaviour is fixed in{71.2}PRODUCT; this spec fixes how each invariant lands in the codebase.
Code-intelligence orientation (gitnexus + ast-dataflow + ledger, knowledge-hub, 15/06/2026)
Section titled “Code-intelligence orientation (gitnexus + ast-dataflow + ledger, knowledge-hub, 15/06/2026)”Per the binding orientation rule, the symbols this spec mandates be modified were queried before drafting. Outputs cited verbatim (not paraphrased) so the Checker can confirm the step:
- Single tool-registry insertion point (Option A anchor).
gitnexus_query("MCP tool registration search consolidation")returnsregisterTools(lib/mcp/tools/index.ts~48-75, moduleTools) as the single registry barrel, withregisterSearchTools→findSimilarItemsImpl(lib/mcp/tools/search.ts:381-497) andloadDomainNames(search.ts:44-58) as the find-consolidation surface, and the L4 layerrunSearchToolChecks(scripts/mcp-eval/functional-correctness.ts:260-618) +callTool(functional-correctness.ts:171-228) as the eval substrate. The search formatters areformatSearchResults(lib/mcp/formatters/search.ts:49-90) andformatChunkSearchResults(search.ts:195-241). - MCP tool names are string literals, not graph symbols.
gitnexus_contextforcreate_content_itemandlist_user_workspacesBOTH returned"Symbol '…' not found"— because they aredefineTool(server, 'create_content_item', …)string-literal registrations, not function names. Tool-name modification is therefore an ast-dataflowstring-literal-uses+ grep surface, NOT agitnexus_renamesurface. This is load-bearing for the bid→forms rename mechanics (OQ-4). - The one-queue seam already exists.
gitnexus_context("unifiedToDashboardData")returnsunifiedToDashboardData(lib/dashboard.ts~104-122) — a legacy adapter mapping the newerUnifiedDashboardDatashape back toDashboardData, called only byapp/api/dashboard/route.ts:GET. The genuinely-unified substrate islib/attention.ts:AttentionSourceData(attention.ts:80-101) already mergesgovernance_review_count+stale_content_count+quality_flag_count+coverage_gap_countinto one source, andproduceGovernanceReviewItems(attention.ts:122-141) +SEVERITY_ORDER(attention.ts:107-112) emit oneAttentionItem[]list with atypediscriminator. The governance MCP facet isformatGovernanceQueue(lib/mcp/formatters/governance.ts~161-207, called only byregisterGovernanceTools); the content facet isPublicationReviewActionBar(components/review/publication-review-action-bar.tsx:51-161)fetchPublicationReviewQueue(lib/query/fetchers.ts:542-570) + query-keysqueue(lib/query/query-keys.ts:38-39) /publicationReviewQueue(query-keys.ts:50-51).
- OQ-1 cutover state (re-verified, all four cites + prod-state update).
app/api/ingest/url/route.ts:206-212callssupabase.rpc('reference_ingest', …)unconditionally (no flag/env guard); the RPC migration20260614010200_id110_reference_ingest_rpc.sql:48-50apply-log reads “applied to staging … PROD push is a GATED operator step (NOT applied here)” — but that comment is point-in-time: the gated operator step has SINCE executed, andreference_ingestis now LIVE ON PROD on both prod projects (Orchestrator-verified 15/06/2026 via Supabase MCPpg_proc—rovrymhhffssilaftdwd+zjqbrdctesqvouboziae, 14 args).lib/edit-intent/write-back.ts:132-283writeBackFileFirstoperates only on EXISTINGcontent_itemswith a linkedsource_document(the source-less branch at:178-191explicitly does NOT auto-create — it writes KH-DB-only and logs an anomaly); andcreate_content_item(lib/mcp/tools/content.ts:247-527, tool #12, editor+ gated) writes directly viasupabase.from('content_items').insert(insertData)(content.ts:523-527) — no reference layer. Conclusion: file-first / reference-layer ingest is LIVE ON PROD; the cutover gate is SATISFIED; andwriteBackFileFirstis an edit-path affordance, not a create verb (a NEW create-into-store leg is needed — M-CREATE). See OQ-1. - ID-104 is
spec_needed, not built.bun scripts/ledger-cli.ts show task 104confirms ID-104 ownsscripts/eval-runner.ts(exit 0/1/2), severityblock|warn|info|infra+variance_bandextendinglib/eval/baseline.ts, baseline lifecycle (promoteBaseline+ git-audited history +compareBaselines), the touchpoint-registry concept (every tool/prompt/skill: owner + eval + version), the Claude-as-judge tool-description rubric, andrecordAiCall()cost tracking. The existing substrate is onlylib/eval/baseline.ts(EvalBaselinewithmetrics+thresholds:{min,max_drop}—lib/eval/types.ts:38-43) and the L1/L3/L4 mcp-eval suite;recordAiCalldoes not yet exist (grep returns nothing). See OQ-2. - Rename surface (ast-dataflow + grep, mixed bid/procurement).
gitnexus_renamepreview ofuseBidActions→useFormActionsis a single high-confidence graph edit inapp/procurement/[id]/page.tsx:68(importing from the already-procurement-namedhooks/procurement/use-procurement-actions.ts). The DB layer is ALREADY renamed (form_responses,form_questions,get_form_question_statsper migration20260601180058_id64_origin_kind_rename_form_response.sql); the residual bid naming is at the MCP-surface string-literal + plugin layer: toolget_bid_question(lib/mcp/tools/procurement.ts:334), resourcesbid_workspace/kb://bids/{id}(resources.ts:148-149),ui://bid-dashboard/app.html(resources.ts:662), promptsbid_briefing(resources.ts:835) /bid_pipeline_review(resources.ts:1029), plugin commandsbid-pipeline-review.md/bid-status.md, plugin skillbid-writing, queuejob_type='bid_draft_all'+bid_idbody field (lib/queue/handlers/procurement-draft-all.ts), and fixtures (scripts/mcp-eval/fixtures.ts:95-97,242-267). See OQ-4. - Remote-MCP + IONOS/Coolify substrate exists. The remote MCP transport route is
app/api/mcp/[transport]/route.ts(B-INV-10 incoming connectivity), guarded by theproxy.tspublicRoutesallowlist; the Option A role-separation seam iscreateMcpClient(lib/mcp/auth.ts:42, per-user RLS) +checkMcpRole(auth.ts:99). The IONOS/Coolify box already hosts the cocoindex pipeline image via.github/workflows/onprem-deploy.yml(the goose co-location target). See OQ-3.
Orientation outcome: not greenfield — every mandated change refines an existing,
indexed substrate. No ccc search fallback or greenfield disclaimer applies. Tool/query
catalogues: .gitnexus/CLAUDE.md, .ast-dataflow/CLAUDE.md.
Line anchors are indicative, not exact. Cited line numbers locate the symbol at authoring time and may drift by a line or two as files change; the symbol name + file path is the durable anchor. The Executor should resolve by symbol, not line.
TECH OQ resolutions {#OQ}
Section titled “TECH OQ resolutions {#OQ}”OQ-1 — create_content_item ingest shape: WRITE-TO-CANONICAL-STORE (cutover SATISFIED) {#OQ-1}
Section titled “OQ-1 — create_content_item ingest shape: WRITE-TO-CANONICAL-STORE (cutover SATISFIED) {#OQ-1}”Binding outcome: create_content_item = write-to-canonical-store (PRODUCT OQ-1 DEFAULT,
Option A). The TECH-GATE precondition is now MET: the earlier DEFER verdict was premised on
reference_ingest being staging-only, and that premise is now FALSE.
Cutover SATISFIED (Orchestrator-verified 15/06/2026 via Supabase MCP pg_proc; cite, do
NOT re-query): the reference_ingest RPC is LIVE ON PROD — present on BOTH prod
projects, knowledge-hub-phew (ref rovrymhhffssilaftdwd) and knowledge-hub-platform
(ref zjqbrdctesqvouboziae), 14 args, routine_count=1. The migration-file comment in
20260614010200_id110_reference_ingest_rpc.sql:48-50 (“PROD push is a GATED operator step,
NOT applied”) was point-in-time; the gated operator step has since executed. File-first /
reference-layer ingest is therefore the live prod path.
Resolution mechanics (grounded on Task ID-59 — the in-progress edit-intent / file-first
write-back substrate, ledger status: in_progress, title “Per-UC write-back” — the canonical
write-back home; NOT onboarding):
create_content_itemgains a write-to-canonical-store create-leg (NEW changeM-CREATE), NOT a direct-DB.insertand NOT the edit-pathwriteBackFileFirst. The create-verb creates thesource_document/ reference FIRST (the reference layer /reference_ingest, LIVE on prod, provides this), THEN materialises thecontent_itemfile-first on ID-59’s substrate. This satisfies the{59.10}source-less GUARD (bl-266), which currently BLOCKS file writes for a source-lesscontent_item(write-back.ts:178-191) — the create-leg must therefore mint the source binding BEFORE the file leg, so the guard passes rather than trips.- Shape-mismatch reconciled (the one I flagged in PRODUCT OQ-1):
writeBackFileFirst(write-back.ts:132-283) is the EDIT path (PATCH/api/items/[id], runSweep/rollbackSweep) requiring an existingcontent_itemsrow + linkedsource_document— its source-less branch (:178-191) refuses to auto-create. The create-verb needs a NEW create / propose-into-store leg on ID-59’s substrate, adjacent to the{59.19}/{59.22}corpus-promotion pattern (promoteCorpusExtractions— the existing create-into-store shape).writeBackFileFirststays the sanctioned HC-4 edit-back destination (B-INV-12);M-CREATEis the create-into-store leg. - v1.1 framing: per
themes/canonical-pipeline/reference/deferral-register.md, the project moves to v1.1 imminently; the create-verb write-to-store is v1.1-cycle canonical-pipeline scope on the ID-59 substrate — NO new deferral-register row, NOT routed to onboarding. ID-71 couples to ID-59 (the write-back substrate owner) for sequencing; this REPLACES the old “ID-110 cutover → onboarding” intent (§X).
OQ-2 — per-agent eval-contract: BOTTOM-UP, ID-104-OWNED (hard upstream dep) {#OQ-2}
Section titled “OQ-2 — per-agent eval-contract: BOTTOM-UP, ID-104-OWNED (hard upstream dep) {#OQ-2}”Binding outcome (Liam steer 15/06/2026 — did NOT ratify reuse+extend): the per-agent
AgentEvalContract is designed BOTTOM-UP as the long-term agent-eval layer, OWNED by ID-104
(the eval-engine Task). ID-71 CONSUMES the contract only. Liam’s steer: ID-71 + ID-104 are
a BOTTOM-UP rebuild, not a “build onto what we already have” shortcut — nearly all current
MCP tooling is verdicted review/adapt/retire, so for something as load-bearing as the new
agent-eval layer, the approach chosen NOW must be the long-term one, even if it means
splitting into separate standalone tasks/subtasks.
Consequences:
- The reuse-vs-rebuild decision is DEFERRED to ID-104’s bottom-up design — do NOT
pre-commit to reusing the legacy L3/L4 +
lib/eval/baseline.tslayers. Whether the bottom-up layer reuses the existing baseline lifecycle /callToolharness or rebuilds them is ID-104’s call, made from a clean-sheet design, not assumed here. - ID-104’s eval-engine spec is a HARD UPSTREAM dependency, sequenced BEFORE ID-71’s born-evaluable waves (Wave 2 + Wave 3). ID-71 cannot ship B-INV-13/14/15/38/40 until the ID-104-owned contract + severity model + touchpoint registry exist to consume.
- ID-71 MUST NOT implement
eval-runner.ts/ the severity model /recordAiCall()/ the contract definition. Those are ID-104 deliverables, full stop.
The contract SHAPE ID-71 consumes (illustrative — ID-104 owns the canonical definition; fields below are the consumption surface ID-71’s born-evaluable guard reads):
// OWNED + canonically defined by ID-104 (bottom-up). Shown here only as the// consumption surface ID-71's guard (M38) reads; ID-104 may refine.interface AgentEvalContract { touchpoint_id: string; // stable id: tool name | prompt name | skill | recipe slug kind: 'tool' | 'prompt' | 'skill' | 'inline' | 'agent_recipe'; owner: string; // touchpoint registry: owner of record suite_name: string; // the eval suite this touchpoint runs under grounding_shape: // B-INV-35: exactly one of three 'structured_output' | 'forced_tool_strict' | 'citations' | 'n/a'; severity_on_fail: 'block' | 'warn' | 'info' | 'infra'; // ID-104 model variance_band: number; // ID-104 model; tolerance before regression graduation_metric?: string; // B-INV-15 / B-INV-19: in-house WS-5 auto-apply metric}Fallback (NOT intent): if ID-104’s spec lags ID-71’s born-evaluable guard subtask at
dispatch time, ID-71 may ship the consumption-surface shape above as a last-resort
placeholder interface in lib/eval/types.ts, clearly marked provisional, for ID-104 to
reconcile. This is a schedule-slip fallback, NOT the design intent — the intent is
ID-104-first.
OQ-3 — goose runtime/deploy mechanics + version-pin (co-location RATIFIED) {#OQ-3}
Section titled “OQ-3 — goose runtime/deploy mechanics + version-pin (co-location RATIFIED) {#OQ-3}”RATIFIED 15/06/2026 (Liam): co-locate on the existing IONOS/Coolify box. The recommendation below stood; no design change. Mechanics unchanged: Recipes + cron + remote-MCP +
goose runonly (NOTgoosed); pin-and-soak version policy; self-signed-TLS health-probe (#7685) handled in-spec.
Runtime mechanics (settled by HR-1 / §4.1): rely on the stable surfaces only —
YAML Recipes (parameters / retry / sub-recipes) + the built-in cron scheduler
(goose schedule add) + remote-MCP (SSE / Streamable-HTTP + auth headers, pointed at
app/api/mcp/[transport]/route.ts) + goose run (one-shot headless). Do NOT depend on
the goosed daemon (a bespoke ~103-endpoint REST surface backing the desktop app — not a
stable embedding contract). Pin the image at a specific tag (ghcr.io/block/goose:<pinned>);
the version-pin policy is pin-and-soak: bump only behind a re-run of the §MVP pilot recipe
on staging-equivalent, never auto-track weekly releases (goose ships weekly; the moving
surface is the §4.1 biggest risk). Configure the self-signed-TLS health-probe wrinkle (goose
issue #7685) away on Coolify’s healthcheck.
Deploy posture (RATIFIED 15/06/2026 — co-locate on the existing IONOS/Coolify box) as a
separate Coolify service (its own container, not sharing the cocoindex image). The box
already runs the cocoindex pipeline via onprem-deploy.yml; a second small goose service
avoids a new box’s provisioning/auth/cost. Residual risk to manage (recorded, not a
blocker): the box is ~16 GB and onprem-deploy.yml already records Coolify burn-guard
pressure from the ~5.3 GB cocoindex build — the co-located goose service competes for that
headroom, so size the goose container conservatively and watch the burn guard during the
soak. Either way the pilot is gated: goose is committed as the launch substrate ONLY after
the §MVP pilot validates the §7 must-be-true assumptions (B-INV-21).
OQ-4 — bid→forms rename lockstep: ONE coordinated client-contract break {#OQ-4}
Section titled “OQ-4 — bid→forms rename lockstep: ONE coordinated client-contract break {#OQ-4}”Ontology RULE the rename follows (BLOCKER fix — get this exactly right; PLAN must NOT inherit an inverted ontology). Two DISTINCT axes, cited:
application_type(CV 25) = the UMBRELLA / application axis. 6 core values:procurement, intelligence, sales_proposal, product_guide, competitor_research, training_onboarding(lib/mcp/tools/workspaces.ts:30-35;…/intended-architecture/04-workspace-types.md §3.2;platform-direction.md §v1-shape).procurementis an application umbrella value on THIS axis.form_type(CV 26) = a DISTINCT sibling axis — the type of form a respondent fills; 8 core incl.bid, rfp, pqq, itt, tender(…/ontology/26-form-type.md; migration20260520120828_t2_combined_pr_intel_shape_b_form_type_split.sql:627-635).form_types.applicable_application_types[]is the cross-link.- Therefore:
procurementis the application umbrella;bidis aform_typeWITHIN procurement (migration:257— “bid survives as a form_type value within procurement”;:95— “‘bid’ → ‘procurement’ (procurement umbrella rename)”). There is NOactivity_typeaxis in the schema (grep: zero hits) — the umbrella axis isapplication_type.04-workspace-types.md §11lists the umbrella/form-type inversion as a RATIFIED-REJECTED anti-pattern. - Naming RULE the bottom-up rename enforces: application-axis names use
application_types.key(e.g.procurement); form-axis names useform/form_type, never barebid.bidsurvives ONLY as aform_typesvalue, so no user-facing tool carries bare “bid” post-cutover — but a tool whose name is an APPLICATION-umbrella read (list_active_procurement, which genuinely queries.eq('application_types.key','procurement')—lib/mcp/tools/procurement.ts:178) is already correctly named and is KEPT for that reason, NOT because procurement is a form-type.
Mechanics: one atomic break across six lanes, aligned with the prod DDL cutover wave.
The DB layer is already renamed; the residual surface is MCP string literals + plugin +
fixtures + evals + client guide. Because MCP tool/resource/prompt names are string
literals (orientation), gitnexus_rename covers ONLY the graph-tracked code symbols
(hook exports useBidActions/useBidTransitions, BidsPage); the string-literal surface
is an ast-dataflow string-literal-uses + grep sweep across TS, Python, and SQL. The six
lanes (must land in ONE PR / cutover wave so no client sees a half-renamed surface —
B-INV-31):
- Code symbols (gitnexus_rename, high-confidence graph):
useBidActions→useFormActions,useBidTransitions→useFormTransitions(hooks/procurement/use-procurement-actions.ts),BidsPage→FormsPage(app/procurement/page.tsx),use-bid-data/use-bid-dialogsidentifiers. Verify completeness withast-dataflow callerspost-rename (rename-sweep skill). - MCP surface string literals (ast-dataflow
string-literal-uses+ grep): toolget_bid_question→get_form_question(tools/procurement.ts:334); resourcesbid_workspace+kb://bids/{id}→kb://forms/{id}(resources.ts:148-149),ui://bid-dashboard/app.html→ui://forms-dashboard/app.html(resources.ts:662,670,680); promptsbid_briefing→form_briefing(resources.ts:835),bid_pipeline_review→form_pipeline_review(resources.ts:1029). KEEPlist_active_procurement/get_procurement_detail— these are APPLICATION-umbrella reads (they queryapplication_types.key='procurement',procurement.ts:178), already correctly named post-DB-rename per the ontology RULE above; they are NOT renamed. What retires is the genericbidform vocab (get_bid_question→get_form_question, the bare-bidMCP resources/prompts) — becausebidis aform_typevalue, not a tool-name axis. No user-facing tool carries bare “bid” post-cutover. - Plugin bundle (
bun run build:pluginregenerates committedplugin-bundle.ts): rename commandsbid-pipeline-review.md→form-pipeline-review.md,bid-status.md→form-status.md; plugin skillbid-writing→completing-forms(the WS-9 named generalisation, B-INV-31). - Queue + API path (PI-13/14 fold):
job_type='bid_draft_all'→'form_draft_all'(lib/queue/handlers/procurement-draft-all.ts,lib/queue/dispatch.tscase, thes224_widen_job_type_checkCHECK widened in a new migration),bid_idbody field→form_id, pathapp/api/bids/[id]/…→app/api/forms/[id]/…(add the new route toproxy.tspublicRoutesonly if the old one was listed). - Fixtures + evals (
mcp-fixture-sync.test.tsdrift-guard forces this in lockstep):scripts/mcp-eval/fixtures.ts:95-97,242-267canonical tool/prompt/resource lists; the L4 checks infunctional-correctness.ts; Pythonscripts/tests/test_cocoindex_server.py(grep — ast-dataflow does not cover Python). - Inventory + client-doc refresh (M-DOCS):
mcp-parser.ts/mcp-inventory-parser.test.tscount assertions update with the rename; the client-facing tool guide regenerates. Beyond the tool-guide regen, the broader client-doc refresh is a named ID-71 deliverable (M-DOCS): the Platform Overview + Claude Integration Guide are flagged “heavily outdated” (SYNTHESIS §1.8, tracker E.2) and their refresh is “a natural ID-71 deliverable” — refresh both to the rationalised outcome-grouped surface + the new forms vocabulary as part of this cutover wave. PI-13/14: strip stale plugin branding / connector refs — clean break, no live client connectors today (B-INV-41).
This is the one place ID-71 touches DDL: the job_type CHECK widen migration (see §Proposed
changes M31/M41). Per supabase/CLAUDE.md: supabase migration new + foreground db push,
SET search_path = public, extensions, explicit REVOKE … FROM anon on any new function
(none expected here — CHECK-only).
OQ-5 — one-queue + facet reconcile: the facet IS the seam, it already exists {#OQ-5}
Section titled “OQ-5 — one-queue + facet reconcile: the facet IS the seam, it already exists {#OQ-5}”Resolution: M30 ships a NEW faceted-queue MCP tool (whats_in_my_queue) — an additive
GREENFIELD MCP surface OVER the existing lib/attention.ts substrate, NOT a thin wrapper.
The unified attention substrate genuinely exists and already merges governance + quality +
freshness — AttentionSourceData (attention.ts:~80-101) carries one set of counts,
buildAttentionItems emits one AttentionItem[] list, and AttentionItem.type
(attention.ts:~29-39) is the discriminator — but no MCP tool today consumes
AttentionItem[] with a facet filter. Today AttentionItem.type drives the dashboard
icon/colour, and formatGovernanceQueue is a SEPARATE MCP formatter on its own path. So M30
is genuinely new MCP read surface (the faceted-queue tool) built over a real, already-merged
substrate — the build is the MCP consumption seam, not the merge (the merge is done).
The /review vs /api/governance/review split that CLAUDE.md documents as separate
workflows stays at the route/page layer (content-quality review UI vs
freshness/ownership governance UI) — only the MCP consumption surface collapses to one queue
concept (B-INV-30).
Mechanics: a new whats_in_my_queue MCP tool takes
facet?: 'content_quality' | 'governance' | 'all' (default all), reads the
lib/attention.ts producers, and replaces the fragmented get_review_queue /
get_governance_queue / get_assignments_for_user / get_dashboard_summary MCP reads
(B-INV-30, B-INV-32 queue side). The cron freshness writers
(app/api/cron/review-cadence/route.ts ReviewCandidate,
app/api/cron/freshness-transitions/route.ts) and formatGovernanceQueue are unchanged
producers; only the MCP read surface consolidates.
source_document_change facet-scope (explicit — pre-existing substrate gap):
AttentionItem.type lists 'source_document_change' (attention.ts:~38) as a discriminator
value, but AttentionSourceData carries NO count and there is NO producer function for it
(no produceSourceDocumentChange*). M30 scopes source_document_change OUT of the v1
facet set — the v1 whats_in_my_queue facets are content_quality (quality_flag,
stale/expired/unverified content) + governance (governance_review, review-overdue) + the
existing assignment/coverage producers; source_document_change is NOT surfaced until a
producer + count exist. Building that producer is explicitly NOT M30 scope (it is an ID-59 /
source-document-lineage concern, cross-referenced, not built here). The v1 facet enum
therefore omits it, so no facet value resolves to an empty/absent producer.
The plugin-skill question (governance-review vs content-governance, RESEARCH §2.8
[LIAM]) folds the same way: keep both skills as the expertise layer (B-INV-34) but they
orchestrate the one faceted queue, not two.
Proposed changes
Section titled “Proposed changes”Each change is keyed M<N> to the B-INV it satisfies (full table in §M). Changes are
grouped by wave; the §M table is the orphan-check of record.
Wave 1 — Outcome-grouped surface consolidation (Option A; B-INV-25..34)
Section titled “Wave 1 — Outcome-grouped surface consolidation (Option A; B-INV-25..34)”- M27
findconsolidation. Collapsesearch_knowledge_base/search_qa_library/search_content_chunks/find_similar_itemsinto ONEfindtool registered throughregisterTools(tools/index.ts~48-75), parameterisedtype/scope(preservesq_a_pairs+scope_tagcorpus semantics) +granularity(chunk vs item). ReusefindSimilarItemsImpl+ the search formatters as internal branches; preserve the two-step list/preview→verbatim contract (M33). New entry declares anoutputSchema(M37). (B-INV-27, B-INV-33.) - M28 ontology-grounding affordance. Promote
get_entity_relationships+kb://entitiesto a first-class answering affordance offind(or a siblinggroundentry), not a curation-side tool. (B-INV-28.) - M29
where-are-we-exposed. One entry consolidatingget_expiring_content/get_freshness_report/get_coverage_gaps/get_certification_status/audit_content/get_quality_*into the five-layer presentation (data → quality → use-today → gaps → opportunities) withsuggest_content_creationas the attached resolution affordance (“Draft content for X” / “Discuss options for Y”). (B-INV-4, B-INV-29.) - M30
whats_in_my_queue(one queue + facet). Per OQ-5: a NEW faceted-queue MCP tool — additive GREENFIELD read surface OVER the existing (already-merged)lib/attention.tssubstrate, NOT a thin wrapper.facet?: 'content_quality' | 'governance' | 'all';source_document_changeis scoped OUT of the v1 facet set (no producer/count exists — pre-existing substrate gap, not built here). (B-INV-30.) - M-CREATE
create_content_itemwrite-to-canonical-store create-leg. Per OQ-1 (cutover SATISFIED): add a create-into-store leg on ID-59’s file-first write-back substrate — mint thesource_document/reference FIRST (viareference_ingest, LIVE on prod), THEN materialise thecontent_itemfile-first so the{59.10}source-less GUARD (bl-266,write-back.ts:178-191) passes. NOT a direct-DB.insert, NOT the edit-pathwriteBackFileFirst; adjacent to the{59.19}/{59.22}promoteCorpusExtractionscreate-into-store pattern. Cross-Task-coupled to ID-59 (§X). (B-INV-6, B-INV-12.) - M31
completing-forms+ bid→forms rename. Per OQ-4 six-lane break. (B-INV-31.) - M32 get/dedup/assign consolidation. One
get(one-or-many param) forget_content_item/_items; one dedup (scope param) forfind_duplicate_candidates/find_all_duplicates; one assign (one-or-many) forassign_content_owner/bulk_assign_owner. (B-INV-32.) - M33 two-step retrieval preserved on
find+get. (B-INV-33.) - M34 layer placement. Prompts +
/kb:*commands become thin orchestrators over the consolidated entries; 4 MCP Apps stay the visual-density + WS-8 resolution surface; plugin skills stay the expertise layer. No command re-implements tool ability. (B-INV-34.) - M22/M23/M24 verdict framing — surface-design record (this spec’s §M + the rename record) maps every keep/refine/retire/gap to an O/W number; no retire orphans a ranked outcome (each names its surviving entry). (B-INV-22, B-INV-23, B-INV-24.)
- M25/M26 single-server. One human-facing server via
registerTools; fleet additive; no second connector at launch; Option-B deferral trigger recorded (admin/consumption auth surfaces diverge enough to warrant a second connector). (B-INV-25, B-INV-26.)
Wave 2 — Grounding + eval standards rollout (B-INV-35..40)
Section titled “Wave 2 — Grounding + eval standards rollout (B-INV-35..40)”- M35 grounding shapes. Each AI touchpoint (
classify.ts,draft.ts3-pass,quality-check.ts,extract-questions.ts, summary/intelligence/guide passes) declares and uses exactly one of:output_config.format| forced-toolstrict:true+additionalProperties:false| citations oversearch_result. Citations never combined withoutput_config.format;draft.ts3-pass split stays forced. (B-INV-35.) - M36 no silent fallback.
stop_reason:"refusal"/"max_tokens"handled explicitly (log + surface); replacedraft.tsPass-1 bare try/catch; no assistant prefills. (B-INV-36.) - M37
outputSchemaforward-standard on new entries only; not retrofitted onto retiring tools. (B-INV-37.) - M38 forcing-function guard. Extend the
mcp-parser.ts/mcp-fixture-sync.test.ts/mcp-inventory-parser.test.tsguard pattern (and the ID-104recordAiCall()grep-guard, once it lands) so any tool/prompt/skill/inline change FAILS a guard test without acreate-skill/update-skillinvocation AND an eval/fixture update. TheAgentEvalContractpresence-check the guard enforces consumes ID-104’s bottom-up contract (OQ-2 — hard upstream dep, §X). (B-INV-38.) - M39 AI-invisibility. Consumption surfaces present enrichments as native; only admin Provenance exposes lineage. (B-INV-39.)
- M40 eval-is-the-gate. Every grounded touchpoint carries an ID-104 eval in addition to its schema constraint. (B-INV-40.)
Wave 3 — Headless-completeness + fleet substrate (B-INV-1..21)
Section titled “Wave 3 — Headless-completeness + fleet substrate (B-INV-1..21)”- M1–M5 headless-complete set. The L4 layer enumerates exactly {O1 find/answer reads, O4 reorientation/briefing reads (widened beyond KH state — M3), O6 exposure five-layer reads (M4), W5.6 re-syndication (M5)}; each is driven MCP-only to a terminal result with zero human-in-UI step. (B-INV-1, B-INV-2, B-INV-3, B-INV-4, B-INV-5.)
- M6/M7 propose-writes + auto-apply-off. Agents create propose-rows/drafts/resolutions into the queue (M30) with no publication gate; publishing routes to the human gate; per-workflow auto-apply switch exists and is verifiably OFF at launch. The write-to-canonical-store create affordance is the M-CREATE create-leg (OQ-1). (B-INV-6, B-INV-7.)
- M8/M9 dual runtime. The headless-complete set is reachable identically from Claude’s
own runtimes AND the goose runtime via the SAME remote-MCP surface
(
app/api/mcp/[transport]/route.ts); no runtime-privileged entry. (B-INV-8, B-INV-9.) - M10/M11/M12 connectivity. Incoming = remote MCP (exists, M10). Outgoing = one
trigger-driven push channel (RSS/webhook/email) delivering a consumption output (M11) +
write-back scoped to the three sanctioned destinations only (local-fs canonical store —
writeBackFileFirstfor edit-back + M-CREATE for create-into-store, live HubSpot↔Cowork connector, push) with a net-new source-system write-back refused at the surface (M12). (B-INV-10, B-INV-11, B-INV-12.) - M13/M14/M15 born-evaluable (consumes ID-104, bottom-up). Per OQ-2: every headless agent
- new/refined touchpoint ships an ID-104-owned, bottom-up
AgentEvalContract(ID-71 CONSUMES it, does not author the layer); evals authored locally (Raindrop Workshop) committed into KH’s KH-owned eval harness (not Raindrop-proprietary); the WS-5 graduation metric is computed in-house with a network assertion confirming zero client-data egress to Raindrop cloud. ID-104’s eval-engine spec is a HARD UPSTREAM dependency, sequenced before these waves (§X). (B-INV-13, B-INV-14, B-INV-15.)
- new/refined touchpoint ships an ID-104-owned, bottom-up
- M16/M17 scope boundary. W9.3 absent from ID-71’s enumeration, present as an onboarding cross-reference; launch scope = {O1/O4/O6 + W5.6} + one piloted recipe. (B-INV-16, B-INV-17.)
- M18/M19/M21 pilot + graduation. ONE goose recipe (§MVP): cron → remote-MCP → Claude → one O4 briefing → deliver to one outbound channel + write one propose-row. It exercises HC-1/HC-2/HC-4; goose commitment is pilot-gated. Fleet grows additively, per-Task, metric-gated. (B-INV-18, B-INV-19, B-INV-21.)
- M20 net-new capabilities NOT delivered under ID-71 (W5.2/W5.3/W2.3/W3.1-3.3/W2.2); each
has a reserved concept + own-Task pointer (RESEARCH §4 task-split map). WS-10 W5.2-home
assessment + WS-12
proposal-writerexemplar carried forward to the O5/O2 own-Tasks (§X intent #4; PRODUCT B-INV-20). (B-INV-20.)
Wave 1b — Client-doc refresh (rename cutover wave)
Section titled “Wave 1b — Client-doc refresh (rename cutover wave)”- M-DOCS client-doc refresh. Beyond the OQ-4-lane-6 tool-guide regen, refresh the Platform Overview + Claude Integration Guide (SYNTHESIS §1.8 — “heavily outdated”, refresh is “a natural ID-71 deliverable”) to the rationalised outcome-grouped surface + the forms vocabulary. Lands in the OQ-4 cutover wave; coordinated with the docs-site docubot lane (§X intent #5). Binds to B-INV-41 (the surface-design / branding-hygiene invariant the rename lockstep already carries). (B-INV-41.)
Wave 3b — Deferred-with-anchor (no launch change)
Section titled “Wave 3b — Deferred-with-anchor (no launch change)”- M-DEFER-O8 (no launch code change — recorded anchor). O8 W8.4 argument-quality checking is a WANTED affordance recorded DEFERRED-WITH-ANCHOR (PRODUCT B-INV-43, §G): rank-8, below the launch set; it graduates as an O8 affordance in a later group (own-Task / guide-tooling Task), born against an ID-104 eval when it lands. ID-71 builds nothing; the numbered anchor preserves it. (B-INV-43.)
Wave 0 — Carried PI-items (B-INV-41, B-INV-42)
Section titled “Wave 0 — Carried PI-items (B-INV-41, B-INV-42)”- M41 PI-13/14 fold into the OQ-4 rename lockstep (clean break; no live connectors). (B-INV-41.)
- M42 PI-15 retire. Carry PI-15 (per-tenant taxonomy-sync, BROKEN since {68.23}) as
RETIRED in the surface-design record with the one-line no-live-consumer confirmation
(expected: none);
kb://taxonomy(absorbs bl-52) named as the replacement. No code path re-enabled. (B-INV-42.)
MVP pilot (riskiest-assumption-first; B-INV-18/21) {#MVP}
Section titled “MVP pilot (riskiest-assumption-first; B-INV-18/21) {#MVP}”ONE goose Recipe on Coolify/IONOS (co-located, RATIFIED): cron trigger → remote-MCP into KH (Claude) → generate one O4 briefing → (a) deliver to one outbound channel + (b) write one propose-row into KH’s queue (M30). Instrumented with Raindrop Workshop locally; the failure-authored eval committed into the ID-104-owned harness (bottom-up; ID-104 is a hard upstream dep — §X). Proves HC-1 (briefing read) / HC-2 (propose-row) / HC-4 (push + queue write) and the §7 must-be-true assumptions in one slice. Gated: goose is the launch substrate ONLY on pilot success.
Testing and validation
Section titled “Testing and validation”Each B-INV maps to a concrete check. The MCP eval L4 functional-correctness layer
(scripts/mcp-eval/functional-correctness.ts, bun run test:mcp-eval:fc) is the primary
verifier; bun run test is the regression gate (never bun test).
- B-INV-1/2/5 (completable set): an L4 suite enumerates exactly {O1/O4/O6 reads + W5.6} and drives each MCP-only to a terminal result; the Checker confirms the enumeration verbatim and that no member is UI-only.
- B-INV-3/4 (O4 widen / O6 five-layer): L4 fixtures assert a non-KH-state dimension on the O4 read and the five-layer ordering + ≥1 resolution affordance on the O6 read.
- B-INV-6/7 (propose / auto-apply): L4 confirms an agent creates a propose-row with no human step AND is refused at publish (routed to the human gate); every headless write path defaults propose-only; the per-workflow auto-apply switch is verifiably off.
- B-INV-8/9/10 (dual runtime / incoming): the goose-consumed inventory equals the Claude-runtime inventory for the headless set; the remote-MCP-with-auth path is an evaluated connection.
- B-INV-11/12 (outgoing / write-back): an eval asserts one push delivery end-to-end; an L4 check confirms a net-new source-system write-back is refused at the surface.
- B-INV-13/14/15 (born-evaluable): the extended guard (M38) rejects a new/refined
touchpoint lacking an
AgentEvalContract; a headless agent’s eval runs under KH CI; a network assertion confirms zero client-data egress to Raindrop cloud. - B-INV-27/29/30/31/32/33 (surface shape): L4 +
mcp-fixture-sync.test.ts+mcp-inventory-parser.test.tsconfirm one parameterised entry per outcome, preserved semantics (q&a scope, chunk granularity, two-step retrieval), one faceted queue, no user-facing bid entry post-cutover, each single+batch pair consolidated. - B-INV-34/35/36/37/38/39/40 (layer + grounding + eval): unit tests assert each
touchpoint declares one grounding shape and no citations×structured-output combination;
refusal/max-tokens surfaced explicitly; new entries carry
outputSchema; the guard test fails a tooling change without skill+eval update; consumption surfaces present enrichments as native. - B-INV-18/21 (pilot): the §MVP recipe exercises an O4 read + propose-row + push + queue write; goose adoption is pilot-gated.
- B-INV-22/23/24/25/26/41/42 (framing / scope / carried): Checker confirms against this spec’s §M record (verdicts anchored to O/W numbers, no orphaned outcome, single server + deferral trigger, PI-13/14 folded, PI-15 retired with no-consumer confirmation).
- B-INV-16/17/19/20 (scope boundary): Checker confirms W9.3 is cross-reference-only, launch scope unchanged, fleet additions Task+metric-gated, no net-new capability built.
Risks and mitigations
Section titled “Risks and mitigations”- M-CREATE source-less GUARD (bl-266). The
{59.10}guard BLOCKS file writes for a source-lesscontent_item; a naive create-verb that materialises the item before minting its source binding trips the guard. Mitigation: M-CREATE mints thesource_document/ reference (viareference_ingest, LIVE on prod) FIRST, then the file leg — the guard passes. Cross-Task-coupled to ID-59 (§X), which owns the substrate. - goose moving surface (§4.1 biggest risk). Weekly releases;
goosedinstability. Mitigation: pin-and-soak (OQ-3); stable surfaces only; pilot-gated commitment. - Coolify burn headroom. Co-located goose (RATIFIED) competes with the ~5.3 GB cocoindex build on the ~16 GB box. Mitigation: size the goose container conservatively; watch the burn guard during the soak (OQ-3).
- Rename half-break. A partial bid→forms rename shows clients a mixed surface.
Mitigation: OQ-4 one-PR atomic break;
mcp-fixture-sync.test.tsdrift-guard forces fixtures in lockstep;proxy.tspublicRoutesre-check for the new API path. - ID-104 hard-upstream slip. The bottom-up eval-engine (contract + severity model +
registry) is an ID-104 deliverable sequenced BEFORE ID-71 Wave 2/3. If it slips, the
born-evaluable waves block. Mitigation: sequence ID-104 spec first (§X); the
lib/eval/types.tsconsumption-shape placeholder is a last-resort schedule fallback only (NOT intent — OQ-2). ID-71 does NOT implement the engine. - Raindrop egress. Mitigation: B-INV-15 network assertion; Workshop-local only, empty
writeKey.
Cross-Task coordination intents {#X}
Section titled “Cross-Task coordination intents {#X}”These are Orchestrator-applied ledger/coordination notes (sibling-only Subtask dep constraint honoured — these are cross-Task, so they stay at Task level, NOT bent into Subtask deps):
- ID-59 (file-first write-back substrate,
in_progress) → OQ-1 / M-CREATE. Thecreate_content_itemwrite-to-canonical-store create-leg is built on ID-59’s substrate (the canonical write-back home).reference_ingestis LIVE on prod (verified 15/06/2026), so the cutover gate is satisfied; M-CREATE mints the source binding then materialises the item file-first, satisfying the{59.10}source-less guard (bl-266). Coordinate sequencing with the in-progress ID-59. This REPLACES the prior “ID-110 cutover → onboarding” intent — the create verb is v1.1 canonical-pipeline scope on ID-59, NOT onboarding-routed. - ID-104 (eval engine,
spec_needed) → OQ-2 / B-INV-13/14/15/38/40 — HARD UPSTREAM. The per-agentAgentEvalContract+ severity/variance model + touchpoint registry +recordAiCall()are designed BOTTOM-UP and OWNED by ID-104; ID-71 CONSUMES them only and MUST NOT implement them. ID-104’s eval-engine spec is sequenced BEFORE ID-71’s born-evaluable Wave 2/3 (hard dependency, not advisory). The reuse-vs-rebuild decision is ID-104’s to make from a clean-sheet design. Alib/eval/types.tsconsumption-shape placeholder is a last-resort schedule fallback only if ID-104 lags — not the intent. ID-104 deliverable requirements ID-71 surfaces (must be answered, not deferred-by-omission):- (2a) Name the eval-result / observability UI surface explicitly. ID-71 leverages
real third-party + in-repo tooling whose viewers must be named, not left implicit: the
Raindrop Workshop local viewer (
localhost:5899, OTel-fed — for agents/recipes) +create-skill’seval-viewer/viewer.html(in-repo today,.claude/skills/create-skill/eval-viewer/viewer.html— for skills) + a KH-owned ID-104 results surface inheriting the deferred phase-4/admin/refinementstub concept (specs/ai-eval/ai-eval-phase4-hitl-refinement-spec.mdAC#12, ~:1143-1151 — a stub listing registered touchpoints + registry version + per-touchpoint signal/pattern/ proposal/rollback endpoints). Hostedraindrop.aistays EXCLUDED (HR-5 client-data blocker, B-INV-15). This is an explicit ID-104 deliverable requirement. - (2b) Inherit-or-explicitly-scope the phase-4 HITL refinement layer. The historic
phase-4 HITL refinement loop (signal aggregation → pattern detection → Claude-proposed
prompt diffs → A/B → human approve → rollback registry, across all touchpoints;
ai-eval-phase4-hitl-refinement-spec.md §1.2) narrowed in ID-71 to just propose + publication-gate + the B-INV-38 forcing-function guard. ID-104 MUST either inherit that full refinement layer or explicitly scope it — no silent orphan. - (2c) The L1/L3/L4 reuse-vs-rebuild call is DELIBERATE, not by omission. The shipped
CI-wired L1/L3/L4 suite (42+17+37 checks, live in
ci.yml;specs/ai-eval/mcp-evaluation-spec.md §1) must be an EXPLICIT ID-104 reuse-or-rebuild decision (OQ-2 defers the call to ID-104’s bottom-up design — this note makes the deliberateness a requirement, so the existing suite is not silently dropped or silently assumed-reused).
- (2a) Name the eval-result / observability UI surface explicitly. ID-71 leverages
real third-party + in-repo tooling whose viewers must be named, not left implicit: the
Raindrop Workshop local viewer (
- Onboarding Task (O9 / W9.3) → B-INV-16. W9.3 headlessness is owned by the onboarding Task; ID-71 cross-references only. (Note: the create verb is NO LONGER onboarding-routed — it moved to ID-59 per intent #1; this retires PRODUCT OQ-1’s stated TECH-GATE defer-to- onboarding fallback. PLAN states the ID-59 coupling explicitly — §PLAN-readiness.)
- Sales-proposal own-Task(s) → B-INV-20 carry-forward (WS-10 / WS-12). Two RESEARCH
inputs are carried forward to the O5/O2 own-Tasks (NOT built under ID-71): (a) the
WS-10 W5.2-home assessment — W5.2 (sales-trigger→outreach) opens as its OWN Task in the
O5 group, NOT inside the unratified
sales-proposal-workspacesPhase-3 drafts (different outcome + different data home: the live HubSpot↔Cowork connector); the sales-proposal Phase-3 build is a separate future Task whose four arm-a/arm-b substrate drafts still need Liam ratification + canonical-pipeline reconciliation. (b) the WS-12proposal-writerexemplar — carried as a named skill-reuse input to the O2 W2.2 proposal-assembly thread (not W5.2). Orchestrator backlogs both. (PRODUCT B-INV-20 records the same.) - M-DOCS client-doc refresh (ID-71-owned deliverable; coordination note for docs-site lane). The Platform Overview + Claude Integration Guide refresh (OQ-4 lane 6, M-DOCS) is an ID-71 deliverable, but the docs live in the docs-site repo with its own docubot lane — coordinate the refresh PR with that lane so it lands in the cutover wave, not after.
Ratification status
Section titled “Ratification status”Both prior ratify gates are now CLOSED (15/06/2026):
- OQ-2 — eval-contract approach: RESOLVED (Liam steer). Bottom-up, ID-104-owned
AgentEvalContract; ID-71 consumes only; ID-104 is a hard upstream dep. The reuse-vs-rebuild decision is deferred to ID-104’s bottom-up design (NOT pre-committed to reuse). - OQ-3 — goose deploy posture: RATIFIED. Co-locate on the existing IONOS/Coolify box.
No open Liam-ratification items remain in this spec.
PLAN-readiness / decomposition guidance {#PLAN-readiness}
Section titled “PLAN-readiness / decomposition guidance {#PLAN-readiness}”Standing directive for {71.4} PLAN (inherit explicitly): there is NO 25-subtask ceiling.
Decomposition is sized for QUALITY, not to a count budget. Carving standalone tasks/subtasks
is SANCTIONED wherever it yields a higher-quality result. The PLAN pass MUST decompose for
quality — including splitting the bottom-up agent-eval-layer design out (it is ID-104-owned
and a hard upstream dependency; see OQ-2 / §X) and carving the M-CREATE write-to-store
create-leg as its own slice coupled to ID-59 if that is the higher-quality path. Chain
order to respect: ID-104 eval-engine (upstream) → ID-71 Wave 1 surface + rename → Wave 2
grounding/eval-guard → Wave 3 headless/fleet; M-CREATE sequences with ID-59.
PLAN must inherit (from the two fix-passes):
- The corrected ontology RULE (OQ-4).
application_type(umbrella) andform_type(sibling axis) are DISTINCT;procurementis the umbrella,bidis aform_typewithin it;list_active_procurementis an application read and is KEPT/NOT-renamed. PLAN must NOT inherit the inverted “procurement is a form-type” framing (a ratified-rejected anti-pattern). - OQ-1 fallback retired. The create-verb moved onboarding → ID-59; PRODUCT OQ-1’s stated defer-to-onboarding TECH-GATE fallback is RETIRED. PLAN states the ID-59 coupling explicitly (M-CREATE sequences with the in-progress ID-59), not the onboarding route.
- M-DOCS (client-doc refresh) lands in the OQ-4 cutover wave, coordinated with the docs-site docubot lane (§X#5).
- B-INV-43 / M-DEFER-O8 is recorded deferred-with-anchor — PLAN creates NO launch slice for O8 W8.4; it carries the anchor forward to a later O8 group / own-Task.
- WS-10 / WS-12 carry-forward (§X#4) are inputs to the O5/O2 own-Tasks, NOT ID-71 slices.
B-INV → Proposed-change mapping (orphan-check) {#M}
Section titled “B-INV → Proposed-change mapping (orphan-check) {#M}”1:1 mapping; every B-INV has a change (or an explicit “no code change — satisfied by X”).
| B-INV | Proposed change | Notes |
|---|---|---|
| B-INV-1 | M1 | L4 enumerates {O1/O4/O6 reads + W5.6} only |
| B-INV-2 | M2 | each driven MCP-only to terminal |
| B-INV-3 | M3 | O4 widened beyond KH state |
| B-INV-4 | M4 / M29 | O6 five-layer + resolution affordance |
| B-INV-5 | M5 | W5.6 re-syndication MCP-only |
| B-INV-6 | M6 / M30 / M-CREATE | propose-rows to queue; publish human-gated; create-into-store via M-CREATE (OQ-1) |
| B-INV-7 | M7 | per-workflow auto-apply switch off at launch |
| B-INV-8 | M8 | identical surface both runtimes |
| B-INV-9 | M9 | inventories equal |
| B-INV-10 | M10 | no code change — remote MCP exists (app/api/mcp/[transport]/route.ts); evaluated as a connection |
| B-INV-11 | M11 | one trigger-driven push channel |
| B-INV-12 | M12 / M-CREATE | sanctioned destinations; net-new refused; M-CREATE = create-into-store leg, writeBackFileFirst = edit-back |
| B-INV-13 | M13 / M38 | consumes ID-104-owned bottom-up AgentEvalContract (hard upstream dep) |
| B-INV-14 | M14 | evals KH-owned (not Raindrop-proprietary); harness is ID-104-owned bottom-up |
| B-INV-15 | M15 | in-house metric + egress assertion; metric computed on ID-104 infra |
| B-INV-16 | M16 | no code change — W9.3 cross-reference only |
| B-INV-17 | M17 | scope enumeration matches |
| B-INV-18 | M18 / MVP | one piloted recipe |
| B-INV-19 | M19 | fleet additive, Task+metric-gated |
| B-INV-20 | M20 | no code change — net-new capabilities not built; reserved concepts + WS-10/WS-12 carry-forward (§X#4) |
| B-INV-21 | M21 / MVP | pilot proves HC-1/2/4; pilot-gated |
| B-INV-22 | M22 | verdicts anchored to O/W numbers (this §M) |
| B-INV-23 | M23 | keep-concept = outcome retained |
| B-INV-24 | M24 | no retire orphans a ranked outcome |
| B-INV-25 | M25 | one human-facing server; fleet additive |
| B-INV-26 | M26 | no code change — deferral trigger recorded (OQ-5/§Proposed M25/26) |
| B-INV-27 | M27 | one find; trio semantics as params |
| B-INV-28 | M28 | ontology-grounding affordance |
| B-INV-29 | M29 | one where-are-we-exposed five-layer |
| B-INV-30 | M30 / OQ-5 | one queue + facet (lib/attention.ts) |
| B-INV-31 | M31 / OQ-4 | completing-forms + bid→forms rename |
| B-INV-32 | M32 | get/dedup/assign one-or-many consolidation |
| B-INV-33 | M33 | two-step retrieval preserved |
| B-INV-34 | M34 | layer placement holds |
| B-INV-35 | M35 | one grounding shape per touchpoint |
| B-INV-36 | M36 | no silent fallback |
| B-INV-37 | M37 | outputSchema forward-standard |
| B-INV-38 | M38 | forcing-function guard |
| B-INV-39 | M39 | AI-invisibility |
| B-INV-40 | M40 | eval is the gate, not the schema |
| B-INV-41 | M41 / M-DOCS / OQ-4 | PI-13/14 fold into rename; M-DOCS = Platform Overview + Claude Integration Guide refresh |
| B-INV-42 | M42 | PI-15 retired; kb://taxonomy replacement |
| B-INV-43 | M-DEFER-O8 | no launch code change — deferred-with-anchor (O8 W8.4 argument-quality; own-Task/later-group; born-evaluable when it lands) |
Coverage: all 43 invariants mapped; no orphan invariants, no orphan changes. Five “no code change / no launch change” entries (B-INV-10 remote-MCP exists, B-INV-16 W9.3 cross-ref, B-INV-20 net-new not built, B-INV-26 deferral-trigger-recorded, B-INV-43 deferred-with-anchor) are explicit satisfied-by-X records, not gaps. Net-new changes added across the two fix-passes: M-CREATE (OQ-1 write-to-canonical-store create-leg — binds B-INV-6 + B-INV-12, no new invariant) and M-DOCS (client-doc refresh — binds B-INV-41). B-INV-43 is the one NEW invariant (PRODUCT §G, 42→43) and maps to the recorded anchor M-DEFER-O8 (no launch code). The 1:1 B-INV↔change coverage is preserved across the amended PRODUCT + TECH with no orphan invariant and no orphan change.
End of {71.3} TECH (second fix-pass applied 15/06/2026). Five TECH OQs resolved: OQ-1
write-to-canonical-store (cutover SATISFIED — reference_ingest LIVE on prod; M-CREATE
create-leg on the ID-59 substrate); OQ-2 bottom-up, ID-104-owned AgentEvalContract (hard
upstream dep — ID-71 consumes only; reuse-vs-rebuild deferred to ID-104; ID-104 must also name
the eval/observability UI surface + inherit-or-scope phase-4 HITL + make the L1/L3/L4 call
deliberate — §X#2a-c); OQ-3 co-locate RATIFIED + stable-surfaces + pin-and-soak; OQ-4
one-PR bid→forms rename with the corrected ontology RULE (application_type umbrella vs
form_type sibling axis; procurement is the umbrella, bid is a form_type within it —
list_active_procurement KEPT as an application read, NOT renamed); OQ-5 facet as a NEW
greenfield MCP tool over the existing lib/attention.ts substrate (source_document_change
scoped out of v1). 43 B-INV + M-CREATE + M-DOCS → Proposed-change 1:1 mapping in §M (Five
explicit “no code change” records; B-INV-43 = new deferred-with-anchor for O8 W8.4). Cross-Task
coordination intents (§X: ID-59 for create-verb; ID-104 hard-upstream for eval + 3 named
deliverable requirements; onboarding intent REMOVED from the create-verb path; WS-10/WS-12
carry-forward to sales-proposal Task; M-DOCS docs-site coordination). No open Liam-ratification
items. NO 25-subtask ceiling — {71.4} PLAN decomposes for quality (§PLAN-readiness). Feeds
{71.4} PLAN decomposition.