Marlins IA · Báo cáo theo môn, hành trình khoá bố mẹ và cổng ba câu
Một phần của Marlins IA. báo cáo học tập theo môn, khoá bố mẹ thành bảy hành trình, chạy tốt trên điện thoại, khung trang khoá, đọc từng phần và cổng ba câu.
Báo cáo học tập theo môn (SRC-1244)
Chỉ đạo chủ dự án 05.10.2026: trang của con có cụm "Báo cáo học tập" liệt kê các môn; bấm từng môn tới trang báo cáo của môn đó; IELTS đầu tiên, Toán thứ hai.
Danh sách môn không lấy từ /progress. per_subject của nó đọc đồ thị kỹ năng K12 (learner_skill_state), mà đo trên production 05.10.2026: IELTS có bằng chứng ở 32 learner nhưng chỉ 2 learner có dòng IELTS trong bảng ấy, vì sân luyện IELTS ghi vào sổ bằng chứng và lát cắt IELTS riêng. Dùng per_subject là xoá đúng môn chủ dự án muốn đứng đầu khỏi trang của 30/32 đứa trẻ. Nên có GET /v1/learners/{learnerId}/report-subjects: một môn "có báo cáo" khi có dấu vết ở BẤT KỲ sổ nào trong ba (bằng chứng, trạng thái kỹ năng, lát cắt IELTS), một câu UNION.
Báo cáo IELTS là trang riêng (IeltsReport), không phải một tab của báo cáo K12: báo cáo K12 vẽ bản đồ mức vững từ đồ thị kỹ năng, nên mở IELTS ở đó là mở một trang trống. Trang IELTS đọc lát cắt IELTS (/ielts-model?fresh=0, ĐỌC chứ không tính lại, để một lượt bố mẹ mở trang không đẻ thêm ảnh chụp vào lịch sử model của con): bốn kỹ năng, band hoặc "Chưa biết" kèm lý do (bài luyện không được quy ra band, quyết định SRC-849), mục tiêu, kỹ năng nên tập trung, và con tự đánh giá mình có khớp bằng chứng không. Không có band tổng: một con số overall khi vài kỹ năng còn chưa biết là một con số bịa. Các môn khác mở báo cáo K12 có sẵn ở /child/{id}/report/{subject}.
Thứ tự môn một nguồn: apps/marlins/src/subjects.ts. Trước đây chép tay ở hai file (ChildReport.tsx, Metrics.tsx) và chỉ khớp nhau vì chưa ai sửa một bản.
Khoá bố mẹ thành một vòng hành trình (SRC-1252)
Chủ dự án 06.10.2026: khoá học của bố mẹ không chỉ là "đọc rồi làm quiz". Bố mẹ học để làm khác đi với con, nên khoá phải dẫn họ đi hết một vòng: hiểu, thử, quan sát, điều chỉnh. Giao diện lấy nhịp của trang IELTS trên www.nemo12.com (chip eyebrow, câu hỏi lớn làm tiêu đề, cột bước đánh số, thẻ tóm tắt) nhưng giữ nền biển sâu và thẻ đặc --card-deep của Marlins.
Triết lý. Bố mẹ: I understand → I try → I observe → I adapt. Đặt cạnh vòng của learner I learn → I practice → I prove → I grow ngay trên trang khoá, để thấy hai vòng khác nhau ở đâu.
Cấp khoá: sáu hành trình thành vòng (trang /parent-courses/{code}, cột bước dọc):
| Hành trình | Câu hỏi | Mang về | Lưu |
|---|---|---|---|
| GOAL | Tôi muốn thay đổi điều gì? | My Parenting Goal (Discover my situation → Choose my goal → Define my goal) | goal |
| UNDERSTAND | Tôi và con đang ở đâu? | My Family Starting Point (về con, về tôi, về quan hệ; Strength, Challenge, Parent pattern) | understand |
| LEARN | Điều gì đang thật sự diễn ra? | Understanding (Concept → Example → Think about my child → Connect) | mốc đọc ở parent_course_progress |
| TRY WITH MY CHILD | Tối nay tôi thử điều gì với con? | Phản ứng của con, gom từ mọi chỗ học | try cấp chỗ học |
| REFLECT | Tôi rút ra được gì? | My Growth (Before/After) và Next Step, gom từ mọi chỗ học | reflect cấp chỗ học |
| DECIDE | Tôi nên làm gì tiếp theo? | Understand → Consider → Decide; quyết định thành GOAL của vòng sau | decide |
Cấp chỗ học: năm bước (trang /parent-courses/{code}/u/{n}/l/{m}), thanh tiến độ DÍNH trên đầu cột nội dung: GOAL ━━ LEARN ━━ TRY ━━ REFLECT ━━ NEXT, ● đã xong hoặc đang ở, ○ chưa tới. GOAL hỏi "Sau Unit này, tôi có thể làm gì khác đi?"; LEARN là thân bài cũ (SCQA, ví dụ, chỗ dễ hiểu lầm, quiz); TRY là nhiệm vụ "Try this tonight" rồi bố mẹ quay lại chọn phản ứng của con 😊 Tích cực / 😐 Bình thường / 😣 Tiêu cực / 🤔 Bất ngờ kèm "Điều gì đã xảy ra?"; REFLECT hỏi điều đã xảy ra, điều bất ngờ, điều hiệu quả, điều chưa, Before/After, bước tiếp; NEXT dẫn sang chỗ học sau.
Không soạn thêm nội dung. Câu GOAL của chỗ học ghép từ tên chỗ học (đã là việc bố mẹ làm), nhiệm vụ TRY dựng từ Guiding Question và lấy ví dụ đầu tiên của thân bài làm hình mẫu (parentJourney.ts).
Lưu trữ. Bảng parent_course_journeys (migration 0334), một dòng cho một bước của một phụ huynh ở một chỗ; cấp khoá dùng unit_index = lesson_index = -1. API GET/PUT /v1/parent/course-journeys lấy người dùng từ phiên, không nhận user_id (QG-008); bước sai cấp hoặc thân sai hình dạng trả 400.
Parent Model. Mỗi lần lưu ghi thẳng một mẩu vào parent_evidence (nguồn parent_journey), và lượt nạp bù có thêm nguồn thứ mười hai cùng event_id nên không ghi trùng: TRY là tried_with_child (chiều acting, độ tin .70), REFLECT là reflection_written (understanding, .70), GOAL, UNDERSTAND, DECIDE là lời tự khai (.50).
Chạy tốt trên điện thoại (SRC-1254)
Chủ dự án 06.10.2026: "Hãy đảm bảo hệ thống marlins chạy tốt trên mobile". Rà mọi route ở bề ngang 375px trên production (trang chủ, khoá bố mẹ, chi tiết khoá, Unit, chỗ học, thư viện, chương sách, sự kiện, lớp của con, lịch, trang con, báo cáo, báo cáo IELTS, giới thiệu bạn bè, about). Không route nào tràn ngang (scrollWidth không vượt bề rộng màn); ba chỗ hỏng là chỗ CHẠM:
| Chỗ | Hỏng ở 375px | Sửa |
|---|---|---|
| Menu chính trên thanh trên | Dải năm mục cuộn ngang chỉ còn chỗ cho nửa chữ "Sự kiệ", bốn mục kia khuất mà không có dấu hiệu cuộn; nút cao 32px | Dưới md: một nút menu 44px mở danh sách dọc (shadcn Popover, MainNav.tsx). Từ md: dải ngang như cũ, nút cao 44px |
| Thanh năm bước của chỗ học | Nút bước cao 26px, vạch nối chen chữ NEXT | Dưới sm: bỏ vạch nối và chấm, năm nút chia đều bề ngang, mỗi nút cao 44px |
| Ô link mời bạn bè | min-w-64 và chữ 14px: iOS phóng to trang khi chạm vào ô | Chữ 16px dưới sm, bỏ bề rộng tối thiểu cứng. Sửa ở canonical packages/design-system/ui/ReferralPanel.tsx, nên bản sao ở learn cũng được |
Luật giữ lại: ô nhập trên màn hẹp chữ từ 16px trở lên, nút chạm từ 44px, và menu không bao giờ là một dải cuộn ngang. Cổng: apps/marlins/src/MainNav.test.ts.
Trang khoá học có khung riêng (SRC-1258)
Chủ dự án 06.10.2026: vào chi tiết một khoá thì thấy quá nhiều thông tin thừa. Trang phải chỉ còn thông tin của khoá ấy, NavBar chỉ mang thành phần của khoá, và một Progress Bar cho tiến độ từng Journey.
| Thành phần | Trước | Sau |
|---|---|---|
| Thanh trên | Thanh chung của cổng: logo, câu định danh, menu chính năm mục, avatar | NavBar của khoá: nút quay lại /parent-courses, tên khoá, sáu Journey, menu tài khoản tối giản |
| Tiến độ | Một vòng nhỏ ở cuối cột sáu hành trình | Thanh dính ngay dưới NavBar: sáu đoạn, mỗi đoạn tô theo % của Journey ấy, cộng % chung |
| Thân trang | Breadcrumb, hero lớn, "Có phải bạn đang gặp?", "Học xong bạn sẽ", năng lực, danh sách unit, cột phải học phí | Bìa nhỏ cạnh tên khoá, một dòng học phí gọn (chỉ khi chưa học), rồi sáu Journey; danh sách unit và năng lực nằm TRONG thẻ LEARN |
| Chỗ học, tổng quan unit | Không có thanh trên | NavBar + thanh tiến độ của khoá ở đầu trang (không dính, để thanh năm bước của chỗ học vẫn dính như cũ); bấm một Journey là về /parent-courses/{code}/j/{key} |
Cách tính % (journeyProgress trong apps/marlins/src/parentJourney.ts, đọc GET /v1/parent/course-journeys và GET /v1/parent/course-progress):
| Journey | Tỉ lệ |
|---|---|
| GOAL, UNDERSTAND, DECIDE | số ô đã viết / số ô của form (3, 6, 3) |
| LEARN | số chỗ học đã mở / tổng số chỗ học |
| TRY, REFLECT | số chỗ học đã ghi / số unit, kẹp ở 100% |
% chung là trung bình sáu Journey. Khoá bố mẹ chưa có bản ghi ghi danh riêng, nên "đã vào học" nghĩa là đã có dấu vết học (mở một chỗ học hoặc lưu một Journey); chỉ khi chưa có mới hiện dòng học phí.
Scroll spy: Journey đang sáng trên NavBar là thẻ cuối cùng mà đầu thẻ đã đi qua mép dưới thanh dính. Màn hẹp (dưới lg): sáu Journey thành một dải chip 44px cuộn ngang TRONG chính nó, chip đang ở tự kéo vào giữa; trang không cuộn ngang. Đây là dải điều hướng TRONG một khoá, không phải menu chính, nên luật "menu không là dải cuộn ngang" của SRC-1254 vẫn đứng cho MainNav. Nhãn TRY WITH MY CHILD rút thành TRY trên NavBar. Test: apps/marlins/src/parentJourney.test.ts.
Bảy hành trình, 3 skill, chế độ tập trung cho LEARN (SRC-1261)
Chủ dự án 06.10.2026, trên trang khoá bố mẹ (ví dụ "The Student Portrait", bố mẹ là người học): sáu tab cũ dẫn tới những form chữ dài. Nay mỗi tab là một Guided Journey (guided-journey): menu chọn hành trình, thanh chấm cam của riêng hành trình đang chọn, thẻ đánh số mỗi thẻ một quyết định, chế độ xem / sửa với ô Sửa cố định và nút Xác nhận. Thay hẳn bố cục cột sáu thẻ của SRC-1252 và thanh tiến độ sáu đoạn của SRC-1258; CourseChrome.tsx đã gỡ.
Bản đồ hành trình
Trang khoá /parent-courses/{code}[/j/{journey}[/{step}]]:
| Hành trình | Câu hỏi của bố mẹ | Các bước (chấm cam) | Lưu ở |
|---|---|---|---|
| GOAL | Tôi muốn giỏi lên ở đâu? | 1 Chọn tối đa 3 skill → 2..4 Level mục tiêu cho từng skill đã chọn | goal.skills[].target |
| WHERE AM I | Tôi đang ở đâu, và cần bao lâu? | 1..3 Level hiện tại của từng skill đã chọn → Thời gian (thẻ tính, nút "Đã hiểu") → chân dung "Kế hoạch của bạn" | goal.skills[].current |
| UNDERSTAND | Nhà mình đang thế nào? | Về con → Về tôi → Quan hệ → Điểm mạnh → Thách thức → Thói quen (6 thẻ, mỗi thẻ một câu) | understand |
| LEARN | Điều gì đang thật sự diễn ra? | Mỗi unit một chấm; bấm vào là sang chế độ tập trung | parent_course_progress |
| TRY | Tôi đã thử gì với con? | Mỗi unit một thẻ, gom phản ứng của con từ các chỗ học | try cấp chỗ học |
| REFLECT | Tôi rút ra được gì? | Mỗi unit một thẻ, gom Before / After / bước tiếp | reflect cấp chỗ học |
| DECIDE | Tôi nên làm gì tiếp theo? | Hiểu → Cân nhắc → Quyết định | decide |
Chế độ tập trung của LEARN (bấm tab LEARN là màn đổi hẳn: thanh trên của khoá và bảy tab nhường chỗ cho một thanh tối giản gồm nút thoát, "LEARN · ...", và các unit dưới dạng chấm nhỏ):
| Màn | Hành trình (chọn bằng menu) | Các bước | Theo chuẩn |
|---|---|---|---|
/j/learn | LEARN | Unit 1 → ... → Unit n (xong = mọi chỗ học của unit đã mở) | |
/u/{n}/{journey}/{step} | Unit Discovery | Câu hỏi (Compelling + Essential Question) → Big Idea → Khái niệm → Skill (skill unit nhắm, bậc và chỉ báo của khung) | CD-9 thành phần 1, 3 |
| Unit Learning | Chỗ học 1 → ... → Chỗ học n → Performance Task | CD-9 thành phần 4, 8 | |
/u/{n}/l/{m}/{journey}/{step} | Lesson Discovery | Mục tiêu (Learning Objective + Guiding Question) → Vào bài (SCQA) → Ví dụ → Hiểu lầm | CD-8 thành phần 1, 2, 4, 6 |
| Lesson Assessment | Quiz (Formative Task) → Thử với con → Rút ra → Tiếp theo | CD-8 vòng Formative Task → Evidence → Interpretation → Next Action |
Bước không có nội dung thì bỏ, không soạn thêm (unit không có Key Concept, chỗ học không có ví dụ). /l/{m}/quiz cũ trỏ thẳng vào bước Quiz. Chỗ học ngoài phần học thử chỉ mở bước Mục tiêu; các bước khác khoá và hiện thẻ trả phí như trước. Performance Task chỉ là đề + sản phẩm + tiêu chí: khoá chưa có chỗ nộp (khoảng trống đã biết).
Khung năng lực dùng
Marlin Competency Framework (khung marlin của b21 trong D1, đọc qua GET /v1/b21/frameworks/marlin/..., không cần đăng nhập). Skill được chọn là các skill mà CHÍNH khoá này nâng, suy từ bản đồ unit trong apps/marlins/src/parentCompetency.ts (cấp khoá = tổng các unit): competency chính trước, skill "khoá này chạm tới" sau. Với "The Student Portrait": PC.1.1, PC.1.4, PC.1.5, PC.1.6 (PC.1 "Đọc nơi con tôi thực sự đang ở") và PC.3.3, PC.5.5, PC.6.4. Mỗi skill có năm bậc trong khung, mỗi bậc ba chỉ báo song ngữ; trang chỉ hiện Bậc 1, 2, 3. Tên skill và câu chỉ báo luôn đọc từ khung lúc chạy, không chép vào mã. Bậc nào khung chưa có chỉ báo thì hiện "Khung chưa có mô tả cho bậc này" (rà 06.10.2026: mọi skill PC.1 tới PC.6 đều đủ Bậc 1 tới 3). Mã PC.x không hiện cho bố mẹ (SRC-705).
Luật
- Tối đa 3 skill: chọn skill thứ tư bị chặn kèm câu "Bạn đã chọn đủ 3 skill. Bỏ một skill trước khi chọn skill khác." API cũng chặn (400).
- Level mục tiêu là 1, 2 hoặc 3. Level hiện tại là 0 (chưa tới Bậc 1), 1, 2 hoặc 3, và chỉ đặt được cho skill đã chọn ở GOAL: hai level nằm chung một phần tử của
goal.skills, nên không có level hiện tại nào lơ lửng ngoài 3 skill. API từ chối level hiện tại khi chưa có level mục tiêu. - Thời gian: 5 giờ cho mỗi level của mỗi skill (kiến thức + luyện tập + nhiệm vụ).
giờ(skill) = max(0, mục tiêu - hiện tại) × 5, tổng là cộng 3 skill. Trang hiện từng skill và tổng kèm câu luật; skill thiếu level thì "Chưa đủ dữ liệu", không đoán. Tính ở client (timeEstimatetrongapps/marlins/src/courseJourneys/model.ts).
Lưu trữ
Không thêm bảng, không migration. Bước goal của parent_course_journeys (migration 0334) nhận thêm khoá tuỳ chọn skills: [{ skill, target?, current? }] (zod trong workers/api/src/modules/parent/journeys.ts, tối đa 3, không trùng, mã dạng PC.1.5); dòng goal chỉ có chữ của SRC-1252 vẫn hợp lệ. Mọi lần lưu vẫn ghi một mẩu tự khai (.50) vào parent_evidence. Dấu "đã đọc" của từng bước Discovery nằm trong trình duyệt (n12.parentLesson.done.* như cũ, n12.parentUnit.done.* mới), cùng lý do như SRC-671: máy chủ chỉ ghi "đã mở chỗ học" và điểm quiz.
Bố cục mọi màn: NavBar, Progress Bar, Status Card
Luật bố cục của chủ dự án cùng ngày, chi tiết ở guided-journey §8b: NavBar mang bảy journey, journey hiện tại nền coral; ngay dưới là thanh các bước của journey hiện tại với tên bước luôn hiện (375px dùng tên ngắn, thanh cuộn ngang nếu cần); Status Card góc trên phải vùng nội dung, 3 đến 5 dòng dữ liệu đã lưu. Trong LEARN, NavBar thu thành dải chip có LEARN nổi coral, thanh là các unit, rồi các bước của journey unit / chỗ học. Status Card đọc lại tiến độ sau khi chỗ học được ghi là đã mở và sau khi điểm quiz lưu xong, để con số không đứng sau thực tế.
Thanh dính: .od-root mang overflow: hidden, biến <main> thành khung cuộn nên sticky top-0 bên trong trôi theo trang. Ba route của khoá thêm overflow-clip. Test: apps/marlins/src/courseJourneys/model.test.ts, focusModel.test.ts, workers/api/src/modules/parent/journeys.test.ts.
Đọc từng phần ngắn, cổng ba câu sau mỗi phần (SRC-1265)
Chủ dự án 06.10.2026: chỗ học của khoá bố mẹ đưa quá nhiều chữ một lúc. Mọi chỗ học của mọi khoá bố mẹ nay đọc thành nhiều phần ngắn, mỗi lúc một phần, và cuối mỗi phần là một cổng đọc (mẫu chung ở guided-journey §10, luật soạn câu ở CD-8b).
| Phần | Nội dung (lấy nguyên từ thân bài, không chép lại) |
|---|---|
| 1 Chuyện quen | situation + complication của SCQA |
| 2 Câu trả lời | question + answer của SCQA |
| 3, 4, 5 Ví dụ 1-3 | mỗi phần một ví dụ |
| 6, 7, 8 Hiểu lầm 1-3 | mỗi phần một chỗ dễ hiểu lầm |
Lesson Discovery thành Mục tiêu → P1 → ... → P8; thanh tiến độ ghi tên từng phần. Lesson Assessment giữ nguyên (Quiz 20 câu → Thử với con → Rút ra → Tiếp theo).
Luật
- Cuối mỗi phần luôn có nút "Tôi đọc xong rồi, kiểm tra nhanh" (đúng câu chủ dự án chốt). Bấm vào hiện đúng 3 câu siêu ngắn, mỗi câu 3 phương án ngắn, một đáp án đúng.
- Phải trả lời đủ 3 câu mới nộp được. Nộp xong chỉ hiện tổng ("2/3 câu đúng"): không đánh dấu câu nào đúng câu nào sai, không lời giải.
- Lời giải của cả 3 câu chỉ hiện khi đúng 3/3, kèm nút sang phần tiếp.
- Chỉ 100% mới mở phần sau. Dưới 100% thì làm lại được, nhưng chỉ sau 3 phút kể từ lúc lần trượt kết thúc; nút hiện đếm ngược "Làm lại sau 2:41". Lần làm lại có thể là cùng 3 câu, thứ tự phương án được xáo (lần đầu giữ thứ tự soạn; cùng một lần làm thì tải lại trang vẫn thấy cùng thứ tự).
- Phần đã qua mở để đọc lại mãi, không phải làm lại quiz. Phần sau phần chưa qua thì khoá, cả trên thanh tiến độ lẫn khi mở thẳng URL.
- Chỗ học chưa có câu cổng (chưa soạn) giữ ba bước dài của SRC-1261; hiện cả 162 chỗ học đều đã có.
Nội dung và lượt làm nằm ở đâu
- Câu hỏi:
apps/marlins/src/parentLessonGates/<code>.ts(15 file, 162 chỗ học × 8 phần × 3 câu = 3.888 câu), cạnh thân bàiparentLessons/. Bản D1 ởcurriculum_lesson_gate_quiz+curriculum_lesson_gate_choices(migration 0335), nạp bằngscripts/seed-parent-gates-1.sqltới-4.sqlsinh từscripts/curriculum/gen-parent-gates.mjsqua workflow seed-data. Coral chưa có chỗ sửa câu cổng (khoảng trống đã biết): sửa trong file rồi chạy lại script sinh seed. - Lượt làm: bảng
parent_lesson_gates(migration 0335), một dòng mỗi phụ huynh mỗi phần: số lần, tổng điểm lần gần nhất, lúc trượt gần nhất, lúc qua. Không lưu đáp án đã chọn. Thời gian chờ đo bằng đồng hồ của D1:GET /v1/parent/lesson-gates?course_code=trảretry_after_stính ở server,POST /v1/parent/lesson-gates/attempt(part_index,total: 3,correct) trảaccepted: falsekhi phần đã qua hoặc còn trong 180 giây, và điều kiện ấy nằm ngay trong câu upsert nên hai tab nộp cùng lúc không lọt được. Trình duyệt giữ một bản sao (n12.parentGate.*) chỉ để dùng khi lượt nộp không tới được server; gộp hai bản luôn lấy thời gian chờ dài hơn. - Kiểm câu cổng khi soạn:
node scripts/curriculum/check-parent-gates.mjs [code].
Test: apps/marlins/src/lessonGate.test.ts (luật cổng, chỉ hiện tổng, lời giải chỉ khi 3/3, 180 giây, lưu lại sau tải trang, xáo khi làm lại), apps/marlins/src/parentLessonGates.test.ts (phủ đủ 162 chỗ học), workers/api/src/modules/parent/lesson-gates.test.ts (hành vi API trên D1 thật).
Lịch sử quyết định
Vòng duyệt cổng ba câu của khoá bố mẹ 08.10.2026 (SRC-1297)
Chủ dự án uỷ quyền duyệt toàn bộ nội dung đã soạn (08.10.2026). Vòng này chỉ sửa CHỮ trong apps/marlins/src/parentLessonGates/* (3.888 câu, 162 lesson): không đổi lesson, phần, câu, phương án hay vị trí đáp án, nên khoá lưu giữ nguyên.
- Lỗi nặng nhất: câu cổng chép nhầm khoá. Unit 2 và 3 của
from-pressure-to-ownership(lesson 2.1-3.3, 144 câu) là bản chép từfuture-skills, không khớp bài đọc. Đã viết lại cả 144 câu từ đúng bài đọc. Test mớicrossCourse.test.tsđỏ khi cùng một câu (đề + phương án) xuất hiện ở hai khoá hoặc một lesson chung từ 3 đề trở lên với lesson của khoá khác. - Đáp án dài nhất (lỗi hệ thống): trước vòng duyệt 2.181/3.888 câu (56%) có đáp án dài nhất theo chữ, 479 câu dài hơn mọi nhiễu từ 3 chữ trở lên. Sửa tay toàn bộ 479 ca nặng (chủ yếu cho nhiễu mang đúng chi tiết của hiểu lầm); còn 1.709 ca lệch 1-2 chữ chưa sửa, để vòng sau.
- Soát nghĩa theo mẫu phân tầng (ít nhất 2 lesson mỗi khoá, đầu và cuối khoá): không thấy câu nhiều đáp án đúng hay nhiễu đúng; sửa 1 câu không trả lời được từ phần của nó (assessment 3.2), 1 lời giải sai, và 5 tham chiếu "bài trước" sang lesson khác (đổi để phần đang đọc tự trả lời được).
- Ký tự cấm: 0 trước và sau. 16 phương án kiểu "Tất cả" đều là phương án đếm mang hiểu lầm, không phải lựa chọn "tất cả đều đúng", nên giữ.
- Seed sinh lại bằng
scripts/curriculum/gen-parent-gates.mjs(bốn filescripts/seed-parent-gates-1.sqltới-4.sql).