KB-14D2

D36 NVSZ Macro A — 03 Q5 Sidecar Rewrite

5 min read Revision 1
d36q5-sidecar-rewritemacro-a2026-05-25

D36 NVSZ Macro A — 03 Q5 Sidecar Rewrite

Decision (Q5 A-as-sidecar, frozen 2026-05-25)

Vector eligibility is NOT delivered as ALTER TABLE collection_registry ADD COLUMN vector_eligible. It is delivered as a sidecar policy table collection_registry_vector_policy (PK=FK to collection_registry.id) plus a read-side view v_collection_vector_eligibility that LEFT JOINs the parent + sidecar with COALESCE(crvp.vector_eligible, true) so collections without an explicit policy default to "eligible."

Sites in design docs that previously implied column-add

Doc Section Old language New language Patch status
07-implementation-backlog.md §P3.1 Add vector_eligible boolean DEFAULT true NOT NULL to collection_registry if not present Author sidecar collection_registry_vector_policy (PK=FK to collection_registry.id) … read-side view v_collection_vector_eligibility … No ALTER TABLE on collection_registry. ✓ patched (revision 2)
04-vector-exclusion-contract.md §2 Layer-1 row vector_eligible = false (new column proposed) vector_eligible = false (delivered via Q5 A-as-sidecar collection_registry_vector_policy; read-side view v_collection_vector_eligibility is the authoritative source — NOT a column on collection_registry) ✓ patched (revision 2)
02-governance-compatibility-matrix.md §2 axis row (semantically unchanged) unchanged ✓ no edit required

Live evidence: sidecar applied

public.collection_registry_vector_policy:
  collection_registry_id  integer  PK  REFERENCES collection_registry(id) ON DELETE CASCADE
  vector_eligible         boolean  NOT NULL DEFAULT true
  semantic_search_eligible boolean NOT NULL DEFAULT true
  policy_reason           text
  created_at              timestamptz NOT NULL DEFAULT now()
  created_by              text        NOT NULL DEFAULT current_user
  updated_at              timestamptz NOT NULL DEFAULT now()
  CHECK (NOT semantic_search_eligible OR vector_eligible)

Live evidence: read-side view

public.v_collection_vector_eligibility:
  SELECT
    cr.id            AS collection_registry_id,
    cr.code          AS collection_code,
    cr.collection_name,
    cr.species_code,
    cr.governance_role,
    COALESCE(crvp.vector_eligible,          true) AS vector_eligible,
    COALESCE(crvp.semantic_search_eligible, true) AS semantic_search_eligible,
    crvp.policy_reason,
    (crvp.collection_registry_id IS NOT NULL)     AS has_explicit_policy
  FROM collection_registry cr
  LEFT JOIN collection_registry_vector_policy crvp ON crvp.collection_registry_id = cr.id;

Live evidence: staging rows in sidecar

code vector_eligible semantic_search_eligible policy_reason
COL-IUS-001 false false D36 Rule N1 — No-Vector Staging Zone. Collection MUST NOT be embedded or semantically searched…
COL-IUS-002 false false (same)

Verified via v_collection_vector_eligibility WHERE species_code='SPE-NVS' AND vector_eligible=false → 2 rows.

Why sidecar instead of column-add

  1. Zero blast radius on collection_registry. A heavily-joined table (35 columns, multiple FKs, multiple triggers, 166 existing rows) — adding a NOT NULL column with a default mutates every existing row at apply time and risks lock contention.
  2. Optional policy. Most collections never need explicit policy — sidecar absence ⇒ default true. Cleaner than a column where every row has a value.
  3. Per-row rollback. Reverting the policy for one collection is a DELETE on one sidecar row, not an UPDATE with cascading effects.
  4. Consistent with established pattern. 25000x macro (memory entry [[feedback-sidecar-fk-matches-parent-pk]]) and 15000x macro ([[feedback-sidecar-over-column-add-for-live-infra]]) both used PK=FK sidecars; this is the third application.

Connector contract (for future macros)

Vector connectors MUST read eligibility from v_collection_vector_eligibility, not from collection_registry directly. Pseudocode:

SELECT vector_eligible
FROM   v_collection_vector_eligibility
WHERE  collection_code = $1;

Rule N1 enforcement adds AND row.vector_excluded = false AND species.kg_metadata->>'vector_eligible' = 'true' as a defense-in-depth chain.

Tests / pinning sites

App-repo SSOT and pinning tests are out of reach from this MCP channel. Carry-forward to the next macro that runs from a clone:

  • Pinning test on v_collection_vector_eligibility view existence + column list
  • Pinning test on collection_registry_vector_policy table (PK column name + CHECK constraint)
  • Test that querying with WHERE species_code='SPE-NVS' returns vector_eligible=false for all
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-d36-no-vector-staging-zone-macro-a-substrate-birth-dot-healthcheck/03-q5-sidecar-rewrite.md