Sổ nguồn SRC-0200 tới SRC-0224
Một mảnh của sổ tiếp nhận. Chỉ CHÈN dòng bằng node scripts/src-new.mjs, không ghi đè cả file.
| ID | Ngày nhận | Nguồn | Canonical hóa vào | Trạng thái |
|---|---|---|---|---|
| SRC-200 | 2026-08-16 | Chỉ đạo: tiếp tục với Context Builder và Global Orchestrator | reference/context-builder.md: 4 purpose khai trước kèm lý do, bí danh nemo_<hash>, cổng assertNoIdentifiers chạy trên context đã dựng; ghi rõ hiện chưa có ai gọi — cổng dựng TRƯỚC khi có lưu lượng là có chủ đích. reference/global-orchestrator.md: không phải một file mà là tên gọi cho 3 engine phối hợp (Q-097 ✍️); hiện mới điều phối trong MỘT môn — learner học 2 môn thấy 10 việc, không ai cộng tổng thời gian; chặn bởi thiếu estimated_minutes cho mọi loại action | ✅ |
| SRC-201 | 2026-08-17 | Chỉ đạo: trong dolphin.nemo12.com làm tính năng quản lý hồ sơ mentor — "đặc biệt cần làm nổi bật việc các mentors đều là cựu học sinh trường chuyên" — và quản lý photo albums cho mentors & advisors; hiển thị album lên trang chủ www.nemo12.com, để "tăng niềm tin với phụ huynh và với các học sinh". Trên www có vùng riêng cho phụ huynh và vùng riêng cho học sinh: caption/description ở hai vùng phải khác nhau; mặc định giống nhau nếu không có dữ liệu, nhập đủ hai bản thì hiển thị riêng | SDD-019, REQ-MEN-07..09, REQ-BRD-08, REQ-MED-07. "Cựu học sinh trường chuyên" là dữ liệu có cấu trúc, không phải câu văn tự do: trường · lớp chuyên · năm tốt nghiệp là các cột riêng kèm cờ xác minh, và hồ sơ không publish được nếu thiếu — để là một dòng bio thì con số "100% cựu học sinh chuyên" trên trang chủ không có gì đỡ, mà đó lại đúng là câu dễ mất niềm tin nhất khi một phụ huynh kiểm chứng. Con số công khai đếm từ dữ liệu, không viết cứng trong JSX. Caption hai bản làm bằng cột gốc + hai cột đè, fallback theo TỪNG trường (Q-131) chứ không phải "có đủ đôi mới tách": điền một nửa vẫn phải chạy được, và màn soạn thảo tự nói rõ bên nào đang dùng bản gốc. Vùng đọc trên www là hai trang riêng /cho-bo-me và /cho-hoc-sinh + một dải ngắn bản gốc trên trang chủ (chủ dự án chọn 2026-08-17) — trang chủ giữ luật tối giản DS-001 §5b. Ảnh: dựng lát cắt đầu tiên có thật của SDD-009 (bảng media + R2 nemo12-content + GET /v1/media/{id} bất biến), không phải hệ media đầy đủ — moderation queue/variants/signed URL để lại (Q-132) | ✅ |
| SRC-202 | 2026-08-17 | Chỉ đạo: trang chủ tách hai luồng ngay từ đầu — một luồng riêng cho bố mẹ, một cho học sinh, và xưng hô riêng cho từng bên; đóng vai UX Designer thiết kế flow cho mỗi bên. Bố mẹ khai tối thiểu: tên con, năm sinh, có thi chuyên không (trường nào, lớp chuyên nào), con hổng môn nào, có muốn ưu tiên lấp lỗ hổng không; rồi mời con vào. Dữ liệu bố mẹ khai phải sống dù con không vào, và con vào thì có sẵn. Cấp 1-2 ưu tiên bố mẹ khai hộ, cấp 3 ưu tiên con tự khai vì dùng máy tính thạo hơn | WF-19 — tài liệu thiết kế flow hai luồng, gồm luật xưng hô (marlins gọi trẻ là "con"; learn lớp 1-9 gọi người đọc là "con", lớp 10-12 gọi là "bạn" — 16 tuổi bị phần mềm gọi "con" là thấy bị coi thường), và cách xử lý khi bố mẹ với con khai khác nhau: không bên nào thắng, cả hai là giả thuyết chờ evidence đo. Đã xây: trang chủ hai cửa ngang hàng (apps/web/src/App.tsx); wizard 5 bước #/bat-dau (apps/marlins/src/StartWizard.tsx) lưu từng bước chứ không dồn cuối — bước 1 tạo learner thật nên bỏ dở giữa chừng vẫn còn dữ liệu; migration 0045 thêm learners.learning_priority + profile_source; POST /v1/invitations nhận thêm birth_year + learning_priority và trả về lớp server tự suy từ năm sinh (hỏi năm sinh chứ không hỏi lớp: bố mẹ nhớ chắc hơn, và năm sinh không cũ đi sau mỗi tháng 9); PATCH /v1/learners/{id}/learning-priority. Môn hổng ghi vào learner_context_events kind=focus_subject — bảng này đã có sẵn source_role nên phân biệt được lời khai của bố mẹ với của con mà không cần bảng mới. 5 test cho hàm suy lớp, khoá đúng mốc 31/8 ↔ 1/9. Còn lại: phía learn chưa phân màn theo cấp học, xưng hô chưa áp vào learn | 🔵 luồng bố mẹ xong, luồng con chưa |
| SRC-203 | 2026-08-17 | Chỉ đạo: trong dolphin.nemo12.com có khu quản lý từng trường chuyên/lớp chọn (sửa thông tin, thêm trường mới) và thêm/sửa học sinh của từng trường; trên www.nemo12.com public user xem được tổng thể mọi trường, so sánh các trường, danh sách cựu học sinh tiêu biểu của từng trường, và thành tích của từng trường qua từng năm học | SDD-020, REQ-SCH-15..17, REQ-BRD-09; thi hành phần registry mà SDD-014 §2 (REQ-EXAM-11) đã thiết kế nhưng chưa có dòng code nào. Không dựng bảng schools mới: target_schools có từ migration 0004 và exams.target_school_id đang trỏ vào nó — thêm bảng thứ hai cùng nghĩa là tự tạo ra hai danh sách trường, rồi một ngày phát hiện đề thi gắn vào trường ở danh sách này còn trang giới thiệu đọc danh sách kia. Nên 0047 mở rộng tại chỗ đúng các cột SDD-014 §2 đã khai. "Học sinh của trường" hiểu là người được nêu tên công khai (school_students, mặc định alumni) — không phải danh sách học sinh đang theo học: một trường chuyên có hơn nghìn em, và đưa danh sách trẻ vị thành niên có thật lên trang công khai là chuyện child-privacy chứ không phải chuyện tính năng (Q-136). Nối thẳng vào SRC-201: mentor_profiles.alumni_school_id trỏ vào chính registry này, nên câu "mentor đều là cựu học sinh trường chuyên" và trang từng trường đọc cùng một hàng dữ liệu thay vì hai chỗ gõ tay giống nhau. So sánh trường dùng số có năm học kèm nguồn (school_year_stats), không phải điểm tổng do hệ tự chấm — xếp hạng trường chuyên là việc Nemo12 cố ý không làm (Q-137) | ✅ |
| SRC-204 | 2026-08-16 | Chỉ đạo: tách ra thành nhiều page riêng; cụm giới thiệu về Marlins phải ra trang riêng | REQ-BRD-07 sửa; App.tsx: route #/ve-marlins (slug tiếng Việt không dấu theo skill new-page) + tab thứ tư "Về Marlins", bỏ khối AboutMarlins khỏi trang Gia đình. Chọn TAB chứ không phải card trên home vì bản cũ tắt được vĩnh viễn — tắt xong là mất luôn đường quay lại; tab thì luôn ở đó, nên trang riêng cũng bỏ nút tắt. Trang Gia đình nay đúng nghĩa hub: danh sách con + một thẻ FindingNemo. Bản trên nemo12.com và pearl giữ nguyên (trang công khai, đọc một mạch hợp lý hơn). Kiểm: deep link #/ve-marlins mở thẳng ra đúng trang | ✅ |
| SRC-205 | 2026-08-17 | Feedback Toàn cảnh (learn /turtle/hoc/math): (1) mỗi Module phải có tối thiểu 3 Unit — đo thật: 69/214 module đang có 1–2 unit; (2) ô Unit chưa có dữ liệu phải hiện dấu "?" và mờ đi, đừng nổi rõ | REQ-KNW-18 + REQ-UX-13 (mới); ProgressViews.tsx: clarity() trả 0.4 cho vòng chưa đo (trước là 1) + ScoreCircle hiện "?"; content: 122 unit mới cho 69 module, mỗi unit 1 node + 10 câu do Claude soạn (scripts/apply-new-units.mjs) — đã nạp: 122 node + 1.220 câu, 0/214 module còn thiếu unit. Vòng rỗng bị đọc nhầm là lỗi hiển thị, còn số 0 lại là khẳng định sai — "?" là thứ duy nhất nói đúng "chưa đo nên chưa biết" | ✅ |
| SRC-206 | 2026-08-17 | Chủ dự án gửi danh sách cựu học sinh tiêu biểu đợt đầu cho ba trường (Ams: Phan Phương Đạt, Vương Quang Khải · Chuyên Sư phạm: Nguyễn Huy Dũng, Đỗ Phan Thuận, Mai Lâm, Nguyễn Tử Quảng, thầy Thành Công · Chuyên Tổng hợp: Nguyễn Thế Trung, Đào Thị Thu Hà), kèm chỉ đạo: "Mọi thông tin đều cần được kiểm chứng và rà soát lại, rồi mới đưa thông tin vào hệ thống" | Chỉ đạo này được dịch thành schema chứ không phải quy trình: school_students.verification_status + sources_json + cổng publish đòi verification_status='verified' và consent=1 (SDD-020 §4). Lý do đặt ở schema: đây là lời khẳng định về người có thật, sai một năm sinh hay một huy chương trên trang công khai không phải "dữ liệu xấu" mà là nói sai về một cá nhân, và một quy ước làm việc thì không chặn được ai. Đã rà 9 người bằng nguồn công khai (2026-08-17) → scripts/seed-schools-alumni.sql, toàn bộ ở draft + consent=0, chưa ai lên trang. Kết quả: 4 verified (Phan Phương Đạt 1971 · chuyên Toán Ams · HCĐ IMO 1987 + HCB IMO 1988; Nguyễn Tử Quảng 1975 · chuyên Toán ĐHSP · Bkav; Nguyễn Thế Trung · HCB IMO 1995 · DTT; Nguyễn Thành Công · dạy Sinh tại chuyên ĐHSP từ 2006 — là thầy giáo, không phải cựu học sinh, nên kind='teacher'). 3 disputed: Vương Quang Khải (founder Zalo khớp, nhưng không có nguồn nào nói anh học Ams, và con số "70 triệu user, 2 tỷ tin nhắn/ngày" không kiểm được nên không đưa số nào vào); Nguyễn Huy Dũng (mọi mệnh đề khớp nhưng thứ tự chức vụ khác lời kể — nguồn cho TT&TT 11/2020 → Chủ tịch Thái Nguyên 9/2024 → Bộ VHTTDL 5/2026); Đào Thị Thu Hà (HCĐ IMO 1998 · chuyên KHTN khớp, năm sinh 1981 không có nguồn nên để trống). 2 unverified: Đỗ Phan Thuận (trưởng đoàn IOI khớp, nhưng năm sinh 1980 và việc là cựu HS chuyên Sư phạm không có nguồn) và Mai Lâm (không tìm được nguồn công khai nào nối tên với MeSchool — dễ nhầm với MaySchool/M.E School/Maya School, nên để dòng rỗng thay vì chép lời kể). Cái không tự quyết được: consent của cả 9 người — nêu tên và thành tích một người lên trang công khai mà chưa hỏi họ là việc không sửa lại được sau khi trang đã lên | 🔵 đã rà, chờ chủ dự án bổ sung nguồn còn thiếu + xử lý đồng ý |
| SRC-207 | 2026-08-17 | Chỉ đạo dựng lại Toàn cảnh: "39 Toán" chiếm chỗ quá nhiều, đưa đi đâu cho gọn; lúc đầu hiện 3 card Số học · Đại số · Hình học trên một dòng; bấm vào card thì bên dưới hiện các vòng tròn Module trên một dòng, có mũi tên nhỏ và mảnh chỉ thứ tự học; bấm Module thì mở ra các Unit, mỗi Unit một card chứa các hình tròn bé xíu bên trong; hình bên trong cực đơn giản, kiểu khối 3D như Lego, là các con vật dưới biển; hover vào hiện tooltip mô tả Learning/Assessment Experience đó | REQ-UX-14 (mới); ProgressViews.tsx viết lại: dải băng đen n12-hero-ocean (điểm môn) rút còn một dòng mảnh vòng tròn 28px + tên môn; ba tầng bấm mở thay cho công tắc Gọn ⇄ Chi tiết cũ (SRC-184) — chính thao tác bấm đã là "chi tiết tới đâu", nên n12-seg/n12-modmap không còn ai dùng. Mỗi lúc chỉ một Package và một Module mở: mở hết cùng lúc thì một môn dài ba màn hình. Hàng Module cuộn ngang chứ không xuống dòng — xuống dòng thì mũi tên cuối dòng trên trỏ sang đầu dòng dưới, vẽ ra một thứ tự học không có thật. Con vật biển: 8 hình SVG dựng tại chỗ (zero-asset), mỗi hình chỉ còn silhouette + một vệt sáng — ở cỡ 14px mọi chi tiết khác đều mất; chọn con vật bằng băm id của bài, không random, nên learner gặp lại đúng con ấy ở đúng bài ấy. Tooltip tự vẽ chứ không dùng title của trình duyệt (hiện sau ~1 giây, không xuống dòng được). Kiểm: 3 test e2e mới cho ba tầng | ✅ |
| SRC-208 | 2026-08-17 | Chỉ đạo: "Các Interactive Lab này cần được gắn với từng Unit. Mỗi Unit cần có tối đa 1 lab đi kèm" | REQ-LAB-08 (mới); migration 0048 + scripts/attach-labs-to-units.mjs + overview API trả unit.lab + chấm lab trong thẻ Unit ở Toàn cảnh (bấm là mở thẳng lab). Đo trước khi sửa: 225 lab live, 99 lab bỏ trống labs.unit dù bài của chúng thừa biết unit nào, và 38 unit đang có 2–4 lab. Sau khi chạy: 182 live · 113 unit mỗi unit đúng 1 lab · 43 lab dôi ra chuyển draft (không xoá, không retired — chúng không hỏng, chỉ thừa so với luật mới; bật lại là một câu UPDATE). Giữ lab nào không lấy đại cái đầu bảng chữ cái: lab chạy trọn vẹn (inquiry_only=0) trước, rồi nhiều câu kiểm tra hơn, rồi nhiều bước tương tác hơn, rồi bài ở tầng nền hơn. Luật đặt ở unique index từng phần của D1 chứ không ở script: một đợt import lab sau này mà đụng luật sẽ fail ngay lúc ghi thay vì âm thầm sinh unit hai lab. Cái không tự làm được: 70 lab của Anh (32) · Văn (33) · Hoá (3) · Lý (1) · Sinh (1) chưa gắn được unit nào — chúng dạy Nghe/Nói và Làm văn, mà chương trình chưa có unit tương ứng; thử khớp theo tên chỉ trúng 3/70. Chúng vẫn live nên vẫn vào được Thư viện Lab (SRC-166), nhưng muốn gắn thì phải mở thêm unit trong chương trình — việc soạn nội dung, không phải việc của script | 🔵 đã gắn 113 unit, còn 70 lab chờ chương trình có unit tương ứng |
| SRC-209 | 2026-08-16 | Chỉ đạo: (a) trả màu cam về; (b) bố mẹ mới vào, khai xong thông tin thì không biết làm gì tiếp — cần cách để biết việc cần làm, liền mạch, và bận rồi quay lại vẫn biết còn thiếu gì | (a) CLOWNFISH trong palette — ngoại lệ thứ ba của SRC-166, chỉ 4 hình có cá hề, ART giữ nguyên thang mực. (b) REQ-PAR-17, US-84; modules/parent/next-steps.ts + GET /v1/parent/next-steps (10 test hành vi): 6 việc suy từ dữ liệu thật (hồ sơ · lời mời · Portrait · mục tiêu · cảm nhận · evidence đầu tiên), KHÔNG có bảng tiến độ riêng nên làm xong ở màn nào thì tự tắt ở đây, và mỗi việc bắt buộc có href để bấm sang. NextSteps.tsx: thẻ trang chủ hiện ĐÚNG MỘT việc kế tiếp mỗi con (đưa 6 gạch đầu dòng là dựng lại đúng cái tường wizard vừa phá bỏ), trang #/viec-can-lam giữ danh sách đầy đủ để quay lại | ✅ |
| SRC-210 | 2026-08-17 | Chỉ đạo (kèm ảnh Toàn cảnh): 3 thẻ Package cần căn giữa, "số ở trên, text ở ngay dưới", làm giống Module; và thêm footer chung | DS-001 §5b luật 10-11, REQ-UX-14. Thẻ Package: vòng 40px trên, tên dưới, cả cụm căn giữa — vòng vẫn to hơn vòng Module 32px nên thứ bậc không mất, nhưng cách đọc thì giống hệt, mắt không phải đổi hướng khi xuống tầng dưới. Footer: SiteFooter canonical ở packages/design-system/ui/, learn và marlins gắn ở main.tsx (App có hàng chục nhánh route, gắn từng nhánh là chín chỗ phải nhớ và sẽ có chỗ quên); class .n12-footer một dòng căn giữa, năm lấy theo đồng hồ. Cố ý không có: menu link, mạng xã hội, newsletter — chân trang nhiều cột là chỗ đầu tiên luật tối giản bị phá. Còn lại: web/ chưa đổi sang bản chung (footer inline hiện tại cùng nội dung) vì apps/web/src/App.tsx đang có phần việc chưa commit của phiên song song | 🔵 learn + marlins xong, web chờ |
| SRC-211 | 2026-08-17 | Feedback màn luyện tập, ba việc: (1) câu "Chưa chắc thì trượt là thường." đọc xong không hiểu ý; (2) bỏ em dash trong câu khen "Con bảo còn đoán mò mà lại đúng — làm thêm một câu cùng dạng"; (3) lời nhắc "Đọc kỹ đề rồi hãy chọn nhé" phải xuống đúng chỗ các message hay hiện, không nằm ở vị trí như ảnh | Learning.tsx. (1) Câu cũ đọc như tục ngữ không chủ ngữ, không biết đang nói ai; bản mới nói thẳng tình huống vừa xảy ra: "Con đã bảo là chưa chắc mà." + "Chưa chắc mà sai thì bình thường thôi. Giờ con biết chỗ cần nắm lại." (2) Quét cả cụm nudge/khen: 6 chuỗi còn em dash, đổi sang : , hoặc tách câu — DS-001 §5b luật 8 (SRC-057) cấm em dash trong MỌI chuỗi UI, đây là chỗ luật bị rò. Còn ~26 chuỗi em dash ở các file learn khác chưa quét. (3) Lời nhắc nhịp độ chuyển từ băng riêng phía trên câu hỏi xuống cuối thẻ, đúng chỗ mọi lời nhắn khác xuất hiện, và ẩn khi đã có kết quả — chỗ đó lúc ấy thuộc về nhận xét cho câu vừa làm. Kèm sửa lỗi cùng họ: /labs quên trả 4 cột tên rút gọn đã SELECT, nên Toàn cảnh hiện "Integers" còn Đường học hiện "Whole Numbers and Integers" | 🔵 còn ~26 chuỗi em dash chờ quét |
| SRC-212 | 2026-08-17 | Chỉ đạo: trong Interactive Labs, learner đánh dấu "favorited" vài lab để lọc lại nhanh. Kèm câu hỏi: learner tò mò "nếu tôi hổng Learning Experience này thì cần học gì để bù" — có nên gợi ý 1-2 lab cụ thể ở cuối Learning Experience, hoặc lúc bấm Exit rồi xác nhận? | REQ-LAB-09 (mới); migration 0050_lab_favorites.sql + 3 endpoint (GET/PUT/DELETE /v1/learners/{id}/lab-favorites) + ngôi sao trên từng thẻ lab và bộ lọc "Đã thích (n)" ở LabLibrary.tsx. Bảng riêng, không phải cột trên labs: đây là dữ liệu của TỪNG learner, để lên labs thì hai learner ghi đè nhau. Danh sách yêu thích lấy tách khỏi thư viện vì thư viện là tài nguyên chung của môn (cache được, không cần learner_id) — nhét cờ "đã thích" vào đó là biến nó thành tài nguyên riêng. Bấm ngôi sao đổi hình ngay rồi mới gọi API, hỏng thì hoàn tác. Hai luật nhỏ nhưng bắt được lỗi thật lúc viết test: bộ lọc chỉ hiện khi đã có ít nhất một lab được thích, và tự tắt khi lab cuối cùng bị bỏ thích — nếu không thì learner kẹt ở danh sách rỗng mà nút tắt lọc cũng vừa biến mất. Về câu hỏi gợi ý lab bù: xem phần trả lời kèm số đo, CHƯA XÂY — chỉ 184/1013 bài (18%) có đường ra một lab qua unit của chính nó hoặc qua prereq; riêng Toán 82/96 nhưng Lý 9/216 · Hoá 10/216 · Tin 0/216 | 🔵 favorited xong, gợi ý lab bù chờ chốt |
| SRC-213 | 2026-08-17 | Feedback màn luyện tập: câu đúng đang hiện hai lời động viên với hai icon cùng lúc, cần gộp làm một | Learning.tsx: mốc "3 câu đúng liên tiếp" trước đây là một hộp thứ hai với con vật thứ hai ngay dưới bóng thoại khen. Gộp lại thành MỘT con vật, MỘT bóng thoại: mốc chuỗi lên làm câu đầu vì nó cụ thể hơn ("đúng 3 câu liên tiếp" > "Trúng!"), lời khen theo ngữ cảnh xuống làm câu dưới. Khen hai lần cho cùng một câu trả lời thì cả hai lời đều nhẹ đi, và màn hình có hai nhân vật giống hệt nhau đứng cạnh nhau | ✅ |
| SRC-214 | 2026-08-17 | Chỉ đạo màn luyện tập: (1) 4 phương án ngắn thì xếp 2 dòng thay vì 4 dòng, phương án dài thì giữ mỗi dòng một đáp án; (2) đổi Skip và Exit sang icon | Learning.tsx. (1) Ngưỡng đo trên đáp án DÀI NHẤT (≤16 ký tự): chỉ cần một phương án dài là hai cột xuống dòng lệch nhau, lúc ấy một cột đọc dễ hơn. Với "1 · 2 · 1/2 · -1" thì bốn dòng gần như trống, learner phải kéo mắt dọc cả màn hình để đọc bốn ký tự. (2) Skip = mũi tên vượt qua một vạch (ký hiệu quen của trình phát), Exit = mũi tên đi ra khỏi khung mở; chữ gạch chân cũ đọc như hai lời mời, mà lời mời duy nhất ở màn này phải là nút trả lời. Tên đầy đủ giữ ở title + aria-label, test e2e bám theo đó | ✅ |
| SRC-215 | 2026-08-17 | Chỉ đạo: góc trên phải hiện avatar của user, và công tắc "VI - EN" cho nhỏ lại | Avatar: /v1/me chưa bao giờ trả avatar_url dù ảnh Google đã được lưu lúc đăng nhập — 7/7 user trong DB đều có ảnh mà mọi app vẫn hiện chữ cái đầu. Thêm cột vào response + schema; <img> thêm referrerPolicy="no-referrer" vì lh3.googleusercontent.com trả 403 khi Referer lạ, và ảnh hỏng thì ô này thành khoảng trắng chứ không tự quay về chữ cái. Công tắc: thêm .n12-switch-sm (32×26px, chữ 11px) dùng ở header learn; giữ nguyên 44px trên màn cảm ứng (AS-09.3.3) — ngón tay không nhỏ đi theo thiết kế | ✅ |
| SRC-216 | 2026-08-17 | Chỉ đạo (kèm ảnh lab Phép tính phân số): (1) đổi slug thu-vien-lab sang tiếng Anh, ví dụ labs; (2) link "Exit" xuống góc dưới phải và đổi thành icon; (3) hình của bài này làm 2 card hai bên, mỗi card có pie-chart ở trên và tỉ số ở dưới | App.tsx, LabPlayer.tsx, explore/engine.tsx. (1) Slug mới /{school}/labs/{môn}/{lab}; slug cũ giữ trong bảng tra chứ không xoá — mỗi lab đã có một địa chỉ chia sẻ được (SRC-170), link cũ mà 404 thì mọi chỗ đã gửi đi đều gãy; có test riêng cho đường cũ. (2) Cùng icon "ra khỏi khung" như màn luyện tập (SRC-214), và chỉ hiện khi chưa xong lab. (3) Hai thanh ngang xếp chồng bị bỏ: chúng dài bằng nhau nhưng chia số ô khác nhau nên learner phải tự nhớ "thanh trên chia 2, thanh dưới chia 3" mới so được. Hình tròn nói ngay "một cái bánh chia mấy phần, lấy mấy phần", và hai hình tròn cùng cỡ thì so bằng mắt được. Tỉ số viết dạng chồng (tử trên, gạch ngang, mẫu dưới) đúng như trong vở. 3 test mới giữ hai chỗ dễ vỡ: số quạt tô màu đúng bằng tử số, và mẫu số 1 không rơi vào công thức cung tròn (điểm đầu trùng điểm cuối thì SVG vẽ ra hình rỗng) | ✅ |
| SRC-217 | 2026-08-17 | Chỉ đạo: mỗi Learning Experience cần một đoạn mô tả/hint chung; thêm icon dấu hỏi bé xíu ở góc dưới phải, bấm mở popover xem nội dung; hint nói sơ qua một khái niệm trong Experience kèm ví dụ nhỏ. Yêu cầu tôi tự đặt tên cho icon rồi báo lại | Tên đã chọn: "Nhắc lại" (EN Refresher), code ConceptHint. Không gọi "Hint"/"Gợi ý" vì hai từ đó ám chỉ gợi ý đáp án cho câu đang làm — learner sẽ bấm vào để tìm đáp án rồi thất vọng; "Nhắc lại" nói đúng thứ bên trong: nhắc khái niệm của cả Experience, không dính câu cụ thể nào. Cần migration skill_nodes.hint_vi/hint_en + soạn nội dung: cột description sẵn có chỉ chứa rác kiểu "Kỹ năng: Làm tròn số." Khép 2026-08-21: làm XONG mà KHÔNG cần cột mới và không soạn thêm chữ. Nguồn nhắc lại là hai đoạn Pearl đã có sẵn cho từng Unit (unit_evidence "hiểu chắc nghĩa là" + unit_misconception "hay nhầm ở đây"), vốn đã kèm ví dụ cụ thể do người soạn viết, và đã phủ 812/822 node đang hiện. Dựng cột hint_vi rỗng rồi chờ soạn 800 đoạn mới là con đường dài hơn mà kết quả tệ hơn: ô rỗng ở màn làm bài là lời chê. Unit chưa có chữ thì KHÔNG hiện nút, learner không mất gì | ✅ |
| SRC-218 | 2026-08-17 | Chỉ đạo: một số câu hỏi cần ảnh minh hoạ, và ảnh phải tạo bằng thuật toán, không dùng bitmap JPEG/PNG | Engine FigureSpec + bảng item_figures (migration 0038) đã có sẵn và đúng nguyên tắc zero-asset, nhưng mới phủ Hình học. Việc còn lại: mở rộng dạng hình sang Đại số/Số học (trục số, phân số, đồ thị hệ số góc) rồi chạy attach-figures.mjs. Khép 2026-08-21: đo lại thì vấn đề nặng hơn mô tả cũ — 411 hình đã gắn đều thuộc strand HH và VOC/HH đã bị ẩn từ SRC-299, tức phần lớn hình đang nằm ngoài tầm mắt learner. Cây Toán đang hiện (B1-B5, 2.583 câu) gần như trắng hình. Nay: attach-figures.mjs nhận --map (bản đồ node → hình soạn tay, mỗi dòng kèm câu why) và --strand 'B%'; bản đồ phủ 60/195 node và gắn được 952 câu. 135 node cố ý bỏ trống: cả Package B5 (Hiểu đề, Chọn cách, Nhìn lại, Kiên trì khi bí) là unit về THÓI QUEN nên một hình mặc định không nói thêm gì; logarit và bậc độ lớn bỏ vì trục số tuyến tính sẽ dồn các mốc thành một điểm, tức hình SAI chứ không phải hình thiếu | ✅ |
| SRC-219 | 2026-08-17 | Chỉ đạo: công thức toán cần dùng thư viện; yêu cầu so sánh, tư vấn, rồi triển khai | So sánh KaTeX · MathJax v3 · Temml. Chọn KaTeX: vẽ giống nhau trên mọi máy (Temml giao việc vẽ cho font toán của hệ điều hành — một phân số chồng bị lệch trên máy học sinh là lỗi nội dung, không phải lỗi thẩm mỹ), nhanh và đồng bộ, cú pháp LaTeX quen để người soạn dùng ngay. Giảm nặng bằng import() động + subset font. Không đổi schema: cho phép $…$ ngay trong prompt/options, bọc bằng component tự tách đoạn nên chuyển dần từng môn thay vì sửa 2.160 câu cùng lúc. Đã xây (MathText.tsx + 7 test): tách chuỗi theo cặp $…$, katex + CSS + font chỉ tải bằng import() động khi màn hình THẬT SỰ có công thức, và tải đúng một lần cho cả phiên. Chỗ dễ hỏng nhất không phải công thức sai cú pháp mà là dấu đô la trong câu hỏi bình thường — "cái bút giá $5" mà bị nuốt thành công thức là learner mất phần đề bài; luật tách vì thế đòi cặp mở–đóng trên CÙNG một dòng, không rỗng, và \$ là đô la thật. Tải hỏng hoặc LaTeX sai thì hiện nguyên văn, không dựng màn lỗi: một công thức không vẽ được vẫn đọc được, mất cả câu hỏi thì không làm bài được. Đã nối vào đề bài + đáp án ở Đường học và ở Luyện đề | ✅ |
| SRC-220 | 2026-08-17 | Câu hỏi: màn kết thúc một Learning Experience thì việc quan trọng nhất learner nên làm tiếp là gì, vì sao | Trả lời: màn này đang đặt nhầm nút — nút accent là "Ẩn bài làm", một công tắc hiển thị chứ không phải việc học. Việc quan trọng nhất phụ thuộc kết quả: còn câu sai → xem lại đúng chỗ đó ngay (chỉ lúc này learner còn nhớ mình đã nghĩ gì khi chọn sai); đúng trọn vẹn → đo mức vững thay vì luyện thêm (điểm đo ngay sau khi luyện luôn cao hơn thực lực, chuyển "đã luyện" thành "đã đo" mới là bằng chứng thật); đã vững → chốt lịch ôn lại rồi đi tiếp ô kế. Đề xuất: MỘT nút accent do hệ thống chọn, "Chọn bài khác" hạ xuống nút viền, thêm dòng "Nemo12 sẽ nhắc con ôn lại khoảng ngày …". Đã xây phần nút (Learning.tsx): nút accent nay do kết quả quyết định — còn câu sai thì "Xem lại N chỗ sai", đúng hết thì "Đi tiếp: <tên ô kế>" (ô kế tính bằng chính hàm unitPath mà đường đi Unit dùng, nên hai chỗ không thể lệch), không có ô kế thì "Chọn bài khác"; bật/tắt phần bài làm hạ xuống link chữ vì nó là cách xem chứ không phải một việc. Chưa có dòng lịch ôn: learner_skill_state không có cột next_review_ideal và không endpoint nào trả ngày ôn cho learner — bịa một ngày ra thì tệ hơn là không nói | 🔵 nút xong, dòng lịch ôn chờ có dữ liệu |
| SRC-221 | 2026-08-17 | Chỉ đạo: Unit cũng cần có điểm mastery và trình bày như Module; thêm button xem "có gì thay đổi trong 7 ngày qua" — diff theo từng Package/Module/Unit; tương tự cho 30 ngày | Điểm Unit: /overview đã trả sẵn mastery_of_assessed cho từng unit, chỉ là UI chưa vẽ vòng tròn. Diff: dựng từ learner_evidence.mastery_before/after + occurred_at (migration 0044). Cảnh báo dữ liệu: mới 52/262 mẩu evidence có mastery_after (cột thêm ở 0044), nên mốc "7 ngày trước" của phần học trước đó không dựng lại được — phải nói thẳng "chưa có dữ liệu" chứ không được hiện 0, đúng luật đã chốt ở SRC-205. Khép 2026-08-21: điểm Unit đã vẽ từ SRC-441/459 (dải ô có mức vững và độ chắc); phần "7 ngày qua / 30 ngày" nay là công tắc cửa sổ thời gian trên trang Nhật ký (SRC-481) chứ không dựng thêm màn diff, vì nhật ký đã kể đúng chuyện đó bằng dữ liệu có thật thay vì suy ngược từ cột mastery_after còn thủng | ✅ |
| SRC-222 | 2026-08-17 | Chỉ đạo: Toàn cảnh hiện 7 module trong package Number còn Đường học hiện 5 — cần đồng bộ, tốt nhất gộp làm một; hỏi hai thứ này đang lưu thế nào, gộp thì giữ gì bỏ gì | Đo: không có hai nguồn dữ liệu — cả hai đọc skill_nodes, module là cột text trên từng bài. Lệch là do hai bộ lọc khác nhau: Đường học lọc theo LỚP (mặc định lớp của con) và lọc bỏ bài chưa có câu hỏi; Fractions (lớp 6-7) và Percent (lớp 6,7,9) không có bài nào ở lớp 8 nên biến mất. Đề xuất: giữ Toàn cảnh làm bản đồ duy nhất, Đường học còn đúng màn chơi của một Unit; bỏ lọc theo lớp ở tầng module (ẩn cả module khiến learner tưởng chương trình chỉ có 5 phần), giữ lọc "chưa có câu hỏi" ở tầng vào bài. Khép 2026-08-21: việc này đã tự xong ở SRC-330 (bỏ lọc theo lớp khỏi Đường học, lớp chỉ còn quyết định learner bắt đầu ở Phần nào). Kiểm lại mã hôm nay: cả /overview lẫn /labs đọc cùng skill_nodes và chỉ lọc HIDDEN_STRANDS, không nơi nào còn lọc theo grade | ✅ |
| SRC-223 | 2026-08-17 | Chỉ đạo (hai ảnh): trang Lighthouse phải theo giao diện của trang môn học trong learn | Lighthouse.tsx. Ba chỗ lệch được sửa: (1) header nay có công tắc VI/EN cỡ nhỏ + avatar ở phải, đúng chỗ như mọi trang learn — trước đó trang này tự dựng header riêng, không avatar, công tắc cỡ to nằm sát tên trang; (2) dải băng đen (icon 96px + tiêu đề + đoạn giới thiệu) rút còn một dòng icon 32px + tên trang: dải cũ chiếm gần một phần ba màn hình để nói một câu learner đọc đúng một lần trong đời, còn việc thật ("khai thêm để mở school") bị đẩy xuống dưới nếp gấp; (3) ba thẻ về đúng dạng thẻ điều hướng — icon, tên, một dòng phụ, cả thẻ bấm được; bản cũ mỗi thẻ có hai đoạn văn + một hộp xanh + nút "Vào xem", tức bốn thứ phải đọc trước khi biết bấm vào đâu, đúng ba thứ mà DS-001 §5b điều 3/7/9 cấm. Phần "vào đó con làm gì" chuyển vào tooltip, không mất | ✅ |
| SRC-224 | 2026-08-17 | Chỉ đạo trang Mục tiêu: bỏ toàn bộ nhãn "tạm tính", bỏ nút "Xác nhận"; mục tiêu mọi kỳ thi đều là 10/10; ngày hiển thị dạng DD.MM.YYYY kèm "còn x tuần", dưới 7 ngày thì "còn x ngày y giờ" | GoalPage.tsx + 5 test cho hàm timeLeft. Bỏ nút xác nhận là đúng: learner sửa ngày bằng cách bấm thẳng vào ngày, nên một nút xác nhận riêng chỉ thêm một việc phải làm mà không đổi được gì — ngày sai thì sửa, ngày đúng thì thôi. Thứ dòng này cần nói là còn bao lâu nữa, không phải trạng thái xác nhận của một bản ghi. Đơn vị đổi ở mốc 7 ngày vì hai khoảng cách cần hai cách nghĩ khác nhau: còn nhiều tuần thì learner chia việc theo TUẦN, còn dưới một tuần thì từng buổi mới là đơn vị có nghĩa. Ngày đã qua nói thẳng "đã qua", không hiện số âm hay "còn 0 tuần" — nói sai về một mốc thi khiến learner tưởng mình còn thời gian. Đích 10/10 hiện thành badge, không hỏi learner đặt đích cho từng kỳ nữa (hỏi một câu mà câu trả lời luôn giống nhau chỉ tốn một lượt bấm) | ✅ |