Parent Model
Model trả lời câu hỏi mà Learner Model cố tình không trả lời: "bố mẹ đang nghĩ gì về con, và điều đó lệch bao nhiêu so với thực tế?"
Thiết kế: SDD-002 §4/§13 · Code: workers/api/src/modules/parent/routes.ts · Test quyền: parent/authz.test.ts · Workflow: WF-12
1. Parent Model là declared model, không phải computed model
Đây là điều dễ hiểu sai nhất, nên nói ngay:
| Learner Model | Parent Model | |
|---|---|---|
| Loại | Computed — engine sinh | Declared — người khai |
Có trong MODEL_KINDS? | ✅ learner | ❌ không |
| Có version + hash? | ✅ | ❌ |
| Có engine chạy định kỳ? | ✅ | ❌ |
| Lưu ở | learner_model_versions | parent_beliefs + interactions |
Không có parent trong MODEL_KINDS (shared/runlog.ts) và không có Parent Engine sinh model. Cái mà mã nguồn gọi là "Parent Engine" thực chất là hai đường ghi dữ liệu khai báo cộng với một hàm suy luận khuyến nghị chạy tại chỗ lúc đọc (§5) — không lưu, không version.
Đây là lựa chọn có chủ ý: niềm tin của phụ huynh không được phép trở thành một model chạy ngầm suy diễn về đứa trẻ. Nó là dữ liệu để đối chiếu, không phải để phán quyết.
2. Hai dòng dữ liệu
2.1 Parent Belief — niềm tin định kỳ theo môn
Bảng parent_beliefs (migration 0018, SRC-051).
| Cột | Kiểu | Ý nghĩa |
|---|---|---|
learner_id + user_id + subject_id | TEXT | Ai nghĩ về ai, ở môn nào. Có user_id nên bố và mẹ khai riêng, không đè nhau |
worry_level | INT 1–5 | 1 rất yên tâm … 5 vô cùng lo lắng |
perceived_state | TEXT | hong · lung_lay · on_dinh · chac — bố mẹ cảm thấy con đang ở đâu |
predicted_score | REAL | Điểm bố mẹ hình dung con đạt khi thi thật |
score_scale | REAL | Thang điểm (mặc định 10; cho phép tới 1600 để dùng cho SAT) |
will_pass | INT | 1 tin đủ điểm đỗ · 0 chưa tin · NULL chưa rõ |
note | TEXT | Lời tự do |
recorded_at | TEXT | Mốc thời gian |
Mỗi lần khai là một dòng mới — không update đè. Đây không phải chi tiết kỹ thuật mà là toàn bộ giá trị của bảng: chỉ khi giữ lịch sử thì mới trả lời được "tháng trước mẹ lo mức 5, giờ mức 2 — điều gì đã đổi?". Update đè sẽ xoá mất chính thứ đáng giá nhất.
Belief KHÔNG vào Evidence Registry
Migration 0018 ghi rõ ngay dòng đầu: không ghi vào learner_evidence. Niềm tin của phụ huynh không phải bằng chứng năng lực của đứa trẻ.
Mẹ tin con yếu Toán không làm mastery Toán giảm một chút nào. Nếu để nó ảnh hưởng, hệ thống sẽ biến lo lắng của người lớn thành "sự thật" về đứa trẻ — đúng cái vòng luẩn quẩn mà Nemo12 tồn tại để phá vỡ.
2.2 Parent Observation — quan sát tự do
Ghi vào bảng interactions (target_type='learner', author_role='guardian', visibility='learner_parent'), phân loại theo category: motivation · focus · time · emotion · behavior · other.
Khác với belief, observation có vào Evidence Registry:
INSERT INTO learner_evidence (..., subject_id, node_id, source, type, observed_performance, reliability, ...)
VALUES (..., '', '', 'parent_observation', <category>, 0.5, 0.6, ...)Ba con số cần đọc kỹ:
| Trường | Giá trị | Vì sao |
|---|---|---|
node_id | rỗng | Không gắn với kỹ năng nào → updateMastery() chạy theo node nên không bao giờ chạm tới evidence này. Nó là tín hiệu ngữ cảnh, không phải phép đo năng lực |
observed_performance | 0.5 cố định | Trung tính. "Con hôm nay mất tập trung" không phải điểm số |
reliability | 0.6 | Quan sát của người thân: đáng tin hơn đoán bừa (0.05), kém hơn bài làm thật (1.0) |
Nói cách khác: quan sát được ghi nhận và giữ lại, nhưng không được phép dịch chuyển mastery. Bố mẹ được lắng nghe mà không vô tình chấm điểm con mình.
Cặp bảng này là hai thứ khác nhau về bản chất: belief là phán đoán, observation là quan sát. Trộn chúng vào một chỗ là cách nhanh nhất để mất khả năng phân biệt "mẹ lo" với "hôm qua con ốm".
3. Cơ chế CẬP NHẬT
3.1 Ai được ghi — chỉ phụ huynh, và learner bị chặn có chủ đích
Mọi route parent đi qua guardGuardian():
const access = await resolveLearnerAccess(c, learnerId, { action });
if (access instanceof Response) return access;
if (access.via === "self") return errorResponse(c, "AUTHORIZATION_ERROR", "Chức năng dành cho phụ huynh");Đây là guard chặt hơn learnerAccess() chuẩn: nó loại via === "self". Chính đứa trẻ không được ghi belief hay observation về mình — vì đây là dòng dữ liệu ghi lại góc nhìn của người lớn, và để nó lẫn tiếng nói của trẻ thì phép đối chiếu ở §4 mất hết ý nghĩa.
Nemo có tiếng nói riêng ở chỗ khác: cột của con trong Student Portrait và reaction. Không phải ở đây.
Mentor/staff/admin đọc được (qua resolveLearnerAccess, có ghi audit) nhưng cũng không ghi được — via của họ không phải self nên qua được guard, nhưng đó là chủ ý: mentor cần đọc để hiểu bối cảnh gia đình. Xem ma trận quyền.
3.2 Đường ghi
| Việc | Endpoint | Ghi vào | Event |
|---|---|---|---|
| Ghi quan sát | POST /v1/learners/{id}/observations | interactions + learner_evidence (một DB.batch) | parent.observation.recorded |
| Ghi niềm tin | POST /v1/learners/{id}/beliefs | parent_beliefs (INSERT mới) | parent.belief.recorded |
Observation dùng DB.batch cho cả hai statement: hoặc cả quan sát lẫn evidence cùng vào, hoặc không gì cả. INSERT OR IGNORE với event_id = parent-obs:{id} chống ghi trùng khi client retry.
Không có bước nào chạy engine. Ghi belief/observation không kích hoạt WF-04 — vì không có gì trong Learner Model thay đổi. So sánh với việc nộp bài (chạy WF-04 ngay): khác biệt này chính là ranh giới "dữ liệu người lớn khai" và "bằng chứng của trẻ".
3.3 Đường đọc
| Endpoint | Trả về |
|---|---|
GET /v1/learners/{id}/observations | 50 quan sát gần nhất, mới trước |
GET /v1/learners/{id}/beliefs?subject_id= | { history, latest } — latest là bản ghi mới nhất của từng môn, gộp sẵn từ history |
latest được tính bằng cách duyệt history (đã ORDER BY recorded_at DESC) và giữ dòng đầu tiên gặp cho mỗi môn — không cần query thứ hai.
4. Cách DÙNG (1): đối chiếu niềm tin với thực tế
Đây là lý do Parent Model tồn tại.
Tại marlins #/child/{id}/beliefs, cạnh mỗi lần khai của phụ huynh là ước tính của hệ thống cho cùng môn đó, để bố mẹ tự so. Ghi chú trong code nói rõ tinh thần:
"Ước tính của hệ thống để bố mẹ tự so với cảm nhận của mình (không phán xét ai đúng)."
Bốn tình huống, và hành động đúng cho từng cái:
| Bố mẹ tin | Hệ thống đo | Ý nghĩa | Việc cần làm |
|---|---|---|---|
| Lo (4–5) | Đang ổn | Lo quá mức | Cho bố mẹ thấy bằng chứng cụ thể — thường là gốc của việc đăng ký thêm lớp không cần thiết |
| Yên tâm (1–2) | Có gap nghiêm trọng | Điểm mù | Chỉ đúng gap, không nói "con yếu" |
| Lo | Có gap | Đồng thuận | Cùng làm việc trên gap đó |
| Yên tâm | Đang ổn | Đồng thuận | Không cần can thiệp gì |
Hệ thống không tuyên bố ai đúng. Nó đặt hai con số cạnh nhau và để gia đình nói chuyện. Đó là toàn bộ thiết kế.
5. Cách DÙNG (2): Parent Recommendation — WF-12
GET /v1/learners/{id}/parent-recommendation?subject_id=
Không phải model được lưu — là hàm suy luận chạy tại chỗ lúc đọc, dựa trên cockpit của learner. Không có version vì output luôn suy được lại từ trạng thái hiện tại.
Cây quyết định (thứ tự ưu tiên, dừng ở nhánh đầu tiên khớp)
1. assessed_nodes == 0 → "Con chưa làm bài chẩn đoán"
2. mode == exam_prep → "Còn N ngày tới kỳ thi — luyện đề, giữ nhịp nghỉ"
3. có gap 'critical' → "Tập trung vào <tên node> — gốc đang chặn nhiều phần sau"
4. có goal, chưa on_track → "Đang tiến bộ nhưng chưa đạt — duy trì đều đặn"
5. còn lại → "Con đang đúng hướng — không cần tăng tải"Thứ tự này là một khẳng định về giáo dục: deadline gần thắng gap sâu. Còn 5 ngày thi mà đi vá lỗ hổng nền tảng là hại con — lúc đó việc đúng là luyện đề và ngủ đủ.
Output
{
"subject_id": "math",
"headline": "Tuần này, giúp con tập trung vào \"Hằng đẳng thức\" — đây là gốc đang chặn nhiều phần phía sau. **Chưa cần đăng ký thêm lớp.**",
"support_actions": [
"Dành 20 phút hỏi con về \"Hằng đẳng thức\", để con giải thích lại cho bạn nghe.",
"Khen nỗ lực khi con chịu làm phần khó, thay vì chỉ khen điểm."
],
"dont_do": "Tránh phản xạ 'thấy điểm thấp → cho học thêm'. Nguyên nhân thường là một gap nền tảng cụ thể, không phải yếu toàn bộ môn.",
"readiness": 0.68, "on_track": true,
"critical_gaps": ["Hằng đẳng thức", "Phân tích đa thức"],
"mode": "deep_learning"
}dont_do là trường bắt buộc, không phải trang trí
REQ-PAR-04 — chống intervention error. Mọi nhánh của cây quyết định đều có dont_do, kể cả nhánh "con đang ổn".
Sai lầm phổ biến nhất của phụ huynh Việt Nam không phải là làm quá ít, mà là phản xạ "thấy điểm thấp → cho học thêm". Một hệ thống chỉ biết nói "nên làm gì" sẽ khuếch đại đúng phản xạ đó. Vì vậy "tuần này chưa cần làm gì thêm" là một output hợp lệ và đầy đủ — không phải dấu hiệu hệ thống bí ý tưởng.
Ba nhánh nói thẳng "chưa cần đăng ký thêm lớp", và headline nhánh 3 in đậm câu đó ngay giữa lời khuyên tập trung.
Lời khuyên nói bằng tên bài, không bằng con số
titles map node_id → title_vi được nạp trước để headline nói "Hằng đẳng thức" chứ không phải "node math-8-alg-03" hay "mastery 0.32". Phụ huynh cần một câu có thể mang tới bàn ăn tối.
6. Ai thấy được gì
| Dữ liệu | Learner | Phụ huynh | Mentor | Admin |
|---|---|---|---|---|
| Belief của bố mẹ | ❌ không đọc được | ✅ ghi + đọc | 📝 đọc (có audit) | 📝 |
| Observation | ❌ | ✅ ghi + đọc | 📝 đọc | 📝 |
| Parent recommendation | ❌ | ✅ | 📝 | 📝 |
Learner không đọc được belief của bố mẹ. Có chủ đích: "mẹ lo mức 5 về Toán của con" là suy nghĩ riêng của người lớn, chưa được diễn đạt thành lời để nói với trẻ. Đưa thẳng con số lo lắng cho đứa trẻ là gây tổn thương mà không tạo ra hành động nào tốt hơn.
Thứ đứa trẻ được thấy và phản hồi là Student Portrait — nơi kỳ vọng đã được bố mẹ viết ra thành câu tử tế, có chỗ cho con viết lại bằng lời của mình.
7. Bất biến — vi phạm là bug
parent_beliefskhông bao giờ ghi vàolearner_evidence.- Parent observation vào evidence với
node_idrỗng — không bao giờ chạmupdateMastery(). - Mỗi lần khai belief là INSERT mới, không UPDATE.
- Chính learner không ghi được belief/observation (
via === "self"bị chặn). - Mọi nhánh parent recommendation phải có
dont_do. - Learner không đọc được belief của bố mẹ qua bất kỳ endpoint nào.
- Ghi belief/observation không kích hoạt WF-04.
8. Khoảng trống đã biết
| Việc | Trạng thái |
|---|---|
| REQ-PAR-08 — adaptive questions cho phụ huynh dựa trên evidence gap | ⏳ cần Parent Model phase 2 |
| REQ-PAR-11 — weekly plan có đánh dấu hoàn thành | 🔵 khung dùng chung WF-12, còn thiếu phần tick việc |
| REQ-PAR-12 — digest định kỳ qua email/notification | ⏳ chưa có kênh gửi; xem schedules |
| Tự động phát hiện lệch belief↔hệ thống và nêu thành tín hiệu | ⏳ hiện để bố mẹ tự so bằng mắt |
Trace
- REQ-PAR-01 (giải thích bằng evidence) · REQ-PAR-02/04 (recommendation + chống intervention error) · REQ-PAR-05 (Parent Model + niềm tin định kỳ) · REQ-PAR-10 (observation → evidence).
- US-09, US-10, US-12, US-71 · WF-12.
- Nguồn: SRC-006 (JTBD phụ huynh), SRC-051 (niềm tin định kỳ), SRC-105.
- Thiết kế: SDD-002 §4/§13.
- Kiểm chứng: QG-005; quyền:
parent/authz.test.ts, QG-008. - Liên quan: Student Portrait · Models · Permissions.