KB-247C rev 12

Kế hoạch — Sửa rẻ / Nhập UI v0 (Rev 6): 2 bảng PG + BỘ KIT + Definition of Done + NO-VECTOR + đường ống vận hành (7 quyết định ĐÃ CHỐT)

31 min read Revision 12
sua-renhap-uipg-firstconcept-ledgervan-hanhform-intakekittui-thuoc-dong-sandefinition-of-doneno-vector-policydotreportsv0rev6hold-pre-flightchot

KẾ HOẠCH — "SỬA RẺ" / NHẬP UI v0 (Rev 6)

2 bảng PG nháp + BỘ KIT "túi thuốc đóng sẵn" (đã có ở JS → chuyển PG) + đường ống vận hành + NO-VECTOR + report bằng khuôn có sẵn

TRẠNG THÁI: HOLD_PRE_FLIGHT — 7 quyết định §11 ĐÃ CHỐT (Owner 2026-07-06); Rev 6 hoàn thiện theo GPT simplify-locks + đồng bộ nhãn. CHƯA chạy DDL/DML, CHƯA tạo seed/kit artifact, CHƯA soạn prompt execution. Bước kế: Claude Code (claude-go, VPS, read-only) đọc bản này, chạy PRE-FLIGHT GATES (§9) + đi bộ lại B1→B6 → báo cáo KB → chỉnh doc nếu cần → chỉ khi TẤT CẢ gate xanh mới bàn mở G1. Tác giả: Fable (Reviewer #3). Ngày: 2026-07-06. Rev 6. Liên kết bằng chứng:

  • Codex review (HOLD): knowledge/dev/laws-new/kestra/sua-re/nhap-ui/codex-review-ke-hoach-nhap-ui-v0-rev2.md
  • Rà soát TƯƠNG THÍCH hệ thống (Fable, 2026-07-06): knowledge/dev/laws-new/kestra/sua-re/nhap-ui/compat-review-2026-07-06.md
  • GPT review simplify (2026-07-06): knowledge/dev/laws-new/kestra/sua-re/nhap-ui/gpt-review-rev6-simplify-2026-07-06.md
  • Handoff phiên: knowledge/dev/laws-new/kestra/sua-re/handoff-2026-07-06.md
  • KIT SỐNG (đã đọc-verify trên VPS): /opt/incomex/docs/mcp-writes/ui-preview/SUA-RE-README.md (README kit, "START HERE", luật nghiệm thu §3) + concept-ledger.js (v0.5, 13 thẻ) + ui-contracts.js (v0.1-chot2, 30 usage = 27 matched + 2 candidate + 1 review) + verify-contracts.js. Cùng mốc 2026-07-06T03:53:44Z.

0. MỤC TIÊU (một câu) + ANTI-GOAL

Mục tiêu: Cowork vẽ UI thoải mái; PG đếm đầu mối / khử trùng / so khái niệm cũ-mới RẺ, để Cowork KHÔNG tốn công kiểm điểm hợp đồng thông tin. Bộ 2 bảng + đường ống + kit là phương tiện, không phải đích.

ANTI-GOAL (Owner nhấn rất nhiều lần — đặt trên mọi thứ):

  • ĐỪNG đẻ quái vật. Không có DOT nào đi đọc / quét / OCR / đếm lại UI — đó chính là con quái vật. Cowork vừa vẽ nên biết thừa nó tạo trường gì và để làm gì (User nhắc được purpose). Cây cầu DUY NHẤT từ "Cowork biết" sang "PG đếm được" là một cái FORM Cowork điền.
  • Đơn giản không phải mục đích tự thân — nó là cách giữ số bước đủ ít để soi được từng bước có GAP hay không. Rủi ro nằm ở từng bước (kể cả bước đơn giản nhất). Một việc khả thi = đủ đơn giản không có GAP trong quy trình vận hành. Kế hoạch cũ "trên trời" vì không ai đi bộ từng bước vận hành — Rev 4/5/6 sửa đúng chỗ đó (§3, §3A, §3B).
  • KHÔNG đẻ kit mới. Kit đã tồn tại ở thời JS (SUA-RE-README.md + schema ui-contracts.js + renderUIContract + verify-contracts.js). Việc của ta = chuyển kit sang PG, giữ nguyên triết lý, đổi đúng một bước.
  • Khuôn /reports (PG view → v_report_* → Nuxt) ĐÃ XONG production (PG Census = ví dụ sống). TÁI DÙNG, không rebuild, không thiết kế UI mới.
  • Mọi thứ CHỐT phải hạ xuống KB (file này hoặc file cùng thư mục) — không để chết trong chat.

1. NGUYÊN TẮC BẤT DI (chống phình lại)

  1. 100% DOT cho DDL + ghi PG (cổng dot-pg-atomic-apply). Fable/MCP chỉ READ PG. Không psql tay, không sửa schema bằng Directus UI.
  2. PG → app chỉ qua Directus/Nuxt bằng KHUÔN CÓ SẴN (đăng ký collection + table_registry + SharedDirectusTable). Không Codex ở Nuxt.
  3. v0 chỉ 2 bảng. Không bảng scan/alias/ui/history riêng.
  4. v0 chỉ exact / alias / ILIKE. KHÔNG pg_trgm, KHÔNG Qdrant, KHÔNG fuzzy auto-match. Máy chỉ GỢI Ý; Owner QUYẾT cái mới.
  5. KHÔNG XÂY MỚI nếu khuôn/kit có sẵn kham được. Vượt ra → DỪNG, hỏi Owner.
  6. Cowork chỉ khai QUAN SÁT THÔ (§3, §3A). Không tự gán khóa/dedupe/match. Kit PG rút NGẮN việc Cowork: bỏ KHỬ-TRÙNG + KHỚP-SỔ tay (đúng "tốn công kiểm điểm" cần diệt) cho PG+Owner.
  7. Đồ nháp phải chui vùng NO-VECTOR (§7) — enforcement bằng policy thật, không chỉ nhãn.

2. HAI BẢNG (schema hội tụ) — DB directus, tên _nhap, status='draft'/'active'

(Lý do DB directus: các ổ cắm tích hợp + khuôn reports đều ở đó; để incomex_metadata phải FDW cross-DB.)

Bảng 1 — sua_re_khai_niem_nhap (DANH MỤC = ĐỊNH NGHĨA, 1 bản/khái niệm)

Cột Kiểu Ghi chú
id bigserial PK hợp khuôn (khuôn dùng id; balo dùng stt → khuôn xử được PK khác, nhưng id ít ma sát nhất).
concept_key text UNIQUE Id NGỮ NGHĨA (role.nguoi_lap) — đồng tiền tham chiếu xuyên hệ. Giữ cứng unique ở DB nếu tool cho.
ten text NOT NULL Tên hiển thị.
concept_kind text NOT NULL Enum đúng 6 loại của sổ: workflow, step, task, field, role, org. Đổi tên từ loai (tránh đụng "loài"=entity_species). Là từ vựng NHÃN-UI, KHÔNG phải species (compat-review Ⓑ).
mo_ta text NOT NULL Định nghĩa chuẩn. Gate ≥15 (§2-guard).
ranh_gioi text KHÔNG-phải-gì.
aliases jsonb default [] Tên gọi khác.
match_policy text GIỮ — 2 thẻ họ thời gian/trạng thái mang review (phanh chống-khớp-nhầm). Thẻ vắng = auto.
status text default draft seed 'chot''active'. Enum draft/active/retired.
note, date_created, date_updated Lý lịch.

KHÔNG bê vào bảng: locations (bảng usage CHÍNH LÀ locations chuẩn hóa), examples/non_examples/id_rules (giữ trong seed artifact). Bảng mảnh mà không mất gì.

Bảng 2 — sua_re_ui_khai_niem_nhap (NƠI DÙNG = bảng kê từng UI/scan)

Cột Kiểu Ghi chú
id bigserial PK hợp khuôn.
item_key text UNIQUE CỔNG SINH tất định (G-F): hash(ui_id, scan_id, location_or_index, raw_label). location trống → dùng INDEX của item trong items[] làm fallback. Cowork KHÔNG bịa khóa. item_key chỉ cần UNIQUE trong một scan.
ui_id text NOT NULL = surface_id (master-list-quy-trinh-v1).
ui_file text File thật.
scan_id text NOT NULL CỔNG sở hữu = hash CANONICAL JSON của companion (§3A). Không đổi → cùng scan_id → no-op; đổi → scan mới.
scan_at timestamptz
is_current boolean default true Bản mới nhất của ui_id. Scan lại → bản cũ false.
raw_label text NOT NULL Nhãn thô Cowork khai.
purpose text NOT NULL Cọc neo. Gate ≥15 (§2-guard). Thiếu/ngắn = fail import.
location text Vị trí trong UI (tùy — thiếu thì item_key dùng index).
dedupe_key text NOT NULL = duplicate_group: matched → concept_key; pending → pending.<hash(raw_label chuẩn hóa + purpose)> (KHÔNG chỉ raw_label — cùng "Trạng thái" hai nghĩa khác không được gộp; overcount an toàn hơn undercount sai). "Số khái niệm phân biệt" chính xác cho matched, xấp xỉ cho pending.
concept_id bigint FK→sua_re_khai_niem_nhap(id) null nếu chưa matched. Resolve lúc import (G-G).
owner_concept_id bigint FK, nullable Owner GHIM. Nguồn sự thật cho matched khi Owner đã quyết.
decision_note text Owner ghi VÌ SAO (§3A B5).
near_concepts jsonb Mảng {concept_key, why, confidence} — theo concept_key, KHÔNG ép FK id số.
date_created, date_updated

match_status KHÔNG lưu cột enumSUY TRONG VIEW (§4): owner_concept_id có → matched; concept_id khớp → matched; alias/ILIKE → review; còn lại → candidate; vừa import chưa khớp → raw. (Fallback nếu G-A cản: lưu enum {raw,matched,candidate,review} — bỏ deferred.)

MẶC ĐỊNH KHÔNG TÁCH HISTORY: current + history sống chung một bảng usage (scan_id + is_current). KHÔNG tách bảng history riêng trừ khi Claude Code trích được luật dòng chảy cấm cụ thể (§9 G-J) — tách = phức tạp hóa. Tiền lệ: IU iu_staging_record versioning trong một bảng, được chấp nhận.

GATE TOÀN VẸN (biến luật → ràng buộc máy; nơi đặt = §9 G-D)

  1. purpose/mo_ta ≥15: DB CHECK nếu tool cho; không thì import-gate FAIL CỨNG. Không dời/bỏ qua. ≥15 chỉ là sàn cơ học.
  2. dedupe_key NOT NULL, concept_key/item_key UNIQUE giữ cứng DB nếu được; tool không kham → import UPSERT theo khóa nghiệp vụ. Idempotency KHÔNG dời verify.
  3. Re-scan = UPSERT trong import (KHÔNG DOT bất biến, KHÔNG bảng scan): lật is_current=false bản cũ → chèn mới is_current=true, atomic.
  4. Registry idempotent (G2/G3): precheck + readback (map CHƯA có unique DB, đã có cặp trùng — KHÔNG cậy ON CONFLICT).

3. VÒNG VẬN HÀNH THỰC TẾ ⭐ (đi bộ từng bước — trái tim kế hoạch)

Hình tượng: đã thiết kế cái kho (2 bảng). Phần này thiết kế phiếu nhập kho, ai viết phiếu, cổng nào nhận, thủ kho so hàng cũ/mới. Thiếu đường ống này thì hệ chết vì vận hành, không phải vì schema.

B1 — Cowork vẽ/sửa UI. Đủ điều kiện. Không GAP.

B2 — Cowork điền FORM (UI_SCAN_JSON). (khâu SỐNG-CÒN) Khai CHỈ QUAN SÁT THÔ: raw_label, purpose(≥15), location, đoán type_guess/proposed_concept_key. KHÔNG tự gán dedupe_key/match_status/concept_id. Chống-quên = Definition of Done + coverage (§3A). Chưa từng thử → G1b.

B3 — FORM vào PG qua CỔNG. Nhận → kiểm (purpose≥15) → sinh scan_id+item_key → UPSERT → lật is_current, atomic. Cổng KHÔNG đọc lại UI. Ưu tiên dot-pg-atomic-apply + lớp kiểm mỏng (G-A/G-I). Seed = scan #0.

B4 — PG so cũ/mới = VIEW SUY. exact/alias→matched; ILIKE→review; không thấy→candidate; máy gợi ý, Owner quyết. Owner tạo concept mới → candidate cũ tự khớp lại.

B5 — Owner quyết. 3 action duy nhất: map_existing (set owner_concept_id=concept có sẵn) / create_new (insert concept vào bảng 1 + set owner_concept_id) / keep_pending (để null). Ghi owner_concept_id + decision_note qua dot-pg-atomic-apply. Chưa decision-DOT → G3.

B6 — Sửa nút. Màu/layout/icon → KHỎI. Label/field/filter/drawer → quét toàn UI. Sửa companion → nội dung đổi → hash đổi → scan mới → lật cũ. Tự động.


3A. BỘ KIT "TÚI THUỐC ĐÓNG SẴN" ⭐ — ĐÃ CÓ ở JS, chuyển sang PG

Ý Owner: mỗi UI cần chỗ riêng để lắp vào; đóng gói chuẩn như túi thuốc gia đình — có UI là khoác vào, khai tối thiểu, quét được data là đủ. Kit đã tồn tại (SUA-RE-README.md: "Quy trình sống trong FILE (git), không sống trong prompt hay trong đầu ai"). Việc của ta = giữ kit, đổi bước ② sang PG.

🔑 ĐIỀU KIỆN NGHIỆM THU — Definition of Done [GAP quan trọng nhất]

Chính là luật nghiệm thu §3 của SUA-RE-README.md, cập nhật cho PG. Đây là câu biến "Cowork nhớ điền form" thành điều kiện nghiệm thu.

UI_DONE = (UI file tồn tại) + (companion .scan.json cạnh UI) + (companion PASS validation)
UI mới/sửa lớn THIẾU companion hợp lệ = UI CHƯA XONG.

Cưỡng chế hai lớp: (a) LUẬT — câu nghiệm thu trên nằm trong README kit (agent đọc START HERE); (b) MÁY DÒ — coverage report (dưới) liệt kê UI thiếu companion / companion chưa import → "quên" thành nhìn thấy được. Luật cấm, dò lộ.

Ba phần của kit (dựng MỘT lần, mọi UI khoác)

Phần Thời JS (đã có) Thời PG
README gốc SUA-RE-README.md — START HERE, 6 bước, luật nghiệm thu §3 GIỮ file; sửa: bước ② "KÊ-UI" → điền companion + chạy cổng; ③④ KHỬ-TRÙNG/KHỚP-SỔ bỏ khỏi việc Cowork (PG+Owner lo); ⑥ → SELECT đếm. Cập nhật luật §3 = Definition of Done trên.
Slot mỗi UI 1 object surface trong ui-contracts.js companion <ui_file>.scan.json cạnh UI — CHỈ quan sát.
Công cụ quét renderUIContract + verify-contracts.js cổng import + view đếm/khớp + report page (§5).

Khoác kit cho một UI (tối giản)

  1. Copy ui-scan.template.json → điền quan sát tối thiểu → lưu ui-preview/<ui_file>.scan.json. 2. Chạy cổng. Xong. Không bảng/DOT mới cho mỗi UI.

KHAI TỐI THIỂU

Bắt buộc: ui_id + mỗi item {raw_label, purpose(≥15)}. Chừng đó ĐỦ để PG đếm. location/type_guess/proposed_concept_key = gợi ý tùy.

UI_SCAN_JSON — TEMPLATE (ui-scan.template.json, chuẩn duy nhất)

{
  "ui_id": "master-list-quy-trinh-v1",
  "ui_name": "Master list quy trình",
  "ui_file": "master-list-quy-trinh-v1.html",
  "scan_reason": "new_ui | major_edit | label_field_change",
  "items": [
    {
      "raw_label": "Người lập",
      "purpose": "Người hoặc DOT đã tạo ra bản ghi/định nghĩa đang xem (created_by), hệ ghi tự động",
      "location": "drawer.header.nguoi_lap",
      "type_guess": "role",
      "proposed_concept_key": "role.nguoi_lap"
    }
  ]
}

Cowork CHỈ điền: raw_label, purpose, location, type_guess, proposed_concept_key. KHÔNG điền: item_key, dedupe_key, concept_id, match_status, scan_id.

Nơi lưu — companion cạnh UI, BÁO CÁO vào KB

  • Companion vận hành: cạnh UI/opt/incomex/docs/mcp-writes/ui-preview/<ui_file>.scan.json. Lịch sử do PG giữ (is_current=false) → không cần thư mục scans/. [CHỐT §11-5]
  • Báo cáo/mốc quyết định vào KB: seed freeze, kết quả G1b, log import, quyết định Owner → lưu KB (thư mục sua-re/). Không copy mọi companion vào KB, nhưng mốc + báo cáo phải vào KB (bộ nhớ dài hạn).

scan_id = hash CANONICAL JSON [GAP 2]

Cổng tính scan_id = hash(canonical_json(companion)): sort keys · trim string · bỏ field volatile (nếu có) · chỉ hash field nội dung thật. KHÔNG hash raw text file (tránh scan giả do khoảng trắng/thứ tự key). Không đổi nội dung → cùng scan_id → import no-op; đổi → scan mới, lật is_current cũ.

Coverage report — nguồn so TỪ FILESYSTEM, scope rõ [GAP 5]

Hai phép rẻ (ls + SELECT), chỉ chạy trong root /opt/incomex/docs/mcp-writes/ui-preview/, loại trừ archive/, backup/, generated/, test* (Claude Code xác nhận dir + pattern — G-I):

  1. File *.html (UI) KHÔNG có companion .scan.jsonchưa khoác kit (quên khai).
  2. Companion chưa import PG current → chưa chạy cổng. v0: coverage là AUDIT/OUTPUT của cổng hoặc pre-flight — CHƯA publish /reports. Chỉ kiểm UI/companion trong root này — không cố phát hiện mọi UI toàn hệ (tránh lời hứa giả).

Artefact kit cần tạo/sửa ở G1 (nhỏ)

SỬA SUA-RE-README.md (bước ②/③④/⑥ + luật §3 = Definition of Done); TẠO ui-scan.template.json. Công cụ = cổng + view + report (§5).


3B. ĐI BỘ VẬN HÀNH — HỎI/ĐÁP (gộp câu GPT + câu tương tự)

Vi-bước Câu hỏi Đáp đơn giản nhất
Sắp vẽ Làm sao biết phải khai? SUA-RE-README.md START HERE + Definition of Done. Không trông trí nhớ.
Phải thuộc 13 khái niệm? Không. Khai mù: thô + đoán.
Điền Khai gì tối thiểu? ui_id + mỗi item {raw_label, purpose≥15}.
KHÔNG điền gì? item_key/dedupe_key/concept_id/match_status/scan_id.
Lưu Companion ở đâu? Cạnh UI. Báo cáo/mốc → KB.
Cổng Ai kích hoạt? 1 DOT quét docroot mọi *.scan.json → validate → import.
scan_id/item_key? scan_id = hash canonical JSON; item_key = hash(ui_id,scan_id,location_or_index,raw_label).
So Cách / hiển số? VIEW suy; matched=chính xác, pending=tạm (không show tổng như chắc 100%).
Owner 3 action? map_existing/create_new/keep_pendingowner_concept_id+decision_note.
Quên? Nguồn UI kỳ vọng? Filesystem, scope ui-preview root + exclude.
Sửa nút Chạy lại? Màu/layout/icon → khỏi; label/field/filter/drawer → quét toàn UI.
Xong chưa? Definition of Done? UI file + companion + validation PASS. Thiếu companion = chưa xong.
Nháp có vector? KHÔNG — chui vùng no-vector qua policy (§7).

Câu tương tự (Fable): 2 UI cùng raw_label nghĩa khác → per-UI dùng WHERE ui_id; cross-UI dùng concept_id(matched) → non-issue. Cowork đoán key trùng → view bắt (ILIKE→review). Catalog lớn lên? → chỉ qua Owner create_new; Cowork KHÔNG ghi catalog. Kit sửa ở đâu? → một chỗ (git).


4. VIEW / SELECT ĐẾM (5–7 câu, trên 13 concept — không pg_trgm)

  1. Đếm khái niệm phân biệt 1 UI (current): count(DISTINCT dedupe_key) WHERE ui_id=:ui AND is_current. 2. Thô→sau khử trùng: count(*) vs count(DISTINCT dedupe_key). 3. Khớp/treo: view suy match_status. 4. Hàng chờ chốt: WHERE match_status IN ('candidate','review') AND is_current + purpose + near_concepts. 5. Dùng ở bao nhiêu nơi: GROUP BY concept_id → count(DISTINCT ui_id). 6. Lịch sử mô tả 1 khái niệm: mọi purpose theo scan_at (gồm bản cũ). 7. Matrix khái niệm×UI: view XUẤT ra, không lưu.

5. REPORT (G2) — bằng khuôn có sẵn + tách matched/pending

SỬA recon Rev 2: thực địa có HAI khuôn: (a) list sống từ collection (view_sql NULL, VD tbl_loaientity_species, tbl_balo_*balo_thuc_the PK stt); (b) report TÍNH TOÁN từ view_sqlv_report_* snapshot (VD tbl_report_pg=PG Census). Mission cần = khuôn (b), y hệt PG Census.

v_report_sua_redot-report-publish/reports/report-sua-re. Report PHẢI tách: matched_count (chính xác) vs pending_count (tạm, theo pending.<hash(raw_label+purpose)>, cần Owner chốt). KHÔNG một tổng như chắc 100%. Không Nuxt, không UI mới, không làm trước khi import xong. (Lưu ý: report page = collection registered → phải có vector policy false, §7.)


6. GIAI ĐOẠN (chuỗi giảm rủi ro — chứng minh INTAKE trước khi dựng bề mặt)

  • G1a — nạp + đếm: freeze seed → nạp 13 concept + 30 usage (scan #0) → SELECT đếm thô. (Chứng minh schema+import+đếm; 30 dòng council soạn → chưa chứng minh B2.)
  • G1b — CỬA THỬ BẮT BUỘC: Cowork xuất UI_SCAN_JSON cho UI THẬT (theo template), đẩy qua cổng. PASS khi: (1) companion đúng template; (2) cổng KHÔNG sửa tay form; (3) mọi purpose≥15; (4) import thành scan mới (is_current đúng); (5) SELECT trả: thô / sau dedupe / matched-review-candidate; (6) ≥1 item được gợi ý review/candidate HOẶC xác nhận matched. Thiếu bất kỳ → FAIL, chưa mở G2. [CHỐT §11-2]
  • G2 — report page: v_report_sua_re/reports/report-sua-re (tách matched/pending).
  • G3 — nếu cần: cổng quyết định chuyên dụng, species_collection_map, balo_thuc_the, list chi tiết.
  • HOÃN tuyệt đối: pg_trgm, Qdrant, fuzzy auto-match, tab UI thật.

7. FORK tạo bảng: Path A (mặc định — [CHỐT §11-4]) / Path B — + NO-VECTOR

Chọn đường theo NGUYÊN TẮC ĐƠN GIẢN: đơn giản KHÔNG phải "cố dùng tool có sẵn bằng mọi giá" — đơn giản là đường ít bước / ít rủi ro / ít patch tùy biến nhất.

  • PATH A (mặc định — CHỈ chọn nếu pre-flight CHỨNG MINH đủ 4 điều): (1) dot-collection-create tạo được 2 bảng/collection ĐÚNG SHAPE (JSONB/FK/unique/CHECK); (2) có rollback rõ (G-B); (3) gắn được collection_registry_vector_policy vector_eligible=false (G-C); (4) KHÔNG cần nhiều patch tùy biến. Đủ 4 → A (table + collection + registry). Lằn ranh cứng: G1 CHỈ tới "2 collection/bảng + seed import + SELECT đếm" — KHÔNG report-publish/list/balo/species-map.
  • PATH B (nếu A phải vá nhiều / không đủ 4 điều): DOT nhỏ tạo bảng PG-thuần, hoãn Directus+species sang G2. (PG-thuần chưa đăng ký collection → KHÔNG bị vector pipeline nhìn thấy → inherently no-vector ở G1.)
  • Không ép A bằng mọi giá: nếu A thành bụi rậm (vá nhiều lớp) → B đơn giản hơn, chọn B.

🔒 NO-VECTOR — vùng cách ly nháp (khóa Owner + GPT)

CÂU CHỐT: Sửa-rẻ / nhập UI v0 là vùng nháp NO-VECTOR. SPE-NVS chỉ là NHÃN quản trị; enforcement BẮT BUỘC là collection_registry_vector_policy với vector_eligible=false + semantic_search_eligible=false cho MỌI collection sua_re_*_nhap. KHÔNG có policy này thì CHƯA được đăng ký collection.

  • Quy tắc: mọi sua_re_*_nhap mặc định no-vector. Chỉ khi Owner chốt thành hợp đồng thông tin / tri thức chính thức mới xét đưa sang vùng vector.
  • Vì sao bắt buộc: data ở đây = concept nháp, candidate/review chưa duyệt, purpose Cowork khai, scan cũ/mới, pending tạm, near_concepts chỉ gợi ý. Lọt embedding/semantic search = rác nghĩa (hỏi hệ sau này kéo ra khái niệm nháp / mô tả lệch / candidate chưa chốt). Đúng thứ D36 sinh ra để cấm.
  • KHÔNG vector (v0): sua_re_khai_niem_nhap, sua_re_ui_khai_niem_nhap, companion .scan.json, seed artifact, candidate/review, scan history, report đếm sửa-rẻ.
  • Có thể xét vector SAU: hợp đồng thông tin đã chốt, tài liệu thiết kế chính thức, định nghĩa đã promote ra vùng chính thức.
  • Theo Path: A (tạo collection ngay) → gắn policy false NGAY sau khi tạo, không chờ. B (PG-only, chưa collection) → chưa cần policy ở G1; khi nào đăng ký thành collection thì PHẢI gắn (cùng câu chốt).
  • Yên tâm (Owner xác nhận): vùng né vector đã có sẵn & proveniu_staging_record/iu_staging_payload đang nằm trong đó (vector_eligible=false), luật D36 verify PASS nhiều lần. Ta chỉ dùng đúng cửa (policy row), không đẻ cơ chế mới. Agent dùng yên tâm.

8. XÂY MỚI TỐI THIỂU vs DÙNG LẠI

Dùng lại tối đa: PG · Directus/report (khuôn (b)) · dot-collection-create · cổng dot-pg-atomic-apply · kit SUA-RE-README.md (giữ, sửa 1 bước) · collection_registry_vector_policy (cửa no-vector sẵn có) · Cowork prompt/template (không parser). Mới tối thiểu: (1) ui-scan.template.json; (2) lớp kiểm intake bọc cổng (có thể không phải DOT mới); (3) view v_report_sua_re; (4) [G3] đường quyết định. Tối thiểu để VẬN HÀNH.


9. PRE-FLIGHT GATES (Claude Code trả lời — KÈM output thật, READ-ONLY; KHÔNG thiết kế lại)

Mỗi gate: PASS/HOLD/FAIL + bằng chứng thật. Đọc seed + infra từ VPS LIVE (Codex "seed missing" vì checkout local stale — seed sống ở path đầu doc; không đi tìm). Claude Code CHỈ soi + báo PASS/HOLD/FAIL, KHÔNG redesign.

  • G-A dot-collection-create: đọc source + --help/--dry-run. Tạo CHÍNH XÁC gì (table? collection? registry? meta? birth? species? permissions?). Kham JSONB? UNIQUE? FK? CHECK(purpose≥15)? CHỌN/HOÃN species? Soi 1 collection đã tạo.
  • G-B rollback: đường LÙI CHUẨN của tool. Không rõ → gate ĐỎ.
  • G-C vector-exclusion: no-vector KHÔNG do loài — do collection_registry_vector_policy (view v_collection_vector_eligibility mặc định COALESCE(...,true) = opt-out). Xác nhận: dot-collection-create để mặc định eligible hay tự set policy? insert exclusion (vector_eligible=false, semantic_search_eligible=false) cho 2 collection chạy được + idempotent + precheck (policy có unique trên collection_registry_id?). SPE-NVS map = nhãn tùy, riêng.
  • G-D BẢNG ĐẶT CHỖ constraint: {concept_key unique, item_key unique, concept_id FK, purpose≥15, enum concept_kind, (nếu lưu) match_status} → DB / import-gate / verify-SELECT. Unique+UPSERT KHÔNG dời verify.
  • G-E seed purpose: ĐO THẬT 43 chuỗi, đếm ký tự sau trim, liệt kê <15.
  • G-F item_key: xác nhận hash(ui_id, scan_id, location_or_index, raw_label) (location trống → index). Tính thử 30 khóa → 30 UNIQUE, 0 va chạm.
  • G-G FK resolution: resolve 27 matched về 13 concept; 3 dòng → null. concept_key nào không khớp?
  • G-H map giá trị seed: status 'chot''active'; concept_kind 6 loại; match_status 3 giá trị.
  • G-I intake gate + kit: (1) dot-pg-atomic-apply NHẬN file JSON companion + validate(purpose≥15) + UPSERT + lật is_current — hay cần lớp/DOT mỏng? Nếu không nhận JSON trực tiếp → agent chuyển JSON→SQL rồi atomic apply được không? (2) cổng glob *.scan.json docroot được không (hay truyền path)? (3) scan_id canonical-JSON + item_key index-fallback cài được không? (4) coverage 2 phép + scope root ui-preview/ + exclude archive/backup/generated/test chạy bằng ls+SELECT — xác nhận dir + pattern THẬT.
  • G-J dòng chảy data [MỚI Rev 6]: usage table giữ current+history một bảng (is_current) có bị luật dòng chảy Đ22–Đ45 (Nguyên tử/Log/Action không trộn) cấm không? Mặc định GIỮ 1 bảng (tiền lệ IU iu_staging_record); CHỈ tách history nếu trích được điều luật cấm cụ thể — nêu rõ số điều. Không tự tách.
  • AUDIT PHỨC TẠP HÓA (ngang hàng audit rủi ro): chỗ nào nặng hơn cần? bỏ cột/guard/bước nào mà KHÔNG mất mission? NGƯỢC LẠI: chỗ nào CẮT quá tay (mất "sửa nhiều lần"/cọc seed-purpose-scan)?
  • AUDIT RỦI RO: Directus track JSONB+FK? SharedDirectusTable render? khuôn dùng primary_key hay ép id? v_report_pg tự đếm thêm 2 bảng → tác dụng phụ? Va chạm tên (collection/table_id/page_url)? Permissions collection mới? Artefact nào CHỈ có trên VPS?
  • Khuyến nghị Path A/B DỨT KHOÁT dựa G-A/G-B/G-C (đủ 4 điều §7 → A; thiếu → B).
  • Đầu ra: verdict từng gate + bảng đặt chỗ (G-D) + "PHỨC TẠP HÓA THỪA"/"CẮT QUÁ TAY" + Path A/B + "Rev 6 PHẢI sửa/bổ sung gì". Upload KB: knowledge/dev/laws-new/kestra/sua-re/nhap-ui/claude-code-infra-eval-2026-07-06.md.

10. v0 TUYỆT ĐỐI KHÔNG LÀM (rào quái vật)

  • KHÔNG parser/OCR/quét DOM. KHÔNG DOT "đi đọc/đếm lại UI" (chính con quái vật).
  • KHÔNG fuzzy auto-match (chỉ exact/alias→matched). KHÔNG pg_trgm/Qdrant.
  • KHÔNG decision-DOT (→G3). KHÔNG report đẹp. KHÔNG species-map/balo (→G2/G3). KHÔNG tab UI thật.
  • KHÔNG 3 DOT custom lớn. KHÔNG rollback DOT riêng nếu tool có đường lùi chuẩn. KHÔNG bảng scan riêng. KHÔNG bảng history riêng (trừ khi luật cấm current+history — G-J). KHÔNG 4 index. KHÔNG species mới.
  • KHÔNG đẻ kit mới (giữ SUA-RE-README.md). KHÔNG thư mục scans/ (companion cạnh-UI + PG đủ).
  • KHÔNG để đồ nháp vào vector (bắt buộc policy false nếu có collection — §7).
  • Cowork v0 khai-mù. KHÔNG rebuild reports/Nuxt từ local stale.

11. QUYẾT ĐỊNH — ĐÃ CHỐT (Owner 2026-07-06, theo đề xuất council)

# Quyết định Chốt
1 Cowork chỉ khai QUAN SÁT THÔ (không tự gán dedupe/match) ✔ YES
2 G1b (Cowork xuất FORM thật) là CỬA BẮT BUỘC trước khi dựng bề mặt ✔ YES
3 match_status SUY trong view ✔ YES (fallback lưu enum nếu tool cản)
4 Path A mặc định (dot-collection-create) — CHỈ nếu đủ 4 điều §7 ✔ YES (sau pre-flight PASS; thiếu → Path B)
5 Companion <ui_file>.scan.json cạnh UI ✔ YES
6 scan_id = hash canonical JSON companion ✔ YES
7 Coverage v0 từ filesystem (ui-preview root + exclude) = audit/output ✔ YES

Khóa vận hành (GPT, Owner chuyển tiếp): Definition of Done (UI thiếu companion = chưa xong) · scan_id canonical JSON · item_key location-or-index · pending dedupe = hash(raw_label+purpose) · coverage scope+exclude, chưa /reports · companion cạnh-UI + báo cáo vào KB · Owner decision 3 action · NO-VECTOR bằng collection_registry_vector_policy vector_eligible=false (SPE-NVS = nhãn), KHÔNG có policy thì chưa đăng ký collection · KHÔNG tách history trừ khi luật cấm (G-J) · Path A chỉ chọn nếu ít-patch.

Đã chốt trước: id PK+business key · không loài mới · không Nuxt G1 · không workflow cho 2 bảng · DB directus · giữ match_policy · giữ scan_id/is_current · purpose/dedupe bắt buộc · near_concepts jsonb · decision_note · giữ kit.


12. RỦI RO + ROLLBACK

  • Cowork quên FORM → Definition of Done (luật) + coverage (dò). - 2 SSOT (JS+PG): migrate xong JS đóng băng. - Auto-match mạnh: exact/alias/ILIKE; fuzzy chỉ gợi ý. - dedupe pending sập: hash(raw_label+purpose), overcount an toàn hơn undercount; report tách. - Draft lọt vector = rác nghĩa: enforce collection_registry_vector_policy vector_eligible=false (§7), KHÔNG chỉ nhãn SPE-NVS. - Draft hiểu nhầm chính thức: _nhap, status=draft. - Trùng loài/collection/report: idempotent precheck+readback. - Rollback: đường lùi CHUẨN của tool (G-B).

13. CHANGELOG + COUNCIL TRACE

Rev 5 → Rev 6 (rà soát TƯƠNG THÍCH hệ thống + GPT simplify-locks + đồng bộ nhãn):

  • [Đồng bộ nhãn] toàn file thống nhất Rev 6 / HOLD_PRE_FLIGHT (title, metadata, output §9); bỏ [Rev 5] rải rác trong thân — lịch sử version chỉ giữ ở changelog.
  • [NO-VECTOR — câu chốt Owner+GPT] §7 ghi rõ: sua_re_*_nhap là vùng nháp no-vector; enforcement = collection_registry_vector_policy vector_eligible=false + semantic_search_eligible=false; KHÔNG có policy thì chưa đăng ký collection; SPE-NVS = nhãn. + danh sách no-vector / có-thể-vector-sau. Vùng né vector đã proven (iu_staging_*, D36 PASS) — agent dùng yên tâm.
  • [Path A conditional] A chỉ chọn nếu pre-flight chứng minh đủ 4 điều (shape/rollback/vector-policy/ít-patch); vá nhiều → Path B. "Đơn giản = ít bước/rủi ro/patch nhất, không cố dùng tool bằng mọi giá."
  • [Không tách history] mặc định 1 bảng usage (scan_id+is_current); chỉ tách nếu Claude Code trích luật cấm cụ thể → thêm gate G-J.
  • [Coverage] v0 = audit/output, chưa publish /reports.
  • [Claude Code] nhấn read-only + KHÔNG redesign; G-I thêm nhánh JSON→SQL fallback.
  • [BẮT BUỘC từ compat-review] Sửa cơ chế no-vector §7: (đã áp) SPE-NVS = nhãn, no-vector thật = policy row. Không xung đột kiến trúc: meta_catalog KHÁC TẦNG (kho vs nhãn-UI); tên sua_re*/report-sua-re sạch (0 va chạm, query thật). concept_kind ≠ species.

Rev 4 → Rev 5 (khóa 7 lỗ vận hành GPT — không sửa kiến trúc): thêm Definition of Done; scan_id canonical JSON; item_key location-or-index; pending dedupe hash(raw_label+purpose); coverage scope+exclude; companion cạnh-UI + báo cáo KB; Owner 3 action; §11 chốt; gate G-I. Rev 3→4 (tóm): §3A Bộ Kit (kit ĐÃ CÓ ở JS), §3B walk-through, decision_note, PASS G1b, tách matched/pending, coverage-filesystem. Rev 2→3 (tóm): PK id bigserial+business key; loaiconcept_kind; near_concepts jsonb; match_status suy view; recon reports (2 khuôn); bỏ 3-DOT/rollback-DOT/scan-invariant/4-index; thêm §3 vòng vận hành + G1b. (Rev cũ ở lịch sử revision.)

GIỮ (cọc sống còn): scan_id/scan_at/is_current · purpose≥15 gate cứng · dedupe_key=duplicate_group · seed freeze artifact có lý lịch+hash · match_policy · 100% DOT · kit sống trong file · mọi CHỐT vào KB · đồ nháp no-vector.

Council trace: Owner = bảo vệ đơn giản, "đừng đẻ quái vật", bắt nhìn vận hành từng bước + rà tương thích + mọi chốt vào KB; xác nhận vùng né vector proven. GPT = giữ scan/seed/purpose + 7+7 GAP vận hành (Definition of Done) + simplify-locks (Path A conditional, no-vector policy, không tách history). Fable = tool-verify (seed sống bác "seed missing"; PG Census; SUA-RE-README.md phát hiện kit đã có; rà tương thích: no-vector = policy chứ không phải loài, meta_catalog khác tầng, tên sạch). Codex = 3 blocker (PK/seed/DOT) từ recon.


GUARD ĐƠN GIẢN (đọc cuối, nhớ đầu)

v0 = 2 bảng + kit đóng sẵn (README + companion) + cổng ghi sẵn có + vài SELECT/1 view + đúc report bằng khuôn cũ. HẾT. Vượt ra → DỪNG, hỏi Owner. Phức tạp = thất bại. Không có DOT nào đi đọc lại UI — Cowork điền phiếu. Kit đã có sẵn — chỉ khoác vào. UI thiếu companion hợp lệ = UI chưa xong. Đồ nháp phải chui vùng no-vector bằng policy thật.