KB-4F15

G1-1 Create Core — SUA-RE

6 min read Revision 1
sua-reg1g1-1pa3create-corepg-nhapdot-pg-atomic-apply2026-07-07

G1-1 Create Core — SUA-RE

Ngày: 2026-07-07. Phạm vi: SỬA RẺ G1 (PA3) — chỉ tạo 2 bảng PG nháp. Chưa seed, chưa view, chưa promote, chưa DOT mới, chưa trigger/function.

1. Verdict

APPLIED — thành công, atomic COMMIT, verify read-only PASS toàn bộ.

Đường đi tuân đúng ranh giới: ghi đúng 1 file SQL trong allowlist, append đúng 1 dòng manifest, chạy đúng dot-pg-atomic-apply trên đúng file đó, verify bằng SELECT read-only. Không DROP/DELETE/TRUNCATE, không psql tay, không commit repo, không sửa UI, không tạo bảng thứ 3.

2. File SQL

Pha 0 (DDL vàng — golden trước khi apply):

  • golden_path = /opt/incomex/docs/mcp-writes/sua-re/golden/create-core.golden.sql
  • apply_path = /opt/incomex/dot/sql/sua-re/create-core.sql
  • golden_sha256 = 2839def83d054407a922e189eb4887c03a1172340cda98f08726038f8c109d0a
  • apply_sha256 = 2839def83d054407a922e189eb4887c03a1172340cda98f08726038f8c109d0a
  • diff_result = identical (diff -u rỗng, 2 sha256 bằng nhau, cùng 5121 bytes / 141 dòng)
  • manifest = /opt/incomex/dot/sql/approved-sql-manifest.tsv
  • manifest_relpath = sua-re/create-core.sql (append đúng 1 dòng: 4 → 5 dòng; format sha256<TAB>relpath)

Apply file được tạo bằng cp từ golden ⇒ 2 file byte-identical theo cấu trúc, không chép tay.

3. Self-check (Pha 1)

Mục Kỳ vọng Kết quả
Chỉ chứa CREATE TABLE / CREATE (UNIQUE) INDEX IF NOT EXISTS đúng PASS — 2 CREATE TABLE + 1 CREATE UNIQUE INDEX + 5 CREATE INDEX
Đúng 2 bảng sua_re_khai_niem_nhap, sua_re_ui_khai_niem_nhap PASS
Không DROP/DELETE/TRUNCATE/INSERT/UPDATE/ALTER/CREATE VIEW/FUNCTION/TRIGGER (dạng lệnh) 0 PASS — các từ này chỉ nằm trong comment --, không phải statement
ui có slot_key, item_key, location_anchor NOT NULL, match_status GENERATED, owner_decision, decision_by, decision_at PASS
khai_niem có concept_key, first_seen_*, contract_ref, promoted_at PASS
Không có date_updated ở cả 2 bảng 0 PASS
Unique partial index ux_sruk_slot_current PASS
Không có CHECK cho match_status (vì generated) 0 PASS
slot_key KHÔNG chứa raw_label/scan_id/index (chỉ ui_id + location_anchor) đúng PASS (ghi trong comment quy ước)
item_key = slot_key '::' scan_id (quy ước loader G1-2) đúng PASS (ghi trong comment quy ước)
match_status là cột GENERATED, không ghi tay đúng PASS

Kiểm guardrail của gateway trước khi apply (đọc source dot-pg-atomic-apply): DDL không dính pattern cấm nào — DROP chỉ xuất hiện dạng KHÔNG DROP. (sau DROP là dấu ., không phải \s+<object>); tên sua_re_* / ck_* / ix_* / ux_* không khớp danh sách prefix cấm (meta_catalog|birth_registry|table_registry|qt001_|v_registry_).

4. Apply result (Pha 2)

dot-pg-atomic-apply /opt/incomex/dot/sql/sua-re/create-core.sql:

manifest match:  PASS
guardrail:       PASS
execution:       docker exec -i postgres psql -U workflow_admin -d directus -v ON_ERROR_STOP=1 -1 -f -
CREATE TABLE
CREATE TABLE
CREATE INDEX  (x6)
exit code:       0
✅ COMMIT thành công
  • Transaction status: COMMIT (một transaction atomic, -1 + ON_ERROR_STOP=1).
  • DB đích: directus / schema public / container postgres / role workflow_admin.

5. Verify read-only (Pha 3)

Query qua read-only role (READ ONLY transaction):

  • 2 bảng tồn tại: sua_re_khai_niem_nhap, sua_re_ui_khai_niem_nhap.
  • Số bảng sua_re_% ngoài phạm vi: 0 (đúng 2 bảng, không có bảng thứ 3).
  • match_status là generated column: is_generated = ALWAYS, generation_expression = CASE WHEN concept_id IS NOT NULL THEN 'matched' WHEN dedupe_key ~~ 'review.%' THEN 'review' WHEN dedupe_key ~~ 'candidate.%' THEN 'candidate' ELSE 'pending' END (STORED).
  • Không có date_updated: ĐÚNG — cả 2 bảng chỉ có date_created. Số cột: khai_niem = 17, ui = 23; không cột nào tên date_updated.
  • Index ux_sruk_slot_current: CREATE UNIQUE INDEX ux_sruk_slot_current ... USING btree (slot_key) WHERE is_current. Tổng 10 index/bảng-cặp: 6 index khai báo (ux_sruk_slot_current, ix_sruk_slot, ix_sruk_ui_cur, ix_sruk_concept, ix_sruk_owner_concept, ix_srkn_contract_ref) + 2 PK + 2 UNIQUE-constraint (concept_key, item_key).
  • Số row hiện tại: 0 / 0 (cả 2 bảng rỗng — chưa seed, đúng phạm vi G1-1).

6. Ghim cho G1-2 và G1-5

  • G1-2 (nạp seed 13 concept + 30 usage):
    • Self-check slot_key distinct (30 slot_key phân biệt) TRƯỚC khi INSERT usage, nếu không sẽ bị ux_sruk_slot_current chặn ở các bản is_current.
    • KHÔNG liệt kê cột match_status trong INSERT — cột GENERATED, PG tự sinh. Chỉ INSERT concept_id + dedupe_key; match_status suy ra: matched khi có concept_id, review/candidate theo prefix dedupe_key, còn lại pending.
    • slot_key = ui_id || '::' || location_anchor; item_key = slot_key || '::' || scan_id. Loader phải tự ghép, DDL không tự tính (chỉ ràng buộc NOT NULL/UNIQUE).
    • Kỳ vọng kết quả match: 27 matched / 2 candidate / 1 review (đối chiếu ở G1-2).
  • G1-5 / QT-B (SQL delta khi sửa 1 slot):
    • Phải UPDATE bản cũ is_current = false TRƯỚC, rồi mới INSERT bản mới is_current = true. Làm ngược thứ tự sẽ đụng ux_sruk_slot_current (partial unique trên slot_key WHERE is_current).

7. Caveat

  • Không có blocker kỹ thuật với DDL/apply/verify. Tất cả xanh.
  • Ghi nhận thao tác phụ trong vùng cho phép: thư mục golden mới tạo bằng root (qua SSH) ban đầu là root mode rwxr-sr-x nên tiến trình MCP write_file (chạy gid 10001) không ghi được. Đã chown 10001:10001 + chmod 2775 cho /opt/incomex/docs/mcp-writes/sua-re.../golden để khớp đúng quy ước của cây mcp-writes (các thư mục khác đều 10001:10001 mode 2775). Chỉ chỉnh quyền trong vùng docs/mcp-writes, KHÔNG đụng /opt/incomex/dot/sql, KHÔNG đổi nội dung DDL, KHÔNG mở rộng phạm vi.
  • Chưa làm (đúng ranh giới G1-1): seed, view, promote, DOT mới, Directus collection, registry/birth/species, vector/Qdrant, trigger/function, commit repo, sửa UI.