KB-1752

P5 — Schema Draft v0.2: Text as Code — Unit / Publication / Metadata

48 min read Revision 1
dieu38p5schematext-as-codeofficial

P5 — Schema Draft v0.2: Text as Code — Unit / Publication / Metadata

Loại: Schema design note — Điều 38 Text as Code Phase: P5 (Schema Phase), đầu vào từ C1 + C2 + C1A + LSL-01 Trạng thái: DRAFT v0.2 — Patched theo GPT Round 1 (12 điểm) + Round 2 (7 điểm). Chờ User duyệt final. Ngày soạn: 2026-04-26 | Phiên: S181 Agent soạn: Opus 4.6 (Desktop) GPT review: Round 1 — PASS có điều kiện (12 patches). Round 2 — PASS có điều kiện nhẹ (7 patches). Inputs: LSL-01 v0.3 + v0.4, C1A (OFFICIAL), C1, C2, HOW-TO-READ, Mainline Cross-check, Đ24 label system, Đ33 PG Law


1. Mục tiêu

Chuyển design notes tiền-schema (C1 + C2 + C1A) thành draft schema cụ thể — đủ chi tiết để GPT review tính nhất quán, đủ rõ để chuyển thành DDL thật sau khi P5 PASS và User duyệt implementation/migration path.

P5 v0.2 trả lời: "Băng chuyền chính gồm bao nhiêu bảng, bảng nào chứa gì, quan hệ thế nào, lifecycle chạy ra sao?"

P5 v0.2 là bản vẽ kỹ thuật — pseudo-DDL để diễn đạt ý, KHÔNG apply vào production. DDL thật chỉ được thực hiện sau khi P5 PASS và User duyệt implementation/migration path riêng.


2. Phạm vi / Không làm

2.1 Trong phạm vi

  1. logical_unit — danh tính miếng thông tin
  2. unit_version — nội dung miếng tại 1 thời điểm
  3. publication — bản công bố (document/luật/SOP/knowledge)
  4. publication_member — membership: publication trỏ tới unit_versions
  5. Label mapping tương thích Đ24 (entity_labels)
  6. section_type_vocab — controlled vocabulary cho section_type
  7. Length flags / exception metadata trên unit_version
  8. Vector projection hooks (sync status + chunk manifest concept)
  9. Review / change-set / APR integration hooks
  10. Birth gate readiness hooks

2.2 Không làm

  • Không full Component/BOM schema (thuộc C3/P5b)
  • Không migration thật / apply SQL vào production
  • Không production write path / transaction code
  • Không DOT implementation / cron jobs (thuộc P6 — checker/DOT design)
  • Không Qdrant implementation / embedding pipeline
  • Không sửa C1/C2/C1A/LSL/L1–L5
  • Không UI / workflow engine / rendering engine

3. Nguyên tắc thiết kế

DP-1: 2 bảng tách biệt cho logical unit và unit version

Quyết định: Giải quyết C1-OD12 + C2-OD-M1.

Chọn 2 bảng (logical_unit + unit_version) thay vì 1 bảng gộp.

Rationale:

  • LSL-01 §4 phân biệt rõ: logical unit = danh tính (sống xuyên versions), unit version = nội dung (tại 1 thời điểm).
  • Identity metadata (canonical_address, parent, sort_order, section_type, owner) ổn định xuyên versions → gắn logical_unit.
  • Content metadata (title, body, description, review_state) thay đổi per version → gắn unit_version.
  • Gộp 1 bảng buộc duplicate identity metadata mỗi version, vi phạm NT11 (Khai tối thiểu).

Tradeoff: 2 bảng = thêm 1 JOIN khi query. Nhưng JOIN trên PK/FK indexed là O(1), chấp nhận được. Lợi ích: address truly bất biến, parent thay đổi 1 chỗ, version history sạch.

DP-2: Publication là bảng riêng, membership là bảng junction

Quyết định: Giải quyết C1A-OD-C1A-08.

  • publication = bảng chứa governance metadata (doc_code, version, lifecycle, owner, authority).
  • publication_member = bảng junction (publication_id, logical_unit_id, unit_version_id, render_order).
  • Bảng publication_member dùng cho MỌI lifecycle stage (proposed lẫn enacted). Khi publication enacted → membership bị lock (immutable). Khi proposed → membership có thể thay đổi.
  • Membership tách biệt hoàn toàn với Đ24 entity_labels classification label doc=X.

Rationale: CI-4 (label ≠ membership). Label "miếng này nói về Đ38" ≠ "miếng này là phần chính thức của PUB-Đ38-v3.0-ENACTED". Junction table rõ ràng, có constraint UNIQUE per (publication_id, logical_unit_id), hỗ trợ render_order per publication.

DP-3: Classification labels dùng Đ24 entity_labels

Quyết định: Giải quyết C1A-OD-C1A-04.

Logical unit có code (canonical_address hoặc entity code) → map vào entity_labels.entity_code. KHÔNG tạo label table riêng. Nếu scale issue phát sinh, giải quyết bằng indexing/partitioning trên entity_labels, KHÔNG phá Đ24 SSOT.

DP-4: section_type là FK controlled vocabulary, thuộc logical_unit

Quyết định: Giải quyết C2-OD-M8.

section_type gắn logical_unit (mô tả vai trò cấu trúc, ổn định xuyên versions). Thay đổi section_type = structural change, qua change-set. section_type KHÔNG phải Đ24 classification label (IN-3 HOW-TO-READ), nhưng có thể map sang Đ24 làm facet nếu cần — quyết định map thuộc P6.

Lưu ý: section_type_vocabpublication_type_vocabcontrolled vocabulary cho structural/governance metadata, không thay thế Đ24 taxonomy_facets / entity_labels. Nếu cần pivot cross-system (ví dụ: query tất cả entity loại article xuyên hệ thống), thì map/sync sang Đ24 bằng rule riêng — không đặt classification data vào vocab tables.

DP-5: Profile metadata phân tầng theo object family

Quyết định: Giải quyết C2-OD-M2.

Chọn JSONB cho profile metadata, nhưng phân tầng rõ:

Object Profile field Mô tả
logical_unit identity_profile JSONB Profile cho identity metadata mở rộng per section_type (ví dụ: legal_effect, is_normative, canonical_doc_label). Ổn định xuyên versions.
unit_version content_profile JSONB Profile cho content metadata mở rộng per section_type/doc_family (ví dụ: enforcement_date, actor, frequency). Thay đổi per version.
publication publication_profile JSONB Profile cho publication metadata mở rộng per publication_type (ví dụ: review_deadline, distribution_list, kb_path).

Profile trên component, relation, change-set = deferred cho C3/P5b/P6.

Rationale: C2/L3 nói metadata áp cho nhiều object families. JSONB linh hoạt, thêm field không cần ALTER TABLE. JSON Schema validation (application-level hoặc PG check constraint) đảm bảo required fields.

Tradeoff: JSONB mất type safety ở DB level. Bù bằng: birth gate validation + DOT daily check + JSON Schema.

DP-6: Publication member là membership table, không materialized view

Quyết định: Giải quyết C2-OD-M6.

Dùng publication_member table cho mọi lifecycle stage. Enacted publication → membership locked (trigger/app block INSERT/UPDATE/DELETE). Table với lock mechanism = kiểm soát tốt hơn materialized view.

DP-7: Canonical address sinh tại birth, unique constraint

Quyết định: Giải quyết C1A-OD-C1A-05.

  • Format: {DOC_CODE}-S{section}-P{paragraph}[-{sub}] (giữ tương thích hiện tại).
  • UNIQUE constraint trên logical_unit.canonical_address.
  • Sinh bởi: Agent manual hoặc system-auto (birth path).
  • Nếu system-auto: reservation mechanism qua SELECT FOR UPDATE hoặc sequence, tránh race condition.
  • Bất biến sau birth — trigger hoặc application-level enforcement.

4. Entity map

┌──────────────┐     1:N      ┌──────────────┐
│ logical_unit │─────────────▶│ unit_version  │
│              │              │              │
│ identity     │              │ content      │
│ address      │              │ body         │
│ parent_id ◄──┼── self-ref   │ lifecycle    │
│ section_type │              │ content_prof │
│ identity_prof│              │ content_hash │
│ doc_code ────┼── structural └──────────────┘
│   (NOT FK)   │  lineage            │
└──────┬───────┘  binding      N:M via
       │                       publication_member
       │ N:M via                     │
       │ entity_labels (Đ24)         ▼
       │                      ┌──────────────┐
       ▼                      │ publication  │
┌──────────────┐              │              │
│ entity_labels│              │ doc_code     │
│ (Đ24 exist.) │              │ version      │
│              │              │ lifecycle    │
│ entity_code  │              │ authority    │
│ facet_code   │              │ pub_profile  │
│ label_value  │              └──────────────┘
└──────────────┘

Controlled vocabularies (structural/governance, NOT Đ24 replacement):
┌──────────────────────┐  ┌──────────────────────┐
│ section_type_vocab    │  │ publication_type_vocab│
│ (FK from logical_unit)│  │ (FK from publication) │
└──────────────────────┘  └──────────────────────┘

Change-set & review (hooks):
┌──────────────┐     1:N     ┌──────────────────────┐
│ change_set   │────────────▶│ change_set_member     │
│              │             │ (logical_unit_id,     │
│ lifecycle    │             │  old_version_id,      │
│ apr_ref      │             │  new_version_id)      │
│ snapshot_ref │             └──────────────────────┘
└──────────────┘

Vector projection (hooks + manifest concept):
unit_version.vector_sync_status
unit_version.vector_synced_at
unit_version.vector_chunk_count (derived/cache)
→ Chunk manifest table/structure thuộc P6 design,
  P5 cung cấp hook đủ kiểm CI-2.

5. Draft table/collection model

CẢNH BÁO: Pseudo-DDL dưới đây là design notation — KHÔNG apply vào production. Tên bảng/cột/kiểu dữ liệu là ĐỀ XUẤT, chưa phải chốt.

5.1 logical_unit

-- PSEUDO-DDL — KHÔNG APPLY
CREATE TABLE logical_unit (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    canonical_address TEXT NOT NULL UNIQUE,
        -- Bất biến sau birth. Format: {DOC_CODE}-S{n}-P{n}[-{sub}]
        -- Identity field, KHÔNG phải label (LSL-01 §6.2, §8.4)
    
    -- Structural / document-lineage binding
    doc_code          TEXT NOT NULL,
        -- doc_code là STRUCTURAL / DOCUMENT-LINEAGE BINDING
        -- của logical_unit — xác định miếng này thuộc dòng 
        -- tài liệu nào (D38, HP, SOP-DEPLOY...).
        -- KHÔNG PHẢI classification label Đ24.
        -- Classification doc=X nếu cần phải nằm ở 
        -- Đ24 entity_labels.
        --
        -- FK NOTE: KHÔNG FK trực tiếp vào publication.doc_code
        -- vì publication.doc_code không unique (nhiều versions).
        -- Validate sự tồn tại bằng application/trigger
        -- kiểm doc_code tồn tại trong publication lineage 
        -- registry / document_series / publication.doc_code set.
        -- Chi tiết registry: deferred theo OD-P5-04.
    parent_id         UUID REFERENCES logical_unit(id),
        -- Self-ref. NULL = root unit. Cùng doc_code (I5).
        -- Structural relation, integrity rule (C1 §4.5).
    sort_order        INTEGER NOT NULL DEFAULT 0,
        -- Thứ tự canonical trong cây. 
        -- Khác render_order (thuộc publication).
    
    -- Identity metadata
    section_type      TEXT NOT NULL REFERENCES section_type_vocab(code),
        -- Unit metadata, KHÔNG phải Đ24 classification label (IN-3).
        -- Mặc định logical unit-level (DP-4, C2 OD-M8).
    section_code      TEXT,
        -- Human-readable alias (§1, §2.1, §A3...).
        -- Có thể đổi. KHÔNG phải identity.
    owner             TEXT NOT NULL,
        -- Mặc định kế thừa từ publication owner.
    
    -- Identity profile (DP-5 phân tầng)
    identity_profile  JSONB DEFAULT '{}',
        -- Profile mở rộng per section_type cho identity-level.
        -- Ví dụ: {"is_normative": true, "canonical_doc_label": "Đ38"}
        -- Ổn định xuyên versions. JSON Schema validation ở app level.
    
    -- System auto
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    
    -- Derived / cache
    tier              TEXT,
        -- DERIVED / CACHE: DOT/checker tính từ vị trí 
        -- trong cây cấu trúc (M7, NT11). 
        -- Agent KHÔNG khai tay. DOT derive + checker verify.
    lifecycle_status  TEXT NOT NULL DEFAULT 'draft_only'
        CHECK (lifecycle_status IN (
            'active',      -- Có ≥1 version enacted
            'draft_only',  -- Chỉ có draft versions, chưa bao giờ enacted
            'retired'      -- Quyết định retire qua change-set + APR.
                           -- Khi retired: version enacted cuối → retired,
                           -- miếng hết hiệu lực.
        )),
        -- Explicit column (không derived) vì:
        -- 1) Tránh query N versions mỗi lần check status.
        -- 2) DOT verify consistency với versions.
        -- Transition: active→retired chỉ qua change-set+APR.
    
    -- Constraints
    -- parent_same_doc: parent phải cùng doc_code (I5).
    -- Enforce via trigger/birth gate (PG check constraint 
    -- không thể self-join).
);

-- Indexes
CREATE INDEX idx_lu_doc_code ON logical_unit(doc_code);
CREATE INDEX idx_lu_parent ON logical_unit(parent_id);
CREATE INDEX idx_lu_section_type ON logical_unit(section_type);

5.2 unit_version

-- PSEUDO-DDL — KHÔNG APPLY
CREATE TABLE unit_version (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    logical_unit_id   UUID NOT NULL REFERENCES logical_unit(id),
    
    -- Content metadata
    version_number    INTEGER NOT NULL DEFAULT 1,
        -- Sequential per logical_unit.
    title             TEXT NOT NULL,
    body              TEXT,
        -- Content payload. NULL cho heading/container units 
        -- (OD-C1A-09: structural node không có content).
    description       TEXT,
        -- Mặc định required cho content-bearing unit.
        -- Exception theo section_type/profile rule:
        -- heading/container MAY have NULL description.
        -- Birth gate enforce per section_type config.
    
    -- Content integrity
    content_hash      TEXT,
        -- DERIVED: hash bao gồm body + title + description 
        -- + content_profile. System auto compute.
        -- Phục vụ: change detection, review verification,
        -- vector re-embed trigger.
    
    -- Lifecycle (per C1 §5.1)
    lifecycle_status  TEXT NOT NULL DEFAULT 'draft'
        CHECK (lifecycle_status IN (
            'draft',       -- Mới tạo, chưa approve. Sửa tại chỗ.
            'enacted',     -- Approve qua change-set + APR. BẤT BIẾN.
            'superseded',  -- Bị thay bởi version mới enacted. Giữ audit.
            'retired'      -- Cascaded từ quyết định retire logical_unit.
                           -- Khi logical_unit retired → version enacted
                           -- cuối cùng chuyển retired (C1 §6.4).
                           -- INVARIANT: unit_version.retired CHỈ hợp lệ
                           -- khi logical_unit.lifecycle_status = 'retired'.
                           -- Xem INV-RETIRE §15.
        )),
        -- OD-P5-11: Council có thể mở rộng enum (withdrawn, 
        -- archived) nếu cần. Hiện giữ đúng C1 §5.1.
    
    -- Review
    review_state      TEXT DEFAULT 'unreviewed'
        CHECK (review_state IN (
            'unreviewed', 'in_review', 'review_passed', 
            'review_failed', 'needs_re_review'
        )),
    
    -- Length management (C1A §8)
    length_flag       TEXT DEFAULT 'normal'
        CHECK (length_flag IN ('normal', 'soft_limit', 'hard_limit')),
        -- Derived: DOT hoặc trigger tính từ word count.
    length_exception_reason TEXT,
        -- Nếu hard_limit mà được approved giữ nguyên → ghi lý do.
        -- NULL = chưa cần exception hoặc chưa quyết.
    
    -- Content profile (DP-5 phân tầng)
    content_profile   JSONB DEFAULT '{}',
        -- Profile mở rộng per section_type/doc_family cho content-level.
        -- Ví dụ: {"enforcement_date": "2026-05-01", "actor": "ops-team"}
        -- Thay đổi per version. JSON Schema validation ở app level.
    
    -- Provenance
    editor            TEXT,
        -- Ai sửa version này (khác owner logical unit).
    provenance        TEXT DEFAULT 'PROV-AI',
        -- Phải map/tương thích Đ24 FAC-PROV hoặc controlled 
        -- vocabulary provenance hiện hành.
        -- Values hợp lệ: PROV-AI / PROV-HUMAN / PROV-DOT / 
        -- các giá trị khác theo Đ24 FAC-PROV registry.
        -- Agent KHÔNG tự sáng tác provenance value ngoài 
        -- vocabulary đã đăng ký.
    
    -- Vector projection hooks
    vector_sync_status TEXT DEFAULT 'pending'
        CHECK (vector_sync_status IN ('pending', 'synced', 'stale', 'error')),
    vector_synced_at   TIMESTAMPTZ,
    vector_chunk_count INTEGER DEFAULT 0,
        -- DERIVED / CACHE: số canonical chunks hiện tại trong Qdrant 
        -- cho version này. DOT/sync worker cập nhật.
        -- Phục vụ: kiểm CI-2 (canonical chunk ≤ 1 unit_version),
        -- monitoring, và trigger re-sync.
        -- Chi tiết chunk manifest (chunk_id, span_start, span_end, 
        -- embedding_model...) thuộc P6 design — xem §10.5.
    
    -- System auto
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    enacted_at        TIMESTAMPTZ,
        -- System set khi lifecycle_status → enacted.
    
    -- Constraints
    UNIQUE (logical_unit_id, version_number),
        -- Mỗi logical unit không trùng version number.
    
    -- Business rules (enforce via trigger/app):
    -- 1. Tối đa 1 version enacted per logical_unit tại bất kỳ thời điểm.
    -- 2. Enacted version bất biến (C1 I2): block UPDATE trên 
    --    body/title/description/content_profile khi enacted.
    -- 3. INV-RETIRE: retired CHỈ khi logical_unit.lifecycle_status = 'retired'.
);

-- Indexes
CREATE INDEX idx_uv_logical_unit ON unit_version(logical_unit_id);
CREATE INDEX idx_uv_lifecycle ON unit_version(lifecycle_status);
CREATE INDEX idx_uv_vector_sync ON unit_version(vector_sync_status)
    WHERE vector_sync_status != 'synced';

5.3 publication

-- PSEUDO-DDL — KHÔNG APPLY
CREATE TABLE publication (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    doc_code          TEXT NOT NULL,
        -- Ví dụ: D38, HP, SOP-DEPLOY. Trùng across versions.
        -- Structural identifier, KHÔNG phải Đ24 label.
    version           TEXT NOT NULL,
        -- Ví dụ: '3.0', '4.6.3'.
    
    -- Governance metadata
    publication_type  TEXT NOT NULL REFERENCES publication_type_vocab(code),
        -- law, policy, sop, constitution, knowledge, design_note, 
        -- report, memo, draft, working.
        -- Quyết định default risk tier (C1A §11.3).
    name              TEXT NOT NULL,
    owner             TEXT NOT NULL,
    description       TEXT,
    
    -- Lifecycle
    lifecycle_status  TEXT NOT NULL DEFAULT 'proposed'
        CHECK (lifecycle_status IN (
            'proposed', 'enacted', 'superseded', 'retired'
        )),
        -- §9.7 C1A: PROPOSED → ENACTED → SUPERSEDED → RETIRED.
    
    -- Authority
    enacted_at        TIMESTAMPTZ,
    council_score     NUMERIC,
    approved_by       TEXT,
    
    -- Risk tier (C1A §11.3, LSL-01 §10.2)
    risk_tier         TEXT NOT NULL DEFAULT 'medium'
        CHECK (risk_tier IN ('low', 'medium', 'high', 'highest')),
    
    -- Publication profile (DP-5 phân tầng)
    publication_profile JSONB DEFAULT '{}',
        -- Profile mở rộng per publication_type.
        -- Ví dụ: {"review_deadline": "2026-05-01", 
        --         "kb_path": "knowledge/dev/laws/dieu38.md",
        --         "distribution_list": ["council", "ops"]}
    
    -- System auto
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    
    -- Constraints
    UNIQUE (doc_code, version)
);

-- Indexes
CREATE INDEX idx_pub_doc_code ON publication(doc_code);
CREATE INDEX idx_pub_lifecycle ON publication(lifecycle_status);

5.4 publication_member

-- PSEUDO-DDL — KHÔNG APPLY
-- Tên: publication_member (KHÔNG "published_snapshot_member")
-- Dùng cho MỌI lifecycle stage:
-- - proposed: membership có thể thay đổi, MAY reference draft versions
-- - enacted: membership LOCKED (immutable), CHỈ enacted versions (CI-5)
CREATE TABLE publication_member (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    publication_id    UUID NOT NULL REFERENCES publication(id),
    logical_unit_id   UUID NOT NULL REFERENCES logical_unit(id),
    unit_version_id   UUID NOT NULL REFERENCES unit_version(id),
    
    -- Render order (C1A §9.6)
    render_order      INTEGER NOT NULL DEFAULT 0,
    
    -- System auto
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    
    -- Constraints
    UNIQUE (publication_id, logical_unit_id),
        -- Mỗi logical unit tối đa 1 version per publication (C1 I8).
    
    -- Business rules (enforce via trigger/app):
    -- 1. CONSISTENCY CONSTRAINT (bắt buộc):
    --    unit_version.logical_unit_id PHẢI = publication_member.logical_unit_id.
    --    Ngăn chặn: INSERT membership với logical_unit_id=A 
    --    nhưng unit_version thuộc logical_unit_id=B.
    --    Enforce: trigger hoặc application validation tại INSERT/UPDATE.
    --
    -- 2. Khi publication.lifecycle_status = 'enacted':
    --    a. unit_version.lifecycle_status PHẢI 'enacted' (CI-5).
    --    b. logical_unit.lifecycle_status PHẢI 'active' (không retired).
    --       Enacted publication không chứa retired logical_unit.
    --    c. Membership LOCKED — block INSERT/UPDATE/DELETE.
    --
    -- 3. Khi publication.lifecycle_status = 'proposed':
    --    a. MAY reference draft versions (C1A §9.2).
    --    b. Membership có thể thay đổi.
    --
    -- 4. Thêm/xóa member từ enacted publication chỉ qua 
    --    publication version mới.
);

-- Indexes
CREATE INDEX idx_pm_publication ON publication_member(publication_id);
CREATE INDEX idx_pm_unit_version ON publication_member(unit_version_id);

5.5 section_type_vocab

-- PSEUDO-DDL — KHÔNG APPLY
-- Controlled vocabulary cho STRUCTURAL/GOVERNANCE metadata.
-- KHÔNG thay thế Đ24 taxonomy_facets / entity_labels.
-- Nếu cần pivot cross-system thì map/sync sang Đ24 bằng rule riêng.
CREATE TABLE section_type_vocab (
    code              TEXT PRIMARY KEY,
        -- 17 candidates từ C1A §6: heading, article, paragraph,
        -- definition, principle, rationale, process, technical_spec,
        -- governance_process, checklist, instruction_block,
        -- reference_mapping, matrix, invariant_list,
        -- open_decision_list, appendix, changelog.
        -- Council chốt chính thức.
    name              TEXT NOT NULL,
    description       TEXT,
    lifecycle_status  TEXT NOT NULL DEFAULT 'active'
        CHECK (lifecycle_status IN ('active', 'deprecated', 'retired')),
    owner             TEXT,
    
    -- Length thresholds per type (C1A §8.2)
    soft_limit_words  INTEGER DEFAULT 500,
    hard_limit_words  INTEGER DEFAULT 1500,
        -- Override per section_type. instruction_block/appendix 
        -- cho phép cao hơn. Calibrate sau pilot data (OD-P5-09).
    
    -- Birth gate config
    description_required BOOLEAN DEFAULT TRUE,
        -- Heading/container units MAY have description optional.
    body_required     BOOLEAN DEFAULT TRUE,
        -- Heading/structural nodes MAY have body = NULL.
    
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

5.6 publication_type_vocab

-- PSEUDO-DDL — KHÔNG APPLY
-- Controlled vocabulary cho GOVERNANCE metadata.
-- KHÔNG thay thế Đ24 taxonomy_facets / entity_labels.
CREATE TABLE publication_type_vocab (
    code              TEXT PRIMARY KEY,
        -- law, policy, sop, constitution, knowledge,
        -- design_note, report, memo, draft, working.
    name              TEXT NOT NULL,
    description       TEXT,
    lifecycle_status  TEXT NOT NULL DEFAULT 'active'
        CHECK (lifecycle_status IN ('active', 'deprecated', 'retired')),
    
    -- Default risk tier per type (C1A §11.3)
    default_risk_tier TEXT NOT NULL DEFAULT 'medium'
        CHECK (default_risk_tier IN ('low', 'medium', 'high', 'highest')),
    
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

5.7 change_set (hook)

-- PSEUDO-DDL — KHÔNG APPLY
-- Hook table — đủ để integration, chi tiết APR thuộc Đ32/P6
CREATE TABLE change_set (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    
    -- Scope
    publication_id    UUID REFERENCES publication(id),
        -- Publication chính đang sửa. 
        -- NULL nếu cross-publication change-set (OD-P5-05).
    scope_description TEXT NOT NULL,
        -- Self-contained (L5 §3.3).
    
    -- Lifecycle
    lifecycle_status  TEXT NOT NULL DEFAULT 'draft'
        CHECK (lifecycle_status IN (
            'draft', 'submitted', 'review_passed', 
            'approval_passed', 'enacted', 'rejected', 'withdrawn'
        )),
    
    -- APR integration (Đ32)
    apr_ref           TEXT,
        -- Opaque reference / FK tới APR system hiện hành.
        -- Kiểu dữ liệu chính xác (UUID, INTEGER, TEXT...) 
        -- xác định ở integration design khi rà APR schema.
        -- Tạo khi submitted.
    
    -- Ownership
    owner             TEXT NOT NULL,
    
    -- System auto
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    submitted_at      TIMESTAMPTZ,
    enacted_at        TIMESTAMPTZ
);

5.8 change_set_member (hook)

-- PSEUDO-DDL — KHÔNG APPLY
CREATE TABLE change_set_member (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    change_set_id     UUID NOT NULL REFERENCES change_set(id),
    logical_unit_id   UUID NOT NULL REFERENCES logical_unit(id),
    
    -- What changed
    change_type       TEXT NOT NULL
        CHECK (change_type IN (
            'create',       -- Tạo logical unit mới
            'new_version',  -- Tạo version mới cho enacted unit
            'retire',       -- Retire logical unit
            'structural'    -- Split/merge/re-parent
        )),
    old_version_id    UUID REFERENCES unit_version(id),
        -- Version trước thay đổi. NULL nếu create.
    new_version_id    UUID REFERENCES unit_version(id),
        -- Version mới. NULL nếu retire.
    
    -- Snapshot (C1 I9: đóng băng khi submitted)
    snapshot_data     JSONB,
        -- Diff/evidence tại thời điểm submit.
        -- Bất biến sau submitted.
    
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now(),
    
    UNIQUE (change_set_id, logical_unit_id)
);

6. Relationship model

6.1 Quan hệ cấu trúc (cây dọc)

Quan hệ Cơ chế Constraint
Logical unit → parent logical_unit.parent_id self-ref FK Parent cùng doc_code (I5). Trigger/app enforce.
Logical unit → document lineage logical_unit.doc_code TEXT (KHÔNG FK) Structural binding. Validate bằng trigger/app kiểm doc_code tồn tại trong publication lineage registry / document_series / publication.doc_code set (deferred OD-P5-04).
Logical unit → children Implicit qua parent_id + sort_order Cây thuần, không DAG (I4).

6.2 Quan hệ content (1:N)

Quan hệ Cơ chế Constraint
Logical unit → versions unit_version.logical_unit_id FK 1:N. Tối đa 1 enacted per logical_unit.

6.3 Quan hệ publication (N:M)

Quan hệ Cơ chế Constraint
Publication → unit versions publication_member junction UNIQUE per (publication_id, logical_unit_id). unit_version.logical_unit_id PHẢI = publication_member.logical_unit_id.
Một unit trong nhiều publications Nhiều rows trong publication_member Cho phép (LSL-01 §6.3).

6.4 Quan hệ classification (N:M via Đ24)

Quan hệ Cơ chế Constraint
Logical unit → labels entity_labels.entity_code = logical_unit.canonical_address (hoặc code mapping) Đ24 entity_labels junction. KHÔNG tạo table riêng (DP-3).

6.5 Quan hệ ngang (horizontal / semantic)

Quan hệ Cơ chế Constraint
Unit ↔ unit (cross-doc) universal_edges (existing) Tách biệt cây dọc (I4). Dùng universal_edges, KHÔNG dùng parent_id.
Successor (split/merge) universal_edges với edge_type='succeeds' Ghi quan hệ cũ → mới khi split/merge.

6.6 Quan hệ change governance

Quan hệ Cơ chế Constraint
Change-set → members change_set_member junction 1:N. Liệt kê units thay đổi.
Change-set → APR change_set.apr_ref opaque reference 1:1 hoặc 1:0 (tạo khi submitted).
Change-set → publication change_set.publication_id FK N:1. Thường 1 change-set gắn 1 publication.

7. Lifecycle / Versioning model

7.1 Unit version lifecycle (per C1 §5.1)

draft ──[change-set enacted]──▶ enacted ──[version mới enacted]──▶ superseded
  │                                │
  │                                └──[logical_unit retire via CS+APR]──▶ retired
  │
  └──[sửa tại chỗ]──▶ draft (update in-place, chưa enacted)

Quy tắc chuyển trạng thái:

  • draft → enacted: CHỈ khi version nằm trong change-set đã enacted/applied.
  • enacted → superseded: TỰ ĐỘNG khi version mới cho cùng logical_unit enacted.
  • enacted → retired: CHỈ khi logical_unit bị retire qua change-set + APR. retired trên unit_version là hệ quả của retire logical_unit (C1 §6.4), không phải quyết định trên riêng version.
  • INV-RETIRE: Không được có unit_version.lifecycle_status = 'retired' nếu logical_unit.lifecycle_status != 'retired'. Xem §15.
  • Không đi ngược. Enacted không quay draft. Sửa = version mới.

Trigger/app enforce:

  • Trước enacted: kiểm version nằm trong change-set enacted.
  • Khi enacted: set enacted_at, auto supersede version cũ.
  • Enacted version: block UPDATE trên body/title/description/content_profile (immutability).
  • retired: chỉ cho phép nếu logical_unit.lifecycle_status = 'retired'.

7.2 Logical unit lifecycle

draft_only ──[first version enacted]──▶ active
                                          │
                                          └──[retire via CS+APR]──▶ retired
  • draft_only: Mới tạo, chưa có version enacted.
  • active: Có ≥1 version enacted.
  • retired: Quyết định retire qua change-set + APR. Version enacted cuối → retired. Miếng hết hiệu lực.

Explicit column (không derived) để tránh query N versions mỗi lần check. DOT verify consistency.

7.3 Publication lifecycle

proposed ──[Council/Owner approve]──▶ enacted ──[version mới]──▶ superseded
                                        │
                                        └──[retire]──▶ retired

Quy tắc:

  • enacted: Membership (publication_member) bất biến. Chỉ enacted/current unit_versions + active logical_units (CI-5).
  • superseded: Khi publication version mới enacted cho cùng doc_code.
  • retired: Quyết định governance.

7.4 Change-set lifecycle

draft ──▶ submitted ──▶ review_passed ──▶ approval_passed ──▶ enacted
            │                                                    
            └──▶ rejected / withdrawn

Mapping với APR (C1 §5.4):

  • submitted: Tạo APR, snapshot đóng băng (I9).
  • review_passed: Reviewers pass trên units.
  • approval_passed: APR quorum đạt (Đ32).
  • enacted: Apply step thành công → unit versions enacted, publication membership update.

7.5 Versioning scheme

Unit version: Sequential integer per logical_unit (version_number). Đơn giản, không ambiguous.

Publication version: Free-form text (semantic: '3.0', '4.6.3'). Publication version bump system-driven khi change-set enacted (C1 §6.5).


8. Label integration with Đ24

8.1 Mapping strategy

Logical unit classification labels sử dụng Đ24 entity_labels hiện có.

entity_labels (existing Đ24 table):
  entity_code  = logical_unit.canonical_address
                 (hoặc code mapping nếu entity_labels dùng format khác)
  facet_code   = 'doc' / 'topic' / 'layer' / 'family' / ...
  label_value  = 'D38' / 'segmentation' / 'law' / ...

8.2 Facets cần thiết cho logical_unit

Facet Mô tả Ví dụ values Status
doc Document gốc D38, D43, HP, SOP-DEPLOY Cần kiểm Đ24 registry
topic Chủ đề nội dung segmentation, lifecycle, metadata Cần kiểm Đ24 registry
layer Tầng kiến trúc law, design, implementation Cần kiểm Đ24 registry
family Nhóm tài liệu law, policy, sop, knowledge Có thể map từ publication_type

Hành động P6: Rà soát Đ24 taxonomy_facets hiện hành. Facets nào đã tồn tại → dùng. Facets nào thiếu → đăng ký qua Đ24 + Council.

8.3 Phân biệt label doc=X vs publication membership

Khía cạnh Classification label doc=X Publication membership
Lưu ở entity_labels (Đ24) publication_member
Ý nghĩa "Miếng này nói về X" (phân loại/pivot) "Miếng này là phần chính thức của PUB-X-v3.0-ENACTED"
Draft unit có thể có? CÓ — draft unit vẫn có thể có label doc=D38 KHÔNG trong enacted pub — draft unit KHÔNG nằm trong enacted publication. CÓ trong proposed pub.
Nhiều values? CÓ — 1 unit có thể có doc=D38 VÀ doc=D43 CÓ — 1 unit có thể nằm trong PUB-D38-v3.0 VÀ PUB-HP-v4.6.3

Đây là CI-4. Nhầm lẫn = bug nghiêm trọng.

8.4 section_type và vocabulary tables KHÔNG phải Đ24 label

section_type là unit metadata gắn logical_unit qua FK section_type_vocab. KHÔNG nằm trong entity_labels.

section_type_vocabpublication_type_vocabcontrolled vocabulary cho structural/governance metadata, không thay thế Đ24 taxonomy_facets / entity_labels. Nếu cần query "tất cả miếng loại article" → JOIN logical_unit.section_type, KHÔNG query entity_labels.

Nếu tương lai cần section_type làm Đ24 facet (để pivot xuyên hệ thống) → tạo facet mới trong Đ24 + sync mechanism. Quyết định thuộc P6.


9. Publication / Membership rules

9.1 Enacted publication rules

  1. Membership chỉ enacted/current versions + active logical_units (CI-5): Trigger/app kiểm:

    • unit_version.lifecycle_status = 'enacted'
    • logical_unit.lifecycle_status = 'active' (không retired) Kiểm trước khi chuyển publication sang enacted.
  2. Membership bất biến sau enacted (C1 I2, I9): Trigger/app block INSERT/UPDATE/DELETE trên publication_member khi publication.lifecycle_status = 'enacted'.

  3. Mỗi logical unit tối đa 1 version per publication (C1 I8): UNIQUE constraint (publication_id, logical_unit_id).

  4. Consistency constraint: unit_version.logical_unit_id PHẢI = publication_member.logical_unit_id. Trigger/app enforce tại INSERT/UPDATE.

9.2 Proposed/draft publication

  • MAY reference draft unit_versions (C1A §9.2).
  • Membership có thể thay đổi khi publication đang proposed.
  • Khi publication enacted → kiểm tất cả members: unit_version enacted + logical_unit active → lock membership.

9.3 Version bumping

Khi change-set enacted/applied cho 1 publication:

  1. Tạo publication version mới (doc_code giữ, version bump).
  2. Copy membership từ version cũ → version mới.
  3. Apply changes:
    • Thêm unit_versions enacted mới.
    • Loại unit_versions superseded CHỈ KHI đã có enacted replacement trong cùng logical_unit.
    • KHÔNG include retired logical_units / retired unit_versions.
  4. Publication cũ → superseded.
  5. Publication mới → enacted.

10. Vector projection hooks

10.1 Sync metadata trên unit_version

Field Mục đích Loại
vector_sync_status pending / synced / stale / error System/DOT managed
vector_synced_at Timestamp lần sync gần nhất System auto
vector_chunk_count Số canonical chunks hiện tại Derived/cache

10.2 Sync trigger points

Event Action
unit_version INSERT (draft) Set vector_sync_status = 'pending'
unit_version content UPDATE (draft) Set vector_sync_status = 'stale' → re-embed
unit_version enacted Set vector_sync_status = 'pending' → re-embed
unit_version metadata-only update Set vector_sync_status = 'stale' → update payload, KHÔNG re-embed
unit_version superseded/retired Update Qdrant payload (mark status)

10.3 Qdrant payload structure (concept)

Qdrant point payload inherit từ PG:

  • logical_unit_id, unit_version_id
  • canonical_address, doc_code, section_type
  • lifecycle_status, version_number, owner
  • Classification labels (từ entity_labels)
  • chunk_id, span_start, span_end, chunk_index (projection metadata riêng)

PG = SoT, Qdrant = projection (LSL-01 §9.4). Drift → PG thắng.

10.4 Canonical chunk invariant

Mỗi canonical chunk nằm trong đúng 1 unit_version (CI-2). KHÔNG gộp nhiều unit_versions vào 1 chunk.

10.5 Chunk manifest — P6 hook

P5 cung cấp vector_chunk_count trên unit_version làm hook kiểm CI-2. Chi tiết chunk manifest thuộc P6 design, bao gồm:

  • Chunk manifest table hoặc structure (chunk_id, unit_version_id, span_start, span_end, chunk_index, embedding_model, synced_at).
  • Constraint: mỗi chunk row trỏ đúng 1 unit_version_id.
  • DOT checker: verify chunk_count khớp manifest, verify không chunk nào gộp 2+ unit_versions.

P5 đảm bảo: hook đủ để P6 thiết kế manifest mà không cần sửa schema unit_version.


11. Review / Change-set / APR hooks

11.1 Review state trên unit_version

review_state field trên unit_version:

  • unreviewedin_reviewreview_passed / review_failedneeds_re_review
  • Review parent ≠ approve children (I6). Không cascade.
  • Reviewer (human hoặc agent) cập nhật review_state.

11.2 Change-set integration

change_set + change_set_member tables (§5.7, §5.8):

  • Gom nhiều unit changes vào 1 change-set.
  • snapshot_data trên change_set_member: đóng băng diff khi submitted (I9).
  • Lifecycle mapping với APR (§7.4).

11.3 APR integration

  • change_set.apr_ref opaque reference tới APR system hiện hành (Đ32). Kiểu dữ liệu xác định ở integration design khi rà APR schema thực tế.
  • P5 KHÔNG redesign APR. Chỉ tạo hook (reference) để liên kết.
  • Khi change-set submitted → tạo APR per Đ32 pipeline.
  • Khi APR applied → change-set enacted → unit versions enacted.

11.4 Structural change-set

Split/merge/re-parent = change_type = 'structural' trong change_set_member:

  • Split: 1 logical_unit retired + N logical_units mới created. Successor relation ghi trong universal_edges (edge_type='succeeds').
  • Merge: N logical_units retired + 1 logical_unit mới created. Successor relation ghi.
  • Re-parent: update parent_id qua change-set. Canonical address KHÔNG đổi (LSL-01 §8.4).

12. Birth gate readiness

12.1 Birth logical_unit mới + draft version đầu tiên

Check Field(s) Enforcement
Address unique canonical_address UNIQUE constraint BLOCK
Doc_code valid doc_code tồn tại trong publication lineage registry / document_series / publication.doc_code set — deferred OD-P5-04 BLOCK (trigger/app)
Parent valid parent_id tồn tại + cùng doc_code BLOCK (trigger/app)
Section_type valid section_type FK section_type_vocab, status='active' BLOCK
Owner present owner NOT NULL BLOCK
Title present unit_version.title NOT NULL BLOCK
Description present unit_version.description — per section_type config BLOCK hoặc PASS (section_type_vocab.description_required)
Body valid body per section_type — heading/container OK if NULL WARN hoặc PASS (section_type_vocab.body_required)
Required profile identity_profile + content_profile chứa required fields per section_type config BLOCK hoặc WARN (config)
Lifecycle default logical_unit.lifecycle_status = 'draft_only', unit_version.lifecycle_status = 'draft' SYSTEM AUTO
Timestamps created_at, updated_at SYSTEM AUTO
Sort_order Giá trị hợp lệ BLOCK
Content hash content_hash computed SYSTEM AUTO

12.2 Birth version mới (cho enacted unit)

Check Field(s) Enforcement
Logical unit exists logical_unit_id FK valid BLOCK
Version number Auto-increment per logical_unit SYSTEM AUTO
Title present NOT NULL BLOCK
Description Per section_type config BLOCK hoặc PASS
Body valid Per section_type WARN hoặc PASS
Required profile Per section_type config BLOCK hoặc WARN
Lifecycle default 'draft' SYSTEM AUTO
Review state 'unreviewed' SYSTEM AUTO
Content hash Computed SYSTEM AUTO

12.3 Length check at birth

  • Tính word count body → so sánh section_type thresholds (section_type_vocab.soft_limit_words / hard_limit_words).
  • Set length_flag tương ứng.
  • WARN, KHÔNG BLOCK draft (C1A §8.3, LSL-01 §11.2).
  • Hard-limit → gate trước enacted (§8.4 C1A): bắt buộc 1 trong 3 decisions.

13. Open decisions còn lại

Code Câu hỏi Đề xuất P5 v0.2 Phase
OD-P5-01 entity_labels entity_code format cho logical_unit Dùng canonical_address. Nếu Đ24 dùng format khác → cần mapping table. P5 v1 (rà Đ24 thực tế)
OD-P5-02 Structural node (heading navigation, OD-C1A-09) cần unit_version không? Đề xuất: CÓ, với body=NULL (section_type_vocab.body_required=FALSE). Giữ version history. P5 v1
OD-P5-03 logical_unit.lifecycle_status explicit hay derived? CHỐT: Explicit + DOT verify. Chốt tại P5
OD-P5-04 doc_code binding: FK tới document_series riêng hay text + validate? DEFERRED: hiện TEXT + trigger/app validate. Nếu cần FK → tạo document_series(doc_code PK). P5 v1
OD-P5-05 Cross-publication change-set change_set.publication_id nullable. Bump versions cho mỗi publication liên quan. P6
OD-P5-06 Retire cascade policy (C1-OD9) Config per publication_type. Law = không auto cascade. Knowledge = warn + propose. P6
OD-P5-07 Successor relation storage Dùng universal_edges với edge_type='succeeds'. P5 v1
OD-P5-08 Profile JSON Schema registry Table riêng profile_schema_registry. P6
OD-P5-09 Length threshold calibration Defaults: 500/1500. Override per section_type. P6
OD-P5-10 publication.doc_code uniqueness CHỐT: UNIQUE (doc_code, version). Chốt tại §5.3
OD-P5-11 Extended lifecycle enum (withdrawn, archived) Giữ C1 §5.1. Council mở rộng nếu cần. P6 / C1 amend

14. PASS criteria

# Criterion Status
1 2 bảng logical_unit + unit_version tách biệt — C1-OD12, C2-OD-M1 ✅ DP-1
2 Publication membership tách biệt label — C1A-OD-C1A-08 ✅ DP-2
3 Classification labels dùng Đ24 entity_labels — CI-9 ✅ DP-3
4 section_type = FK vocab, thuộc logical_unit, KHÔNG phải Đ24 label — IN-3, C2-OD-M8 ✅ DP-4
5 Vocab tables = structural/governance, KHÔNG thay thế Đ24 ✅ DP-4 clarified
6 Profile metadata phân tầng — logical_unit / unit_version / publication ✅ DP-5
7 7 invariants từ handoff đều được bảo toàn ✅ §15 check
8 Pseudo-DDL đủ chi tiết cho GPT review — 8 tables
9 Không apply SQL, không sửa luật, không DOT implementation
10 Birth gate hooks rõ ràng — kiểm gì, block/warn per section_type config ✅ §12
11 Vector hooks + chunk manifest concept — sync status + P6 hook ✅ §10
12 Review/change-set/APR hooks — integration, apr_ref opaque ✅ §11
13 Open decisions liệt kê + đề xuất hướng ✅ §13 (11 ODs)
14 doc_code = structural binding, KHÔNG FK vào non-unique ✅ §5.1
15 tier = derived/cache, không agent manual ✅ §5.1
16 content_hash bao gồm body+title+description+profile ✅ §5.2
17 INV-RETIRE invariant rõ ràng ✅ §15
18 publication_member consistency constraint ✅ §5.4, §9.1
19 Enacted pub kiểm cả logical_unit active ✅ §9.1
20 provenance map Đ24 FAC-PROV ✅ §5.2

Constitutional check

Nguyên tắc / Luật Verdict Ghi chú
NT1 / NT13 — PG là SoT PASS Nội dung authoritative ở PG. Qdrant = projection.
NT2 — Cơ chế máy PASS có điều kiện P5 = hooks. P6 phải thiết kế checker/birth gate thật.
NT4 — Config/registration path PASS có điều kiện Vocabulary/profile quản bằng config/governance, không hardcode.
NT11 — Khai tối thiểu PASS Tách logical_unit/unit_version giảm duplicate. Không registry song song.
Đ24 — Label Law PASS Label dùng entity_labels. Vocab tables ≠ Đ24 replacement.
Đ32 — APR PASS apr_ref hook, không redesign.
Đ33 — PG Law PASS Chưa apply SQL production. Chưa vượt gateway.
LSL-01 / C1A PASS Unit-centric giữ đúng. doc_code = structural binding.

15. Invariants

Code Statement Enforce by Nguồn
INV-UNIT-SOT Miếng thông tin là đơn vị SSOT nội dung nhỏ nhất Architecture (2 tables) NT15, CI-1
INV-ENACTED-IMMUT Enacted version bất biến — block UPDATE body/title/description/profile Trigger/app C1 I2
INV-ADDRESS-IMMUT Canonical address bất biến sau birth UNIQUE + trigger block UPDATE C1 I3, CI-6
INV-PUB-NO-INLINE Publication không chứa content inline — chỉ FK references Table design (publication_member) CI-3, LSL-01 §6.3
INV-LABEL-NEQ-MEMBER Label doc=X ≠ publication membership Tách biệt entity_labels vs publication_member CI-4
INV-ENACTED-PUB-ENACTED-ONLY Enacted publication chỉ chứa enacted versions + active logical_units Trigger/app kiểm trước enacted CI-5
INV-CHUNK-SINGLE-UV Canonical chunk nằm trong đúng 1 unit_version P6 manifest + vector_chunk_count hook CI-2
INV-NO-PARALLEL-REGISTRY Label dùng Đ24, không tạo registry song song Architecture (DP-3) CI-9, P3 v0.4
INV-SECTION-NOT-LABEL section_type ≠ Đ24 classification label FK vocab, tách entity_labels IN-3
INV-SINGLE-PARENT Mỗi logical unit có đúng 1 canonical parent parent_id self-ref, cây thuần CI-11, I4
INV-BIRTH-GATE Mọi miếng mới qua birth gate, không đường tắt Birth gate validation (§12) CI-12, I7
INV-PG-SOT-VECTOR PG = SoT, Qdrant = projection. Drift → PG thắng. Sync worker design CI-10, LSL-01 §9.4
INV-RETIRE unit_version.lifecycle_status = 'retired' CHỈ hợp lệ khi logical_unit.lifecycle_status = 'retired'. retired trên version là hệ quả cascade từ retire logical_unit, không phải quyết định lifecycle độc lập. Trigger/app enforce C1 §6.4, GPT R2 #1
INV-PM-CONSISTENCY publication_member.logical_unit_id PHẢI = unit_version.logical_unit_id (via FK chain) Trigger/app enforce GPT R2 #3
INV-PROVENANCE-VOCAB provenance values phải map/tương thích Đ24 FAC-PROV. Agent không tự sáng tác. Birth gate + DOT check GPT R2 #6, Đ24

GPT Review Patch log

Round 1 (12 patches):

# Điểm Hành động
1 doc_code = structural binding ✅ Sửa comment §5.1
2 Không FK doc_code vào non-unique ✅ TEXT + validate, OD-P5-04 deferred
3 Đổi tên → publication_member ✅ Mọi lifecycle
4 retired lifecycle ✅ ĐIỀU CHỈNH: giữ per C1, clarify cascade, thêm INV-RETIRE
5 body_hash → content_hash ✅ body+title+desc+profile
6 Profile phân tầng ✅ identity/content/publication
7 Vector chunk manifest ✅ vector_chunk_count + §10.5
8 Vocabulary ≠ Đ24 ✅ Ghi rõ
9 tier = derived ✅ Ghi rõ
10 P6 ≠ DDL ✅ Sửa §1
11 apr_ref opaque ✅ TEXT
12 Description exception ✅ Per section_type config

Round 2 (7 patches):

# Điểm Hành động
1 INV-RETIRE invariant ✅ §15 INV-RETIRE + enforce trong §5.2, §7.1
2 §9.3 sửa câu loại superseded/retired ✅ Chính xác hóa 3 bước apply
3 publication_member consistency constraint ✅ §5.4 rule #1, §9.1 rule #4, §15 INV-PM-CONSISTENCY
4 Enacted pub kiểm logical_unit active ✅ §5.4 rule #2b, §9.1 rule #1
5 Birth gate doc_code valid wording ✅ §12.1 deferred OD-P5-04
6 provenance map Đ24 FAC-PROV ✅ §5.2 + §15 INV-PROVENANCE-VOCAB
7 Constitutional check trong PASS criteria ✅ §14 constitutional check table

P5 Schema Draft v0.2 | S181 | 2026-04-26 | Opus 4.6 GPT Review: R1 PASS có điều kiện (12 patches) + R2 PASS có điều kiện nhẹ (7 patches) + Final PASS Chờ: User duyệt final → upload KB