Đề bài — PG read PG (v1.1)
ĐỀ BÀI — PG read PG
Tên hiển thị: PG read PG · Path kỹ thuật:
knowledge/dev/laws-new/pg-read-pg/(không dấu cách, không dấu — Agent/script khỏi lỗi) File này:knowledge/dev/laws-new/pg-read-pg/de-bai-pg-read-pg.mdPhiên bản: v1.1 · Ngày: 2026-06-24 Một câu mục tiêu: Để PG tự đọc PG, thống kê phần lõi kết cấu trước (Nhóm A — catalog authoritative), rồi phụ trợ Nhóm B (vai trò/nhãn, người khai) và Nhóm C (mô tả, để sau) — cho Agent và người nhìn một chỗ là biết hệ thống có gì, hết mù. Chỉ ĐỌC, không xây.
🔒 LUẬT CHẶN CUỐI (đọc đầu tiên)
Nếu một yêu cầu không thể trả lời bằng
SELECTread-only → (view) → report markdown + hiển thị qua renderer Directus/Nuxt CÓ SẴN, thì nó KHÔNG thuộc PG read PG v1.0. Câu này chặn PIDX / readiness / kho tạm / rollback / UI-mới / matview quay lại. Gặp thứ vượt ranh giới này → mở đề bài riêng, không nhét vào đây.
0. Tại sao có đề bài này (đọc kỹ trước khi làm)
Việc "PG đọc PG để kiểm đếm" đã làm tại knowledge/dev/laws-new/workflow-manage/ và thất bại nhiều tháng, dù mọi AI đọc thiết kế đều OK. Bản chất việc này chỉ là vài câu SELECT — đã chứng minh: chạy ra kiểm đếm trong dưới 2 giây, 3 câu read-only. Nó chưa bao giờ là vấn đề kỹ thuật. Nó thất bại vì quy trình quanh việc phình thành quái vật.
Năm cơ chế đã giết các lần trước (cấm tái diễn):
- Phình mục tiêu trong im lặng. "Đếm xem PG có gì" (đọc, không trạng thái) bị nâng thành "Procedure Index" lưu ingredient + tính readiness + drift. Đó là xây app.
- Đắp áo giáp cấp-promotion lên thao tác đọc. Một
SELECTkhông thể làm hỏng gì, vẫn bị quấn Codex review nhiều vòng, BLOCK/patch, "kho tạm", fingerprint, rollback, Owner-auth — nghi thức của thao tác GHI. - Hội đồng AI tự đẻ phức tạp. Reviewer được thưởng khi tìm lỗi; không ai có vai "việc này tầm thường, xóa 90%". Bánh cóc chỉ tiến về phía nhiều caveat → mài giũa quái vật thay vì giết.
- PASS trên giấy ≠ đã chạy. Sinh ra v0.1, v0.2, runbook… zero output thật. Sản phẩm thành tài liệu nói về việc, không phải việc.
- Ontology LEGO (nguyên tử→building, loài) rò rỉ từ phân loại sang thi công. Để test một câu SELECT cũng phải giải "tầng LEGO nào, kho tạm ra sao". Agent không chia sẻ ontology riêng → hiểu sai/đứng hình.
Gốc rễ một câu: Việc thì tầm thường; quy trình quanh việc mới là quái vật. Đừng coi một thao tác đọc read-only như một dự án phần mềm.
1. Mười bốn nguyên tắc bất biến (khóa chống quái vật)
Vi phạm bất kỳ điều nào = FAIL, kể cả khi "chạy được".
- ĐỌC ≠ GHI. Một
SELECTread-only không bao giờ là "build". Không vào pipeline review→patch→kho-tạm→Owner-auth. Pipeline nặng chỉ cho thao tác GHI production. - VIEW, không phải TABLE. Kết quả đếm xuất ra dưới dạng view / câu đọc, KHÔNG tạo bảng lưu sẵn số. View tự tính lại từ nguồn mỗi lần đọc → không có gì phải đồng bộ. (Directus đọc view dễ như đọc table.)
- Lưu CÂU HỎI, không lưu CÂU TRẢ LỜI. Được phép lưu: snapshot markdown append-only có đóng dấu giờ vào KB. Cấm: bảng "số hiện tại = X" đè lên rồi Nuxt tin là chân lý.
- Phép thử vàng: "Xóa nó đi, chạy lại nguồn có dựng lại y hệt không?" Có → an toàn. Không → DỪNG, quái vật.
- Native = không thêm gì để phải NUÔI. Đọc thẳng catalog/registry. Không service mới, không engine, không matview/cron (v1.0), không bảng-phải-đồng-bộ, không agent tự quyết.
- Đếm THẬT từ catalog, KHÔNG dựa khai sinh. Catalog authoritative cho sự thật vật lý; nếu quyền đọc không đủ thì ghi
READ_BLOCKED, không suy diễn (không tự nhận "bất khả sai"). Khai sinh/registry chỉ tô màu; thiếu thì lòi mồ côi. - Ba tầng tách bạch (xem §2). object_kind (Tầng 1) trung tính theo PG — KHÔNG gán nghĩa vai trò (DOT/gate/checker) ở đây.
- Chỉ chia theo cột PG đã có VÀ đo là đầy. Cột rỗng nhiều (vd
operationtrống 84%) → cảnh báo "cần điền", không làm trục. - Phân loại = thêm CHIỀU (cột), không thêm THÙNG (bảng). Cấp/quan hệ = tính ra (recursive CTE), không lưu cấp, không tách bảng theo cấp.
- A/B/C là nhãn ĐỘ TIN trên từng mẩu thông tin, không phải ngăn chứa object. A dùng thẳng; B tìm-ra-ngay-nhưng-phải-kiểm; C chỉ gợi ý. Số đếm chỉ đến từ A.
- Lằn ranh A/B kiểm bằng máy: "PG có cần ai khai để biết cái này không?" Không → A. Có → B. Đừng để chữ "system" lừa xếp nhầm vào A.
- Bảng hiển thị cái PG THẤY (A) trước. Cái chưa có nhãn vẫn hiện (mồ côi lòi ra), không biến mất.
- Hiển thị = lắp view vào renderer CÓ SẴN (Đ28: Nuxt chỉ render từ template đã đăng ký), KHÔNG viết component/trang/khuôn Nuxt mới. Muốn khuôn mới phải đúc khuôn rồi đúc sản phẩm — KHÔNG code trực tiếp trên Nuxt. Nuxt chưa hiện = agent CHƯA TÌM RA khuôn cũ, KHÔNG phải hệ thống thiếu.
- Summary-first + drill, KHÔNG đổ phẳng (catalog >3.000 object; đường đọc giới hạn 500 dòng/lệnh).
Phạm vi KHÔNG (non-goals): PIDX · readiness · ingredient-map · "đủ/thiếu/sẵn sàng" · kho tạm · LEGO staging · fingerprint · rollback · orchestration mới · matview/cron (→ v1.1) · ghi/dán nhãn (→ pha B sau) · component/khuôn Nuxt mới · phụ thuộc Qdrant/vector. CHỈ: đọc → đếm → view → report KB → hiển thị qua khuôn có sẵn.
2. Mô hình 3 tầng + 3 nhóm độ tin
Hai phép đếm khác nhau, không lẫn: Tầng KẾT CẤU (tòa nhà có phòng/cửa/cột gì — ~14.000, lõi đề bài) vs Tầng NỘI DUNG (mỗi phòng chứa bao nhiêu đồ — birth_registry 1,2 triệu dòng).
| Tầng | Là gì | Đếm thế nào | Sót? |
|---|---|---|---|
| 1 — Kết cấu | object PG tự khai | đọc thẳng catalog | Không |
| 2 — Nội dung | số dòng mỗi bảng | ước lượng (mọi bảng) + exact (registry chỉ định) | Không |
| 3 — Vai trò/Nhãn | "function này là DOT"… | đọc registry + đối chiếu A − B | Có → nhưng lòi mồ côi |
Ba nhóm độ tin: A = PG tự sinh (dùng thẳng) · B = người/hệ khác khai (kiểm rồi dùng) · C = mô tả tự do (chỉ gợi ý, chưa xây vector).
3. CÁC VIEW/CÂU ĐỌC PHẢI XUẤT (deliverables)
Mọi câu đọc: read-only, xuất dạng view (không table), có refreshed_at (giờ đọc). Hiển thị = đăng ký view vào Directus → template Nuxt có sẵn.
3.1. Tầng 1 — Nhóm A (kết cấu) — LÀM TRƯỚC
- (A0) Lớp chỗ-mù/sức-khỏe:
refreshed_at; mỗi nguồnEXISTS/READ_BLOCKED/UNKNOWN_SOURCE. Trigger đọc quapg_catalog.pg_trigger, KHÔNGinformation_schema.triggers(cái sau lọc quyền → 0 giả; đúng = 410). - (A1) Census 12 loại (UNION ALL → 1 bảng): schema · table · view · matview · sequence · function · procedure · trigger · constraint · index · foreign_table · column.
- (A2) 5 panel chia nhỏ (trục trung tính theo PG): table→họ tên; field→kiểu dữ liệu (gọn 7 mục); function→kiểu trả về (KHÔNG gọi "checker"); trigger→thời điểm×sự kiện; constraint→loại (nổi FK = quan hệ bảng↔bảng).
- (A3) Coverage/mồ côi:
bảng vật lý (A)−registry biết (B)= mồ côi, liệt kê tên (vd 380 − ~164 Directus = ~188).
3.2. Tầng 2 — Nội dung (số dòng)
- (2A) Ước lượng cho MỌI bảng:
pg_class.reltuples/pg_stat_all_tables— nhanh, không quét. (reltuples = -1= chưa ANALYZE = nghi vỏ rỗng.) - (2B) Exact
count(*)CHỈ cho registry nhỏ/được chỉ định: dot_tools, workflows, directus_fields, apr_action_types, event_type_registry… - Exact toàn bộ: chỉ chạy on-demand, có timeout, không mặc định.
3.3. Tầng 3 — Nhóm B (vai trò) — PHỤ TRỢ, làm sau Tầng 1, CHỈ ĐỌC
- (B-WF) View Workflow — mặt trận 2 chiều:
STT · Tên · Nguồn (Hệ thống/Kestra) · Chuyên môn · Nhiệm vụ · Trigger · Active · Note— đọc các cột PG ĐÃ CÓ. Filter mọi cột, max 50 dòng, view theo cây, drawer. Đánh dấu thị giác cột A vs B. Hiện cả ứng viên chưa có nhãn. Kèm phép trừ lòi mồ côi:workflowskhai 2 vs họwf_/workflow_+ flow Kestra ~30. - (B-DOT) View DOT: đọc
dot_tools(309), chia theodomain(đã đầy). Cảnh báo cột rỗng: classification trống 199, operation trống 259. Phép trừ: 654 function − 309 DOT = 345 ứng viên chưa phong. - Nhãn = future B (KHÔNG làm trong v1.0): v1.0 chỉ HIỂN THỊ cột nhãn nếu PG đã có. KHÔNG tạo ô nhãn mới · KHÔNG ghi nhãn · KHÔNG dán nhãn · KHÔNG thiết kế workflow gắn nhãn. Cơ chế "một ô nhãn, nhiều cửa dán, người gật" để pha sau (vì dán nhãn là WRITE).
3.4. Nhóm C — chỉ NHẬN DIỆN (chưa xây)
- Cột mô tả/note/comment → ghi nhận "vùng C cho vector sau". Không cắm Qdrant/embedding ở pha này.
4. MẪU CHUẨN MỘT CÂU ĐỌC (query deck — lưu câu hỏi, không lưu hệ thống)
Mỗi câu đọc lưu thành một mục trong deck, gồm:
question_id(vdQ-A1-census)- Câu hỏi tiếng Việt
- SQL read-only
- Nguồn (catalog/registry nào)
- Cột output mong đợi
- Max row limit
- Cách hiểu kết quả
- Cảnh báo (nếu có, vd "trigger phải đọc pg_catalog")
→ Đây chính là "lưu câu hỏi". Deck là thư viện câu đọc, không phải app.
5. TIÊU CHÍ PASS / FAIL (thay review-vòng)
PASS: chạy ra bảng số thật trên production (evidence = kết quả query thật) · không tạo object ghi nào (không cả matview ở v1.0) · xuất dạng view · có report KB append-only đóng dấu giờ · phân loại chỉ từ cột PG có thật (cột rỗng = cảnh báo) · trigger đếm qua pg_catalog · hiển thị qua renderer có sẵn. FAIL (bất kỳ): tạo bảng/registry/schema/DOT/luật/matview/cron mới · lưu kết quả phải-đồng-bộ (không qua phép thử §1.4) · gán nghĩa vai trò vào Tầng 1 · bảng giấu cái chưa có nhãn · ghi/dán nhãn · viết UI/khuôn Nuxt mới · đổ phẳng >500 dòng · sinh khái niệm/ontology Agent không đọc được từ PG.
6. READ CARDS (mỗi card độc lập, đọc-thuần, ra output thật — KHÔNG phải milestone dự án)
Mỗi card tự đứng một mình, không phụ thuộc trạng thái lưu của card khác. Xong card nào ra report KB card đó.
- Read Card 01 — Catalog Census: 1 lệnh UNION ALL → 12 loại + số → report KB. (Đã chứng minh chạy được.)
- Read Card 02 — Catalog Breakdown: 5 panel A2 + lớp A0 (read-blocked).
- Read Card 03 — Registry Coverage: A3 mồ côi (phép trừ A − registry).
- Read Card 04 — DOT Detail: view B-DOT (chia domain, phép trừ 654−309).
- Read Card 05 — Workflow Detail: view B-WF (mặt trận 2 chiều, đọc cột có sẵn, phép trừ mồ côi).
- Tương lai: B đầy hơn → thêm card thống kê mới (không sửa lõi A). Query chậm thật → mở v1.1 acceleration (matview/cron) riêng.
Làm Card 01 cho chạy ra số thật TRƯỚC — đừng để có đủ 5 card trên giấy rồi lại "PASS trên giấy" như lần trước.
7. BASELINE SỐ THẬT — mốc neo để verify
Provenance: DB=directus · role=read-only (MCP query_pg) · giờ đọc=2026-06-24 · transaction=READ ONLY · statement_timeout=5s · hard LIMIT=500 · (số phụ thuộc quyền/role; đọc lại có thể khác sau khi hệ thay đổi).
Census 12 loại (A1): schema 2 · table 380 · view 699 · matview 1 · sequence 146 · function 654 · procedure 1 · trigger 410 (qua pg_catalog; information_schema trả 0 giả — giữ nổi bật) · constraint 974 · index 1.357 · foreign_table 1 · column ~9.420. function theo kiểu trả về: scalar 388 · trigger-fn 127 · trả-bảng 62 · boolean 54 · void 15. trigger theo thời điểm: AFTER INSERT 274 · BEFORE INSERT 106 · BEFORE UPDATE 22 · BEFORE DELETE 4 · AFTER UPDATE 3 · AFTER DELETE 1. constraint theo loại: PK 336 · CHECK 332 · FK 119 · UNIQUE 74. field theo kiểu (gọn): chuỗi ~5.137 · boolean 1.189 · số nguyên ~1.694 · thời gian ~640 · jsonb 239 · uuid 169 · numeric 151 · array 48. table theo họ: iu 31 · directus 27 · block 25 · wf 24 · os 24 · qt001 20 · tac 14 · dot 11 · governance 10 · kg 8 · birth 6 · … (nhiều bảng reltuples=-1 = nghi vỏ rỗng). Coverage: 380 − ~164 Directus = ~188 mồ côi; table_registry phủ 21. Registry (Tầng 2B): dot_tools 309 · workflows 2 · directus_fields 1.482 · event_type_registry 52 · apr_action_types 14 · birth_registry 1.214.302. DOT: domain ~41 nhóm; classification trống 199; operation trống 259; → 345 function ứng viên chưa phong DOT.
8. RÀNG BUỘC LUẬT
NT13 PG-FIRST (thuần PG, không Qdrant) · §0-AU cấm hardcode · HÀNH ĐỘNG PHÁ HỦY (không agent tự xóa/stop/modify prod — đề bài read-only nên không phát sinh) · ĐỌC≠GHI (§1.1) · Đ28 Display (Nuxt chỉ render từ template đã đăng ký; cấm code trực tiếp Nuxt) · MERGE≠DONE/§0-AF (evidence = query thật trên production) · Đ41 git SSOT (commit sau khi đặt file/report vào repo).
Kim chỉ nam: Đọc cái PG THẤY trước (A, authoritative, thiếu quyền thì READ_BLOCKED). Tô màu bằng cái người KHAI sau (B, thiếu thì lòi mồ côi). Gợi ý bằng mô tả nếu có (C, chưa xây). Xuất VIEW không xuất bảng. Lưu câu hỏi không lưu câu trả lời. Lắp vào khuôn có sẵn, không thêm gì để phải nuôi.