Skip to content

Audit Standard · AS-01 tới AS-03 ​

Một phần của Audit Standard. Chỉ báo AS-01 tài liệu và đóng vết, AS-02 yêu cầu và sản phẩm, AS-03 kiến trúc và hợp đồng API, kèm ngoại lệ tường minh.

AS-01 — Tài liệu & Đóng vết ​

IDChỉ báoCách kiểm
AS-01.1Nguồn duy nhất & sổ tiếp nhận
AS-01.1.1Mọi đặc tả hệ thống nằm trong docs/; không tồn tại bản copy song song "cho AI" / "cho human" ở nơi khácfind . -name "*.md" -not -path "*/node_modules/*" — mọi kết quả ngoài docs/ phải là README gốc hoặc nội dung app (apps/*/content), không phải đặc tả
AS-01.1.2Mỗi chỉ đạo/tài liệu đầu vào có đúng một dòng SRC-xxx trong intake.md, đủ ngày tuyệt đối + tóm tắt + kết quả canonical hóađọc các mảnh docs/intake/src-*.md
AS-01.1.3Không có SRC nào đã tiếp nhận mà nội dung chưa xuất hiện trong ít nhất một PRD/SDD/QGgrep -rn "SRC-<n>" từng SRC id trong docs/ — phải có ≥1 hit ngoài intake.md
AS-01.1.4Số SRC không trùng (lỗ số được phép từ SRC-951; con trỏ "Nguồn tiếp theo" bỏ từ SRC-1339)script: đếm dòng | SRC-\d+ | trong intake.md, so uniq với tổng dòng
AS-01.1.5Không file .md nào ngoài docs/ (trừ README.md gốc và nội dung app) đóng vai trò đặc tả hệ thốngđọc kết quả AS-01.1.1, xác nhận từng file ngoại lệ là nội dung không phải đặc tả
AS-01.2Frontmatter & metadata
AS-01.2.1100% file trong docs/ mở đầu bằng YAML frontmatternode scripts/check-docs.mjs
AS-01.2.2Mọi frontmatter đủ trường bắt buộc: id, type, title, owner, status, version, last_reviewed, ai_readablescript
AS-01.2.3id duy nhất toàn docs, lowercase, khớp vai trò filescript
AS-01.2.4type thuộc tập cho phép (prd/sdd/quality/convention/index/adr/reference/workflow)script
AS-01.2.5status ∈ {draft, active, deprecated}; file deprecated ghi rõ file thay thếscript + đọc file deprecated (nếu có)
AS-01.3Đóng vết hai chiều
AS-01.3.1Mỗi REQ active nằm trong satisfies của ≥1 doc thiết kế (SDD hoặc reference)scripts/check-docs.mjs mục 2
AS-01.3.2Mỗi REQ active có ≥1 QG ở cột QG của PRD-001 §5đọc PRD-001, mọi dòng `
AS-01.3.3Mỗi SDD khai sources trỏ tới SRC tồn tại trong intakescript
AS-01.3.4Không có doc mồ côi: mọi file được liên kết từ index.md hoặc từ một doc khácscript (mục 4 check-docs.mjs bắt link gãy, không bắt file không được trỏ tới — bổ sung: grep -rL đối chiếu danh sách file với danh sách link đích)
AS-01.3.5Mọi US map tới ≥1 REQ, và mọi REQ priority MUST map tới ≥1 US hoặc WFđọc PRD-001 §6
AS-01.4Trang sinh tự động khớp source
AS-01.4.1🔴🚸 npm run gen:reference chạy xong không tạo diff so với HEAD (bỏ qua dòng last_reviewed)npm run gen:reference && git diff --exit-code -I '^last_reviewed: ' -- docs/reference — đã enforce trong ci.yml bước 5
AS-01.4.2Mọi bảng D1 có trong migrations/ đều xuất hiện ở reference/data-dictionary.mdso bảng — script gen-reference.mjs tự sinh, đối chiếu số bảng ở đầu file
AS-01.4.3Mọi route đăng ký trong router xuất hiện ở reference/api.mdso bảng — npm run contract:diff --print đối chiếu route count
AS-01.4.4Mọi event type phát trong code xuất hiện ở reference/events.mdso EVENT_REGISTRY (workers/api/src/shared/events.ts) với bảng trong events.md
AS-01.4.5Trang sinh tự động ghi rõ "sinh tự động — không sửa tay" ở đầu fileđọc — dòng ⚙️ Trang này sinh tự động…
AS-01.5Tươi mới & vòng đời
AS-01.5.1Mọi doc active có last_reviewed cách ngày audit ≤ 90 ngàyscript
AS-01.5.2Mỗi lần sửa nội dung đáng kể có tăng version trong cùng commitgit log -p -- <file> spot-check ≥5 commit sửa nội dung
AS-01.5.3Không có internal link gãy trong toàn bộ docsnode scripts/check-docs.mjs mục 4
AS-01.5.4Ngày viết tuyệt đối; không có "tuần trước / gần đây / sắp tới" trong doc activegrep -rn "tuần trước|gần đây|sắp tới" docs/ — mọi hit phải là ngôn ngữ UI hiển thị cho người dùng, không phải mốc thời gian tài liệu
AS-01.5.5Mọi quyết định AI tự quyết mang ký hiệu ✍️ và nằm trong open-questions/index.mdđọc open-questions/index.md

AS-02 — Yêu cầu & Sản phẩm ​

IDChỉ báoCách kiểm
AS-02.1Chất lượng REQ catalog
AS-02.1.1Mỗi REQ có ID đúng scheme REQ-<nhóm>-xx, nhóm thuộc bảng nhóm PRD-001 §5grep -oE "REQ-[A-Z]+-[0-9]+" docs/product/prd-001/req/*.md | sort -u đối chiếu bảng nhóm ở conventions.md §2
AS-02.1.2Mỗi REQ mô tả testable: phán quyết đúng/sai được bằng quan sát, không dùng từ mơ hồ ("tốt", "nhanh", "dễ dùng", "thân thiện", "đẹp", "tối ưu")grep -inE "tốt|nhanh|dễ dùng|thân thiện|đẹp|tối ưu" docs/product/prd-001/req/*.md — mỗi hit trong dòng REQ (không phải văn xuôi) là 1 phản ví dụ (L4)
AS-02.1.3Mỗi REQ có priority đúng một trong MUST/SHOULD/COULD — cấm M?, S?grep -nE "| M\? || S\? || C\? |" docs/product/prd-001/req/*.md phải rỗng
AS-02.1.4Mỗi REQ ghi nguồn SRC-xxx hoặc nguồn người + ngàyđọc bảng REQ
AS-02.1.5Không có hai REQ mô tả cùng một hành vi (trùng nghĩa) — đo bằng token-overlap thô: hai description trùng ≥80% từ, chưa gắn 🗄️ superseded hoặc chưa có ghi chú phân biệt tường minhscript token-overlap trên cột "yêu cầu" của mọi REQ; đây là proxy gần đúng, không phải semantic dedup hoàn hảo — ghi rõ giới hạn trong báo cáo
AS-02.2User story & acceptance criteria
AS-02.2.1Mọi US đúng format As a … / I want … / so that …grep -c "As a \*\*" docs/workflows/*.md khớp tổng số US
AS-02.2.2Persona trong US thuộc tập persona đã định nghĩa (Nemo/Marlin/Dolphin/Staff…)đối chiếu PRD §personas
AS-02.2.3Mỗi US có ≥1 acceptance criteria quan sát đượcđọc — bảng US phải có cột AC riêng, không chỉ 3 cột (ID·story·REQ)
AS-02.2.4Acceptance criteria mô tả kết quả người dùng thấy, không mô tả giải pháp kỹ thuậtđọc — AC không chứa tên bảng D1/tên hàm/tên biến
AS-02.2.5Mỗi US MUST đã implement chỉ ra được màn hình/endpoint thậtđối chiếu app — click qua route thật hoặc grep path trong apps/*/src
AS-02.3Persona, JTBD & phủ vai trò
AS-02.3.1Mỗi persona active có ≥1 JTBD được ghiđọc parent-jtbd.md + PRD
AS-02.3.2Mỗi JTBD có ≥1 REQ phục vụtrace
AS-02.3.3Ba cộng đồng (Nemos, Marlins, Dolphins) đều có luồng onboarding được đặc tảđọc docs/workflows/ — có file riêng cho mỗi cộng đồng, hoặc ghi rõ dùng chung
AS-02.3.4Mỗi school (Turtle, Shark, Octopus, Squid, Ray, Whale) có mô hình riêng hoặc khai báo dùng chung tường minhSDD-011
AS-02.3.5Không có màn hình đang chạy production mà không thuộc persona nàorà route từng app, đối chiếu persona trong PRD
AS-02.4Phạm vi & ưu tiên
AS-02.4.1Mọi REQ trạng thái ✔ chỉ ra được artifact thực thi (code/migration/nội dung)trace
AS-02.4.2Không có tính năng đang chạy production mà thiếu REQ tương ứngrà ngược từ app — liệt kê route/feature, đối chiếu PRD
AS-02.4.3Backlog ứng viên (CC-*, FEAT-*) tách bạch khỏi REQ active, không lẫn bảnggrep -c "CC-|FEAT-" docs/product/prd-001/req/*.md phải là 0 trong bảng REQ chính
AS-02.4.4Mỗi FEAT legacy được phân loại: đã port / đã thay / cố ý bỏ (kèm lý do)legacy-feature-inventory.md cột "Phân loại" đóng {đã-port, đã-thay, cố-ý-bỏ, chưa-quyết}; 0 dòng chưa-quyết
AS-02.4.5Không REQ MUST nào ở trạng thái ⏳ quá 30 ngày mà không có ghi chú lý do + ngày tuyệt đốiđọc PRD §7
AS-02.5Quyết định mở & phê duyệt
AS-02.5.1Mọi câu hỏi mở có ID Q-xxx và trạng thái (chờ / đã trả lời — trả lời không rỗng hoặc dòng ✍️)grep -c "| Q-" docs/open-questions/index.md đối chiếu số Q có trả lời/✍️
AS-02.5.2Mọi dòng ✍️ có lý do ≥15 ký tự và không thuộc danh sách cụm rỗng nghĩa ("theo ý chủ dự án", "đã quyết rồi", "tự quyết", "vì cần thiết", "hiển nhiên"); mỗi bảng ✍️ nằm dưới tiêu đề có ngày tuyệt đốigrep -inE "theo ý chủ dự án|đã quyết rồi|tự quyết|vì cần thiết|hiển nhiên" docs/open-questions/index.md phải rỗng trong các dòng ✍️; đo độ dài phần lý do sau ✍️
AS-02.5.3Artifact "Rà mâu thuẫn giữa các quyết định ✍️" tồn tại, ≤90 ngày, khai luật ưu tiên, liệt kê mọi chỗ lệch tìm thấy, và khai rõ phạm vi đã rà (toàn bộ hoặc tập con có lý do — sampling minh bạch được chấp nhận cho đợt trước pilot)đọc artifact — không còn bắt buộc "số Q đã rà == tổng Q"; bắt buộc dòng "Phạm vi: …" không rỗng
AS-02.5.4Bảng "Việc còn chờ chủ dự án" có cột Trạng thái, mọi dòng có giá trịđọc open-questions/index.md §Còn chờ hoặc README
AS-02.5.5Mọi Q đã trả lời có cột "Đã vào" không rỗng (doc+§, path repo, hoặc vận-hành); link resolvescript: với mỗi Q có trả lời, kiểm cột "Đã vào" khác rỗng và (nếu là path) existsSync

AS-03 — Kiến trúc & Hợp đồng API ​

IDChỉ báoCách kiểm
AS-03.1Ranh giới module & monorepo
AS-03.1.1Mọi createRoute( nằm trong workers/api/src/modules/, trừ các ngoại lệ liệt kê tường minh trong bảng "Ngoại lệ tường minh" ngay dưới bảng nàygrep -rln "createRoute(" workers/api/src | grep -v "/modules/" — mỗi hit phải có mặt trong bảng ngoại lệ, nếu không là KHÔNG PASS (L4)
AS-03.1.2Đồ thị phụ thuộc module 0 chu trình và 0 import chéo trực tiếp giữa hai module (phải qua shared/ hoặc event), trừ cạnh liệt kê tường minh trong bảng "Ngoại lệ tường minh"grep -rn "from \"\.\./\.\./[a-z]" workers/api/src/modules --include="*.ts" loại trừ import shared/
AS-03.1.3Không fetch( nào trong apps/*/src ngoài đúng một src/api.ts/appgrep -rln "fetch(" apps/*/src | grep -v "/api.ts" phải rỗng
AS-03.1.4Không app định nghĩa lại CSS custom property đã có trong packages/design-system/tokens/*.css (file art/SVG miễn trừ) — xem thêm AS-09.2.1 (góc khác: hardcode hex khi dùng token, không phải định nghĩa lại token)grep -rn "^\s*--[a-z-]" apps/*/src --include="*.css" đối chiếu tên biến đã có trong tokens/*.css
AS-03.1.5Mọi thư mục cấp 1 của apps//workers/ có tên trong README §cấu trúc và ngược lại; thư mục ngừng phải ghi rõ "đã ngừng"đối chiếu ls apps workers với README
AS-03.2Hợp đồng API
AS-03.2.1OpenAPI sinh từ router; không tồn tại file OpenAPI viết tay ngoài openapi.snapshot.json (chính là snapshot của bản sinh)find . -iname "*.yaml" -o -iname "openapi*.json" | grep -v snapshot phải rỗng
AS-03.2.2Mọi operation có ≥1 response 2xx kèm schema JSON; mọi requestBody kèm schema JSONnpm run contract:diff -- --print | jq đếm operations thiếu schema
AS-03.2.3Mọi path trong spec sinh ra bắt đầu /v1npm run contract:diff -- --print | jq '.paths | keys'
AS-03.2.4🔴🚸 Không breaking change trong /v1 (xoá field/route, đổi kiểu, thêm required ở request) so với openapi.snapshot.json; có mặt ở ít nhất một workflow chạy trên mọi push (nay là ci.yml)npm run contract:diff exit 0 — hiện chạy trong ci.yml bước 6 trên mọi push/PR
AS-03.2.5Probe 404/401/400 trên production trả {error:{code,message}}, không rò ZodError/stackcurl thử endpoint sai, đọc body
AS-03.3Hợp đồng event/queue
AS-03.3.1Mọi entry EVENT_REGISTRY có version(int)+payload(zod object)đọc workers/api/src/shared/events.ts
AS-03.3.2Đối soát hai chiều: mọi tên publishEvent() gọi ∈ registry; mọi entry registry có ≥1 điểm gọi thật HOẶC ghi rõ "cố ý chưa có consumer — lý do + ngày" trong reference/events.md — quá 30 ngày không có REQ liên kết thì tính HH (mồ côi thật), không còn là CXgrep -rn "publishEvent(" workers/api/src/modules đối chiếu tên event với EVENT_REGISTRY keys
AS-03.3.3Tên event khớp domain.entity.action, action ở tập đóng thì quá khứgrep -oE '"[a-z]+\.[a-z]+\.[a-z]+"' workers/api/src/shared/events.ts
AS-03.3.4assertNoFreeText() tồn tại+được gọi trong publishEvent; không z.string() trần/field PII không bị cắtđọc workers/api/src/shared/events.ts — có hàm assertNoFreeText (xác nhận: tồn tại thật, dòng cuối file)
AS-03.3.5Số trong wrangler.jsonc (tên queue, max_batch_size, max_retries, DLQ) khớp đúng queues.mdđối chiếu workers/api/wrangler.jsonc với reference/queues.md
AS-03.4Vệ sinh secret/config
AS-03.4.1🔴 Không pattern key/secret/token hardcode trong source hoặc lịch sử gitgrep -rE "(api[_-]?key|secret|token)\s*[:=]\s*['\"][A-Za-z0-9]{16,}" --include="*.ts" + git log -p --all | grep -E cùng pattern
AS-03.4.2Base URL API xuất hiện ≤1 lần/app, chỉ trong src/api.ts; literal nemo12.com còn lại phải là host trong READMEgrep -rn "nemo12.com" apps/*/src | grep -v "src/api.ts"
AS-03.4.3Mọi biến môi trường bắt buộc được khai kiểu trong workers/api/src/env.tsnode scripts/verify-bindings.mjs Lớp A
AS-03.4.4Mọi binding (D1/KV/R2/Queue/AI) được CI verify là tồn tại thật trên Cloudflare, có trong ci.ymlnpm run verify:bindings Lớp C — cần CLOUDFLARE_API_TOKEN; không có token thì lùi về A+B (ghi rõ trong kết quả, không coi là PASS đủ Lớp C)
AS-03.4.5reference/config.md liệt kê đủ mọi biến cấu hình đang dùng (danh sách đóng khớp wrangler.jsonc)npm run verify:bindings Lớp B
AS-03.5Cấu trúc & kỷ luật pipeline deploy
AS-03.5.1Mỗi wrangler.jsonc có workflow deploy tương ứng với path filter đúng.github/workflows/ đối chiếu apps/workers
AS-03.5.2Mỗi wrangler.jsonc khai custom_domain/routes (không *.workers.dev trần)đọc wrangler config
AS-03.5.3🚸 (nội dung mới, thay "app↔workflow đủ đôi" — xem §1.14) Không thao tác wrangler d1 migrations apply --remote nào chạy trực tiếp từ máy/phiên cục bộ ngoài đường ci.yml trên main và workflow_dispatch của deploy-app.yml. PASS nếu: (a) branch protection required-review bật trên main — kiểm gh api repos/<org>/<repo>/branches/main/protection (200) — HOẶC (b) plan hiện tại không bật được (403 "Upgrade to GitHub Pro") và có quy ước ghi tường minh trong README/CLAUDE.md và AS-04.6.1 không phát sinh dòng mồ côi mới nào trong 7 ngày gần nhất (bằng chứng gián tiếp là không ai apply tay)gh api repos/.../branches/main/protection; nếu 403 thì đọc README + đối chiếu AS-04.6.1
AS-03.5.4Bước apply-migration đứng trước bước wrangler deployđọc ci.yml và deploy-app.yml — xác nhận: dòng apply ở trước bước Deploy ở cả hai
AS-03.5.5Mọi URL production trong README trả 2xx/3xx; khớp đúng tập custom_domain trong mọi wrangler.jsonccurl -sI từng URL trong README, đối chiếu domain list

Ngoại lệ tường minh (AS-03.1.1 / AS-03.1.2) ​

Danh sách đóng — thêm dòng mới khi có ngoại lệ mới, không thêm ngoại lệ ngoài bảng này:

Chỉ báoVị tríLý do
AS-03.1.1workers/api/src/index.ts:81 — healthRouteHealth check là route hạ tầng cấp worker, không thuộc nghiệp vụ một module cụ thể nào; xác nhận đây là hit duy nhất ngoài modules/ tính đến 2026-08-15 (grep -rln "createRoute(" workers/api/src | grep -v "/modules/" → 1 dòng)
AS-03.1.2(bảng trống tới 2026-08-15; 10 cạnh dưới đây khai ngày 2026-08-20 — Audit #004, SRC-412)Tính đến 2026-08-15, grep import chéo giữa 19 module trả 0 kết quả (Audit #001 xác nhận). Audit #004 đo lại và thấy 10 cạnh mới, tất cả đều cố ý; khai ra đây thay vì im lặng chấp nhận
AS-03.1.2coral/routes.ts → content/quality, content/lifecycle, content/review-queueCoral là mặt quản trị của chính miền content (SDD-013): tách qua shared/ sẽ tạo một lớp trung chuyển chỉ có đúng một người gọi. Cạnh một chiều, không có chu trình
AS-03.1.2learning/routes.ts → knowledge/masteryChấm một câu trả lời và cập nhật mastery là một giao dịch nghiệp vụ; đẩy qua event sẽ khiến learner thấy điểm cũ ở màn hình ngay sau khi trả lời
AS-03.1.2learning/routes.ts → retention/service, content/lifecycle, models/serviceBa lời gọi đọc/kích hoạt sau khi có bằng chứng mới (câu nhắc ôn, cờ nội dung AI, dựng lại model nếu cũ). models/service được gọi qua runAllModelsInBackground/refreshIfStaleInBackground nên không chặn request
AS-03.1.2progress/routes.ts → knowledge/masteryDùng lại đúng một hàm thuần stateFor(mastery, confidence); chép sang shared/ sẽ thành hai định nghĩa của cùng một ngưỡng
AS-03.1.2admin/observability.ts → models/service, models/contextEventsAdmin là chỗ bấm chạy engine và đọc taxonomy sự việc; nó phải gọi thẳng vào miền model để có bằng chứng thi hành đồng bộ (workflow_run + engine_run trong cùng lượt)