---
url: https://docs.nemo12.com/architecture/sdd-003-knowledge-quality.md
description: >-
  Knowledge Registry, Skill Graph và hệ chất lượng học liệu: Quality Profile,
  Quality Engine ba lớp, vòng cải tiến liên tục.
---

# SDD-003 — Knowledge & Learning Quality System

**Core loop:** `Model → Build → Review → Score → Detect Problems → Improve → Re-evaluate → Publish → Observe Learners → Improve Again`. Đây là **Learning Knowledge Factory** (continuous improvement), không phải CMS.

## 2. Knowledge Registry (REQ-KNW-01)

`Domain → Area → {Knowledge Node, Skill}`.

* **Knowledge Node** ("biết/hiểu gì"): definition, scope, examples, misconceptions, prerequisites, related nodes, difficulty, grades, school/program, source, quality score, lifecycle.
* **Skill** ("làm được gì"): measurable indicators để Assessment Engine tạo evidence.

## 3. Skill & Knowledge Graph (REQ-KNW-02)

Edges: `prerequisite_of, related_to, part_of, supports, requires, generalizes, applies, similar_to`. Graph trả lời: hổng ở đâu, vì sao không học được X, quay lại node nào, gap ảnh hưởng bao nhiêu capability. **Shared infrastructure toàn school** — cấm graph riêng per school (RISK-003: chuyenchon có 3 bản thể graph — TS files 6.5k LOC, mori seed, learning_graph_nodes; Nemo12 seed từ TS graphs, một registry duy nhất trong D1, school chỉ thêm context — SDD-007 §5).

## 4. Learning Package (REQ-KNW-03)

Đơn vị đóng gói dạy được một mục tiêu: target skill + prerequisites + concept/examples/misconceptions/explanation/practice/assessment/experiences/scaffolds/extension. Một skill nhiều package theo age/level/school/exam context.

## 6. Quality Profile (REQ-KNW-07)

Rubric 8 chiều: Accuracy, Clarity, Pedagogy, Cognitive Demand, Alignment, Engagement, Assessment Validity, Accessibility. Mỗi score lưu `{dimension, score, reason, evidence, evaluator, rubric_version, timestamp}` — không chỉ điểm trung bình.

## 7. Quality Engine — 3 lớp (REQ-KNW-08)

1. **Deterministic:** missing prerequisite/source/assessment, orphan node, circular dependency, invalid difficulty, duplicate ID, broken reference.
2. **Algorithmic/graph:** assessment chỉ test recall trong khi skill đòi application; experience đòi kiến thức ngoài prerequisite graph.
3. **LLM theo rubric cụ thể** (cấm hỏi chung "có tốt không"): clarity, phù hợp tuổi, distractor quality, misconception, inquiry thật không.

**Một rubric registry duy nhất** (fix RISK-005: legacy có 4+ hệ rubric song song + 2 framework .mjs). Kế thừa CC-QAF-1.0 (10 clusters/50 criteria/250 indicators) làm rubric gốc, evidence-gated scoring (điểm >0 phải có evidence).

## 8. Multi-Evaluator (REQ-KNW-09)

Rule Engine + Graph Validator + LLM A + LLM B + Learner Evidence. `score variance > threshold → Flag for Review`. Human review bắt buộc: curriculum definitions, high-stakes assessment, disputed content, major graph changes.

## 9. Quality Registry & Dashboard (REQ-KNW-11)

`QualityEvaluation {entity_id, entity_version, rubric, evaluator, scores, findings, severity, timestamp}`. Dashboard: school nào thấp nhất, area thiếu coverage, experience <3/5, node chưa có assessment, package quá 6 tháng chưa review.

## 10. Improvement + Priority Engine (REQ-KNW-10)

* Improvement Engine: analyze findings → generate revision → **Candidate Version** → re-run Quality Engine. Cấm sửa production trực tiếp. Lifecycle: `Draft → Review → Candidate → Evaluated → Approved → Published → Deprecated`.
* Priority Engine: `Priority = Severity × LearnerImpact × UsageFrequency × GraphImportance × Confidence ÷ ImprovementCost` — lỗi nhỏ ở node nền tảng 20k learners dùng > lỗi lớn ở lesson hiếm dùng.
* Remediation queue chạy trên **Cloudflare Queues** (fix RISK-018: chuyenchon dùng cron-poll D1 + lease tables).

## 11. Learner evidence là trọng tài cuối (REQ-KNW-13)

LLM chấm 4.8/5 nhưng 65% learner cùng mắc một misconception → content phải xem lại. Quality loop khép kín bằng dữ liệu học thật.

## 13. Versioning & Provenance

Mọi entity có version; mọi update giữ `{previous_version, change_reason, author, AI_model, evaluation, source, approval}`. (Kế thừa source-provenance + content intelligence của mori — FEAT-043.)

## 14. Vùng kiểm định tại chỗ cho người rà (SRC-454, SRC-467)

Evaluator "Learner Evidence" ở §8 chỉ đọc được dữ liệu làm bài; nó không nói được **hỏng ở đâu**. Vùng kiểm định là kênh thu tín hiệu có địa chỉ, đặt ngay dưới TỪNG câu trong màn làm bài.

**Quyền — server quyết cả hai đầu.** Danh sách theo email (`workers/api/src/shared/qcEmails.ts`, `isQcEmail`, cùng khuôn với `QUEUE_EXPLAIN_EMAILS` của SRC-424). `POST /v1/learning/practice/start` trả cờ `qc`; client chỉ bày vùng khi server nói có. Endpoint report tự tra email của session để gắn nhãn — **client tự xưng QC không có tác dụng**. Ẩn ở client là tiện, không phải hàng rào. Ngày nào cần hệ role thật thì đổi một chỗ: `QC_EMAILS` thành một cột trong `users`, mọi nơi gọi `isQcEmail` giữ nguyên.

**Sáu nhãn lỗi tách theo CHỖ CẦN SỬA**, vì người nâng cấp câu cần biết sửa vào đâu: Câu hỏi sai (`question_wrong`) · Đáp án sai (`wrong_answer`) · Nhiều đáp án đúng (`multiple_correct`) · Giải thích sai (`explanation_wrong`) · Đề khó hiểu (`unclear`) · Chính tả (`typo`). Một nhãn gộp "câu này sai" là vô dụng ở bước Improvement Engine §10.

**Hàng KHEN đứng TRƯỚC hàng lỗi** — `good_question` ("👍 Câu hỏi hay") và `good_options` ("👍 Bộ đáp án hay"). Lý do là luật, không phải trang trí: kho **chỉ thu tín hiệu xấu thì không phân biệt được câu tốt với câu chưa ai đọc** — cả hai đều là "không có báo cáo". Không có tín hiệu dương thì Coral cũng không biết khuôn nào đáng nhân bản.

**Luồng dữ liệu** (`POST /v1/content/items/{itemId}/report`, dùng lại hạ tầng SRC-365, không dựng đường mới):

1. Mọi báo cáo → `content_reports`, reason mang tiền tố `QC báo: ` khi người gửi thuộc danh sách QC — tín hiệu của người được giao đi rà đặc hơn báo cáo tình cờ, Coral xếp lên trước.
2. **Lời khen dừng ở bước 1.** `good_question`/`good_options` cố ý **KHÔNG** vào `content_review_queue` và trả `review_id` rỗng: hàng đó là danh sách việc-phải-sửa, nhét lời khen vào là người xử lý phải bấm qua từng lời khen để tìm lỗi thật.
3. Báo lỗi → chạy `screenItem` ngay lúc báo. Máy cũng thấy lỗi mức chặn (`correct_index_out_of_range`, `option_empty`, `options_duplicate`) thì `retireItem` gỡ câu khỏi luồng học luôn, không đợi người soát — learner tiếp theo không phải gặp lại đúng câu đó.
4. Báo lỗi → `content_review_queue` kèm cả lý do người báo lẫn cờ máy thấy → đổ về "Việc đang chờ" của Coral (SRC-447), nơi từng câu được sửa qua **candidate version** theo §10 (cấm sửa production trực tiếp).

## 15. Chuẩn hoá chữ trong dữ liệu nội dung (SRC-469)

**Luật: chữ learner đọc được lưu ở dạng đã render sẵn — cấm cú pháp đánh dấu trong `prompt`, `options_json`, `misconception`.** Màn làm bài cố ý không render markdown (một trình render trên chữ do máy soạn là một mặt tấn công và một nguồn vỡ layout), nên `**ăn**` hiện nguyên hoa thị cho learner. Một đợt soạn đã để lọt **25 chỗ** (22 prompt · 2 options · 1 misconception, chủ yếu Ngữ văn); đã bóc bằng REPLACE trên D1.

Câu vào production dưới dạng **dữ liệu**, không qua code review, nên phải canh bằng máy ở **hai cổng**:

* **Cổng nạp** — `scripts/seed-items-from-json.mjs` từ chối câu còn `**` ngay lúc nạp (chặn trước khi vào kho).
* **Cổng rà** — `scripts/audit-data.mjs`, mục "markdown thô \*\* trong prompt/options", quét toàn bộ `items` đang `published` (bắt thứ đã lọt vào bằng đường khác, ví dụ SQL seed).

## 16. Đường đi của một câu bị báo lỗi (SRC-542)

Một câu bị báo là một **việc**, không phải một tin nhắn. Đường xử lý cố định:

1. Vào `content_review_queue` → "Việc đang chờ" của Coral, xếp theo Priority §10.
2. Người sửa nội dung viết bản mới thành **candidate version**; nội dung đổi thì **hồ sơ chất lượng cũ bị xoá** (`quality_json`, `quality_score`, `evaluator_count=0`) — hồ sơ cũ chấm một đề không còn tồn tại, giữ lại là nói dối.
3. Cron screening chạy lại, đưa câu qua §7 rồi mới nâng lại `published`. Không có đường bấm-duyệt-tay bỏ qua bước chấm.
4. **Lý do sửa ghi ngay ở header của patch** — luật rút ra phải sống cùng chỗ với thay đổi, để lần sau người soạn đọc được.

Hai luật đã rút ra từ ca `COV-DIVISIBILITY-RULES-04`:

* **Dạng `find_error`: lời giải mẫu phải chứa đúng MỘT dòng sai, kiểm được độc lập.** Nếu bài dùng một quy tắc sai thì phải chọn dữ liệu sao cho quy tắc sai cho ra **KẾT LUẬN SAI** — dữ liệu mà quy tắc sai vẫn ra kết luận đúng thì không có dòng nào để bấm, bài vô nghiệm dù mọi dòng đều đúng về sự kiện.
* **Máy sàng lọc phải chấm theo đúng dạng câu.** Screening soạn trước SDD-022 chấm câu nhập-đáp-số bằng thước của trắc nghiệm, giữ nhầm **42 câu** `numeric`/`estimate` với cờ `options_too_few`. Nay hai dạng đó sàng `answer_spec_json` (numeric phải có `answer`; estimate phải `min < max`) với cờ mới `answer_spec_invalid` mức **chặn**, thay vì sàng phương án; `mcq`/`find_error`/`order_steps` giữ luật cũ. Một cờ sai hàng loạt còn hại hơn không có cờ: nó dạy người rà bỏ qua cả cột.

## Trace

| REQ | Mục |
| --- | --- |
| REQ-KNW-01/02/03 | §2–§4 |
| REQ-KNW-07..11, 13 | §6–§11, §13 |
| REQ-KNW-09/10 (SRC-454, SRC-467) | §14 |
| REQ-KNW-08 (SRC-469) | §15 |
| REQ-KNW-10 (SRC-542) | §16 |
