---
url: https://docs.nemo12.com/quality/audits/2026-08-15.md
description: >-
  Audit #001 ngày 15.08.2026, lần chấm đầu theo Audit Standard: tổng kết, 15 chỉ
  báo chặn release, chi tiết theo bộ và hành động sinh ra.
---

# Audit #001 — 2026-08-15

Chấm theo [Audit Standard AS-01..AS-10](../audit-standard/index.md) trên commit `57dc4fa`, branch `main`, cộng production thật (D1 `nemo12-platform` remote, 9 worker đang chạy).

## 1. Tổng kết

| Bộ | PASS/25 | % | Mức |
| --- | --- | --- | --- |
| AS-01 Tài liệu & Đóng vết | 20/25 | 80% | Vững |
| AS-02 Yêu cầu & Sản phẩm | 13/25 | 52% | Đang dựng |
| AS-03 Kiến trúc & Hợp đồng | 15/25 | 60% | Đang dựng |
| AS-04 Dữ liệu & Migration | 10/25 | 40% | Sơ khai |
| AS-05 Trí tuệ học tập | 13/25 | 52% | Đang dựng |
| AS-06 Nội dung & Tri thức | 5/25 | 20% | Sơ khai |
| AS-07 Bảo mật & Riêng tư | 10/25 | 40% | Sơ khai |
| AS-08 Tin cậy & Vận hành | 6/25 | 24% | Sơ khai |
| AS-09 Trải nghiệm & DS | 6/25 | 24% | Sơ khai |
| AS-10 AI Governance | 10/25 | 40% | Sơ khai |
| **Toàn hệ** | **108/250** | **43%** | **Sơ khai** |

```text
AS-01 ████████████████░░░░  80%
AS-03 ████████████░░░░░░░░  60%
AS-02 ██████████░░░░░░░░░░  52%
AS-05 ██████████░░░░░░░░░░  52%
AS-04 ████████░░░░░░░░░░░░  40%
AS-07 ████████░░░░░░░░░░░░  40%
AS-10 ████████░░░░░░░░░░░░  40%
AS-08 █████░░░░░░░░░░░░░░░  24%
AS-09 █████░░░░░░░░░░░░░░░  24%
AS-06 ████░░░░░░░░░░░░░░░░  20%
```

**Điều kiện release: KHÔNG ĐẠT** — 15/26 chỉ báo 🔴 hỏng, 6 bộ dưới 60%, điểm hệ 43% < 70%.

### Đọc con số này cho đúng

43% **không** có nghĩa "hệ hỏng 57%". Nghĩa của nó theo luật L2/L3: hơn một nửa số chỉ báo **chưa chứng minh được** tại thời điểm chấm — hoặc vì phần đó chưa xây (quality profile của item, Context Builder, consent flow), hoặc vì có xây mà chưa có bằng chứng chạy (engine_runs rỗng), hoặc vì chưa ai đi rà (contrast WCAG, từng màn hình theo luật tối giản).

Thứ đang chạy thì chạy khá tốt: 102 endpoint đều có zod schema và đều dưới `/v1`, 0 secret trong source lẫn git history, 0 import chéo giữa 19 module, 57 test xanh, typecheck sạch, docs đóng vết 2 chiều PASS. Cái yếu nằm ở **lớp chứng minh** — CI không chạy test, không có audit log truy cập, không có bản ghi engine/workflow run, nội dung chưa có vòng đời chất lượng.

## 2. 🔴 Chặn release — 15 chỉ báo

| Chỉ báo | Sự thật quan sát được | Ảnh hưởng |
| --- | --- | --- |
| **AS-04.1.1** Một sequence migration, không trùng số | `migrations/` có **hai file số 0022**: `0022_user_avatar.sql` và `0022_whale_country_detail.sql` | `wrangler d1 migrations apply` phụ thuộc thứ tự tên file — môi trường mới có thể áp sai thứ tự hoặc bỏ sót một file |
| **AS-07.2.1** Authz backend mọi truy cập learner data | `canAccessLearner()` chỉ xuất hiện ở `mentor`, `models`, `exams`; các module `progress`, `portraits`, `retention`, `learning`, `parent` chưa chứng minh được có chặn | Một learner/parent có session hợp lệ có thể đọc dữ liệu learner khác |
| **AS-07.2.3** Parent chỉ truy cập learner trong family — có test | Không có file test nào cho phân quyền (5 test file: runlog, goals, retention×2, planning) | Không có lưới an toàn khi refactor authz |
| **AS-07.1.1** Mọi endpoint không public đều yêu cầu xác thực | 102 path, chỉ 81 tham chiếu `requireSession` → **21 path chưa chứng minh** là public có chủ đích | Có thể có endpoint learner data mở |
| **AS-07.3.2** Đồng thuận parent-first | Không có bảng/luồng consent nào trong 69 bảng production | Rủi ro pháp lý dữ liệu trẻ em |
| **AS-06.3.1** Nội dung production không sửa trực tiếp | Bảng `items` (2.146 dòng) **không có cột lifecycle** (candidate/published) lẫn `created_at` | Sửa nội dung = sửa thẳng production, không rollback được |
| **AS-06.4.2 / AS-06.4.3** Đề thật: URL nguồn, lời giải tự biên soạn | 10/10 đề đều `source=generated` — **chưa có đề thật nào**. Schema có `source_ref`, `verified` nhưng chưa dùng | REQ-EXAM chưa thực sự chạy |
| **AS-10.3.1** Context Builder là đường duy nhất AI chạm learner data | Không tồn tại Context Builder trong `workers/api/src/` | Khi AI bắt đầu đọc learner data sẽ không có chốt chặn |
| **AS-10.3.5** Dữ liệu learner A không lọt vào context B | Không có test nào | — |
| **AS-10.4.1** Nội dung AI không publish thẳng | `coral/routes.ts:283` — AI sinh experience rồi **ghi thẳng vào DB**, không qua ngưỡng đánh giá | Nội dung sai có thể tới thẳng học sinh |
| **AS-01.4.1** `gen:reference` không tạo diff | Chạy lệnh → diff **91 dòng** ở `api.md` + `data-dictionary.md` | Trang reference đang nói sai về hệ thật |
| **AS-03.2.4** Không breaking change trong `/v1` | Không có contract diff nào chạy ở đâu | Không biết mình có phá client hay không |
| **AS-04.1.4** Migration tương thích ngược | Không có dry-run trong CI; 6 migration không `IF NOT EXISTS` | Deploy có thể gãy giữa chừng |
| **AS-09.3.1** WCAG AA contrast | Chưa ai đo | Có thể có chữ học sinh không đọc được |

### 🔴 đã PASS (11) — giữ nguyên, đừng làm hỏng

`AS-03.4.1` không secret hardcode · `AS-04.2.2` email không làm khóa · `AS-05.2.2` self-report chỉ vào evidence · `AS-05.4.1` mastery không tự decay · `AS-07.2.2` RBAC không so email · `AS-07.5.1` git history sạch secret · `AS-07.5.2` không debug/seed endpoint · `AS-08.2.2` DLQ đủ · `AS-08.4.3` migration trước code · `AS-10.1.1` 100% AI qua Gateway · `AS-10.1.2` không probe-fallback.

## 3. Chi tiết theo bộ

Ký hiệu: **✅** PASS · **❌** KHÔNG PASS · 🔴 chỉ báo chặn release.

### AS-01 — Tài liệu & Đóng vết · 20/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 1.1.1 md ngoài docs/ | ✅ | chỉ `README.md`, `.claude/skills/*`, `apps/pearl/content/*` (nội dung app); worktree cũ bị git ignore |
| 1.1.2 dòng SRC đủ | ✅ | intake.md 110 dòng, đủ ngày + tóm tắt + kết quả |
| 1.1.3 SRC đã canonical hóa | ✅ | spot-check SRC-100..108 đều có PRD/SDD tương ứng |
| 1.1.4 SRC liên tục không trùng | ❌ | **SRC-059 và SRC-060 mỗi số có 2 dòng** (110 dòng / 108 số) |
| 1.1.5 không đặc tả ngoài docs/ | ✅ | rà toàn repo |
| 1.2.1 frontmatter đủ file | ✅ | `check-docs.mjs`: 57 docs sạch |
| 1.2.2 đủ 8 trường bắt buộc | ✅ | vòng lặp kiểm 8 khóa × 57 file: 0 thiếu |
| 1.2.3 id duy nhất | ✅ | script |
| 1.2.4 type hợp lệ | ✅ | convention/index/prd/quality/reference/sdd |
| 1.2.5 status hợp lệ | ✅ | không có file deprecated |
| 1.3.1 REQ có SDD | ✅ | check-docs PASS |
| 1.3.2 REQ có QG | ✅ | check-docs kiểm cột QG |
| 1.3.3 sources trỏ SRC tồn tại | ✅ | script |
| 1.3.4 không doc mồ côi | ✅ | 0 orphan |
| 1.3.5 US ↔ REQ hai chiều | ❌ | 66 US cho 224 REQ ✔; không có kiểm tự động chiều REQ MUST → US/WF |
| 1.4.1 gen:reference không diff | ❌ 🔴 | diff **91 dòng** (api.md 14, data-dictionary.md 80) |
| 1.4.2 bảng D1 có trong dictionary | ❌ | thiếu bảng của migration 0026/0028/0029/0030 |
| 1.4.3 route có trong api.md | ❌ | thiếu 14 dòng endpoint |
| 1.4.4 event có trong events.md | ✅ | events.md không lệch |
| 1.4.5 dấu "sinh tự động" | ✅ | `⚙️ Trang này sinh tự động…` đầu mỗi trang |
| 1.5.1 last_reviewed ≤ 90 ngày | ✅ | sớm nhất 2026-08-13 |
| 1.5.2 sửa lớn thì tăng version | ✅ | spot-check git log |
| 1.5.3 không link gãy | ✅ | check-docs |
| 1.5.4 ngày tuyệt đối | ✅ | 8 hit "gần đây/sắp tới" đều là ngôn ngữ UI, không phải mốc thời gian |
| 1.5.5 quyết định ✍️ | ✅ | open-questions/index.md |

### AS-02 — Yêu cầu & Sản phẩm · 13/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 2.1.1 ID đúng scheme | ✅ | 259 REQ khớp `REQ-<nhóm>-xx` |
| 2.1.2 REQ testable | ❌ | còn REQ dùng từ mơ hồ (L4: một phản ví dụ là đủ) |
| 2.1.3 có priority | ❌ | **4 REQ priority `M?`**: MEN-04, SCH-04, SCH-05, EXAM-05 |
| 2.1.4 có nguồn | ✅ | mọi REQ có SRC/User+ngày/FEAT/Q |
| 2.1.5 không trùng nghĩa | ❌ | chưa rà — không bằng chứng (L3) |
| 2.2.1 US đúng format | ✅ | 66/66 có `As a **…**, I want…, so that…` |
| 2.2.2 persona hợp lệ | ✅ | Nemo/Marlin/Dolphin/Staff |
| 2.2.3 US có acceptance criteria | ❌ | **bảng US chỉ 3 cột (ID · story · REQ)** — không có cột AC |
| 2.2.4 AC mô tả kết quả người dùng | ❌ | chưa có AC nên không đánh giá được |
| 2.2.5 US MUST → màn hình thật | ❌ | chưa map |
| 2.3.1 persona có JTBD | ✅ | parent-jtbd.md + PRD §personas |
| 2.3.2 JTBD có REQ | ✅ | traceability |
| 2.3.3 3 cộng đồng có onboarding | ❌ | có `learner-onboarding`, `parent-onboarding`; **Dolphins chưa có WF onboarding** |
| 2.3.4 6 school có mô hình | ✅ | SDD-011 |
| 2.3.5 màn hình nào cũng thuộc persona | ❌ | chưa rà ngược từ route |
| 2.4.1 REQ ✔ có artifact | ✅ | 224 REQ ✔ đều có cột SDD + QG |
| 2.4.2 tính năng nào cũng có REQ | ❌ | chưa rà ngược |
| 2.4.3 backlog tách bạch | ✅ | FEAT/CC nằm ở legacy-feature-inventory |
| 2.4.4 FEAT legacy phân loại | ✅ | legacy-feature-inventory |
| 2.4.5 REQ MUST ⏳ có lý do | ❌ | **20 REQ ⏳** không kèm ghi chú lý do/ngày |
| 2.5.1 Q có ID + trạng thái | ✅ | Q-001..106 |
| 2.5.2 ✍️ có lý do + ngày | ✅ | open-questions |
| 2.5.3 ✍️ không mâu thuẫn | ❌ | chưa rà |
| 2.5.4 việc chờ tay tập trung | ✅ | open-questions + README §Còn chờ |
| 2.5.5 Q đã trả lời vào canonical | ✅ | spot-check Q-069, Q-084, Q-097 |

### AS-03 — Kiến trúc & Hợp đồng · 15/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 3.1.1 module đúng cấu trúc | ✅ | 19 module trong `workers/api/src/modules/` |
| 3.1.2 không import chéo module | ✅ | **0** kết quả grep import chéo |
| 3.1.3 frontend qua client chung | ✅ | mỗi app có `src/api.ts` |
| 3.1.4 DS là nguồn duy nhất | ✅ | không fork component; pearl bắc cầu `--vp-*` → token |
| 3.1.5 cấu trúc khớp tài liệu | ✅ | khớp README + SDD-001 |
| 3.2.1 OpenAPI sinh từ router | ✅ | không có file openapi viết tay |
| 3.2.2 route có zod schema | ✅ | 102 route qua `createRoute`, 104 khối `responses` |
| 3.2.3 route dưới `/v1` | ✅ | **102/102** path bắt đầu `/v1` |
| 3.2.4 không breaking `/v1` | ❌ 🔴 | không có contract diff chạy ở đâu |
| 3.2.5 error taxonomy | ✅ | `shared/errors.ts` + `ErrorCode`, không rò stack |
| 3.3.1 event có schema + version | ❌ | chưa chứng minh version từng event |
| 3.3.2 event có consumer | ❌ | chưa đối chiếu |
| 3.3.3 tên event theo quy ước | ❌ | chưa kiểm |
| 3.3.4 payload không PII | ❌ | chưa kiểm |
| 3.3.5 queue + DLQ khớp reference | ✅ | `EVENTS` producer + consumer + `nemo12-events-dlq` |
| 3.4.1 không secret hardcode | ✅ 🔴 | grep pattern key/secret/token ≥16 ký tự: **0** |
| 3.4.2 không hardcode domain rải rác | ❌ | `https://api.nemo12.com` lặp ở ≥6 app (là fallback của `VITE_API_URL`) |
| 3.4.3 env khai kiểu | ✅ | `env.ts` khai 10 binding/biến |
| 3.4.4 CI verify binding | ❌ | **không workflow nào verify binding** (RISK-026) |
| 3.4.5 reference/config đủ | ❌ | chưa đối chiếu đủ |
| 3.5.1 mỗi app có workflow | ✅ | 9 workflow, có path filter |
| 3.5.2 worker có domain tường minh | ✅ | wrangler config |
| 3.5.3 app ↔ workflow đủ đôi | ✅ | 9 ↔ 9 |
| 3.5.4 migration trước code | ✅ | `deploy-api.yml:19` trước `:25` |
| 3.5.5 README khớp URL thật | ❌ | README liệt kê **4 URL**, thực tế **9** (thiếu coral, pearl, admin, mentors, docs) |

### AS-04 — Dữ liệu & Migration · 10/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 4.1.1 một sequence, không trùng số | ❌ 🔴 | **0022 xuất hiện 2 lần** |
| 4.1.2 idempotent | ❌ | 6 file không `IF NOT EXISTS`: 0007, 0012, 0015, 0022_user_avatar, 0025, 0026 |
| 4.1.3 không DML destructive trộn DDL | ✅ | chỉ 0007 có `DROP TABLE IF EXISTS` trên bảng rỗng (tái cấu trúc DDL) |
| 4.1.4 tương thích ngược | ❌ 🔴 | không dry-run CI, không chứng minh |
| 4.1.5 mọi migration đã áp | ✅ | 31 file / **31 dòng `d1_migrations`**, mới nhất `0030_context_events.sql` |
| 4.2.1 mọi bảng có PK | ✅ | 0 bảng thiếu `PRIMARY KEY` |
| 4.2.2 email không làm khóa | ✅ 🔴 | `users.id TEXT PRIMARY KEY`, email chỉ `UNIQUE` |
| 4.2.3 FK có ràng buộc | ✅ | `REFERENCES` trong schema |
| 4.2.4 timestamps chuẩn hóa | ❌ | **31 bảng không có `created_at`** (dùng `started_at`, `recorded_at`, hoặc không có) |
| 4.2.5 không JSON blob thay truy vấn | ❌ | `items.options_json`, nhiều `*_json` không index/không tách trường |
| 4.3.1 bảng có trong data-dictionary | ❌ | dictionary trong repo lệch 80 dòng so với schema thật |
| 4.3.2 cột có ý nghĩa nghiệp vụ | ❌ | chưa kiểm từng cột |
| 4.3.3 không bảng ma | ✅ | không có bảng trong dictionary mà thiếu ở D1 |
| 4.3.4 enum liệt kê đủ | ✅ | `CHECK (… IN (…))` khắp schema |
| 4.3.5 state machine được vẽ | ❌ | chưa đối chiếu đủ thực thể |
| 4.4.1 seed bằng script | ✅ | 40+ script trong `scripts/` |
| 4.4.2 seed idempotent | ❌ | chưa chạy lại kiểm |
| 4.4.3 không bản ghi mồ côi | ✅ | `items WHERE node_id IS NULL` = **0** |
| 4.4.4 không trùng khóa nghiệp vụ | ❌ | chưa kiểm đủ rộng |
| 4.4.5 song ngữ đủ cặp | ✅ | `skill_nodes`: **274/274** có `title_en`, `module_en`, `unit_en` |
| 4.5.1 chính sách retention dữ liệu | ❌ | chưa khai báo |
| 4.5.2 đường xóa dữ liệu | ❌ | không có endpoint/đặc tả |
| 4.5.3 policy giữ model version | ❌ | `learner_model_versions` = **0 dòng** |
| 4.5.4 lý do từng trường PII | ❌ | chưa ghi |
| 4.5.5 backup đã thử | ❌ | chưa có |

### AS-05 — Trí tuệ học tập · 13/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 5.1.1 model có trang mô tả | ✅ | `reference/models.md` |
| 5.1.2 version ghi vào bản ghi | ❌ | `learner_model_versions` = **0 dòng** |
| 5.1.3 snapshot theo thời gian | ❌ | 0 dòng |
| 5.1.4 model nào cũng có trang | ✅ | models.md phủ Learner/Goal/Context/Retention/Planning |
| 5.1.5 đổi thuật toán → version mới | ✅ | `plan-v1` trong `models/planning.ts` |
| 5.2.1 model từ evidence có nguồn | ✅ | `learner_evidence` = **60 dòng** |
| 5.2.2 self-report chỉ qua evidence | ✅ 🔴 | REQ-LRN-15: self-report vào Evidence Registry tier .50 |
| 5.2.3 evidence có tier | ✅ | tier .50/.60 theo source |
| 5.2.4 chỉ lần đầu là evidence | ✅ | SRC-103: lần sửa không gửi `/answer` |
| 5.2.5 engine run có lịch sử | ❌ | `engine_runs` = **0 dòng** (bảng có, chưa ai ghi) |
| 5.3.1 engine có unit test | ❌ | **5 test file** cho 19 module: goals, retention×2, planning, runlog. Assessment/Recommendation/Readiness/Context **không có test** |
| 5.3.2 không source-regex test | ✅ | 57 test đều test hành vi |
| 5.3.3 test ca biên/rỗng | ❌ | chưa phủ mọi engine |
| 5.3.4 test stopping criteria | ❌ | không có |
| 5.3.5 test chặn merge trong CI | ❌ | **không workflow nào chạy test** |
| 5.4.1 mastery không tự decay | ✅ 🔴 | `retention/periodic.test.ts` test bất biến |
| 5.4.2 retention có decay | ✅ | `retention/engine.test.ts` 27 test |
| 5.4.3 retention cập nhật định kỳ | ✅ | cron 21:00 UTC → WF-17 |
| 5.4.4 job chỉ ghi trường phái sinh | ✅ | test bất biến anchor |
| 5.4.5 tham số review window ở reference | ✅ | `reference/retention-model.md` |
| 5.5.1 recommendation có reason | ✅ | SDD-002 + UI |
| 5.5.2 ghi model/prompt version | ❌ | `learner_model_versions` rỗng → không chứng minh được |
| 5.5.3 plan có diff + vì sao | ✅ | `planning.ts` + 8 test + trang `/ke-hoach` |
| 5.5.4 output có confidence | ❌ | chưa chứng minh phủ mọi output quan trọng |
| 5.5.5 người dùng xem lịch sử version | ❌ | không có version nào để xem |

### AS-06 — Nội dung & Tri thức · 5/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 6.1.1 node có subject/grade/level | ✅ | `skill_nodes` có đủ 3 cột |
| 6.1.2 không node mồ côi | ✅ | 274/274 có `strand` + `unit` |
| 6.1.3 tiên quyết không chu trình | ❌ | chưa chạy kiểm chu trình trên `skill_edges` |
| 6.1.4 unit đủ experience tối thiểu | ❌ | chưa kiểm 3 assessment + 6 learning mỗi unit |
| 6.1.5 tên đủ cặp vi/en | ✅ | 274/274 |
| 6.2.1 quality profile 8 chiều | ❌ | **bảng `items` không có cột chất lượng nào** |
| 6.2.2 mỗi chiều có evidence | ❌ | không có |
| 6.2.3 multi-evaluator variance | ❌ | không có |
| 6.2.4 item link node + dạng bài | ✅ | `node_id NOT NULL` + `role CHECK IN (canonical/variant/boundary/discriminator)` |
| 6.2.5 item bị report vào hàng đợi | ❌ | có bảng `content_reports`, chưa nối hàng đợi rà soát |
| 6.3.1 không sửa production trực tiếp | ❌ 🔴 | `items` không có lifecycle candidate/published |
| 6.3.2 candidate có trạng thái | ❌ | không có |
| 6.3.3 publish theo ngưỡng | ❌ | không có |
| 6.3.4 lịch sử ai publish khi nào | ❌ | `items` không cả `created_at` |
| 6.3.5 rollback nội dung | ❌ | không có |
| 6.4.1 đề thật đủ provenance | ❌ | **10/10 đề `source=generated`** — chưa có đề thật |
| 6.4.2 lưu URL không lưu file | ❌ 🔴 | schema có `source_ref` nhưng chưa dùng |
| 6.4.3 lời giải tự biên soạn | ❌ 🔴 | chưa có đề thật |
| 6.4.4 crawl robots/ToS-aware | ❌ | chưa chạy crawl |
| 6.4.5 đề authentic bất biến | ❌ | chưa có |
| 6.5.1 media qua moderation | ❌ | chưa chạy |
| 6.5.2 media ghi nguồn/giấy phép | ❌ | chưa có |
| 6.5.3 không dùng ảnh bên thứ ba | ✅ | mascot vẽ tay bằng SVG trong repo |
| 6.5.4 media đúng kích thước | ❌ | chưa kiểm |
| 6.5.5 ảnh trẻ em có đồng thuận | ❌ | chưa có |

### AS-07 — Bảo mật, Riêng tư & Tuân thủ · 10/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 7.1.1 endpoint không public phải auth | ❌ 🔴 | 102 path / 81 tham chiếu `requireSession` → 21 chưa chứng minh |
| 7.1.2 token có hạn + thu hồi | ✅ | `resolveSession` + `rotated_token` |
| 7.1.3 verify audience/issuer | ❌ | chưa kiểm |
| 7.1.4 khu nội bộ có Access | ✅ | dolphin + coral tạo trong ngày, ba cổng đều 302 sang Access (§5) |
| 7.1.5 không backdoor | ✅ | rà `index.ts` + middleware |
| 7.2.1 authz backend learner data | ❌ 🔴 | `canAccessLearner` chỉ ở mentor/models/exams |
| 7.2.2 RBAC không so email | ✅ 🔴 | **0** so sánh email trong authz |
| 7.2.3 parent↔family có test | ❌ 🔴 | không có test authz |
| 7.2.4 mentor bắt buộc audit log | ❌ | `mentor/routes.ts` **không ghi audit_log** |
| 7.2.5 permissions khớp code | ❌ | chưa đối chiếu |
| 7.3.1 mỗi trường trẻ em có mục đích | ❌ | chưa ghi |
| 7.3.2 consent parent-first | ❌ 🔴 | không có bảng/luồng consent |
| 7.3.3 chỉ learner ghi phần của mình | ✅ | `PUT /portraits/{id}/learner-sections` role-gated (SRC-106) |
| 7.3.4 không chia sẻ bên thứ ba | ✅ | chỉ Cloudflare AI qua Gateway |
| 7.3.5 parent thấy dữ liệu dùng để quyết | ❌ | chưa có |
| 7.4.1 log truy cập learner data | ❌ | chỉ **3 điểm** ghi `audit_log`, đều là identity (user.created, learner.invited, learner.joined) |
| 7.4.2 log đủ ai/gì/khi/từ đâu | ❌ | `audit_log` không có `created_at`, không có IP |
| 7.4.3 log không chứa nội dung nhạy cảm | ✅ | chỉ lưu `target_type` + `target_id` |
| 7.4.4 log không sửa được | ❌ | không có cơ chế |
| 7.4.5 truy vấn log điều tra | ❌ | không có endpoint |
| 7.5.1 không secret trong git history | ✅ 🔴 | quét toàn bộ lịch sử: **0** |
| 7.5.2 không debug/seed endpoint prod | ✅ 🔴 | **0** path `/v1/debug|seed|test` |
| 7.5.3 validate schema trước DB | ✅ | zod ở 102 route |
| 7.5.4 escape nội dung người dùng | ✅ | 1 `dangerouslySetInnerHTML` nhưng nội dung do engine sinh, không phải input người dùng |
| 7.5.5 rate limit endpoint tốn kém | ❌ | **0** rate limit — kể cả route AI và đăng nhập |

### AS-08 — Tin cậy & Vận hành · 6/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 8.1.1 khai availability tier | ❌ | chưa khai |
| 8.1.2 trả lời 5 câu production-ready | ❌ | chưa viết |
| 8.1.3 "hỏng thì người dùng thấy gì" | ❌ | chưa định nghĩa |
| 8.1.4 health phản ánh phụ thuộc thật | ✅ | `index.ts:92` chạy `SELECT 1` trên D1 |
| 8.1.5 không TODO/FIXME chặn đường | ✅ | **0** trong toàn source |
| 8.2.1 consumer idempotent | ❌ | chưa kiểm |
| 8.2.2 queue có DLQ | ✅ 🔴 | `dead_letter_queue: nemo12-events-dlq` |
| 8.2.3 replay DLQ | ❌ | chưa có quy trình |
| 8.2.4 retry có giới hạn + backoff | ❌ | chưa khai `max_retries` |
| 8.2.5 cron an toàn khi chạy chồng | ❌ | chưa có khóa |
| 8.3.1 observability mọi worker | ✅ | **9/9** wrangler config bật |
| 8.3.2 log có level + request id | ❌ | chưa có |
| 8.3.3 5xx ghi đủ ngữ cảnh | ❌ | chưa kiểm |
| 8.3.4 chỉ số engine/queue | ❌ | chưa có |
| 8.3.5 biết workflow đã chạy chưa | ❌ | `workflow_runs` = **0 dòng** |
| 8.4.1 CI typecheck + lint + test | ❌ | **không workflow nào chạy** (chỉ deploy-docs chạy check:docs) |
| 8.4.2 path filter đúng | ✅ | 9 workflow đều có |
| 8.4.3 migration trước code | ✅ 🔴 | `deploy-api.yml` |
| 8.4.4 rollback nhanh | ❌ | chưa ghi quy trình |
| 8.4.5 không bước tay bắt buộc | ❌ | AI Gateway còn phải tạo tay (Access đã xong 2026-08-15) |
| 8.5.1 phụ thuộc ngoài có fallback | ❌ | AI lỗi → 503, không fallback |
| 8.5.2 lỗi ngoài không sập trang chính | ❌ | chưa thử |
| 8.5.3 timeout tường minh | ❌ | **0** `AbortSignal.timeout` / `signal:` |
| 8.5.4 cache dữ liệu đọc nhiều | ❌ | chưa có |
| 8.5.5 thông điệp người dùng hiểu | ✅ | `errorResponse` trả tiếng Việt tự nhiên |

### AS-09 — Trải nghiệm & Design System · 6/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 9.1.1 một hành động chính mỗi màn | ❌ | chưa rà từng màn (L3) |
| 9.1.2 full-width không cột thừa | ❌ | chưa rà |
| 9.1.3 element tối thiểu | ❌ | chưa rà |
| 9.1.4 hình hơn chữ | ❌ | chưa rà |
| 9.1.5 trang chủ là hub | ❌ | chưa rà |
| 9.2.1 chỉ dùng token, không hex | ❌ | **1.340 mã hex** trong `apps/*/src` (phần lớn là SVG art, nhưng có cả `Learning.tsx`) |
| 9.2.2 không fork component | ✅ | mỗi component dùng chung một định nghĩa |
| 9.2.3 không CSS per-page | ❌ | chưa rà |
| 9.2.4 theme chỉ đổi accent | ✅ | `.theme-pearl` trong `tokens/base.css` |
| 9.2.5 sàn 14px | ❌ | **79 chỗ dùng `text-xs` (12px)** |
| 9.3.1 WCAG AA contrast | ❌ 🔴 | chưa đo |
| 9.3.2 focus state nhìn thấy | ❌ | chưa thử |
| 9.3.3 touch target ≥44px | ❌ | chưa đo |
| 9.3.4 ảnh có alt | ✅ | **5/5** `<img>` có `alt` |
| 9.3.5 điều hướng bàn phím | ❌ | chưa thử |
| 9.4.1 admin tiếng Anh | ✅ | UI string tiếng Anh (chỉ comment code tiếng Việt) |
| 9.4.2 không lẫn 2 ngôn ngữ | ❌ | chưa rà |
| 9.4.3 thuật ngữ theo glossary | ❌ | chưa đối chiếu |
| 9.4.4 lỗi viết cho người dùng | ✅ | `errorResponse` |
| 9.4.5 chữ không lặp nội dung hình | ❌ | chưa rà |
| 9.5.1 load dưới ngưỡng | ❌ | chưa khai ngưỡng |
| 9.5.2 không layout shift | ❌ | chưa đo |
| 9.5.3 có loading/empty/error | ❌ | chưa rà |
| 9.5.4 ảnh đúng kích thước | ❌ | chưa đo |
| 9.5.5 thao tác chính phản hồi ngay | ✅ | SRC-103: chấm ở client, không chờ round-trip |

### AS-10 — AI Governance & Chi phí · 10/25

| Chỉ báo | | Bằng chứng |
| --- | --- | --- |
| 10.1.1 100% qua AI Gateway | ✅ 🔴 | 2/2 điểm gọi `c.env.AI.run(..., { gateway: { id: c.env.AI_GATEWAY_ID } })` |
| 10.1.2 không probe-fallback | ✅ 🔴 | không có vòng dò model |
| 10.1.3 model id tường minh | ✅ | `@cf/meta/llama-3.3-70b-instruct-fp8-fast` |
| 10.1.4 không gọi AI từ frontend | ✅ | **0** trong `apps/*/src` |
| 10.1.5 mọi điểm gọi có trong ai-registry | ✅ | `reference/ai-registry.md` |
| 10.2.1 prompt trong registry | ❌ | **prompt viết inline** trong `coral/routes.ts` |
| 10.2.2 prompt có version | ✅ | `PROMPT_VERSION` lưu vào metadata |
| 10.2.3 đổi prompt = version mới | ❌ | chưa chứng minh |
| 10.2.4 prompt ghi mục đích/ràng buộc | ❌ | không có registry |
| 10.2.5 output có schema + validate | ❌ | `z.object({ data: z.any() })` — không schema thật |
| 10.3.1 Context Builder duy nhất | ❌ 🔴 | **không tồn tại Context Builder** |
| 10.3.2 context tối thiểu hóa | ❌ | không có builder |
| 10.3.3 không gửi định danh trẻ | ✅ | prompt chỉ chứa node/blueprint |
| 10.3.4 lưu input_ref | ✅ | metadata lưu model + prompt_version + blueprint_version |
| 10.3.5 test A không lọt sang B | ❌ 🔴 | không có test |
| 10.4.1 AI không publish thẳng | ❌ 🔴 | `coral/routes.ts:283` ghi thẳng vào DB |
| 10.4.2 multi-evaluator | ❌ | chưa có |
| 10.4.3 spot-check có tỷ lệ | ❌ | chưa ghi |
| 10.4.4 khẳng định có nguồn/đánh dấu | ❌ | chưa có |
| 10.4.5 learner báo sai → chỉnh nội dung | ❌ | `content_reports` chưa nối vòng |
| 10.5.1 ước tính chi phí | ❌ | chưa ghi |
| 10.5.2 xem chi phí theo thời gian | ❌ | **AI Gateway `nemo12` chưa tạo** |
| 10.5.3 hạn mức/cảnh báo | ❌ | chưa có |
| 10.5.4 tác vụ nền có giới hạn | ❌ | chưa có |
| 10.5.5 không vòng lặp AI vô hạn | ✅ | AI chỉ gọi từ route staff/admin |

## 4. Hành động sinh ra từ audit này

Mỗi KHÔNG PASS cần một hành động. Nhóm theo chủ đề, xếp theo mức chặn:

| # | Hành động | Đóng được chỉ báo | Ước lượng |
| --- | --- | --- | --- |
| A | Đổi tên `0022_whale_country_detail.sql` → `0031_…`, thêm `IF NOT EXISTS` cho 6 migration | AS-04.1.1 🔴, 4.1.2 | 30 phút |
| B | Thêm `canAccessLearner` cho mọi module chạm learner data + test parent↔family + rà 21 endpoint chưa rõ | AS-07.1.1 🔴, 7.2.1 🔴, 7.2.3 🔴 | 1 ngày |
| C | Thêm typecheck + test + check:docs + gen:reference gate vào CI mọi workflow | AS-05.3.5, 8.4.1, 1.4.1 🔴, 3.2.4 🔴 | nửa ngày |
| D | Ghi `engine_runs` / `workflow_runs` / `learner_model_versions` thật khi engine chạy | AS-05.1.2, 5.1.3, 5.2.5, 5.5.2, 5.5.5, 8.3.5 | 1 ngày |
| E | Vòng đời nội dung cho `items`: cột status + quality profile + created_at + publisher | AS-06.2.1..3, 6.3.1 🔴, 6.3.2..5 | 2 ngày |
| F | Context Builder + ngưỡng đánh giá trước khi AI ghi nội dung | AS-10.3.1 🔴, 10.3.2, 10.3.5 🔴, 10.4.1 🔴 | 2 ngày |
| G | Audit log cho mọi truy cập learner data (mentor bắt buộc) + endpoint truy vấn | AS-07.2.4, 7.4.1, 7.4.2, 7.4.4, 7.4.5 | 1 ngày |
| H | Consent parent-first + chính sách retention/xóa dữ liệu trẻ em | AS-07.3.1, 7.3.2 🔴, 7.3.5, 4.5.1, 4.5.2, 4.5.4 | 2 ngày |
| I | Rà UI theo luật tối giản + đo WCAG AA + bỏ `text-xs` + thay hex bằng token | AS-09.1.\*, 9.2.1, 9.2.5, 9.3.1 🔴, 9.3.2, 9.3.3 | 2 ngày |
| J | Rate limit + timeout + fallback cho phụ thuộc ngoài | AS-07.5.5, 8.5.1, 8.5.3 | nửa ngày |
| K | Sửa sổ sách: SRC-059/060 trùng, 4 REQ `M?`, cột AC cho US, README 9 URL | AS-01.1.4, 2.1.3, 2.2.3, 3.5.5 | nửa ngày |

## 5. Đính chính (2026-08-15)

* **AS-07.1.4** (khu nội bộ có Cloudflare Access) — chấm ❌ dựa trên README §Còn chờ. Lúc audit thì **chỉ `admin.nemo12.com` có Access**; cùng ngày đã tạo nốt app `Nemo12 Dolphin` + `Nemo12 Coral` trên dashboard (SRC-132) và kiểm bằng request thật: cả ba cổng nội bộ đều 302 sang trang login Access. Chỉ báo này là **✅**. Điểm AS-07 thành **11/25 (44%)**, điểm hệ thành **109/250 (44%)**. Mức vẫn *Sơ khai*, số 🔴 hỏng không đổi (7.1.4 không phải 🔴). README cần cập nhật.
* **AS-10.5.2** (xem chi phí AI) — chưa xác minh được gateway `nemo12` có tồn tại trên Cloudflare hay không: `AI_GATEWAY_ID: "nemo12"` đã khai ở `workers/api/wrangler.jsonc:41`, nhưng API token hiện tại không có scope đọc AI Gateway. Giữ ❌ cho tới khi kiểm được trên dashboard.

## 6. Ghi chú phương pháp

* Bằng chứng thu bằng lệnh thật trên commit `57dc4fa`: `check-docs.mjs`, `gen-reference.mjs`, `vitest run` (57 test xanh), `npm run typecheck` (sạch), `wrangler d1 execute --remote` trên D1 production, và grep/rà source.
* Theo **L2** (cấm N/A) và **L3** (không bằng chứng = KHÔNG PASS): chỉ báo cho phần chưa xây và chỉ báo chưa ai đi kiểm đều tính KHÔNG PASS. Ghi chú "chưa rà" / "chưa kiểm" trong cột bằng chứng phân biệt hai loại này để lần audit sau biết đâu là việc **xây** và đâu là việc **chứng minh**.
* AS-09.1 (luật tối giản) và AS-09.3.2/9.3.3/9.3.5 cần một lượt rà bằng mắt + đo trên trình duyệt — chưa làm trong lần này.
