D36 NVSZ Macro A — 03 Q5 Sidecar Rewrite
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
- 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. - Optional policy. Most collections never need explicit policy — sidecar absence ⇒ default
true. Cleaner than a column where every row has a value. - Per-row rollback. Reverting the policy for one collection is a DELETE on one sidecar row, not an UPDATE with cascading effects.
- Consistent with established pattern.
25000xmacro (memory entry [[feedback-sidecar-fk-matches-parent-pk]]) and15000xmacro ([[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_eligibilityview existence + column list - Pinning test on
collection_registry_vector_policytable (PK column name + CHECK constraint) - Test that querying with
WHERE species_code='SPE-NVS'returns vector_eligible=false for all