G1-1 Create Core — SUA-RE
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 -urỗ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; formatsha256<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 | có | PASS |
| khai_niem có concept_key, first_seen_*, contract_ref, promoted_at | có | PASS |
| Không có date_updated ở cả 2 bảng | 0 | PASS |
| Unique partial index ux_sruk_slot_current | có | 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/ schemapublic/ containerpostgres/ roleworkflow_admin.
5. Verify read-only (Pha 3)
Query qua read-only role (READ ONLY transaction):
- 2 bảng tồn tại: CÓ —
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: CÓ —
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: CÓ —
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_keydistinct (30 slot_key phân biệt) TRƯỚC khi INSERT usage, nếu không sẽ bịux_sruk_slot_currentchặn ở các bản is_current. - KHÔNG liệt kê cột
match_statustrong INSERT — cột GENERATED, PG tự sinh. Chỉ INSERTconcept_id+dedupe_key; match_status suy ra:matchedkhi có concept_id,review/candidatetheo prefix dedupe_key, còn lạipending. 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).
- Self-check
- G1-5 / QT-B (SQL delta khi sửa 1 slot):
- Phải UPDATE bản cũ
is_current = falseTRƯỚC, rồi mới INSERT bản mớiis_current = true. Làm ngược thứ tự sẽ đụngux_sruk_slot_current(partial unique trên slot_key WHERE is_current).
- Phải UPDATE bản cũ
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à
rootmoderwxr-sr-xnên tiến trình MCPwrite_file(chạy gid 10001) không ghi được. Đãchown 10001:10001+chmod 2775cho/opt/incomex/docs/mcp-writes/sua-revà.../goldenđể khớp đúng quy ước của câymcp-writes(các thư mục khác đều10001:10001mode2775). Chỉ chỉnh quyền trong vùngdocs/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.