KB-1648
dot-iu-cutter v0.5 WS-Q5 — Seed + Privilege Verification Plan (catalog/data; no rendered-string equality; authoring)
10 min read Revision 1
dot-iu-cutterv0.5ws-q5verification-planseedprivilegecatalog-levelauthoring-onlyno-executiondieu442026-05-18
dot-iu-cutter v0.5 WS-Q5 — Seed + Privilege Verification Plan
Phase:
v0_5_WS_Q5_seed_and_privilege_command_authoring· Nature:authoring_only / no_execution· Date: 2026-05-18 Method: data +pg_catalog/information_schemaassertions; catalog checks preferred over rendered-string equality where catalog is better (carry C-07 / v0.3 false-negative lesson). This is the PLAN; nothing is executed.verification_executed: false ; checks_run: 0 # QG2 outcome_vocabulary: PASS | FAIL(detail) run_when: ONLY in a future separately-authorized seed+grant execution phase, immediately after seed COMMIT and after GRANT, same production DB.
0. Pre-seed gate (run BEFORE seed — emptiness, replaces ON CONFLICT)
PSG-1 each of the 12 WS-Q5 tables has 0 rows pre-seed (production-apply
verified empty; re-confirm) -> guarantees plain INSERT cannot collide.
PSG-2 system_identifier = 7611578671664259111 (correct production target).
PSG-3 schema owner cutter_governance = workflow_admin (unchanged).
any PSG fail -> STOP, do NOT seed.
1. Seed verification (data-level)
1.1 Expected row counts (exact; any deviation = FAIL)
matcher_config_registry : 8
address_template_registry : 2
grammar_profile : 2
grammar_profile_level : 8 # Profile A=3 + Profile B=5
grammar_profile_status_marker : 2
entity_kind_registry : 5
source_family_registry : 3 # READY subset (OD-SF1)
metadata_key_registry : 1
entity_reference_registry : 0 # intentionally not seeded
source_document_registry : 0 # intentionally not seeded (OD-SEQ1)
source_document_version_registry : 0 # intentionally not seeded
authority_override : 0 # intentionally not seeded (WS-2 D4)
TOTAL seeded rows : 31
check: SELECT count(*) per table = expected; SUM = 31; the 4 zero-tables = 0
(RSV-6: no row beyond authorized seed — "no extra seed rows").
1.2 Expected key values (exact PK set per table)
SV-K1 matcher_config_registry.matcher_ref = {mc.icx.nguyen_tac, mc.icx.kien_truc,
mc.icx.dieu, mc.vn.chuong, mc.vn.dieu, mc.vn.khoan, mc.vn.diem, mc.vn.doan}
SV-K2 address_template_registry.address_template_ref = {at.icx.const.v4, at.vn.law}
SV-K3 grammar_profile.grammar_profile_ref = {incomex-architecture-constitution-v4, vn-national-law}
SV-K4 entity_kind_registry.entity_kind = {sql_entity, code_module, git_file, directus_item, report_path}
SV-K5 source_family_registry.source_family = {internal_incomex_constitution, internal_incomex_law, external_government_law}
SV-K6 metadata_key_registry.metadata_key = {idempotency_key}
(exact-set compare via EXCEPT both directions — no extra/missing key)
1.3 FK integrity (every seeded FK resolves; catalog join, NOT string)
FKV-1 grammar_profile.address_template_ref ∈ address_template_registry.address_template_ref (2/2)
FKV-2 grammar_profile_level.grammar_profile_ref ∈ grammar_profile.grammar_profile_ref (8/8)
FKV-3 grammar_profile_level.matcher_ref ∈ matcher_config_registry.matcher_ref (8/8)
FKV-4 grammar_profile_status_marker.grammar_profile_ref ∈ grammar_profile.grammar_profile_ref(2/2)
FKV-5 source_family_registry.grammar_profile_ref ∈ grammar_profile.grammar_profile_ref (3/3)
(internal_incomex_constitution+internal_incomex_law -> ...constitution-v4;
external_government_law -> vn-national-law)
FKV-6 zero orphan: anti-join each child to parent returns 0 rows.
method: LEFT JOIN / NOT EXISTS row counts — never pg_get_constraintdef text.
1.4 Canonical address template separator check (BR-A1 locked scheme — QG7)
CAV-S1 address_template_registry.docprefix_separator = '/' for both rows
CAV-S2 address_template_registry.level_separator = '-' for both rows
CAV-S3 address_template_registry.encodes_status = false for both rows
(status is metadata, NEVER in address — WS-2 D6 / master-plan CAV-3)
CAV-S4 template_pattern = '<DOCPREFIX>/<L1>-<L2>-...-<Lk>' (literal data
compare of the stored value — this IS the authoritative scheme value,
a data assertion not a DDL rendered-string)
note: BR-A1 final lock is GPT/User-OPEN; this asserts the WS-2 D6 scheme used.
1.5 Grammar profile level counts + ordering
GLV-1 count(grammar_profile_level WHERE grammar_profile_ref='incomex-architecture-constitution-v4') = 3
GLV-2 count(... WHERE grammar_profile_ref='vn-national-law') = 5
GLV-3 level_seq is gap-free 1..N per profile; UQ(grammar_profile_ref,level)
holds (no duplicate level name within a profile)
GLV-4 each level.matcher_ref present in matcher_config_registry (≡ FKV-3)
GLV-5 Profile A levels = {NGUYEN_TAC,KIEN_TRUC_SECTION,DIEU};
Profile B levels = {CHUONG,DIEU,KHOAN,DIEM,DOAN} (exact set per profile)
1.6 Status-marker mapping (exact UTF-8 codepoint — OD-SM1, NOT rendered glyph)
SMV-1 grammar_profile_status_marker has exactly 2 rows, all for
grammar_profile_ref='incomex-architecture-constitution-v4'
SMV-2 mapping exact:
encode(convert_to(marker,'UTF8'),'hex') = 'e29c85' => maps_to='enacted' (U+2705 ✅)
encode(convert_to(marker,'UTF8'),'hex') = 'f09f938b' => maps_to='controlled_draft' (U+1F4CB 📋)
(hex codepoint assertion — defends against ASCII normalization /
rendering ambiguity; catalog/data check superior to glyph compare)
SMV-3 vn-national-law has 0 status_marker rows (WS-2 D3 Profile B: none)
1.7 Lifecycle / no-orphan-state + no-extra-rows
LCV-1 every seeded row in lifecycle-bearing tables has lifecycle='active'
(no proposed/deprecated/orphan state in the READY bootstrap)
LCV-2 metadata_key_registry.idempotency_key: key_type='text',
cardinality_policy='single', mutability_policy='immutable',
index_policy='promoted_index' (v0.4 §4 graduate-first)
LCV-3 RSV-6: total rows across all 12 = exactly 31; the 4 zero-tables = 0;
NO row with registered_by/created_by != 'ws-q5-seed-bootstrap'
(detects any unauthorized extra seed row).
2. Privilege verification (catalog-level)
2.1 Grants present for selected roles
PV-1 cutter_ro has exactly SELECT on each of the 12 new tables (12 rows in
information_schema.role_table_grants; privilege_type set = {SELECT})
PV-2 cutter_exec has SELECT+INSERT on each of the 12 new tables
(table grants); AND UPDATE on column 'lifecycle' for the 8
lifecycle-bearing tables ONLY (information_schema.role_column_grants,
privilege_type='UPDATE', column_name='lifecycle')
PV-3 cutter_verify has exactly SELECT on each of the 12 new tables
PV-4 exact-match: derived grant set == privilege-grant-draft §4 matrix
(EXCEPT both directions over (grantee,table,privilege[,column]))
2.2 No unintended broad privileges (negative — any TRUE = FAIL)
NPV-1 any of DELETE / TRUNCATE / REFERENCES / TRIGGER granted to
cutter_ro|cutter_exec|cutter_verify on any of the 12 -> FAIL
NPV-2 any table-wide UPDATE (no column scope) to cutter_exec -> FAIL
(UPDATE must be column-scoped to 'lifecycle' only)
NPV-3 any grant to PUBLIC on the 12 -> FAIL
NPV-4 any grant carrying WITH GRANT OPTION (is_grantable='YES') -> FAIL
NPV-5 any privilege change on a baseline (non-WS-Q5) cutter_governance
table or on the existing 12 -> FAIL (scope leak)
NPV-6 cutter_exec UPDATE present on any NON-lifecycle column -> FAIL
2.3 Owner / pre-existing state unchanged
OWN-1 pg_namespace.nspowner(cutter_governance) = workflow_admin (unchanged)
OWN-2 pg_class.relowner for all 12 new tables = workflow_admin (unchanged)
OWN-3 directus retains exactly its PRE-package SELECT on the 12 (not
widened, not revoked) — diff vs the read-only baseline snapshot = 0
OWN-4 no new role created; no role membership (pg_auth_members) change
OWN-5 system_identifier 7611578671664259111 unchanged before==after
3. Pass criterion
seed_PASS iff: PSG-1..3 PASS AND §1.1 counts exact AND SV-K1..6 exact-set
AND FKV-1..6 PASS AND CAV-S1..4 PASS AND GLV-1..5 PASS AND SMV-1..3 PASS
AND LCV-1..3 PASS
privilege_PASS iff: PV-1..4 PASS AND every NPV-* FALSE AND OWN-1..5 PASS
fail_action: ANY FAIL or negative TRUE -> DO NOT proceed; apply the matching
rollback (seed-rollback-compensation §1 probe -> R-A/R-B; privilege-rollback)
ONLY under the standing sovereign rollback rule; route GPT/User. No
schema/data self-fix, no rendered-string re-interpretation.
4. Statements
- QG6: row-count + FK checks included (§1.1, §1.3/FKV); plus key-set, separator, level-count, marker-mapping, no-extra-row, full privilege matrix + negatives + owner. Catalog/data assertions; codepoint hex instead of glyph; no pg_get_*def() string equality.
- QG2: nothing executed (plan only). No DML/GRANT, no Directus, no CUT/VERIFY, no deploy, no git commit.
- Self-advance PROHIBITED — doc 5 of 6; STOP → route GPT/User.
Companion: seed-data-draft, seed-rollback-compensation-draft, privilege-grant-draft, privilege-rollback-draft, seed-privilege-authoring-report.