KB-34FD rev 6

Điều 35: Luật Quản trị DOT v5.2 FINAL BAN HÀNH

34 min read Revision 6
lawdieu-35dotgovernanceenactedv5.2finals178-fix15fix_repair_dotops-code

ĐIỀU 35: LUẬT QUẢN TRỊ DOT — v5.2 FINAL (BAN HÀNH 2026-04-18 S178 Fix 15)

v5.2 FINAL | 2026-04-18 S178 Fix 15 — BAN HÀNH sau enact gói DOT Repair Governance v4 FINAL. Base: v5.1 FINAL (2026-04-14 S177 Fix 8) — xem history/changelog và backup v5.0 tại dieu35-dot-governance-law-v5-0-backup.md. Tham chiếu HP: v4.6.3 (13 NT). Amend trọng tâm so với v5.1: flow fix_repair_dot end-to-end, verify 3 tầng, ADMIN fallback có audit schema, paired test retrofit, và liên kết APR risk/quorum với Đ32 v1.1. Tình trạng: Đã tiếp thu đầy đủ sign-off Council cho gói S178 Fix 15.** TUÂN THỦ: HP v4.6.3, Đ0-G, Đ0-H, Đ22 v1.1, Đ26, Đ31, Đ32 v1.1, Đ36, Đ41 v1.1.

7 fix Council R2 đã apply inline:

  1. dot_config.value cho phép NULL + sentinel law_v5_1_enacted_at + UTC ISO format (§4.4)
  2. H14 mới — bắt law_v5_1_enacted_at chưa set > 24h (§8.1)
  3. fn_log_issue BỎ severity khỏi signature → severity leo thang trên cùng row (§4.1B)
  4. PRECHECK dedupe system_issues open trước CREATE UNIQUE INDEX (§4.1B)
  5. §5.1 viết cứng: infer fail = CẤM POST partial row (§5.1)
  6. H13 chỉ báo động, KHÔNG self-repair dot-metadata-repair (§5.2)
  7. BLOCK 4 thêm bước 4.0 snapshot + 4.3 lưu old_file_path + 4.10 atomic transaction + 4.13 cleanup (§9.2)

§1. MỤC TIÊU

"DOT là cổng duy nhất thao tác dữ liệu (Điều 0-H). Nhưng nếu không quản trị CHÍNH DOT — ai biết DOT nào đang làm gì, thiếu gì, hỏng gì?"

3 mục tiêu (giữ từ v5.0):

# Mục tiêu Đo bằng Tính chất
MT1 Nhìn toàn cảnh: Biết mọi DOT đang làm gì, thuộc domain nào, phục vụ luật nào, thiếu/thừa/hỏng ở đâu dot_tools có đầy đủ metadata cho 100% DOT Vĩnh viễn
MT2 Đo được bằng số: Coverage, pairing rate, automation rate — đếm bằng 1 query PG dot_coverage_required + pivot = % coverage Tự thích nghi
MT3 Tự vận hành khép kín: Phát hiện → tạo APR → sửa → verify 3+ DOT tự quản trị + dual-trigger Tự động 100%

Thứ tự ưu tiên: Nhìn thấy → Đo được → Tự vận hành.

★ MT4 MỚI (v5.1): Luật áp cả entity CŨ, không chỉ entity MỚI

Luật ban hành không để lại legacy mãi vênh. Mọi luật có impact trên bảng sẵn data CŨ → bắt buộc kèm retrofit mechanism (§11). Áp cho cả luật mới VÀ luật đã ban hành (xem §11.4).


§2. PHẠM VI

TRONG phạm vi Điều 35:

  1. Quản trị sổ đăng ký DOT (dot_tools — SSOT duy nhất)
  2. Phân loại DOT theo domain, tier, operation, trigger_type — TẤT CẢ qua PG SSOT tables, KHÔNG text tự do
  3. Quản lý domain DOT (dot_domains — FK enforce, 4 lớp bảo vệ)
  4. Đo coverage: domain × operation × tier — mẫu số TỰ ĐỘNG cập nhật
  5. Quản lý vòng đời DOT: tạo → active → deprecated → retired
  6. Kiểm tra sức khoẻ DOT: pairing, domain, target, file_path, cron, metadata completeness (v5.1)
  7. DOT 2 cấp: Cấp A (kiểm tra) + Cấp B (thực thi) — paired bắt buộc
  8. ★ Retrofit luật mới cho entity cũ (v5.1 — §11)

★ v5.1 LƯU Ý VẬN HÀNH:

  • fn_birth_gate mặc định mode='warn' ngay sau ban hành. Chuyển 'block' qua UPDATE dot_config SET value='block' WHERE key='birth_gate_mode' khi đạt tiêu chí cứng §10.
  • UNIQUE(file_path) WHERE file_path IS NOT NULL: partial index chỉ cho phép nhiều row có file_path NULL cùng tồn tại; KHÔNG cho phép duplicate non-null. 45 cặp duplicate hiện hữu PHẢI dedupe TRƯỚC khi tạo index — xem BLOCK 4 §9.2.

NGOÀI phạm vi:

Vấn đề Luật phụ trách Đ35 chỉ làm
Nội dung cụ thể DOT xử lý Luật tương ứng Biết DOT phục vụ luật nào
Collection mà DOT tác động Đ36 Khai báo target_collections
Khai sinh entity DOT Đ0-G Trigger khai sinh khi tạo DOT
Phê duyệt thay đổi DOT Đ32 Tạo APR
Toàn vẹn hệ thống Đ31 Báo cáo sức khoẻ DOT
Escalation → con người Đ22 Self-healing Đẩy vào system_issues

§3. DOT 2 CẤP

Thuộc tính Cấp A — Kiểm tra Cấp B — Thực thi
Vai trò Giám sát, quét, báo cáo Ghi, sửa, tạo dữ liệu
Quyền Read-only Read + Write (có secret GSM)
Ví dụ dot-dot-health, dot-collection-health dot-schema-ensure, dot-apr-execute
Auto-approve ✅ Có ❌ Pending duyệt
Bắt buộc paired Không PHẢI có DOT Cấp A (paired_dot FK)

Quy tắc paired_dot (luật nội tại Đ35):

  • Mỗi DOT Cấp B ghi dữ liệu → PHẢI có DOT Cấp A kiểm tra cùng scope.
  • paired_dot FK → dot_tools.code. FK enforce.
  • Cấp A IDLE = Cấp B làm đúng. Cấp A phát hiện lỗi → APR → Cấp B sửa → A re-verify.

★ PG TRIGGER enforce paired_dot:

CREATE OR REPLACE FUNCTION fn_dot_enforce_paired() RETURNS TRIGGER AS $$
BEGIN
  IF NEW.tier = 'B' AND NEW.paired_dot IS NULL THEN
    RAISE EXCEPTION 'DOT Cấp B (%) PHẢI có paired_dot.', NEW.code;
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_dot_enforce_paired
  BEFORE INSERT OR UPDATE ON dot_tools
  FOR EACH ROW EXECUTE FUNCTION fn_dot_enforce_paired();

§4. SCHEMA

4.1 dot_tools — 11 fields (v5.1: thêm _dot_origin chính thức)

Field Type Constraint v5.0 Constraint v5.1 Mục đích
tier TEXT FK → dot_tiers.code Giữ Cấp DOT (A/B)
domain TEXT FK → dot_domains.code, NOT NULL, DEFAULT 'unclassified' Giữ Domain
operation TEXT FK → dot_operations.code, nullable + NOT NULL sau grace + Block 4 Loại thao tác
paired_dot TEXT FK → dot_tools.code, nullable Giữ (trigger enforce B) DOT Cấp A
trigger_type TEXT FK → dot_trigger_types.code + NOT NULL sau grace Cơ chế kích hoạt
cron_schedule TEXT nullable + NOT NULL sau grace ('' cho manual) Lịch cron
file_path TEXT nullable + NOT NULL sau grace + UNIQUE partial WHERE NOT NULL Đường dẫn file
last_executed TIMESTAMPTZ nullable Giữ Lần chạy cuối
coverage_status TEXT FK → dot_coverage_statuses.code + NOT NULL sau grace Trạng thái bao phủ
_dot_origin TEXT (không có v5.0) ★ v5.1 MỚI: NOT NULL DEFAULT 'unknown' Truy vết công cụ tạo DOT (RC-3)
extra_metadata JSONB DEFAULT '{}' Giữ Metadata mở rộng

★ v5.1 KHOẢN 1 — UNIQUE PARTIAL + NOT NULL + REFERENCE TABLES

WORDING ĐÚNG về UNIQUE partial:

  • UNIQUE INDEX ... WHERE file_path IS NOT NULL chặn 2 row cùng có cùng file_path non-null. Cho phép nhiều row file_path IS NULL cùng tồn tại.
  • 45 cặp duplicate non-null hiện hữu sẽ làm CREATE UNIQUE INDEX FAIL ngay.
  • BLOCK 4 §9.2 PHẢI dedupe TRƯỚC khi CREATE INDEX.
-- v5.1 BLOCK 4 — CHỈ chạy SAU dedupe verify 0 row duplicate non-null:
CREATE UNIQUE INDEX uq_dot_tools_file_path
  ON dot_tools(file_path) WHERE file_path IS NOT NULL;

-- v5.1 BLOCK 4 — CHỈ chạy SAU DOT_METADATA_AUDIT báo 0 drift:
ALTER TABLE dot_tools
  ALTER COLUMN operation SET NOT NULL,
  ALTER COLUMN coverage_status SET NOT NULL,
  ALTER COLUMN trigger_type SET NOT NULL,
  ALTER COLUMN file_path SET NOT NULL,
  ALTER COLUMN cron_schedule SET NOT NULL,
  ALTER COLUMN _dot_origin SET NOT NULL;

Reference tables (v5.1 mở rộng dot_operations từ 9 → 18 op):

CREATE TABLE dot_tiers (code TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT);
INSERT INTO dot_tiers VALUES ('A', 'Kiểm tra', 'Read-only'), ('B', 'Thực thi', 'Read+Write');

CREATE TABLE dot_operations (code TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT);
INSERT INTO dot_operations VALUES 
  -- 9 op từ v5.0:
  ('health','Kiểm tra sức khoẻ',''), ('create','Tạo mới',''), ('sync','Đồng bộ',''),
  ('ensure','Đảm bảo tồn tại',''), ('register','Đăng ký',''), ('report','Báo cáo',''),
  ('execute','Thực thi',''), ('refresh','Làm mới',''), ('classify','Phân loại',''),
  -- 9 op MỚI v5.1 (CLI S177 C6 phát hiện 8/12 op runtime ngoài luật seed v5.0):
  ('verify','Kiểm tra hợp lệ',''), ('delete','Xoá',''), ('update','Cập nhật',''),
  ('restore','Khôi phục',''), ('import','Nhập liệu',''), ('snapshot','Chụp ảnh',''),
  ('seed','Gieo dữ liệu',''), ('audit','Kiểm toán',''), ('backfill','Điền ngược','');

CREATE TABLE dot_trigger_types (code TEXT PRIMARY KEY, name TEXT NOT NULL);
INSERT INTO dot_trigger_types VALUES 
  ('cron','Lịch định kỳ'), ('event','Sự kiện Directus'), ('on-deploy','Khi deploy'),
  ('on-demand','Khi yêu cầu'), ('manual','Thủ công'), ('one-off','1 lần duy nhất');

CREATE TABLE dot_coverage_statuses (code TEXT PRIMARY KEY, name TEXT NOT NULL);
INSERT INTO dot_coverage_statuses VALUES 
  ('complete','Đầy đủ'), ('partial','Một phần'), ('orphan','Mồ côi'),
  ('phantom','Ma'), ('deprecated','Lỗi thời');

★ v5.1 KHOẢN 1B — ĐỊNH NGHĨA 2 HÀM PHỤ TRỢ

-- B1: fn_is_in_grace_period()
CREATE OR REPLACE FUNCTION fn_is_in_grace_period()
RETURNS BOOLEAN
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, pg_catalog
AS $$
DECLARE
  v_days INT;
  v_enacted TIMESTAMPTZ;
BEGIN
  SELECT value::INT INTO v_days FROM dot_config WHERE key = 'grace_period_days';
  SELECT value::TIMESTAMPTZ INTO v_enacted FROM dot_config WHERE key = 'law_v5_1_enacted_at';
  IF v_days IS NULL OR v_enacted IS NULL THEN
    RETURN TRUE; -- fail-open
  END IF;
  RETURN NOW() < v_enacted + (v_days || ' days')::INTERVAL;
END;
$$;
ALTER FUNCTION fn_is_in_grace_period() OWNER TO workflow_admin;

-- B2: fn_log_issue() — v5.1 FINAL: signature BỎ severity → escalate trên cùng row
CREATE OR REPLACE FUNCTION fn_log_issue(
  p_source     TEXT,
  p_severity   TEXT,
  p_category   TEXT,
  p_summary    TEXT,
  p_entity_code TEXT DEFAULT NULL
) RETURNS BIGINT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, pg_catalog
AS $$
DECLARE
  v_id BIGINT;
  v_signature TEXT;
BEGIN
  -- signature KHÔNG có severity → 1 issue/(source,category,entity), severity leo thang cùng row
  v_signature := md5(coalesce(p_source,'') || '|' || coalesce(p_category,'') || '|' || coalesce(p_entity_code,''));

  INSERT INTO system_issues (source, severity, category, summary, entity_code, issue_signature, status, created_at, updated_at)
  VALUES (p_source, p_severity, p_category, p_summary, p_entity_code, v_signature, 'open', NOW(), NOW())
  ON CONFLICT (issue_signature) WHERE status = 'open'
  DO UPDATE SET 
    -- Chỉ leo severity lên, không tụt
    severity = CASE 
      WHEN (CASE EXCLUDED.severity WHEN 'critical' THEN 3 WHEN 'warning' THEN 2 ELSE 1 END) 
           > (CASE system_issues.severity WHEN 'critical' THEN 3 WHEN 'warning' THEN 2 ELSE 1 END)
      THEN EXCLUDED.severity
      ELSE system_issues.severity
    END,
    summary = EXCLUDED.summary, 
    updated_at = NOW()
  RETURNING id INTO v_id;
  RETURN v_id;
END;
$$;
ALTER FUNCTION fn_log_issue(TEXT,TEXT,TEXT,TEXT,TEXT) OWNER TO workflow_admin;
GRANT EXECUTE ON FUNCTION fn_log_issue(TEXT,TEXT,TEXT,TEXT,TEXT) TO incomex;

-- BLOCK 1 preflight (v5.1 FINAL): dedupe system_issues TRƯỚC khi tạo unique partial index.
-- WITH dups AS (
--   SELECT md5(coalesce(source,'')||'|'||coalesce(category,'')||'|'||coalesce(entity_code,'')) AS sig,
--          MIN(id) AS keep_id, COUNT(*) AS cnt
--   FROM system_issues WHERE status='open'
--   GROUP BY 1 HAVING COUNT(*) > 1
-- )
-- UPDATE system_issues SET status='resolved', updated_at=NOW(),
--        summary = summary || ' [auto-merged duplicate sig pre-v5.1]'
-- WHERE id IN (
--   SELECT s.id FROM system_issues s
--   JOIN dups d ON md5(coalesce(s.source,'')||'|'||coalesce(s.category,'')||'|'||coalesce(s.entity_code,''))=d.sig
--   WHERE s.status='open' AND s.id <> d.keep_id
-- );
-- Sau đó:
-- ALTER TABLE system_issues ADD COLUMN IF NOT EXISTS issue_signature TEXT;
-- CREATE UNIQUE INDEX IF NOT EXISTS uq_system_issues_open_sig ON system_issues(issue_signature) WHERE status='open';

SECURITY DEFINER an toàn: Mọi function SECDEF v5.1 đặt SET search_path = public, pg_catalog. Owner = workflow_admin.

4.2 dot_domains (giữ v5.0)

CREATE TABLE dot_domains (
  code TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  parent_domain TEXT REFERENCES dot_domains(code)
);

4 lớp bảo vệ: DEFAULT 'unclassified' + NOT NULL + FK + ON DELETE RESTRICT. Seed 24 domains: Phụ lục A.

4.3 dot_coverage_required (giữ v5.0)

CREATE TABLE dot_coverage_required (
  id SERIAL PRIMARY KEY,
  domain TEXT NOT NULL REFERENCES dot_domains(code),
  operation TEXT NOT NULL REFERENCES dot_operations(code),
  tier TEXT NOT NULL REFERENCES dot_tiers(code),
  description TEXT,
  UNIQUE(domain, operation, tier)
);

4.4 dot_config (v5.1 FINAL fix — nullable + UTC ISO)

-- v5.1 FINAL fix Council R2 GPT #1: value nullable (cho phép seed law_v5_1_enacted_at=NULL)
CREATE TABLE dot_config (
  key TEXT PRIMARY KEY,
  value TEXT,                         -- v5.1: nullable
  description TEXT,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

INSERT INTO dot_config VALUES 
  ('dot_base_path', 'bin/dot/', 'Thư mục gốc DOT'),
  ('stale_threshold_days', '7', 'Ngày stale'),
  ('grace_period_days', '7', 'Grace mặc định — có thể UPDATE để gia hạn'),
  ('health_cron', '0 3 * * *', ''),
  ('coverage_cron', '0 2 * * 0', ''),
  ('birth_gate_mode', 'warn', 'v5.1: warn mặc định. UPDATE=block khi đạt §10 checklist'),
  ('law_v5_1_enacted_at', NULL, 'v5.1: SET tại thời điểm ban hành (UTC ISO). H14 báo nếu NULL > 24h');

-- BƯỚC BẮT BUỘC khi ban hành (BLOCK 2 cuối):
-- UPDATE dot_config SET value=to_char(NOW() AT TIME ZONE 'UTC','YYYY-MM-DD"T"HH24:MI:SS"Z"')
--   WHERE key='law_v5_1_enacted_at';

GUARD H14 (v5.1 FINAL): dot-dot-health H14 bắt law_v5_1_enacted_at IS NULL + BLOCK 1 đã chạy > 24h → fn_log_issue('dot-dot-health','critical','grace_never_set','...').


§5. QUY TRÌNH TẠO DOT MỚI — 8 BƯỚC (v5.1 strengthened bước 4)

Bước Hành động Cơ chế Luật
1 Tạo APR request_type='new_dot' Đ32 Đ32
2 Cấp A auto-approve. Cấp B pending APR Đ32
3 Tạo file .ts tại dot_config.dot_base_path Agent
4 Register vào dot_tools 11/11 fields + dual-trigger dot-dot-register + cron repair Đ22
5 Khai báo target_collections dot-dot-register Đ8
6 Khai sinh birth_registry Trigger tự động Đ0-G
7 dot-dot-health kiểm tra Cron/manual Đ31
8 Health PASS → active Tự động Đ22

★ v5.1 KHOẢN 5 (BƯỚC 4 STRENGTHENED)

5.1 Payload TỐI THIỂU ở API boundary (11 fields)

{
  "code": "DOT-...",               // REQUIRED, unique
  "name": "...",                   // REQUIRED
  "tier": "A|B",                   // REQUIRED, FK
  "domain": "xxx.yyy",             // REQUIRED dotted, FK
  "operation": "...",              // REQUIRED, FK
  "trigger_type": "...",           // REQUIRED, FK
  "cron_schedule": "...",          // REQUIRED ('' cho manual)
  "coverage_status": "partial",    // REQUIRED, default 'partial'
  "file_path": "/opt/incomex/...", // REQUIRED absolute
  "_dot_origin": "dot-dot-register" // REQUIRED
}

WORDING NT11: Payload 11 fields = API boundary contract. Nguồn ưu tiên = suy luận tự động. dot-dot-register PHẢI infer trước khi POST.

v5.1 FINAL fix #4 — INFER FAIL = CẤM POST PARTIAL ROW:

Khi dot-dot-register infer thất bại field bắt buộc, TUYỆT ĐỐI CẤM POST partial/placeholder:

  1. fn_log_issue('dot-dot-register','warning','infer_fail',...)
  2. Tạo APR request_type='backfill_metadata'
  3. SKIP file trong run hiện tại
  4. Chờ APR duyệt → re-register

Pattern CẤM: "POST trước, cron sửa sau" — chính là RC-4 đẻ ra 49 DOT POST-S151 vẫn 94% NULL. Không lặp lại.

5.2 DUAL-TRIGGER — sống cả khi mode=block

Path Vai trò Trigger Sống khi block?
Pre-POST inference trong dot-dot-register Engine chính — infer 11 fields TRƯỚC khi POST on-deploy + on-demand ✅ Có
Cron dot-metadata-repair (v5.1 MỚI, Tier B) Lưới đỡ — scan row partial → infer + PATCH; fail → APR Cron 0 * * * * ✅ Có

Health check H13: DOT dot-metadata-repair không tồn tại HOẶC last_executed > 2h → critical.

v5.1 FINAL fix #5 — H13 chỉ là BÁO ĐỘNG:

H13 escalate qua fn_log_issue + APR request_type='fix_repair_dot'. KHÔNG có self-repair tự động (tránh self-paradox DOT canh gác chính nó). Khi repair DOT chết, fn_birth_gate là hàng phòng thủ tạm thời cho DOT mới.

Flow Directus [AUTO-ID] DOT Tools: giữ ACTIVE làm lưới đỡ phụ giai đoạn warn.

5.3 Reject row không đầy đủ sau grace + mode=block

Kết hợp §8.3: sau grace AND birth_gate_mode='block', INSERT thiếu field bị PG reject ngay.


§6. VÒNG ĐỜI DOT (v5.2 mở rộng)

6.1 Trạng thái

created → active → deprecated → retired

Retire 6 bước + Luật Bảo toàn (CẤM rename/xoá file).

6.2 Flow Sửa Bug DOT Canonical Đã Enacted (fix_repair_dot) — v5.2 MỚI

Điều kiện kích hoạt: Phát hiện bug trong DOT đã status='enacted' (không phải draft/review). Ví dụ: cột SQL sai, silent-fail, logic bug.

6 bước bắt buộc:

Bước Hành động Chi tiết Luật
1. DETECT Ghi system_issues kind='dot_bug', dot_code, evidence (file:line + error observed) Đ22
2. PROPOSE dot-apr-propose request_type='fix_repair_dot', proposed_action_code='patch_ops_code', payload gồm diff cũ→mới, root cause, test plan Đ32 v1.1
3. APPROVE Theo cơ chế Đ32 risk_level từ apr_action_types → Council (high) / Chủ tịch (medium) / auto (low) Đ32 v1.1 §3.3
4. APPLY Flow Đ41 §5.8 backup .bak-{session} → patch → dry-run → commit+log. Bắt buộc test case regress bug gốc TRƯỚC khi commit Đ41 v1.1
5. VERIFY Post-deploy scan 3 tầng DOT chạy lại: bug tái hiện = FAIL → rollback từ backup §6.4
6. CLOSE Đóng sổ system_issue → 'resolved', APR → 'applied', vps_deploy_log entry đầy đủ Đ31

6.3 Điều kiện từng bước

  • Bước 1→2: DETECT phải có evidence cụ thể (file, dòng, lỗi quan sát được). KHÔNG "cảm thấy có bug" → DỪNG (NT9).
  • Bước 2→3: Payload APR phải chứa diff (old→new), root cause analysis, test plan verify. Thiếu bất kỳ = APR bị reject.
  • Bước 3→4: Chỉ khi APR status='approved'. Trigger DB fn_apr_quorum_check enforce quorum theo risk_level (P14).
  • Bước 4→5: Backup .bak-{session} TỒN TẠI và verify checksum TRƯỚC khi patch. Không backup = DỪNG.
  • Bước 5→6: 3 tầng verify PASS. Bất kỳ tầng nào FAIL → rollback từ backup, mở system_issues mới.

6.4 Verify 3 tầng (post-deploy)

Tầng Kiểm tra PASS FAIL
1. Syntax File mới parse được (TypeScript: tsc --noEmit, Bash: bash -n) Tiếp tầng 2 Rollback ngay
2. Dry-run DOT chạy với --dry-run (nếu hỗ trợ) hoặc trên data test, output hợp lý Tiếp tầng 3 Rollback ngay
3. Integration DOT chạy thật trên production, verify bug gốc không tái hiện + không regression CLOSE Rollback + system_issues mới

6.5 ADMIN Fallback — Khi chính DOT APR hỏng

Tình huống: dot-apr-propose hoặc dot-apr-execute chính nó bị bug → không thể tạo/thực thi APR bình thường → vòng lặp vô tận.

Quy trình ngoại lệ (chỉ Chủ tịch):

  1. INSERT admin_fallback_log (dot_code, reason, backup_path, patch_diff, verify_evidence, session_code, status='applied') TRƯỚC khi patch.
  2. Patch trực tiếp (bypass APR).
  3. Verify 3 tầng (§6.4).
  4. Tạo retroactive APR trong 24 giờ (retroactive_deadline). Quá hạn → fn_admin_fallback_overdue_scan() tự flip status='audit_overdue' → system_issues kind='fallback_audit_overdue'.
  5. Ghi retroactive_apr_id vào admin_fallback_log khi APR tạo xong.

Giới hạn: Chỉ dùng cho DOT thuộc hệ thống APR chính nó. Không dùng cho DOT nghiệp vụ khác.

6.6 Paired test bắt buộc (NT12)

Mọi DOT bash canonical (thuộc ops-code/) PHẢI đi kèm paired test script kiểm tra hành vi tối thiểu (smoke test). Pattern: dot-XXX-test chạy dry-run, verify output mẫu. Retrofit 90 ngày cho DOT lõi (nrm-*, apr-*, dot-dot-*).

6.7 Retrofit

DOT legacy đã enacted trước §6 này vẫn áp dụng flow fix_repair_dot khi phát hiện bug. KHÔNG có cửa bypass.


§7. ĐO LƯỜNG (giữ v5.0 + bổ sung 7.6)

7.1-7.5 giữ v5.0

★ 7.6 Metadata Completeness Rate (v5.1 MỚI)

  • (DOT có 11/11 fields NOT NULL) / (Tổng DOT) × 100
  • Mục tiêu: 100% sau grace + Block 4 retrofit

§8. DOT TỰ QUẢN TRỊ — 4 CẶP (v5.1 mở rộng)

DOT Cấp Chức năng Paired Trigger
dot-dot-health A 14 health checks v5.1 cron
dot-dot-coverage A Coverage + auto-suggest cron weekly
dot-dot-register B Đăng ký (11/11 fields infer) dot-dot-health on-deploy + on-demand
dot-metadata-repair (v5.1 MỚI) B Cron repair partial → infer + PATCH; fail → APR dot-dot-health (H13) cron 0 * * * *

8.1 dot-dot-health — 14 health checks (v5.1 FINAL)

Check Phát hiện Hành động (dùng fn_log_issue())
H1 domain='unclassified' APR classify
H2 DOT B thiếu paired_dot APR pairing
H3 thiếu target_collections APR
H4 file_path không tồn tại APR fix
H5 retired nhưng cron còn chạy APR disable
H6 last_executed > threshold warning stale
H7 File disk không trong registry APR register
H8 coverage_status không nhất quán APR update
H9 retired mà register cố re-register Block
H10 v5.1: operation IS NULL sau grace critical + APR backfill_operation
H11 v5.1: coverage_status IS NULL sau grace Như H10
H12 v5.1: file_path drift — 2 row cùng trỏ 1 file critical + APR dedupe
H13 v5.1: dot-metadata-repair chết / stale > 2h critical (chỉ báo động, không self-repair)
H14 v5.1 FINAL: law_v5_1_enacted_at IS NULL + BLOCK 1 > 24h critical grace_never_set + APR set_law_enacted_at

Severity (đối chiếu Đ31):

  • warning = trong grace HOẶC drift < 24h
  • critical = sau grace HOẶC drift > 24h HOẶC duplicate file_path

★ v5.1 KHOẢN 2 — ESCALATION BẮT BUỘC qua fn_log_issue()

Mọi H1-H14 phát hiện → BẮT BUỘC gọi fn_log_issue(). CẤM dùng curl ... || true (silent-fail). Cầu nối Đ22 self-healing.

8.2 dot-dot-coverage (Cấp A) — giữ v5.0

8.3 dot-dot-register (Cấp B) — v5.1 strengthened

  • Đọc dot_base_path từ dot_config
  • Quét → so sánh với dot_tools
  • File mới → infer 11/11 fields rồi POST (§5.1). Infer fail → CẤM POST + APR
  • Dual-trigger: kết hợp dot-metadata-repair cron
  • File retired → SKIP

★ v5.1 KHOẢN 3 — fn_birth_gate configurable mode + scope rõ

SCOPE: fn_birth_gate trong Đ35 là gate cho dot_tools metadata, KHÔNG phải birth gate generic của Đ0-G. Code comment: fn_birth_gate (Đ35-scope: dot_tools).

CREATE OR REPLACE FUNCTION fn_birth_gate()
RETURNS TRIGGER LANGUAGE plpgsql SECURITY DEFINER
SET search_path = public, pg_catalog
AS $$
DECLARE
  v_missing text[] := ARRAY[]::text[];
  v_mode text;
  v_grace boolean;
BEGIN
  SELECT value INTO v_mode FROM dot_config WHERE key='birth_gate_mode';
  v_grace := fn_is_in_grace_period();

  IF NEW.operation IS NULL THEN v_missing := array_append(v_missing, 'operation'); END IF;
  IF NEW.coverage_status IS NULL THEN v_missing := array_append(v_missing, 'coverage_status'); END IF;
  IF NEW.trigger_type IS NULL THEN v_missing := array_append(v_missing, 'trigger_type'); END IF;
  IF NEW.file_path IS NULL THEN v_missing := array_append(v_missing, 'file_path'); END IF;
  IF NEW._dot_origin IS NULL THEN NEW._dot_origin := 'unknown'; END IF;

  IF array_length(v_missing, 1) > 0 THEN
    PERFORM fn_log_issue(
      'fn_birth_gate',
      CASE WHEN v_grace THEN 'warning' ELSE 'critical' END,
      'dot_metadata_missing',
      format('DOT %s thiếu: %s', NEW.code, array_to_string(v_missing, ',')),
      NEW.code
    );
    IF NOT v_grace AND v_mode = 'block' THEN
      RAISE EXCEPTION 'DOT % missing required fields: % (grace expired, mode=block)',
                      NEW.code, array_to_string(v_missing, ',');
    ELSE
      RAISE WARNING 'DOT % missing fields: %', NEW.code, array_to_string(v_missing, ',');
    END IF;
  END IF;

  RETURN NEW;
END;
$$;
ALTER FUNCTION fn_birth_gate() OWNER TO workflow_admin;

§9. BOOTSTRAP — 4 BLOCKS (v5.1)

§9.1 Vấn đề gà-trứng (giữ v5.0)

§9.2 Migration PR — 4 BLOCKS

BLOCK 1 — SCHEMA:

  • Tạo dot_domains, dot_coverage_required, 4 reference tables, dot_config
  • Thêm 11 fields nullable vào dot_tools (FK trỏ reference tables)
  • v5.1: Thêm system_issues.issue_signature + preflight dedupe + UNIQUE partial WHERE status='open'

BLOCK 2 — DATA:

  • Seed 24 domains, reference tables (18 op), dot_config (+ birth_gate_mode='warn')
  • UPDATE law_v5_1_enacted_at=NOW() AT TIME ZONE 'UTC' ISO format
  • Backfill dot_tools metadata + _dot_origin='legacy_pre_v5_1'
  • Register 6 bootstrap DOT

BLOCK 3 — CONSTRAINTS + ENABLE:

  • FK constraints
  • trg_dot_enforce_paired
  • v5.1: Tạo fn_is_in_grace_period() + fn_log_issue() + fn_birth_gate v5.1
  • KHÔNG bật NOT NULL (chờ BLOCK 4)
  • KHÔNG bật cron (chờ BLOCK 4)

BLOCK 4 (v5.1 MỚI) — RETROFIT + DEDUPE + NOT NULL — CHECKLIST CỨNG

[ ] 4.0  ★ SNAPSHOT BASELINE (rollback safety):
         - CREATE TABLE dot_tools_pre_v5_1 AS SELECT * FROM dot_tools;
         - CREATE TABLE system_issues_pre_v5_1 AS SELECT * FROM system_issues WHERE status='open';
         - Snapshot 45 cặp duplicate → reports/s177-block4-baseline-<date>.md
         - Mapping canonical ↔ retire → reports/

[ ] 4.1  Snapshot 45 cặp duplicate file_path (chi tiết format)
[ ] 4.2  Chọn canonical row (coverage_status='complete' > created_at sớm hơn)
[ ] 4.3  Row dư: APR retire — LƯU old_file_path TRƯỚC khi NULL:
         BEGIN;
           UPDATE dot_tools 
           SET extra_metadata = extra_metadata || jsonb_build_object(
                 'retired_at', NOW(),
                 'retired_reason', 'block4_dedup_v5_1',
                 'old_file_path', file_path,
                 'canonical_dot', <canonical_code>
               ),
               status = 'retired',
               file_path = NULL
           WHERE code IN (<row_du_codes>);
         COMMIT;

[ ] 4.4  VERIFY: 0 row duplicate non-null file_path

[ ] 4.5  Kích DOT_BIRTH_BACKFILL (TRƯỚC 4.6: khai sinh trước, hoàn thiện hồ sơ sau)

[ ] 4.6  Kích DOT_METADATA_FILL (trong transaction; fail → rollback từ 4.0)

[ ] 4.7  Kích DOT_METADATA_AUDIT → báo cáo drift

[ ] 4.8  VERIFY: DOT_METADATA_AUDIT báo 0 drift

[ ] 4.9  CREATE UNIQUE INDEX uq_dot_tools_file_path WHERE NOT NULL
         (272 row: thường đủ; >100K: khuyến nghị CONCURRENTLY)

[ ] 4.10 ★ ALTER NOT NULL ATOMIC TRANSACTION:
         BEGIN;
           ALTER TABLE dot_tools
             ALTER COLUMN operation SET NOT NULL,
             ALTER COLUMN coverage_status SET NOT NULL,
             ALTER COLUMN trigger_type SET NOT NULL,
             ALTER COLUMN file_path SET NOT NULL,
             ALTER COLUMN cron_schedule SET NOT NULL,
             ALTER COLUMN _dot_origin SET NOT NULL;
         COMMIT;
         (Fail cột nào → rollback toàn bộ 6 cột)

[ ] 4.11 Enable cron dot-dot-health + dot-dot-coverage + dot-metadata-repair

[ ] 4.12 Quan sát 24h. 0 critical → PASS. Critical → restore từ 4.0:
         BEGIN;
           TRUNCATE dot_tools;
           INSERT INTO dot_tools SELECT * FROM dot_tools_pre_v5_1;
         COMMIT;

[ ] 4.13 Sau 7 ngày PASS ổn định → DROP snapshot tables (safety net 7 ngày)

§9.3 Grace period (v5.1 enforce)

  • Mặc định 7 ngày (dot_config.grace_period_days).
  • Có thể gia hạn qua config. Khi DOT_METADATA_AUDIT còn drift → KHÔNG được chuyển mode='block' — gia hạn grace.

§9.4 Maintenance window (giữ v5.0)


§10. SUCCESS METRICS + TIÊU CHÍ CỨNG warn → block

Success Metrics

  • 100% dot_tools có 11/11 fields NOT NULL
  • 100% DOT B có paired_dot
  • 0 hardcode
  • 0 duplicate file_path
  • 14/14 health checks LIVE
  • Flow [AUTO-ID] DOT Tools ACTIVE + dot-metadata-repair cron LIVE
  • system_issues nhận events từ H10-H14 + fn_birth_gate
  • last_executed cập nhật tự động

★ TIÊU CHÍ CỨNG warn → block

Chỉ được UPDATE dot_config SET value='block' WHERE key='birth_gate_mode' khi 4 điều kiện AND:

  1. DOT_METADATA_AUDIT báo 0 drift trong 3 ngày liên tiếp
  2. 0 row duplicate non-null trên file_path
  3. dot-metadata-repair cron LIVE + last_executed < 2h (H13 PASS)
  4. ✅ H10-H14 PASS liên tục 3 ngày (0 critical mới)

Chưa đủ → giữ warn + gia hạn grace.


§11. RETROFIT CLAUSE (v5.1 MỚI)

§11.1 Nguyên tắc

Mọi luật mới áp dụng cho bảng có DATA CŨ BẮT BUỘC kèm DOT retrofit. Luật không có §retrofit = legacy mãi vênh = vi phạm HP NT1.

§11.2 Yêu cầu với mọi luật áp dot_tools (và bảng quản trị khác)

  1. Phải có DOT_<LAW_ID>_BACKFILL (tier B) — scan + infer + backfill, hoặc APR.
  2. Paired với DOT_<LAW_ID>_VERIFY (tier A) — báo entity chưa đáp ứng → system_issues.
  3. Chạy 1 lần sau ban hành TRƯỚC khi bật NOT NULL §4.1.
  4. Cron daily DOT_<LAW_ID>_VERIFY để catch drift.

§11.2.1 RULE auto-backfill vs APR

Trường hợp Hành động
Infer chắc chắn + idempotent + có verify pair Auto-PATCH + log kb_audit_log
Infer mơ hồ HOẶC không idempotent Tạo APR backfill_<field>
DOT Vai trò Kích sau ban hành
DOT_BIRTH_BACKFILL Scan 272 DOT cũ, tạo birth_registry ✅ BLOCK 4 bước 4.5
DOT_METADATA_AUDIT Report drift ✅ Bước 4.7
DOT_METADATA_FILL Backfill metadata ✅ Bước 4.6
DOT_KG_COMPLETENESS Verify paired FILL ✅ Cron daily
DOT_SCHEMA_BIRTH_REGISTRY_ENSURE Schema ensure ✅ Trước BLOCK 3
DOT_BIRTH_TRIGGER_SETUP Verify fn_birth_gate trên 133 collections ✅ Sau BLOCK 3

Race condition: tuần tự có barrier. KHÔNG kích đồng thời.

§11.4 Áp cho luật ĐÃ BAN HÀNH (wording cứng)

Mọi luật đang có hiệu lực mà tác động bảng có data cũ NHƯNG chưa có retrofit clause đều phải mở amend bổ sung retrofit trong kỳ sửa gần nhất. TRƯỚC KHI amend xong, KHÔNG được bật constraint/block mới làm legacy kẹt cứng.

Đ36, Đ37, Đ38, Đ39, Đ41 → audit chéo + amend retrofit. Tracker: knowledge/current-state/retrofit-audit-tracker.md (tạo trong cùng PR).

§11.5 Áp cho luật tương lai

OR soạn luật v1.0 → v1.1 bổ sung checklist: "Luật có impact lên bảng có data cũ → kèm §retrofit + DOT_<LAW>BACKFILL + DOT<LAW>_VERIFY".


§12. (Đã bỏ — PROMPT-LAW DRIFT xử ở OR + Skill Handoff)

  1. OR soạn luật v1.0 → v1.1: checklist "Prompt bootstrap đối chiếu §4+§9, ghi TÊN không chỉ số"
  2. Skill Handoff v7 + AP-22 "Đếm số không đo tên"

PHỤ LỤC A — 24 Domain Seed (giữ v5.0)

code name parent_domain
infrastructure Hạ tầng kỹ thuật NULL
infrastructure.schema Schema & Fields infrastructure
infrastructure.sync Đồng bộ infrastructure
infrastructure.backup Sao lưu infrastructure
infrastructure.deploy Triển khai infrastructure
governance Quản trị NULL
governance.approval Phê duyệt governance
governance.audit Kiểm toán governance
birth Khai sinh NULL
birth.register Đăng ký birth
birth.orphan Mồ côi birth
classification Phân loại NULL
classification.label Nhãn classification
classification.species Loài classification
monitoring Giám sát NULL
monitoring.health Sức khoẻ monitoring
monitoring.integrity Toàn vẹn monitoring
monitoring.dot Quản trị DOT monitoring
pivot Đếm & Báo cáo NULL
sync Đồng bộ 5 tầng NULL
lifecycle Vòng đời NULL
data_quality Chất lượng dữ liệu NULL
workflow Quy trình NULL
collection Collection Protocol NULL

CHANGELOG

Ver Ngày Nội dung
v5.2 FINAL 2026-04-18 S178 Fix 15 BAN HÀNH Amend trực tiếp từ v5.1. Bổ sung flow fix_repair_dot, verify 3 tầng, ADMIN fallback audit, paired test retrofit, bridge/quorum liên kết với Đ32 v1.1 và hành lang ops-code/ theo Đ41 v1.1.
v5.1 FINAL 2026-04-14 S177 Fix 8 BAN HÀNH Council 2 vòng DONE. R1: Gemini 9/10 + GPT 8.3/10 APPROVE WITH CHANGES → fix 5 blocker. R2: Gemini 9.8/10 APPROVE FINAL + GPT 9.1/10 APPROVE WITH MINOR → apply 7 fix inline: (1) dot_config.value nullable + UTC ISO sentinel; (2) H14 grace_never_set > 24h; (3) fn_log_issue bỏ severity khỏi signature + escalate trên cùng row; (4) precheck dedupe system_issues trước CREATE UNIQUE INDEX; (5) §5.1 infer fail CẤM POST partial; (6) H13 chỉ báo động không self-repair; (7) BLOCK 4 +4.0 snapshot +4.3 lưu old_file_path +4.10 atomic transaction +4.13 cleanup. 0 blocker còn lại.
v5.0 FINAL 2026-03-31 S151 Ban hành gốc. Xem backup: dieu35-dot-governance-law-v5-0-backup.md. S177 phát hiện prompt bootstrap S155 thiếu 5 bảng → 49 DOT POST-S151 vẫn 94% NULL operation.

GHI CHÚ BAN HÀNH (post-merge TODO)

Sau khi PR ban hành v5.1 merge, phải thực hiện theo thứ tự:

  1. Tạo knowledge/current-state/retrofit-audit-tracker.md — theo dõi amend Đ36/37/38/39/41 theo §11.4
  2. dot-dot-register payload 11 fields + BẬT [AUTO-ID] DOT Tools Directus flow ACTIVE
  3. Chạy BLOCK 4 checklist §9.2 (13 bước từ 4.0 snapshot → 4.13 cleanup)
  4. UPDATE law_v5_1_enacted_at=NOW() AT TIME ZONE 'UTC' ISO' ngay khi BLOCK 2 xong
  5. Amend song song trong cùng PR:
    • knowledge/dev/ssot/operating-rules-law-drafting.md v1.0 → v1.1: checklist Gap-1
    • knowledge/dev/ssot/anti-patterns.md: thêm AP-22 "Đếm số không đo tên"
    • Skill Handoff v7: bắt buộc ghi TÊN khi ghi N artifact

Điều 35 v5.1 FINAL | BAN HÀNH 2026-04-14 S177 Fix 8 | Council 2 vòng DONE | 0 blocker | Sẵn sàng deploy theo BLOCK 4 §9.2