Dieu 38 P0 Investigation Report
Dieu 38 P0 Investigation Report
Date: 2026-04-02 | Session: S157
D1. LAW_REGISTRY SCHEMA
Columns (12):
| Column | Data Type | Nullable | Default |
|---|---|---|---|
| code | varchar | NO | NULL |
| article_number | varchar | NO | NULL |
| name | varchar | NO | NULL |
| version | varchar | YES | NULL |
| status | varchar | NO | 'draft' |
| category | varchar | YES | NULL |
| scope_summary | text | YES | NULL |
| kb_path | varchar | YES | NULL |
| enacted_session | varchar | YES | NULL |
| council_score | real | YES | NULL |
| composition_level | varchar | YES | 'compound' |
| species_code | varchar | YES | 'law' |
Constraints:
- PK:
law_registry_pkeyon (code) - UNIQUE:
law_registry_article_number_uniqueon (article_number) - CHECK:
chk_law_registry_status— status IN ('draft','enacted','retired')
Indexes: btree on code (PK), btree on article_number (UNIQUE)
Row count: 0 (expected 0 — P1 created schema only, no seed)
Gap Analysis vs Dieu 38 §5.1 normative_registry:
| Action | Columns |
|---|---|
| KEEP as-is | code, article_number, name, version, category, scope_summary, kb_path, enacted_session, composition_level |
| NEED ADD | doc_type (FK→nrm_doc_type_config), doc_level (SMALLINT, auto-trigger), parent_code (FK self), department, enacted_at (TIMESTAMPTZ), retired_at (TIMESTAMPTZ), superseded_by (FK self), priority_offset (SMALLINT DEFAULT 0), valid_from (TIMESTAMPTZ), valid_until (TIMESTAMPTZ), valid_period (tstzrange GENERATED), auto_expire (BOOLEAN DEFAULT false), sections (JSONB NOT NULL DEFAULT '[]'), content_hash, is_legacy_import (BOOLEAN DEFAULT false) |
| NEED MODIFY | status CHECK: expand from 3 values (draft/enacted/retired) to 6 (draft/review/enacted/blocked/warning/retired) |
| NEED MODIFY | council_score: REAL → NUMERIC |
| NEED MODIFY | species_code DEFAULT: 'law' → 'normative' |
| TABLE RENAME | law_registry → normative_registry |
Total: 15 columns ADD, 3 columns MODIFY, 9 columns KEEP, 1 TABLE RENAME
D2. FK DEPENDENCIES
FK pointing TO law_registry (3):
| Source Table | Source Column | Target | Constraint Name |
|---|---|---|---|
| law_jurisdiction | law_code | law_registry.code | fk_jurisdiction_law_code |
| governance_registry | created_by_law | law_registry.code | fk_gov_registry_created_by_law |
| law_dot_enforcement | law_code | law_registry.code | fk_enforcement_law_code |
5 tables row counts (all 0 — expected):
| Table | Count |
|---|---|
| law_jurisdiction | 0 |
| governance_registry | 0 |
| governance_relations | 0 |
| law_dot_enforcement | 0 |
| governance_audit_log | 0 |
FK update needed when RENAME: All 3 FKs must be DROPped and re-CREATEd pointing to normative_registry. Since row_count=0, this is safe.
5 tables full schema:
| Table | Column | Type | Nullable |
|---|---|---|---|
| governance_audit_log | id | integer | NO |
| governance_audit_log | relation_id | integer | YES |
| governance_audit_log | checked_at | timestamptz | YES |
| governance_audit_log | checked_by | varchar | NO |
| governance_audit_log | result | varchar | NO |
| governance_audit_log | detail | json | YES |
| governance_registry | code | varchar | NO |
| governance_registry | name | varchar | NO |
| governance_registry | gov_type | varchar | NO |
| governance_registry | gov_group | varchar | YES |
| governance_registry | output_target | varchar | YES |
| governance_registry | domain | varchar | YES |
| governance_registry | primary_collection | varchar | YES |
| governance_registry | created_by_law | varchar | YES |
| governance_registry | health_dot | varchar | YES |
| governance_registry | status | varchar | YES |
| governance_relations | id | integer | NO |
| governance_relations | source_type | varchar | NO |
| governance_relations | source_code | varchar | NO |
| governance_relations | target_type | varchar | NO |
| governance_relations | target_code | varchar | NO |
| governance_relations | relation_type | varchar | NO |
| governance_relations | is_contract | boolean | YES |
| governance_relations | discovery_source | varchar | NO |
| governance_relations | enforcement_type | varchar | YES |
| governance_relations | enforcement_ref | varchar | YES |
| governance_relations | status | varchar | YES |
| governance_relations | last_verified_at | timestamptz | YES |
| law_dot_enforcement | id | integer | NO |
| law_dot_enforcement | law_code | varchar | NO |
| law_dot_enforcement | dot_code | varchar | NO |
| law_dot_enforcement | enforcement_role | varchar | NO |
| law_dot_enforcement | status | varchar | YES |
| law_jurisdiction | id | integer | NO |
| law_jurisdiction | law_code | varchar | NO |
| law_jurisdiction | domain | varchar | NO |
| law_jurisdiction | coverage_type | varchar | NO |
| law_jurisdiction | description | text | YES |
| law_jurisdiction | status | varchar | YES |
D3. TRIGGERS HIEN CO
20 trigger registrations (15 unique triggers on 5 tables):
| Trigger | Event | Table | Function |
|---|---|---|---|
| trg_birth_law_registry | INSERT | law_registry | fn_birth_registry_auto('code') |
| trg_law_insert_must_be_draft | INSERT | law_registry | fn_law_insert_must_be_draft() |
| trg_law_enacted_immutable | UPDATE | law_registry | fn_law_enacted_immutable() |
| trg_law_enacted_must_have_enforcement | UPDATE | law_registry | fn_law_enacted_must_have_enforcement() |
| trg_law_retire_cascade | UPDATE | law_registry | fn_law_retire_cascade() |
| trg_birth_governance_registry | INSERT | governance_registry | fn_birth_registry_auto('code') |
| trg_gov_validate_health_dot | INSERT/UPDATE | governance_registry | fn_gov_validate_health_dot() |
| trg_gov_validate_primary_collection | INSERT/UPDATE | governance_registry | fn_gov_validate_primary_collection() |
| trg_gov_retire_cascade | UPDATE | governance_registry | fn_gov_retire_cascade() |
| trg_birth_governance_relations | INSERT | governance_relations | fn_birth_registry_auto_id() |
| trg_relations_validate | INSERT/UPDATE | governance_relations | fn_relations_validate() |
| trg_birth_law_dot_enforcement | INSERT | law_dot_enforcement | fn_birth_registry_auto_id() |
| trg_enforcement_validate_dot_code | INSERT/UPDATE | law_dot_enforcement | fn_enforcement_validate_dot() |
| trg_birth_law_jurisdiction | INSERT | law_jurisdiction | fn_birth_registry_auto_id() |
| trg_jurisdiction_one_primary_per_domain | INSERT/UPDATE | law_jurisdiction | fn_jurisdiction_one_primary() |
Mapping Dieu 37 triggers → Dieu 38:
| D37 Trigger | Action | D38 Mapping |
|---|---|---|
| trg_birth_law_registry | KEEP | Rename to trg_birth_normative_registry, same function |
| trg_law_insert_must_be_draft | MERGE | → nrm_status_gate (trigger 4, §6) — expanded logic |
| trg_law_enacted_immutable | MERGE | → nrm_enacted_immutable (trigger 2) — same concept, broader |
| trg_law_enacted_must_have_enforcement | KEEP | Stays — enforcement still required for enactment |
| trg_law_retire_cascade | EXPAND | → nrm_retire_cascade — cascade to normative_relations too |
| 5 birth triggers (others) | KEEP | Birth auto-register unchanged |
| gov_validate_* | KEEP | Unaffected by RENAME (FK column name stays) |
| relations_validate | KEEP | Unaffected |
| enforcement_validate_dot | KEEP | Unaffected |
| jurisdiction_one_primary | KEEP | Unaffected |
NEW triggers needed (Dieu 38 §6):
- nrm_doc_level_auto — auto doc_level from nrm_doc_type_config
- nrm_enacted_immutable — replaces trg_law_enacted_immutable (broader)
- nrm_temporal_auto — auto valid_from/valid_until
- nrm_status_gate — replaces trg_law_insert_must_be_draft (6-state machine)
- nrm_content_hash_auto — auto content_hash from sections
- nrm_sections_validate — validate JSONB sections format
- nrm_cascade_review_on_binding — flag REVIEW when binding changes
- nrm_supersede_auto — auto set old version when superseded_by
- nrm_conflict_detect — conflict detection (same article + overlapping period)
- nrm_shadow_ban_trigger — shadow ban enforcement
- nrm_doc_instance_snapshot — snapshot on sign
- nrm_instance_template_check — only template → instance
- nrm_approval_check — enacted must have approval (D32)
- EXCLUDE constraint — temporal overlap prevention Plus: law_registry_readonly_view trigger (block writes to VIEW)
D4. 22+ KB LAW FILES
Files in knowledge/dev/laws/:
| File | Article(s) | Format |
|---|---|---|
| constitution.md | Hien Phap | "HIEN PHAP... v4.3.0" |
| law-01-foundation-principles.md | Dieu 1 (=Dieu 0) | "DIEU 1: NGUYEN TAC NEN TANG" + version line |
| law-02-registry.md | Dieu 2 | Standard |
| law-03-metadata.md | Dieu 3 | Standard |
| law-04-birth-process.md | Dieu 4 | Standard |
| law-05-five-tiers.md | Dieu 5 | Standard |
| law-06-sync.md | Dieu 6 | Standard |
| law-07-assembly-first.md | Dieu 7 | Standard |
| law-08-dependency.md | Dieu 8 | Standard |
| law-09-schema-governance.md | Dieu 9 | Standard |
| law-10-13-operations.md | Dieu 10-13 | BUNDLED 4 laws |
| law-14-no-duplicate.md | Dieu 14 | Standard |
| law-15-16-state-checkpoint.md | Dieu 15-16 | BUNDLED 2 laws |
| law-17-18-domain-change.md | Dieu 17-18 | BUNDLED 2 laws |
| law-19-orphan-scanner.md | Dieu 19 | Standard |
| law-22-self-healing.md | Dieu 22 | Standard |
| law-00h-5layer-sync.md | Dieu 0-H | Standard |
Files in knowledge/dev/architecture/:
| File | Article | Status |
|---|---|---|
| dieu26-new-registries-counting-law-draft.md | Dieu 26 | enacted |
| dieu28-display-technology-law-v2-draft.md | Dieu 28 | enacted |
| dieu30-review-request.md | Dieu 30 | enacted |
| dieu31-layer3-layer4-law.md | Dieu 31 | enacted |
| dieu32-approval-law-draft.md | Dieu 32 | enacted |
| dieu33-postgresql-law-draft.md | Dieu 33 | DRAFT v1.4 |
| dieu34-workflow-law-draft.md | Dieu 34 | DRAFT |
| dieu35-dot-governance-law-draft.md | Dieu 35 | enacted v5.0 |
| dieu36-collection-protocol-law-draft.md | Dieu 36 | enacted v4.0 |
| dieu37-governance-organization-law-draft.md | Dieu 37 | enacted v3.3 |
| dieu38-normative-document-law-draft.md | Dieu 38 | enacted v2.3 |
| species-collection-law-draft.md | Dieu 0-B | enacted |
Missing from KB: Dieu 0-G (naming), Dieu 20, Dieu 21, Dieu 23, Dieu 24, Dieu 25, Dieu 27, Dieu 29. Some may not exist or are embedded in other docs.
Bundled files (contain multiple laws): law-10-13, law-15-16, law-17-18 Draft files: dieu33 (v1.4), dieu34 Format consistency: MOSTLY consistent — title line with "DIEU N:" or "DIEU N —", version line with "vX.X | SXXX". Some older files use different heading styles. DOT-NRM-DRAFT parser needs to handle: (a) article_number from title, (b) version from version line, (c) status from "enacted"/"draft" keywords, (d) bundled files need splitting.
D5. PG DATA FOR GOVERNANCE
dot_tools: 167 total, 155 active, across 20 domains
| Domain | Total | Active |
|---|---|---|
| infrastructure.schema | 38 | 38 |
| infrastructure.sync | 20 | 20 |
| infrastructure.deploy | 15 | 15 |
| monitoring.integrity | 14 | 12 |
| sync | 12 | 12 |
| workflow | 10 | 10 |
| collection | 10 | 10 |
| data_quality | 8 | 8 |
| pivot | 8 | 0 |
| lifecycle | 8 | 6 |
| monitoring.health | 5 | 5 |
| governance.audit | 4 | 4 |
| classification.species | 3 | 3 |
| governance.approval | 3 | 3 |
| monitoring.dot | 3 | 3 |
| birth.register | 2 | 2 |
| birth.orphan | 2 | 2 |
| classification.label | 1 | 1 |
| infrastructure.backup | 1 | 1 |
dot_domains: 25 domains (birth, birth.orphan, birth.register, classification, classification.label, classification.species, collection, data_quality, governance, governance.approval, governance.audit, infrastructure, infrastructure.backup, infrastructure.deploy, infrastructure.schema, infrastructure.sync, lifecycle, monitoring, monitoring.dot, monitoring.health, monitoring.integrity, pivot, sync, unclassified, workflow)
collection_registry: 153 total
| governance_role | Count |
|---|---|
| observed | 63 |
| excluded | 60 |
| governed | 30 |
D6. APPROVAL_REQUESTS SCHEMA
Columns (22):
| Column | Type | Nullable |
|---|---|---|
| id | integer | NO |
| code | text | YES |
| request_type | text | NO |
| entity_type | text | YES |
| entity_code | text | YES |
| title | text | NO |
| current_state | jsonb | YES |
| proposed_action | jsonb | YES |
| alternative_actions | jsonb | YES |
| evidence | text | YES |
| source | text | YES |
| priority | text | YES |
| status | text | YES |
| reviewed_by | text | YES |
| reviewed_at | timestamp | YES |
| review_note | text | YES |
| applied_at | timestamp | YES |
| date_created | timestamp | YES |
| action | varchar | NO |
| target_collection | varchar | YES |
| target_entity_code | varchar | YES |
| source_context | json | YES |
| date_updated | timestamptz | YES |
| issue_signature | text | YES |
Row count: 165 (existing APR data)
For trigger 13 (nrm_approval_check): Use entity_code (or target_entity_code) to match normative_registry.code, and status to check if approved. No target_code column — use entity_code + entity_type='normative' or target_entity_code.
BLOCKERS
- Bundled law files (law-10-13, law-15-16, law-17-18): DOT-NRM-DRAFT parser must split these into individual records. Each sub-law needs its own article_number.
- Missing KB laws (Dieu 20,21,23-25,27,29): Cannot seed all 22+ laws if KB files don't exist. Need to verify: are these laws enacted? If yes, where are they documented?
- council_score type mismatch: PG has REAL, Dieu 38 specifies NUMERIC. ALTER COLUMN needed.
- No nrm_doc_type_config table yet: Must CREATE before law_registry → normative_registry RENAME (doc_type FK dependency).
- law_registry_readonly_view: After RENAME, must create
law_registryas VIEW with write-blocking trigger per Dieu 38 §3.
RECOMMENDATIONS
- Phase A (Schema): Create nrm_doc_type_config + nrm_approval_rules FIRST. Then ALTER TABLE law_registry (add columns, modify constraints). Then ALTER TABLE RENAME law_registry → normative_registry. Then create law_registry VIEW + write-block trigger. Then update 3 FKs.
- Phase B (Seed): Seed nrm_doc_type_config with 7 doc_types. Seed 22 laws from KB into normative_registry with is_legacy_import=true.
- Phase C (Governance): DOT-GOV-DISCOVER uses dot_tools (167) + dot_domains (25) + collection_registry (153) to auto-populate governance_registry + governance_relations.
- All tables have 0 rows — migration is safe, no data loss risk.
- Bundled files: Consider manual article_number mapping table rather than complex parser.
- Missing laws: Desktop to confirm which article_numbers are enacted. Agent should NOT guess.