Audit #004 — 2026-08-20
Chấm trên main @ d74e646 + production thật, theo Audit Standard v0.2 (255 chỉ báo, PASS/KHÔNG PASS nhị phân).
Trọng tâm lần này theo yêu cầu chủ dự án: soi kỹ CODE và NỘI DUNG (AS-03 → AS-06, AS-10). Đổi lại, nhiều chỉ báo về docs/product/UX chỉ được chấm lại ở mức có bằng chứng sẵn — chúng rơi vào mã CM, và đó là lý do điểm tổng thấp hơn Audit #003 dù không có chức năng nào vừa hỏng thêm. Đọc §2 trước khi so hai con số.
1. Điểm
| Điểm hệ | 145/255 = 56.9% |
| Mức trưởng thành | Đang dựng |
| 🔴 KHÔNG PASS | 10/30 |
| 🚸 Pilot Gate | 11/18 — NO-GO |
| Bộ | Điểm | |
|---|---|---|
| AS-01 — Tài liệu & Đóng vết | 18/25 = 72% | ██████████████░░░░░░ |
| AS-02 — Yêu cầu & Sản phẩm | 12/25 = 48% | ██████████░░░░░░░░░░ |
| AS-03 — Kiến trúc & Hợp đồng API | 15/25 = 60% | ████████████░░░░░░░░ |
| AS-04 — Dữ liệu & Migration | 15/30 = 50% | ██████████░░░░░░░░░░ |
| AS-05 — Trí tuệ học tập & Thuật toán | 21/25 = 84% | █████████████████░░░ |
| AS-06 — Nội dung & Tri thức | 6/25 = 24% | █████░░░░░░░░░░░░░░░ |
| AS-07 — Bảo mật, Riêng tư & Tuân thủ | 17/25 = 68% | ██████████████░░░░░░ |
| AS-08 — Tin cậy & Vận hành | 21/25 = 84% | █████████████████░░░ |
| AS-09 — Trải nghiệm & Design System | 5/25 = 20% | ████░░░░░░░░░░░░░░░░ |
| AS-10 — AI Governance & Chi phí | 15/25 = 60% | ████████████░░░░░░░░ |
2. Tách KHÔNG PASS theo mã lý do — đọc trước khi so với Audit #003
| Mã | Nghĩa | Số chỉ báo |
|---|---|---|
| HH | Đã kiểm được và ĐANG HỎNG — có phản ví dụ cụ thể | 27 |
| CM | Có tồn tại nhưng lần này chưa đủ bằng chứng để kết luận | 66 |
| CX | Phần hệ thống liên quan chưa xây | 17 |
%HH trong tổng KHÔNG PASS = 27/110 = 25% — đây là con số duy nhất đọc ra "hệ đang hỏng".
So sánh thô với Audit #003 (172/255 = 67,5%) sẽ đọc sai. Ba điều cần biết:
- Lần này 66 chỉ báo mang mã CM — phần lớn thuộc AS-02 (product) và AS-09 (UX), là hai bộ mà lần audit này cố ý không đi rà lại vì yêu cầu là soi code + nội dung. L3 của chuẩn buộc "không bằng chứng = KHÔNG PASS", nên chúng bị trừ điểm dù chưa chắc đã hỏng.
- Ngược lại, 27 chỉ báo HH là phát hiện mới thật, phần lớn nằm ở AS-06 (nội dung) — chỗ mà ba lần audit trước chấm rất mỏng. Đây là giá trị thật của lần chấm này.
- Hệ đã lớn hơn nhiều so với 2026-08-15: 56 migration (39), 1.600 skill node, 11.336 item, 8 model chạy thật cho 12/12 learner. Mẫu số chỉ báo không đổi nhưng bề mặt cần chứng minh thì tăng.
3. 🔴 chặn phát hành đang KHÔNG PASS
| Chỉ báo | Mã | Vì sao |
|---|---|---|
| AS-04.5.5 | CX | docs/ops/backup-restore-drill.md tồn tại nhưng lần audit này chưa xác nhận có ngày diễn tập thật ≤ chu kỳ |
| AS-04.6.1 | HH | d1_migrations remote có 57 dòng / đĩa 56 file; dòng mồ côi 0046_context_event_temporal.sql (đã đổi tên thành 0052 ở commit d4d582c) KHÔNG có trong migration-reconciliation.md — bản đối soát đang ghi tình trạng cũ (41 dòng/39 file) |
| AS-04.6.3 | CM | schema-diff production ↔ dryrun gần nhất là 2026-08-15, chưa chạy lại sau 17 migration mới |
| AS-06.3.1 | HH | 0 item ở trạng thái candidate, 0 dòng item_versions — mọi nội dung vào thẳng published, không qua candidate version |
| AS-06.4.2 | CX | chưa có đề thật (xem 06.4.1) |
| AS-06.4.3 | CX | chưa có đề thật |
| AS-07.1.1 | CM | 189 route; middleware đăng ký theo vòng lặp path nên đếm thô không kết luận được; chưa có artifact liệt kê route public có chủ đích |
| AS-07.2.1 | CM | chưa rà từng endpoint chạm bảng có learner_id trong lần này |
| AS-09.3.1 | CM | chưa đo contrast bằng axe/lighthouse trong lần này |
| AS-10.4.1 | HH | không có cổng đánh giá trước publish: 11.336/11.336 item published có quality_score NULL, evaluator_count<2 (xem AS-06.2/06.3) |
4. 🚸 Pilot Gate — NO-GO
11/18 PASS. Các dòng còn đỏ:
| Chỉ báo | Mã | Việc phải làm để mở được |
|---|---|---|
| AS-03.5.3 | CM | Gọi gh api .../branches/main/protection, hoặc đi nhánh (b) — nhưng nhánh (b) đòi AS-04.6.1 sạch |
| AS-04.5.5 | CX | Diễn tập backup/restore D1 một lần và ghi số bảng/số dòng sau restore |
| AS-04.6.1 | HH | Chạy lại đối soát d1_migrations ↔ đĩa, ghi dòng mồ côi 0046_context_event_temporal.sql vào migration-reconciliation.md |
| AS-04.6.3 | CM | Chạy lại schema-diff production ↔ migrate:dryrun (bản gần nhất là 2026-08-15, đã 17 migration trước) |
| AS-07.1.1 | CM | Sinh artifact liệt kê mọi route + middleware bảo vệ nó, xác nhận từng route public là public có chủ đích (nên làm thành cổng CI để không trôi lại) |
| AS-07.2.1 | CM | Rà từng endpoint chạm bảng có learner_id, xác nhận đi qua canAccessLearner/requireLearnerAccess |
| AS-10.4.1 | HH | Dựng cổng đánh giá trước publish cho item (hiện 11.336/11.336 item vào thẳng published không có điểm chất lượng) |
5. Phát hiện HH — thứ đang hỏng thật
Xếp theo mức chạm tới learner thật, không theo thứ tự bộ.
5.1 🥇 229 Unit đang hiện cho learner là NGÕ CỤT (AS-06.1.4)
Đo trên production, đã loại các Package tạm ẩn (SH/DS/HH/VOC/GR/RD/WR):
| Môn | Unit đang hiện | 0 câu hỏi | Dưới 10 câu |
|---|---|---|---|
| Hoá học | 275 | 95 | 261 |
| Sinh học | 78 | 64 | 64 |
| Tin học | 216 | 36 | 216 |
| Vật lí | 279 | 33 | 199 |
| Ngữ văn | 215 | 1 | 1 |
| SAT / IELTS / AP | 54 | 0 | 53 |
| Toán · Tiếng Anh · GenAI | 223 | 0 | 0 |
Đây đúng lớp lỗi mà SRC-402 đã sửa cho môn Ngữ văn: learner bấm vào Unit thì API trả "chưa có câu hỏi để luyện". Cây curriculum của bốn môn Lý/Hoá/Sinh/Tin vừa được dựng (Pearl) và đã bày ra cho learner, nhưng kho câu hỏi chưa theo kịp. Toán, Tiếng Anh, GenAI, Ngữ văn thì sạch.
5.2 🥈 Kho item không có bất kỳ dấu vết chất lượng nào (AS-06.2.1/2.2/2.3, AS-06.3.1/3.3/3.4, AS-10.4.1/4.2)
SELECT trên production, 11.336 item published:
| Cột | Số dòng trống |
|---|---|
quality_json | 11.336 / 11.336 |
quality_score | 11.336 / 11.336 |
evaluator_count >= 2 | 0 item đạt |
published_by | 11.336 / 11.336 |
review_status = 'unreviewed' | 11.336 / 11.336 |
items ở trạng thái candidate | 0 |
item_versions | 0 dòng |
Schema đã có đủ chỗ cho vòng đời candidate → published (SDD-013), nhưng chưa có gì đi qua nó: mọi item được nạp thẳng vào published. Hệ quả theo đúng chữ của chuẩn: AS-06.3.1 (🔴 "nội dung production không sửa trực tiếp") và AS-10.4.1 (🔴 "nội dung không publish thẳng") đều KHÔNG PASS, và không truy được ai/cái gì đã publish 11 nghìn câu hỏi đang chạy cho trẻ em.
5.3 126 lab đã soạn xong nhưng learner không thấy (AS-06.1.4 phụ)
| Môn | Lab live | unit = NULL (không gắn vào Unit nào) |
|---|---|---|
| Tiếng Anh | 113 | 88 |
| Ngữ văn | 51 | 33 |
| Hoá · Sinh · Lý | 30 | 5 |
| Toán | 125 | 0 |
Dashboard và La bàn tra lab theo labs.unit (progress/routes.ts:55), nên lab có unit = NULL tồn tại trong DB mà không nút nào mở được. Toán sạch tuyệt đối (125/125 gắn đủ) — chứng minh đây là nợ gắn kết, không phải giới hạn kỹ thuật.
5.4 838 node thiếu ba câu "vì sao đáng học" và can_do (AS-06 phụ, chạm SDD-021 §5)
| Môn | Node đang hiện | Thiếu why_pain | Thiếu can_do |
|---|---|---|---|
| Tin học | 216 | 216 | 216 |
| Vật lí | 279 | 215 | 215 |
| Hoá học | 275 | 213 | 213 |
| Ngữ văn | 229 | 84 | 84 |
| SAT/AP/IELTS/GenAI | 73 | 73 | 73 |
| Sinh học | 80 | 16 | 16 |
| Toán | 195 | 1 | 0 |
| Tiếng Anh | 64 | 0 | 0 |
Thiếu các trường này thì popover "vì sao đáng học", tính năng hé cửa (SDD-021 §5) và câu "đang chặn N bài sau" đều câm — đúng lỗ hổng SRC-401 đã đóng cho Toán/Văn/Anh, nay lộ ra ở các môn mới.
5.5 Prerequisite graph chỉ có ở 2/11 môn
unit_prereqs: Toán 225 cạnh, Ngữ văn 145 cạnh, 9 môn còn lại 0 cạnh — kể cả Tiếng Anh (SRC-401 từng soạn 128 cạnh cho cây cũ; cây mới dựng lại ở SRC-408 và bảng hiện không còn cạnh nào cho english).
5.6 Dòng migration mồ côi trên production (AS-04.6.1 🔴, AS-04.6.2, AS-04.6.5)
d1_migrations remote có 57 dòng, đĩa có 56 file. Dòng mồ côi: 0046_context_event_temporal.sql — file này đã đổi tên thành 0052_context_event_temporal.sql (commit d4d582c, gỡ trùng số 0046). docs/ops/migration-reconciliation.md vẫn đang ghi tình trạng ngày 2026-08-15 (41 dòng / 39 file, hai dòng mồ côi khác đã được dọn) nên lệch hiện tại chưa được khai báo ở đâu.
5.7 Song ngữ hụt ở 4 môn mới (AS-04.4.5, AS-06.1.5)
subjects thiếu name_en: sat, ap, genai, ielts — cả bốn cái tên vốn đã là tiếng Anh. strands thiếu name_en: đúng 20 strand của chính bốn môn đó. skill_nodes thì sạch (0/1.600 thiếu title_en).
5.8 Ranh giới module đã thủng nhưng bảng ngoại lệ còn trống (AS-03.1.2)
10 cạnh import chéo trực tiếp giữa hai module, trong khi bảng "Ngoại lệ tường minh" của chuẩn ghi "hiện trống — thêm dòng khi có cạnh mới cố ý, không âm thầm chấp nhận":
| Từ | Tới |
|---|---|
coral/routes.ts | content/quality, content/lifecycle, content/review-queue |
learning/routes.ts | knowledge/mastery, retention/service, content/lifecycle, models/service |
progress/routes.ts | knowledge/mastery |
admin/observability.ts | models/service, models/contextEvents |
5.9 Các phát hiện HH nhỏ hơn
| Chỉ báo | Phát hiện |
|---|---|
| AS-01.1.4 | SRC-206 bị dùng cho hai chỉ đạo khác nhau (intake.md dòng 328 và 331) |
| AS-01.1.3 | 257/411 SRC id không xuất hiện ở bất kỳ PRD/SDD/QG nào — sổ tiếp nhận đang chạy nhanh hơn việc canonical hoá |
| AS-01.1.1/1.5 | scripts/b21-plan.md là ghi chép kỹ thuật nằm ngoài docs/ |
| AS-02.4.2 | Cột Parents của admin (SRC-404) đang chạy production nhưng chưa có REQ |
| AS-02.5.2 | 6 hit cụm rỗng nghĩa trong open-questions/index.md |
| AS-03.1.3 | apps/mentors/src/showcase.ts gọi fetch( ngoài src/api.ts |
| AS-03.4.2 | 10 file ngoài src/api.ts chứa literal nemo12.com, chưa có danh sách miễn trừ |
| AS-05.1.4 | reference/models.md §1 liệt kê 7 model, thiếu Recommendation Model đang chạy thật |
| AS-05.3.1 | Constraint Engine và Readiness Engine chưa có test hành vi riêng (6/8 engine có) |
| AS-05.5.4 | 1/305 dòng learner_model_versions có confidence NULL (bản ghi cũ) |
| AS-09.3.4 | 1 thẻ <img> không có alt |
6. Những gì đang VỮNG — không phải chỗ nào cũng nợ
- AS-05 (84%) và AS-08 (84%) là hai bộ khoẻ nhất. 8/8 model tồn tại cho 12/12 learner; 640 engine run và 75 workflow run, 0 dòng failed; cron 21:00 UTC chạy thật; mọi lời gọi ra ngoài có timeout; DLQ 0 message kẹt.
- Kỷ luật migration: 56 file, 0 trùng số, 0 khoảng trống,
migrate:dryrundựng lại được từ D1 rỗng,PRAGMA foreign_key_checkproduction 0 dòng. - Đường AI: đúng một điểm gọi
env.AI.run(trong toàn repo và nó đi qua AI Gateway; 0 lời gọi AI từ frontend; Context Builder là cửa duy nhất chạm learner data, có test chống lẫn learner. - Hợp đồng API: 163/163 route
/v1, spec sinh từ router,contract:diffchặn breaking change trên mọi push; probe production trả đúng{error:{code,message}}. - Bảo mật nền: 0 secret hardcode, admin sau Cloudflare Access, audit log không sửa được từ ứng dụng, parent authz có test chạy trên D1 thật.
7. Hành động sinh ra từ audit này
Mỗi dòng là một việc có kết quả kiểm được. Thứ tự = thứ tự làm.
| # | Việc | Đóng chỉ báo | Cỡ |
|---|---|---|---|
| A1 | Chạy lại đối soát migration + schema-diff, cập nhật migration-reconciliation.md | AS-04.6.1 🔴🚸, 04.6.2, 04.6.3 🔴🚸, 04.6.5 | nhỏ |
| A2 | Sinh artifact phủ auth cho 189 route (kèm cổng CI) và rà authz learner data | AS-07.1.1 🔴🚸, 07.2.1 🔴🚸 | vừa |
| A3 | Nạp name_en cho 4 subject + 20 strand | AS-04.4.5, 06.1.5 | nhỏ |
| A4 | Thêm Recommendation Model vào bảng tổng models.md | AS-05.1.4 | nhỏ |
| A5 | Test hành vi cho Constraint Engine và Readiness Engine | AS-05.3.1 | nhỏ |
| A6 | Gỡ trùng SRC-206; đưa scripts/b21-plan.md vào docs/ | AS-01.1.1, 01.1.4, 01.1.5 | nhỏ |
| A7 | Ghi 10 cạnh import chéo vào bảng Ngoại lệ, hoặc gỡ cạnh nào gỡ được | AS-03.1.2 | nhỏ |
| A8 | apps/mentors/src/showcase.ts gọi qua api.ts; thêm alt cho ảnh thiếu | AS-03.1.3, 09.3.4 | nhỏ |
| A9 | Gắn 126 lab unit = NULL vào đúng Unit | AS-06.1.4 phụ | vừa |
| A10 | Soạn câu hỏi cho 229 Unit ngõ cụt (Hoá 95 · Sinh 64 · Tin 36 · Lý 33 · Văn 1) | AS-06.1.4 | LỚN |
| A11 | Soạn why_pain/why_gain/why_example/can_do cho 838 node | AS-06 phụ, SDD-021 §5 | LỚN |
| A12 | Prerequisite graph cho 9 môn còn trống | AS-06.1.3 phụ | LỚN |
| A13 | Dựng cổng chất lượng trước publish + backfill quality profile cho 11.336 item | AS-06.2.1/2.2/2.3, 06.3.1 🔴, 06.3.3, 06.3.4, 10.4.1 🔴🚸, 10.4.2 | LỚN |
| A14 | Diễn tập backup/restore D1 và ghi lại | AS-04.5.5 🔴🚸 | vừa |
| A15 | Sinh docs/reference/ui-minimalism-audit.md (5 chỉ báo AS-09.1 đang CX vì thiếu artifact) | AS-09.1.1–1.5 | vừa |
| A16 | Đo contrast WCAG AA cho token của design system | AS-09.3.1 🔴🚸 | vừa |
| A17 | Canonical hoá 257 SRC còn treo, bắt đầu từ các SRC có code đang chạy | AS-01.1.3, 02.4.2 | LỚN |
8. Chi tiết theo chỉ báo
Ký hiệu: ✅ PASS · ❌ KHÔNG PASS (kèm mã CX/CM/HH). 🔴 chặn phát hành · 🚸 Pilot Gate.
AS-01.1 — Nguồn duy nhất & sổ tiếp nhận
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-01.1.1 | ❌ HH | scripts/b21-plan.md là ghi chép khảo sát/kế hoạch nằm ngoài docs/, không phải README hay nội dung app |
| AS-01.1.2 | ✅ | 412 dòng ` |
| AS-01.1.3 | ❌ HH | 257/411 SRC id không xuất hiện ở bất kỳ PRD/SDD/QG nào ngoài intake.md (đếm bằng grep toàn docs/) |
| AS-01.1.4 | ❌ HH | SRC-206 xuất hiện HAI lần (intake.md:328 và :331) — dòng 412, uniq 411; không có khoảng trống, 'Nguồn tiếp theo' = 412 khớp max+1 |
| AS-01.1.5 | ❌ HH | cùng phản ví dụ 01.1.1 |
AS-01.2 — Frontmatter & metadata
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-01.2.1 | ✅ | npm run check:docs mục 1 xanh — 91 file docs đủ frontmatter, id duy nhất, type/status hợp lệ |
| AS-01.2.2 | ✅ | npm run check:docs mục 1 xanh — 91 file docs đủ frontmatter, id duy nhất, type/status hợp lệ |
| AS-01.2.3 | ✅ | npm run check:docs mục 1 xanh — 91 file docs đủ frontmatter, id duy nhất, type/status hợp lệ |
| AS-01.2.4 | ✅ | npm run check:docs mục 1 xanh — 91 file docs đủ frontmatter, id duy nhất, type/status hợp lệ |
| AS-01.2.5 | ✅ | npm run check:docs mục 1 xanh — 91 file docs đủ frontmatter, id duy nhất, type/status hợp lệ |
AS-01.3 — Đóng vết hai chiều
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-01.3.1 | ✅ | check-docs mục 2 (trace closure satisfies ↔ REQ) xanh |
| AS-01.3.2 | ✅ | check-docs mục 3: mọi dòng REQ ✔ phải có SDD + QG; 268 tham chiếu QG- trong PRD-001 |
| AS-01.3.3 | ✅ | check-docs kiểm sources trỏ SRC tồn tại — xanh |
| AS-01.3.4 | ❌ CM | check-docs mục 4 chỉ bắt link gãy, không bắt file không ai trỏ tới; lần này chưa chạy đối chiếu file↔link đích |
| AS-01.3.5 | ❌ CM | 275 tham chiếu US- trong PRD-001 có cột REQ, nhưng chiều ngược (mọi REQ MUST có ≥1 US/WF) chưa đo trong lần này |
AS-01.4 — Trang sinh tự động khớp source
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-01.4.1 🔴🚸 | ✅ | npm run gen:reference xong, git diff docs/reference rỗng |
| AS-01.4.2 | ✅ | data-dictionary.md sinh từ migrations bởi gen-reference.mjs, không drift (01.4.1) |
| AS-01.4.3 | ✅ | api.md sinh từ router; snapshot 163 path, contract:diff xanh |
| AS-01.4.4 | ✅ | events.md sinh từ EVENT_REGISTRY (21 entry), không drift |
| AS-01.4.5 | ✅ | các trang sinh tự động mở đầu bằng dòng '⚙️ Trang này sinh tự động' |
AS-01.5 — Tươi mới & vòng đời
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-01.5.1 | ✅ | 0/91 doc active có last_reviewed quá 90 ngày (đo ngày 2026-08-20) |
| AS-01.5.2 | ❌ CM | chưa spot-check ≥5 commit sửa nội dung có tăng version trong lần audit này |
| AS-01.5.3 | ✅ | check-docs mục 4 — 0 internal link gãy |
| AS-01.5.4 | ✅ | 20 hit 'tuần trước/gần đây/sắp tới' — tất cả là trích dẫn, chữ UI, hoặc chính câu cấm trong conventions.md |
| AS-01.5.5 | ✅ | ✍️ xuất hiện ở 14 file, open-questions/index.md là nơi tập trung; audit #003 đã đối chiếu |
AS-02.1 — Chất lượng REQ catalog
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-02.1.1 | ✅ | REQ id đúng scheme REQ-<nhóm>-xx, nhóm khớp bảng conventions.md §2 |
| AS-02.1.2 | ❌ CM | chưa chạy grep từ mơ hồ trên riêng các dòng REQ trong lần này |
| AS-02.1.3 | ✅ | 0 hit M?/S?/C? trong PRD-001 |
| AS-02.1.4 | ✅ | bảng REQ có cột nguồn SRC-xxx |
| AS-02.1.5 | ❌ CM | chưa chạy script token-overlap tìm REQ trùng nghĩa trong lần này |
AS-02.2 — User story & acceptance criteria
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-02.2.1 | ✅ | 98 dòng 'As a' trong PRD-001 §6, đúng format As a/I want/so that |
| AS-02.2.2 | ✅ | persona trong US thuộc tập Nemo/Marlin/Dolphin/Staff đã định nghĩa |
| AS-02.2.3 | ✅ | bảng US có cột AC riêng (quan sát được), ví dụ US-01/US-02/US-03 |
| AS-02.2.4 | ✅ | AC mẫu mô tả điều người dùng thấy (màn hình, nút), không nêu tên bảng D1/tên hàm |
| AS-02.2.5 | ❌ CM | chưa đối chiếu từng US MUST đã implement với route thật trong lần này |
AS-02.3 — Persona, JTBD & phủ vai trò
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-02.3.1 | ✅ | parent-jtbd.md + PRD §personas có JTBD cho từng persona active |
| AS-02.3.2 | ❌ CM | chưa trace từng JTBD → REQ trong lần này |
| AS-02.3.3 | ✅ | docs/workflows/ có learner-onboarding.md, parent-onboarding.md, mentor-onboarding.md |
| AS-02.3.4 | ❌ CM | SDD-011 chưa đối chiếu trong lần này |
| AS-02.3.5 | ❌ CM | chưa rà ngược route từng app về persona trong lần này |
AS-02.4 — Phạm vi & ưu tiên
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-02.4.1 | ❌ CM | chưa trace từng REQ ✔ về artifact thực thi trong lần này |
| AS-02.4.2 | ❌ HH | có tính năng đang chạy production mà chưa có REQ: cột Parents của bảng learner admin (SRC-404) mới chỉ có dòng intake, chưa canonical hoá vào PRD/SDD |
| AS-02.4.3 | ❌ CM | 51 hit CC-/FEAT- trong PRD-001 — chưa tách được hit nào nằm trong bảng REQ chính, hit nào ở phần backlog |
| AS-02.4.4 | ✅ | legacy-feature-inventory.md: 0 dòng 'chưa-quyết' |
| AS-02.4.5 | ❌ CM | chưa rà PRD §7 cho REQ MUST ⏳ quá 30 ngày trong lần này |
AS-02.5 — Quyết định mở & phê duyệt
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-02.5.1 | ✅ | open-questions/index.md dùng ID Q-xxx kèm trạng thái |
| AS-02.5.2 | ❌ HH | 6 hit cụm rỗng nghĩa ('tự quyết'/'theo ý chủ dự án'…) trong open-questions/index.md |
| AS-02.5.3 | ❌ CM | chưa đọc lại artifact 'Rà mâu thuẫn giữa các quyết định ✍️' xem còn ≤90 ngày và khai phạm vi |
| AS-02.5.4 | ✅ | bảng 'Việc còn chờ chủ dự án' có cột Trạng thái, mọi dòng có giá trị |
| AS-02.5.5 | ❌ CM | chưa kiểm từng Q đã trả lời có cột 'Đã vào' resolve được |
AS-03.1 — Ranh giới module & monorepo
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-03.1.1 | ✅ | `grep -rln createRoute workers/api/src |
| AS-03.1.2 | ❌ HH | 10 cạnh import chéo module trực tiếp trong khi bảng Ngoại lệ tường minh còn TRỐNG: coral→content (3), learning→knowledge/retention/content/models (4), progress→knowledge, admin→models (2) |
| AS-03.1.3 | ❌ HH | apps/mentors/src/showcase.ts gọi fetch( ngoài src/api.ts |
| AS-03.1.4 | ✅ | không app nào định nghĩa lại custom property đã có trong design-system tokens |
| AS-03.1.5 | ❌ CM | chưa đối chiếu ls apps workers với README §cấu trúc trong lần này |
AS-03.2 — Hợp đồng API
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-03.2.1 | ✅ | find .yaml/openapi.json ngoài snapshot → rỗng; spec sinh từ router |
| AS-03.2.2 | ❌ CM | chưa đếm operation thiếu schema bằng contract:diff --print trong lần này |
| AS-03.2.3 | ✅ | 163/163 path trong openapi.snapshot.json bắt đầu bằng /v1 |
| AS-03.2.4 🔴🚸 | ✅ | npm run contract:diff xanh; chạy trong ci.yml và deploy-api.yml trên mọi push |
| AS-03.2.5 | ✅ | probe production: /v1/khong-ton-tai → {error:{code:NOT_FOUND}}, /v1/me → AUTHORIZATION_ERROR; không rò ZodError/stack |
AS-03.3 — Hợp đồng event/queue
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-03.3.1 | ✅ | EVENT_REGISTRY 21 entry, mỗi entry có version + payload zod |
| AS-03.3.2 | ❌ CM | chưa đối soát hai chiều publishEvent ↔ registry trong lần này |
| AS-03.3.3 | ✅ | tên event khớp domain.entity.action, action ở thì quá khứ |
| AS-03.3.4 | ✅ | assertNoFreeText() tồn tại và được gọi trong publishEvent |
| AS-03.3.5 | ❌ CM | chưa đối chiếu số queue/max_batch_size/max_retries giữa wrangler.jsonc và queues.md |
AS-03.4 — Vệ sinh secret/config
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-03.4.1 🔴 | ✅ | grep pattern key/secret/token hardcode trên apps+workers+scripts+packages → rỗng |
| AS-03.4.2 | ❌ HH | 10 file ngoài src/api.ts chứa literal nemo12.com (learn/marlins/coral/mentors) — phần lớn là link footer/school info, nhưng chưa có danh sách miễn trừ tường minh |
| AS-03.4.3 | ✅ | verify-bindings Lớp A xanh — mọi biến bắt buộc khai kiểu trong env.ts |
| AS-03.4.4 | ❌ CM | verify:bindings chạy Lớp A+B (không có CLOUDFLARE_API_TOKEN cục bộ); Lớp C chỉ chạy trong CI |
| AS-03.4.5 | ✅ | verify-bindings Lớp B xanh — config.md khớp wrangler.jsonc (8 binding / 9 file) |
AS-03.5 — Cấu trúc & kỷ luật pipeline deploy
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-03.5.1 | ✅ | 9 wrangler.jsonc ↔ 9 workflow deploy-*.yml, path filter khớp |
| AS-03.5.2 | ✅ | 0 file wrangler.jsonc thiếu custom_domain/routes |
| AS-03.5.3 🚸 | ❌ CM | chưa gọi gh api .../branches/main/protection trong lần này; nhánh (b) đòi AS-04.6.1 sạch mà 04.6.1 đang KHÔNG PASS |
| AS-03.5.4 | ✅ | deploy-api.yml: bước 'Apply D1 migrations' đứng trước bước 'Deploy worker' |
| AS-03.5.5 | ❌ CM | chưa curl từng URL production trong README trong lần này |
AS-04.1 — Kỷ luật viết migration
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-04.1.1 🔴🚸 | ✅ | 56 file migration, 0 số trùng, 0 khoảng trống 0001..0056 |
| AS-04.1.2 | ✅ | 0 câu CREATE TABLE/INDEX thiếu IF NOT EXISTS (bỏ dòng comment) |
| AS-04.1.3 | ✅ | mọi DELETE/UPDATE trong migrations đều có WHERE (0035 có WHERE source_kind/status) |
| AS-04.1.4 🔴 | ✅ | npm run migrate:dryrun exit 0, chạy trong ci.yml và deploy-api.yml |
| AS-04.1.5 | ✅ | 0 file trên đĩa chưa áp — chiều file→applied sạch |
AS-04.2 — Thiết kế schema
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-04.2.1 | ❌ CM | chưa dump từng CREATE TABLE production để xác nhận PK trong lần này |
| AS-04.2.2 🔴 | ✅ | grep REFERENCES users(email) → rỗng |
| AS-04.2.3 | ❌ CM | chưa đối chiếu từng cột *_id với REFERENCES/danh sách miễn trừ trong lần này |
| AS-04.2.4 | ✅ | `grep '_at INTEGER |
| AS-04.2.5 | ✅ | 0 hit json_extract trong workers/api/src |
AS-04.3 — Ngữ nghĩa & enum
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-04.3.1 | ✅ | data-dictionary.md sinh tự động từ migrations, không drift |
| AS-04.3.2 | ❌ CM | chưa chạy script so mô tả cột với tên kiểu trong lần này |
| AS-04.3.3 | ✅ | data-dictionary sinh từ chính migrations nên không thể có bảng ma |
| AS-04.3.4 | ❌ CM | chưa đối chiếu từng CHECK(... IN ...) với data-dictionary trong lần này |
| AS-04.3.5 | ❌ CM | chưa đối chiếu state-machines.md với tập CHECK trong lần này |
AS-04.4 — Toàn vẹn vận hành
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-04.4.1 | ❌ CM | chưa rà từng script trong scripts/ có --remote kèm xác nhận trong lần này |
| AS-04.4.2 | ❌ CM | chưa chạy seed script hai lần trên D1 local để đo idempotency trong lần này |
| AS-04.4.3 | ✅ | PRAGMA foreign_key_check trên production → 0 dòng |
| AS-04.4.4 | ❌ CM | chưa đối chiếu khoá nghiệp vụ khai trong data-dictionary với UNIQUE index thật |
| AS-04.4.5 | ❌ HH | 4 subjects (sat, ap, genai, ielts) thiếu name_en và 20 strands của chính 4 môn đó thiếu name_en trên production |
AS-04.5 — Riêng tư & lưu trữ
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-04.5.1 | ✅ | RETENTION_BASELINE trong shared/privacy.ts: mỗi loại dữ liệu có keep_days + rationale + cờ pii |
| AS-04.5.2 | ✅ | module privacy có bảng data_deletion_requests và route xoá dữ liệu theo yêu cầu |
| AS-04.5.3 | ✅ | rp-model-version giữ 365 ngày, rp-engine-run/rp-workflow-run 90 ngày — chính sách khai bằng số |
| AS-04.5.4 | ❌ CM | chưa đối chiếu từng trường PII với lý do tồn tại trong data-dictionary §PII |
| AS-04.5.5 🔴🚸 | ❌ CX | docs/ops/backup-restore-drill.md tồn tại nhưng lần audit này chưa xác nhận có ngày diễn tập thật ≤ chu kỳ |
AS-04.6 — Đối soát production
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-04.6.1 🔴🚸 | ❌ HH | d1_migrations remote có 57 dòng / đĩa 56 file; dòng mồ côi 0046_context_event_temporal.sql (đã đổi tên thành 0052 ở commit d4d582c) KHÔNG có trong migration-reconciliation.md — bản đối soát đang ghi tình trạng cũ (41 dòng/39 file) |
| AS-04.6.2 | ❌ HH | 1 dòng mồ côi (xem 04.6.1) |
| AS-04.6.3 🔴🚸 | ❌ CM | schema-diff production ↔ dryrun gần nhất là 2026-08-15, chưa chạy lại sau 17 migration mới |
| AS-04.6.4 🔴🚸 | ✅ | 0 DROP COLUMN/RENAME COLUMN; 0 ADD COLUMN NOT NULL thiếu DEFAULT kể từ mốc 2026-08-15 |
| AS-04.6.5 | ❌ HH | đúng trường hợp cảnh báo: filename từng có trong d1_migrations production không còn trên đĩa và chưa có dòng giải thích |
AS-05.1 — Định nghĩa model & versioning
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-05.1.1 | ✅ | reference/ có trang riêng cho learner/context/goal/readiness/retention/constraint/learning-plan/recommendation |
| AS-05.1.2 | ✅ | learner_model_versions.model_version = 'deterministic' cho 304/305 dòng; algorithm_version dạng <model>-v1 ghi trong content |
| AS-05.1.3 | ✅ | 305 version trên production, có generated_at, dedupe theo SHA-256 nội dung |
| AS-05.1.4 | ❌ HH | models.md §1 'Bảng tổng' liệt kê 7 model, THIẾU Recommendation Model đang chạy thật (model_kind recommendation, SRC-207) |
| AS-05.1.5 | ✅ | đổi thuật toán đi kèm tăng algorithm_version; runlog dedupe theo hash nội dung |
AS-05.2 — Đường evidence → model
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-05.2.1 | ✅ | learner_evidence 561 dòng, mỗi dòng có source + occurred_at + event_id |
| AS-05.2.2 🔴 | ✅ | route self-report ghi vào learner_evidence trước, engine đọc lại từ đó |
| AS-05.2.3 | ✅ | learner_evidence: 0/561 dòng thiếu reliability; 4 nguồn phân loại |
| AS-05.2.4 | ✅ | learning/selection + expstate test phủ hành vi 'sửa lại không tạo evidence trùng' |
| AS-05.2.5 | ✅ | engine_runs 640 dòng, workflow_runs 75 dòng, 0 dòng failed |
AS-05.3 — Engine correctness
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-05.3.1 | ❌ HH | 2/8 engine không có test hành vi riêng: Constraint Engine (models/constraint.ts) và Readiness Engine (computeReadiness trong knowledge/mastery.ts) — grep test file → 0 |
| AS-05.3.2 | ✅ | không test nào readFileSync mã nguồn rồi .includes() |
| AS-05.3.3 | ✅ | goals/engine.test.ts, recommendation.test.ts, contextEvents.test.ts đều có ca rỗng |
| AS-05.3.4 | ❌ CM | chưa đọc lại test stopping criteria của diagnosis/adaptive trong lần này |
| AS-05.3.5 | ✅ | ci.yml bước 3 và deploy-api.yml bước 'Test' chạy npm test, không ` |
AS-05.4 — Retention & Mastery
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-05.4.1 🔴 | ✅ | retention/periodic.test.ts giữ bất biến mastery không tự suy giảm |
| AS-05.4.2 | ✅ | reference/retention-model.md ghi công thức decay + retention/engine.test.ts |
| AS-05.4.3 | ✅ | wrangler.jsonc crons: [0 21 * * *]; schedules.md ghi đúng lịch; workflow_runs có WF-17 |
| AS-05.4.4 | ✅ | periodic.test.ts giữ bất biến job định kỳ không đụng anchor |
| AS-05.4.5 | ✅ | tham số review window ghi trong reference/retention-model.md |
AS-05.5 — Giải thích được
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-05.5.1 | ✅ | recommendation.ts: mỗi việc kèm why + from truy được về model sinh ra nó |
| AS-05.5.2 | ✅ | learner_model_versions ghi model_version + algorithm_version cho mỗi bản |
| AS-05.5.3 | ✅ | planning.ts ghi diff so với bản trước; UI /ke-hoach hiển thị |
| AS-05.5.4 | ❌ HH | 1/305 dòng learner_model_versions có confidence NULL và 1 dòng model_version NULL (bản ghi cũ trước khi cột tồn tại) |
| AS-05.5.5 | ✅ | admin #/models mở được mọi phiên bản model theo thời gian; learner/parent xem qua marlins |
AS-06.1 — Knowledge graph toàn vẹn
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-06.1.1 | ✅ | skill_nodes: 1600 node, 0 node thiếu subject_id; grade/level có ở cây B21 |
| AS-06.1.2 | ✅ | 0 node thiếu strand; unit gán đủ cho các cây đang hiện |
| AS-06.1.3 | ❌ CM | chưa chạy DFS phát hiện chu trình trên unit_prereqs trong lần này |
| AS-06.1.4 | ❌ HH | 229 Unit đang HIỆN cho learner mà 0 câu hỏi published: chemistry 95, biology 64, informatics 36, physics 33, vietnamese 1 — learner bấm vào là gặp ngõ cụt. Thêm 989 Unit dưới ngưỡng 10 câu |
| AS-06.1.5 | ❌ HH | 4 subjects + 20 strands thiếu name_en (xem 04.4.5); node thì đủ (0/1600 thiếu title_en) |
AS-06.2 — Chất lượng item
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-06.2.1 | ❌ HH | 11.336/11.336 item published có quality_json NULL — 0% có quality profile 8 chiều |
| AS-06.2.2 | ❌ HH | 0 item nào có evidence kèm theo cho từng chiều chất lượng (quality_json rỗng toàn bộ) |
| AS-06.2.3 | ❌ HH | evaluator_count < 2 trên 11.336/11.336 item — không có multi-evaluator variance check trước publish |
| AS-06.2.4 | ✅ | items: 0/11.336 dòng thiếu node_id |
| AS-06.2.5 | ✅ | content_reports nối vào hàng đợi rà soát thật qua ingestContentReports() (coral + forum) |
AS-06.3 — Vòng đời nội dung
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-06.3.1 🔴 | ❌ HH | 0 item ở trạng thái candidate, 0 dòng item_versions — mọi nội dung vào thẳng published, không qua candidate version |
| AS-06.3.2 | ✅ | items.status có CHECK (candidate |
| AS-06.3.3 | ❌ HH | quality_score NULL trên toàn bộ item published — publish không đi qua ngưỡng chất lượng bằng số |
| AS-06.3.4 | ❌ HH | published_by NULL trên 11.336/11.336 item — không truy được ai/cái gì publish |
| AS-06.3.5 | ❌ CX | item_versions rỗng nên rollback nội dung về version trước chưa có đường thật |
AS-06.4 — Đề thi thật & provenance
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-06.4.1 | ❌ CX | 0 dòng exams source_kind='real' — chưa có đề thật nào để chấm |
| AS-06.4.2 🔴 | ❌ CX | chưa có đề thật (xem 06.4.1) |
| AS-06.4.3 🔴 | ❌ CX | chưa có đề thật |
| AS-06.4.4 | ❌ CX | chưa có crawler chạy thật |
| AS-06.4.5 | ❌ CX | chưa có đề thật |
AS-06.5 — Media & bản quyền
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-06.5.1 | ❌ CX | bảng media 0 dòng — pipeline moderation chưa có gì đi qua |
| AS-06.5.2 | ❌ CX | chưa có media |
| AS-06.5.3 | ✅ | REQ-LRN-20 zero-asset: hình sinh bằng SVG từ tham số, không nhúng logo/ảnh bên thứ ba |
| AS-06.5.4 | ❌ CX | chưa có media |
| AS-06.5.5 | ❌ CX | chưa có media chứa hình trẻ em |
AS-07.1 — Xác thực & phiên
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-07.1.1 🔴🚸 | ❌ CM | 189 route; middleware đăng ký theo vòng lặp path nên đếm thô không kết luận được; chưa có artifact liệt kê route public có chủ đích |
| AS-07.1.2 | ✅ | sessions có expires_at, revoked_at, rotated_from — có hạn và thu hồi được |
| AS-07.1.3 | ✅ | auth/access.ts ghim issuer + audience + RS256 + exp; access.test.ts 8 test |
| AS-07.1.4 🚸 | ✅ | admin.nemo12.com đứng sau Cloudflare Access, chỉ dac2205@gmail.com (SRC-129), đã kiểm bằng cách huỷ phiên và tải lại |
| AS-07.1.5 | ✅ | grep bypass/skip auth/debug login → không có đường tắt trên production |
AS-07.2 — Phân quyền backend
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-07.2.1 🔴🚸 | ❌ CM | chưa rà từng endpoint chạm bảng có learner_id trong lần này |
| AS-07.2.2 🔴 | ✅ | grep so sánh email trong logic authz → chỉ 1 hit là chuẩn hoá email của Access token, không phải quyết định quyền |
| AS-07.2.3 🔴🚸 | ✅ | parent/authz.test.ts chạy trên D1 thật, chứng minh parent chỉ thấy learner trong family mình |
| AS-07.2.4 | ❌ CM | audit_log có 59 dòng nhưng 0 dòng actor_role='mentor' — chưa có lượt truy cập mentor nào để chứng minh |
| AS-07.2.5 | ❌ CM | chưa đối chiếu ma trận permissions.md với kiểm tra thật trong code |
AS-07.3 — Dữ liệu trẻ em & đồng thuận
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-07.3.1 | ❌ CM | chưa rà từng trường dữ liệu trẻ em trong data-dictionary |
| AS-07.3.2 🔴🚸 | ✅ | bảng consents có 20 dòng ghi ai bật/tắt cái gì, lúc nào |
| AS-07.3.3 | ✅ | portrait_learner_sections chỉ role learner ghi được — có test |
| AS-07.3.4 | ✅ | lời gọi ra ngoài chỉ tới Cloudflare AI Gateway và Google OAuth — đã khai |
| AS-07.3.5 | ❌ CM | chưa kiểm UI marlins có cho parent xem dữ liệu đang dùng để ra quyết định |
AS-07.4 — Audit log
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-07.4.1 | ❌ CM | chưa rà từng route mentor/staff chạm learner data có ghi audit_log |
| AS-07.4.2 | ✅ | audit_log có actor_user_id, actor_role, action, target_type, target_id, occurred_at, request context |
| AS-07.4.3 | ✅ | audit_log chỉ ghi tham chiếu (target_type + target_id), không ghi nội dung nguyên văn |
| AS-07.4.4 | ✅ | không endpoint nào UPDATE/DELETE audit_log (ghi rõ trong admin/routes.ts) |
| AS-07.4.5 | ✅ | /v1/admin/audit-log có lọc theo actor/target/action/thời gian |
AS-07.5 — Bề mặt tấn công
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-07.5.1 🔴 | ✅ | grep pattern secret trên source → rỗng |
| AS-07.5.2 🔴 | ✅ | không route debug/seed mở trên production |
| AS-07.5.3 | ✅ | mọi route dùng zod schema qua @hono/zod-openapi + defaultHook |
| AS-07.5.4 | ❌ CM | 3 hit dangerouslySetInnerHTML trong apps/*/src chưa xác nhận từng hit không phải input người dùng |
| AS-07.5.5 | ✅ | shared/ratelimit.ts + ratelimit.test.ts; rate_limit_buckets có trên production |
AS-08.1 — Production-ready
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-08.1.1 | ❌ CM | chưa đối chiếu availability tier từng worker trong lần này |
| AS-08.1.2 | ❌ CM | chưa đọc lại 5 câu hỏi production-ready SDD-006 §16 |
| AS-08.1.3 | ❌ CM | chưa rà 'hỏng thì người dùng thấy gì' cho các tính năng mới nhất |
| AS-08.1.4 | ✅ | /v1/health chạy SELECT 1 trên D1 thật; probe production trả 200 |
| AS-08.1.5 | ✅ | 1 hit TODO duy nhất (marlins/StartWizard.tsx:23) là ghi chú nợ kỹ thuật có mô tả, không chặn đường |
AS-08.2 — Idempotency & DLQ
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-08.2.1 | ✅ | consumer dùng idempotencyKey (10 điểm trong code) |
| AS-08.2.2 🔴🚸 | ✅ | wrangler.jsonc khai dead_letter_queue |
| AS-08.2.3 | ✅ | /v1/admin/dead-letters + replay endpoint; queue_dead_letters 0 dòng |
| AS-08.2.4 | ✅ | max_retries khai trong wrangler.jsonc |
| AS-08.2.5 | ❌ CM | chưa đọc lại cron handler xem có khoá chống chạy chồng |
AS-08.3 — Observability
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-08.3.1 | ✅ | 9/9 wrangler.jsonc bật observability |
| AS-08.3.2 | ✅ | log có level + request_id xuyên suốt (thấy trong output test workflow) |
| AS-08.3.3 | ✅ | errorResponse + logger ghi kèm request_id, workflow_code, learner_id |
| AS-08.3.4 | ✅ | engine_runs/workflow_runs đếm được số run + số lỗi; admin #/runs hiển thị |
| AS-08.3.5 | ✅ | workflow_runs 75 dòng — biết workflow đã chạy mà không cần đọc log thô |
AS-08.4 — CI/CD & rollback
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-08.4.1 🚸 | ✅ | ci.yml + deploy-api.yml chạy typecheck+lint+test trước deploy (xác nhận trên run 7a2e577) |
| AS-08.4.2 | ✅ | mọi deploy-*.yml có paths filter |
| AS-08.4.3 🔴 | ✅ | deploy-api.yml: apply migration trước wrangler deploy |
| AS-08.4.4 | ✅ | rollback.yml dùng wrangler rollback, không phụ thuộc build |
| AS-08.4.5 | ✅ | chỉ bước apply-migration là workflow_dispatch, đã ghi rõ lý do |
AS-08.5 — Suy giảm duyên dáng & phụ thuộc ngoài
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-08.5.1 | ✅ | runPrompt có fallback khi AI lỗi; cache KV hỏng chỉ chậm chứ không lỗi |
| AS-08.5.2 | ✅ | reliability.test.ts chứng minh KV/D1 chết vẫn trả dữ liệu thật |
| AS-08.5.3 | ✅ | TIMEOUT_MS + withTimeout phủ mọi lời gọi ra ngoài (7 điểm) |
| AS-08.5.4 | ✅ | shared/reliability.ts cache đọc nhiều, có test |
| AS-08.5.5 | ✅ | errorResponse trả thông điệp tiếng Việt cho người dùng, không stack trace |
AS-09.1 — Luật tối giản (SRC-048)
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-09.1.1 | ❌ CX | docs/reference/ui-minimalism-audit.md CHƯA TỒN TẠI — không có artifact để chấm 5 chỉ báo luật tối giản |
| AS-09.1.2 | ❌ CX | docs/reference/ui-minimalism-audit.md CHƯA TỒN TẠI — không có artifact để chấm 5 chỉ báo luật tối giản |
| AS-09.1.3 | ❌ CX | docs/reference/ui-minimalism-audit.md CHƯA TỒN TẠI — không có artifact để chấm 5 chỉ báo luật tối giản |
| AS-09.1.4 | ❌ CX | docs/reference/ui-minimalism-audit.md CHƯA TỒN TẠI — không có artifact để chấm 5 chỉ báo luật tối giản |
| AS-09.1.5 | ❌ CX | docs/reference/ui-minimalism-audit.md CHƯA TỒN TẠI — không có artifact để chấm 5 chỉ báo luật tối giản |
AS-09.2 — Token & component
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-09.2.1 | ❌ CM | chưa đếm hex hardcode loại trừ file SVG/art trong lần này |
| AS-09.2.2 | ❌ CM | chưa rà component fork giữa apps và packages trong lần này |
| AS-09.2.3 | ❌ CM | chưa rà CSS riêng theo trang |
| AS-09.2.4 | ✅ | tokens/base.css chỉ đổi lớp accent giữa các portal |
| AS-09.2.5 | ❌ CM | 39 hit text-xs trong apps/*/src — chưa xác nhận cỡ chữ thực tế ≥14px |
AS-09.3 — Accessibility
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-09.3.1 🔴 | ❌ CM | chưa đo contrast bằng axe/lighthouse trong lần này |
| AS-09.3.2 | ❌ CM | chưa thử tab qua bàn phím trong lần này |
| AS-09.3.3 | ❌ CM | chưa đo touch target trong lần này |
| AS-09.3.4 | ❌ HH | 1 thẻ |
| AS-09.3.5 | ❌ CM | chưa thử điều hướng bàn phím hết luồng chính |
AS-09.4 — Ngôn ngữ & nội dung UI
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-09.4.1 | ✅ | 0 chuỗi hiển thị tiếng Việt trong apps/admin/src (grep ký tự có dấu giữa hai thẻ) — admin đã tiếng Anh toàn bộ; learn/marlins tiếng Việt |
| AS-09.4.2 | ✅ | popover admin cố ý giữ giải thích tiếng Việt là quyết định SRC-143, không phải lẫn ngôn ngữ ngẫu nhiên |
| AS-09.4.3 | ❌ CM | chưa đối chiếu thuật ngữ UI với glossary.md |
| AS-09.4.4 | ✅ | errorResponse trả câu tiếng Việt cho người dùng |
| AS-09.4.5 | ❌ CM | chưa rà chữ lặp lại nội dung đã hiển thị bằng hình |
AS-09.5 — Hiệu năng cảm nhận
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-09.5.1 | ❌ CM | chưa đo LCP bằng Lighthouse |
| AS-09.5.2 | ❌ CM | chưa đo CLS |
| AS-09.5.3 | ❌ CM | chưa spot-check ≥5 màn cho loading/empty/error |
| AS-09.5.4 | ✅ | zero-asset: hình là SVG sinh từ tham số, không có ảnh quá khổ |
| AS-09.5.5 | ❌ CM | chưa thử tay xác nhận chấm client-side trước khi gửi evidence |
AS-10.1 — Đường AI duy nhất
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-10.1.1 🔴 | ✅ | đúng MỘT điểm gọi env.AI.run( (shared/prompts.ts:303) và nó truyền gateway: { id: env.AI_GATEWAY_ID } |
| AS-10.1.2 🔴 | ✅ | không có vòng lặp probe model id |
| AS-10.1.3 | ✅ | model id khai tường minh trong prompt spec |
| AS-10.1.4 | ✅ | 0 hit env.AI/ai.run trong apps/*/src |
| AS-10.1.5 | ❌ CM | chưa đối chiếu từng điểm gọi AI với ai-registry.md trong lần này |
AS-10.2 — Prompt registry
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-10.2.1 | ✅ | mọi prompt nằm trong shared/prompts.ts, không inline rải rác |
| AS-10.2.2 | ✅ | mỗi prompt spec có version |
| AS-10.2.3 | ❌ CM | chưa spot-check git log chứng minh đổi prompt = version mới |
| AS-10.2.4 | ✅ | registry ghi mục đích, đầu vào, ràng buộc đầu ra |
| AS-10.2.5 | ✅ | output AI parse qua zod schema trước khi dùng |
AS-10.3 — Context Builder & ranh giới dữ liệu
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-10.3.1 🔴🚸 | ✅ | shared/context-builder.ts là đường duy nhất AI chạm learner data, có test |
| AS-10.3.2 | ✅ | builder cắt còn trường cần cho tác vụ |
| AS-10.3.3 | ✅ | builder không đưa tên thật/email vào prompt |
| AS-10.3.4 | ❌ CM | chưa xác nhận mọi output AI lưu input_ref |
| AS-10.3.5 🔴🚸 | ✅ | shared/context-builder.test.ts có ca chứng minh dữ liệu learner A không lọt sang learner B |
AS-10.4 — Đánh giá & chống ảo giác
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-10.4.1 🔴🚸 | ❌ HH | không có cổng đánh giá trước publish: 11.336/11.336 item published có quality_score NULL, evaluator_count<2 (xem AS-06.2/06.3) |
| AS-10.4.2 | ❌ HH | 0 item có multi-evaluator |
| AS-10.4.3 | ❌ CX | chưa có tỷ lệ spot-check bởi người được ghi thành số |
| AS-10.4.4 | ❌ CM | chưa rà nội dung xem khẳng định kiến thức có nguồn/đánh dấu sinh tự động |
| AS-10.4.5 | ✅ | content_reports → ingestContentReports → hàng đợi rà soát Coral, không rơi vào hư vô |
AS-10.5 — Chi phí & hạn mức
| Chỉ báo | Bằng chứng | |
|---|---|---|
| AS-10.5.1 | ❌ CM | ai-registry.md có nhắc chi phí nhưng chưa đối chiếu từng loại lời gọi trong lần này |
| AS-10.5.2 | ❌ CM | chưa mở dashboard AI Gateway (cần scope token đọc gateway) |
| AS-10.5.3 | ❌ CM | chưa xác nhận có hạn mức/cảnh báo cấu hình ở gateway |
| AS-10.5.4 | ✅ | WF-17 chạy 1 lần/ngày, có cap số learner mỗi lượt (deferred hiện trong output) |
| AS-10.5.5 | ✅ | route sinh nội dung AI chỉ mở cho staff/admin; có rate limit |
9. Trace
| Nguồn | Chuẩn | Ghi vào |
|---|---|---|
| SRC-412 (chỉ đạo: "Audit toàn bộ code và content, tạo ra Audit Report. Sau đó sửa dần theo kết quả audit") | audit-standard/index.md v0.2 | báo cáo này + index + các việc A1..A17 |
10. Đính chính — 2026-08-20, trong lúc sửa theo A1..A8
Luật của index audit là không sửa đè báo cáo cũ; hai dòng dưới đây là đính chính ghi thêm, không xoá dòng gốc ở §5.9 và §8.
| Chỉ báo | Chấm ban đầu | Đúng ra là | Vì sao lệch |
|---|---|---|---|
| AS-09.3.4 | ❌ HH — "1 thẻ <img> không có alt" | ✅ PASS | Hit duy nhất nằm trong apps/learn/src/figures/engine.test.tsx:37, và nó là một assertion cấm <img>: expect(html).not.toMatch(/<img|\.png|\.jpe?g/i). Grep bắt đúng chuỗi nhưng đọc ngược ý. Cổng learn không render thẻ <img> nào — đúng luật zero-asset REQ-LRN-20 |
| AS-03.1.3 | ❌ HH — "showcase.ts gọi fetch( ngoài api.ts" | ❌ vẫn KHÔNG PASS, nhưng mức nhẹ hơn mô tả | showcase.ts không phải component gọi lung tung: nó là client thứ hai của cùng cổng mentors, với một bản request() gần như trùng api.ts. Đã sửa ở A8 — nay dùng chung request/API_BASE, còn đúng một fetch thô cho đường tải ảnh (bytes thuần, Content-Type là mime của ảnh nên không thể đi qua request()), có ghi lý do ngay tại chỗ |
Điểm hệ sau đính chính: 146/255 = 57,3% (AS-09 lên 6/25). Các con số khác giữ nguyên.
11. Đã sửa xong trong cùng phiên (A1..A8)
| Việc | Kết quả kiểm được |
|---|---|
| A1 | migration-reconciliation.md có mục 2026-08-20: 58 dòng remote / 57 file đĩa, 1 dòng mồ côi 0046_context_event_temporal.sql đã khai + giải thích; schema-diff production ↔ migrate:dryrun 92 bảng, 0 bảng lệch cột. → AS-04.6.1 🔴🚸 và AS-04.6.3 🔴🚸 PASS. AS-04.6.2 vẫn đỏ có chủ đích: câu DELETE dọn dòng mồ côi là ghi thẳng production, để chủ dự án quyết thời điểm |
| A3 | migrations/0058_bilingual_new_subjects.sql — name_en cho 4 subject + 20 strand (SAT/AP/IELTS dùng đúng tên chính thức của kỳ thi, không dịch máy). migrate:dryrun xanh. Chờ áp lên production qua workflow_dispatch |
| A4 | reference/models.md §1 nay có đủ 8 model — thêm dòng Recommendation Model. → AS-05.1.4 PASS |
| A5 | knowledge/readiness.test.ts (9 test) và models/constraint.test.ts (8 test) — 8/8 engine nay có test hành vi riêng. → AS-05.3.1 PASS |
| A6 | Trùng SRC-206 đã gỡ: dòng "Dolphin có khu rà soát" đổi sang SRC-414 (đổi dòng này chứ không đổi dòng "cựu học sinh", vì traceability.md và request-audit.md đang trỏ tới nghĩa cựu học sinh). Sổ nay: 414 dòng = 414 uniq = max 414, liên tục. scripts/b21-plan.md chuyển thành engineering/content-loading-notes.md. → AS-01.1.1, 01.1.4, 01.1.5 PASS |
| A7 | 10 cạnh import chéo module đã khai vào bảng "Ngoại lệ tường minh" của audit-standard, mỗi cạnh một lý do. → AS-03.1.2 PASS |
| A8 | apps/mentors/src/showcase.ts dùng chung request/API_BASE của api.ts |
| A2 | workers/api/src/shared/authCoverage.test.ts — cổng phủ xác thực + phân quyền, chạy trong npm test nên chặn cả CI lẫn deploy. Soi bảng route lúc chạy thay vì grep mã nguồn: 192 route /v1, 130 đăng ký requireSession, còn 22 route mở và cả 22 đều nằm trong danh sách PUBLIC kèm lý do từng dòng. Đã thử phá để chứng minh cổng có răng: bỏ một dòng PUBLIC ra thì test đỏ đúng tên route đó. Lớp thứ hai chấm phân quyền: 12 module có route {learnerId}, 11 dùng chốt của shared/authz, riêng invitations khoá bằng family_id lấy từ session (đã soi tay, ghi vào ngoại lệ). → AS-07.1.1 🔴🚸 và AS-07.2.1 🔴🚸 PASS | | A9 | migrations/0059_attach_orphan_labs.sql — gắn lab vào 3 Unit tiếng Anh chưa có lab nào. Chỉ 3, không phải 126: rà kỹ thì 70 lab không có node_id lẫn strand (việc biên tập, không suy ra được), 46 lab rơi vào Unit đã có lab khác nên đụng unique index "một lab mỗi Unit" của 0048. Con số thật cần chủ dự án quyết: cây Tiếng Anh mới có 64 Unit trong khi kho có 113 lab — dư ra là do cây cũ chia nhỏ hơn, phải chọn giữ và gắn tay hay cho retired |
| A10 (phần Tin học + Ngữ văn) | 370 câu soạn tay cho 37 Unit ngõ cụt: 360 câu cho cả 36 Unit của Package UD môn Tin học (HTML · CSS · JavaScript · cơ sở dữ liệu · làm dự án · công cụ nghề) và 10 câu cho Unit "Ẩn dụ" của Ngữ văn. Sinh ra .sql để nạp qua seed-data.yml chứ không dùng scripts/d1.mjs — script đó gọi thẳng Cloudflare API từ máy cá nhân, đi vòng qua luật "mọi thứ chạm production phải qua GitHub Actions". Đã kiểm trên SQLite thật dựng từ migrations/: 370 dòng, chạy lại lần hai vẫn 370, 37/37 node id có thật trên production, mỗi Unit đúng 10 câu, 0 câu thiếu misconception. Đã nạp lên production 2026-08-20 qua seed-data.yml |
| A11 (đợt 1) | 72 Unit môn Tin học có đủ why_pain / why_gain / why_example / can_do: Package "Ứng dụng và sản phẩm" và "Lập trình cơ bản". Viết theo đúng khuôn của các node môn Toán đã có (SRC-345, SRC-397); cổng sinh SQL tự chặn ba luật: độ dài tối thiểu từng trường, bắt buộc khuôn "Ngay tí nữa / Mai ngày kia", và cấm em dash. Đã kiểm trên SQLite thật: 72/72 điền đủ, chạy lại không đè lên chữ sửa tay, 72/72 node id có thật trên production và cả 72 đang trống. Đã nạp lên production 2026-08-20 |
| A11 (đợt 2-5) | 289 node nữa: trọn môn Tin học (216/216 node, cả sáu Package) và trọn bốn môn thi chuẩn hoá SAT · IELTS · AP · GenAI (73 node). Cổng sinh SQL được siết thêm một luật sau khi suýt để lọt một lỗi im lặng: nó đếm node theo môn và so với số đo được trên production. Lỗi bị bắt: 17 id IELTS viết theo tiền tố ielts- trong khi id thật không có tiền tố đó, nếu lọt thì câu UPDATE không khớp dòng nào mà seed vẫn báo thành công |
Tổng A11 tới giờ: 289/838 node, tất cả đã nạp lên production. Còn lại 84 node Ngữ văn và 73 node của các môn nhỏ trong phần của tôi; 444 node Lý/Hoá/Sinh do phiên khác làm. Sau đó là A12..A17. Phần Lý/Hoá/Sinh của A10 do một phiên khác làm song song (SRC-414, SRC-420).
Ghi nhận trong lúc làm A10 — một lỗ hổng quy trình chưa có chỉ báo nào bắt: scripts/d1.mjs mở đường ghi thẳng vào D1 production bằng token đọc từ ~/Library/Preferences/.wrangler, và các mẻ nội dung gần đây đều đi đường đó. Nó không vi phạm chỉ báo AS nào đang có (AS-04.4.1 chỉ hỏi script có in tên DB và chờ xác nhận không, AS-03.5.3 chỉ nói về migrations apply), nhưng vi phạm thẳng luật của chủ dự án ngày 2026-08-15. Đề xuất cho lần cập nhật chuẩn kế tiếp: mở rộng AS-03.5.3 sang mọi thao tác ghi production, không riêng migration.
Điểm sau A1..A9
| Trước | Sau | |
|---|---|---|
| Điểm hệ | 145/255 (56,9%) | 154/255 (60,4%) |
| 🔴 KHÔNG PASS | 10/30 | 5/30 |
| 🚸 Pilot Gate | 11/18 | 15/18 |
Ba dòng Pilot Gate còn đỏ: AS-04.5.5 (diễn tập backup/restore — A14), AS-03.5.3 (chứng minh không ai apply migration ngoài CI — cần gh api hoặc nhánh (b)), AS-10.4.1 (cổng chất lượng trước publish — A13, khối lớn).
12. Kết quả sau khi nạp lên production — 2026-08-20
Bốn tệp seed chạy qua seed-data.yml (bốn lượt, mỗi tệp một lượt, đều success). Đo lại chính production sau khi chạy, không đọc log:
| Đo | Trước | Sau |
|---|---|---|
Câu hỏi cho Package UD môn Tin học | 0 | 360 |
| Câu hỏi cho Unit "Ẩn dụ" (Ngữ văn) | 0 | 10 |
Node Tin học có đủ why_pain/why_gain/why_example/can_do | 0 | 216/216 |
| Node SAT · IELTS · AP · GenAI có đủ bốn trường | 0 | 73/73 |
| Unit ngõ cụt của môn Tin học | 36 | 0 |
Migration 0058 (song ngữ 4 subject + 20 strand) và 0059 (gắn 3 lab vào Unit) cũng đã áp: subjects và strands nay 0 dòng thiếu name_en, ba Unit tiếng Anh đã có nút Lab.
Unit ngõ cụt còn lại trên toàn hệ: Hoá 35 · Lý 33 · Ngữ văn 1. Hoá và Lý thuộc đợt của phiên khác. Dòng Ngữ văn còn lại là node idioms thuộc cây cũ TV chứ không phải cây V1-V5 mà learner đang đi: đây chính là hai cây song song mà SRC-401 đã nêu và chưa ai quyết cây cũ có tạm ẩn hay không. Không soạn câu cho nó là có chủ đích, vì soạn tức là ngầm quyết định giữ cây cũ.
13. Tiến độ A13 và A14 — 2026-08-22
Ghi thêm chứ không sửa phần trên: theo luật của index audit, báo cáo đã chấm giữ nguyên, tiến độ về sau viết tiếp xuống dưới.
A14 — diễn tập backup/restore: xong, AS-04.5.5 chuyển sang PASS
Đợt diễn tập mới ghi ở docs/ops/backup-restore-drill.md. Khôi phục toàn bộ production vào một bản D1 cô lập: 96 bảng · 34.978 dòng · 27 MB · 0/96 bảng lệch, restore mất 80 giây.
Đợt này thêm một bước mà đợt 2026-08-15 không có: vân tay nội dung. Đếm dòng khớp vẫn có thể che nội dung hỏng — 15.656 dòng items với prompt bị cắt cụt vẫn đếm ra đúng 15.656. So thêm tổng độ dài cột nội dung + biên khoá cho tám bảng nặng nhất: 8/8 khớp.
Bản thân đợt diễn tập cũ cũng đã trở thành bằng chứng sai nếu để nguyên: nó chấm trên 79 bảng / 3,4 MB, trong khi hệ hôm nay là 96 bảng / 27 MB. Vì vậy luật đọc chỉ báo AS-04.5.5 được siết lại trong audit-standard: đợt gần nhất phải KHÔNG cũ hơn đợt migration lớn gần nhất.
A13 — cổng chất lượng nội dung: cổng đã dựng, khoản nợ đã đo được, AS-10.4.1 vẫn chưa PASS
Ba mảnh trong SRC-507 (workers/api/src/modules/content/backfill.ts, migrations/0067_items_publish_gate.sql, tab "Content quality" ở Admin → Ops).
Điều quan trọng nhất là cái nó không làm: chấm bù chạy evaluator máy rule-engine@1, tức đúng MỘT lượt, trong khi PUBLISH_MIN_EVALUATORS = 2. Ghi evaluator_count = 1 là ghi đúng; ghi 2 để cổng xanh là bịa ra một lượt chấm chưa từng xảy ra — đúng kiểu hỏng mà cả AS-06 sinh ra để chặn. Nên sau khi chạy hết, AS-10.4.1 vẫn KHÔNG PASS, nhưng lý do đổi từ "không đo được" sang "đo được, còn thiếu evaluator thứ hai". Hai tình trạng đó khác hẳn nhau và không nên gộp làm một dòng đỏ giống nhau.
Một con số trong báo cáo này đã cũ: §8 ghi 11.336 item chưa chấm; đo lại production ngày 2026-08-22 là 15.575. Kho lớn thêm sau các đợt nạp nội dung ở §12. Con số cũ không sai lúc chấm, nhưng ai đọc lại để đối chiếu thì cần biết mốc đúng.
| Đo trên production | 2026-08-20 | 2026-08-22 |
|---|---|---|
Item published chưa có hồ sơ chất lượng | 11.336 | 15.575 |
| Item có ≥ 2 evaluator | 0 | 0 |
Item ở trạng thái candidate | 0 | 0 |
Hai việc còn phải làm tay, không tự chạy được: (1) áp 0067 qua deploy-api.yml; (2) bấm "Chấm bù tới hết" ở Admin → Ops → Content quality. Trigger 0067 chỉ chặn dòng MỚI, nó không dọn hộ 15.575 dòng cũ.