Skip to content

Chuẩn Course · Course IELTS, key concepts, ELA và cụm bài đọc ​

Một phần của Chuẩn thiết kế Course · Unit · Lesson (SRC-609). Mạch 12 course IELTS, key concepts và bộ ví dụ, sáu khoá ELA, key takeaways và cụm bài đọc của tầng luyện đọc IELTS.

CD-13 · Mạch 12 course IELTS kiểu mới (SRC-658) ​

Chỉ đạo chủ dự án 2026-08-31. Một progression 12 course, IELTS không chi phối cấu trúc Unit; IELTS chỉ xuất hiện như bối cảnh xác thực để learner biểu hiện năng lực đã dựng được.

TầngCourse
Nền01 Language Foundations · 02 Reading the World · 03 Listening to Meaning
Giao tiếp04 Speaking with Purpose · 05 Writing with Purpose · 06 Ideas and Arguments
Học thuật07 Critical Reading · 08 Academic Language · 09 Research and Synthesis
Tích hợp10 Communication and Interaction
Biểu hiện11 IELTS Performance
Thuần thục12 IELTS Mastery

Nguyên tắc chủ dự án đặt ra và đáng giữ cho cả 12 course: một task IELTS không phải một Learning Experience. "Làm 10 câu True/False/Not Given" là luyện tập hoặc đo, không phải học. Learning Experience là: learner đọc một claim, tìm bằng chứng, phân biệt stated / implied / unsupported, bảo vệ quyết định của mình — rồi mới gặp dạng câu hỏi IELTS. Nhờ vậy IELTS Score tách khỏi Learner Capability, và khi điểm thấp hơn năng lực thì hệ hỏi được câu đúng: nghẽn ở task interpretation, quản lý thời gian, hay ở chính năng lực?

Nội dung nguồn: scripts/course-content/ielts-core/*.json — chữ của chủ dự án, chép nguyên văn. Sinh migration bằng node scripts/ielts-core-to-sql.mjs. subject_id là ielts_core, tách khỏi bốn môn ielts_reading/listening/writing/speaking đang có: 12 course này là MỘT mạch liên tục, xếp vào bốn môn kia là cắt rời chính cái progression làm nên giá trị của nó.

Song ngữ (migration 0181): mỗi mẩu chữ learner đọc ở tầng Course có hai cột _vi và _en. Spec viết bằng tiếng Anh nên lúc nạp ghi tạm chính chuỗi tiếng Anh vào cả hai cột; dấu hiệu "chưa dịch" là _vi = _en, không phải một cột cờ — một bản dịch thật không thể trùng nguyên văn bản gốc, nên dấu hiệu này không nói dối được. Chặng translate trong workers/api lấp dần bản Việt bằng model.

Một Unit có nhiều Essential Question và một Lesson có nhiều Guiding Question: curriculum_unit_questions và curriculum_lesson_questions giữ đủ bộ, còn cột đơn cũ luôn chứa câu thứ nhất để mọi thứ đang đọc nó vẫn chạy.

CD-14 · Key Concepts, Skills và bộ ví dụ (SRC-659) ​

Chỉ đạo chủ dự án 2026-08-31.

Mỗi Unit có hai danh sách TÁCH RIÊNG (curriculum_unit_concepts, migration 0183):

Là gìDạng chữ
Key Conceptthứ learner phải hiểudanh từ hoặc cụm danh từ
Skillthứ learner phải làm đượcbắt đầu bằng động từ, quan sát được

Không gộp một danh sách: một unit đủ concept mà không có skill nào thì nó là bài giảng chứ không phải unit, và gộp lại thì thiếu vắng ấy vô hình. Mỗi mục kèm một câu nói rõ nó nghĩa là gì trong đúng unit này — nhãn trần ("Suy luận") đọc xong ai cũng gật, và chính vì thế nó không kiểm được: hai người hiểu hai kiểu vẫn cùng gật. Cổng rejectConceptShape chặn hai lỗi máy đọc được: một nhãn nằm ở cả hai danh sách, và skill viết thành danh từ.

Mỗi Lesson có 3 ví dụ đúng và 3 ví dụ dễ nhầm (curriculum_lesson_examples). Cặp này phải đi cùng nhau và đó là toàn bộ ý nghĩa của nó: một khái niệm chỉ thật sự rõ khi learner thấy được đường biên của nó. Ba ví dụ đúng dạy cái bên trong; ba ví dụ suýt-đúng mới dạy cái bên ngoài, và biên giới nằm ở giữa. Vì thế near_miss phải trông như đúng và chỉ gãy ở một chỗ nhỏ — một ví dụ sai lộ liễu chỉ làm đủ số, không dạy được gì. Cột why của near_miss là phần đáng giá nhất: không nói ra chỗ gãy thì learner chỉ học thuộc rằng "cái này sai".

Cả hai do xưởng sinh (curriculum.author-unit-concepts v1, curriculum.author-examples v1) qua chặng concepts và examples của runCurriculumAuthoring — cách tốt nhất, tuy từ SRC-672 không còn bắt buộc.

Câu chuyện SCQA có cổng chất lượng, và cổng ấy nhìn lại cả cái đã sinh. rejectStory chặn ba kiểu hỏng: tình huống mở bằng một LOẠI người ("bạn…", "học sinh…") thay vì một người cụ thể; chỗ vướng nói chung chung ("không chắc chắn", "gặp khó khăn") — "chưa biết" không phải một chỗ vướng, nó là chỗ trống; và lối thoát chỉ báo rằng sắp học ("chúng ta cần tìm hiểu…") thay vì kể người ấy đã LÀM GÌ. Luật giống hệt rubric của workers/foundry: hai cỗ máy sinh nội dung phải cùng một thước, không thì cái yếu hơn quyết định chất lượng thật.

Cột curriculum_lesson_stories.weak (migration 0184) đánh dấu dòng cần viết lại, và chặng story nhận cả bài chưa có chuyện lẫn bài có chuyện trượt cổng. Không có cột này thì cổng chỉ chặn cái sắp sinh, còn thứ đã nằm trên production ở lại mãi — đúng cái bẫy đã xảy ra với Big Idea. Lần đánh dấu đầu tiên bắt 249 trong 366 câu chuyện.

Bốn competency bổ sung cho khung ELA — ĐÃ BỎ (SRC-699, chỉ đạo chủ dự án 2026-09-10). ELA.8 Listen for Meaning · ELA.9 Use Academic Language · ELA.10 Adapt to Audience · ELA.11 Improve My Own Performance từng được migration 0183 (SRC-659) thêm vào framework nemo, vì bảy competency gốc của Building 21 không có chỗ treo cho bốn năng lực mà mạch 12 khoá dựng nên. Chủ dự án xem lại khung và quyết bỏ cả bốn, ở cả nemo lẫn khung English (migration 0211).

Chỗ treo dựng lại bằng một lĩnh vực RIÊNG (SRC-700, migration 0212). Bốn năng lực mới nằm trong lĩnh vực EAP — English for Academic and Exam Purposes — của khung english, KHÔNG nối thêm số vào ELA: bảy competency ELA là bản gốc của Building 21, và nối số vào đó chính là chỗ lần trước phải gỡ ra. Chỉ thêm ở khung english, không thêm ở nemo.

CompetencyKhoá dựng nó
EAP.1 Listen for Meaning03 Listening to Meaning
EAP.2 Speak and Interact with Purpose04 Speaking with Purpose · 10 Communication and Interaction
EAP.3 Use Academic Language08 Academic Language
EAP.4 Perform and Improve Under Exam Conditions11 IELTS Performance · 12 IELTS Mastery

Tên và câu tuyên bố lấy từ chính unit của sáu khoá, không nghĩ ra từ đầu, nên mỗi năng lực có thật một mạch bài dạy nó. Quan hệ khoá ↔ năng lực ghi bằng curriculum_course_sources (kind='b21', ref_code='EAP.n') — đây đúng thứ ELA.8-11 ngày trước KHÔNG có, nên "chỗ treo" khi ấy chỉ tồn tại trong tài liệu.

Còn để ngỏ có chủ ý: bốn competency này CHƯA có skill và bậc. Đó là việc soạn nội dung có cổng riêng, không phải thứ sinh kèm trong một migration; bày ra một cái thang bậc nghĩ vội còn tệ hơn chưa có thang, vì Learner Model sẽ chấm theo nó.

CD-14b · Sáu khoá ELA, môn ela (SRC-701) ​

Chỉ đạo chủ dự án 2026-09-10: "Soạn ra 6 khoá khác, không phải là IELTS Core, mà là để học tiếng Anh, dựa theo các competency framework trong English Language Arts."

Môn riêng ela trong Squid, không nhét vào english. Thang core của môn english đã kín 15 slot (level 1-5 × seq 1-3), nhưng lý do chính không phải là chỗ: E1-E15 dựng nền ngôn ngữ (âm, từ, câu, ngữ pháp), còn sáu khoá này dựng năng lực dùng cái nền ấy. Hai mạch trả lời hai câu khác nhau nên đứng thành hai môn.

KhoáCompetency ELA nó dựng
A01 Đọc kỹ, đọc đúngELA.1 Read Critically
A02 Nói ra điều mình nghĩELA.2 Express Ideas
A03 Kể lại một câu chuyệnELA.5 Write Narrative Texts
A04 Giải thích cho người khác hiểuELA.4 Write Informative Texts
A05 Lập luận và tranh luậnELA.3 Compose Evidence-based Arguments · ELA.6 Engage in Discussion
A06 Tìm hiểu và tổng hợpELA.7 Conduct Research

Bảy competency của khung ELA phủ hết trong sáu khoá; A05 mang hai vì lập luận và thảo luận là một năng lực nhìn từ hai phía. Quan hệ khoá ↔ competency ghi bằng curriculum_course_sources (kind='b21'), đọc được bằng một câu SQL — đúng bài học của ELA.8-11 (SRC-699/700).

Mỗi khoá 4 unit × 3 lesson, nạp bằng scripts/ela-to-sql.mjs từ scripts/course-content/ela/*.json (migration 0213). Spec có đủ hai bản vi và en, nên quy ước "_vi === _en nghĩa là chưa dịch" của 12 khoá IELTS Core không áp dụng ở đây.

Còn để ngỏ có chủ ý: lesson mới có tên và Guiding Question. Học liệu, câu kiểm, điều đọng lại để xưởng nội dung soạn tiếp — môn ela đã được thêm vào SUBJECTS của workers/api/src/modules/curriculum/authoring.ts, đúng đường 12 khoá IELTS Core đã đi. Gõ tay hàng trăm câu hỏi ngay trong một migration là cách chắc chắn để có một kho câu không ai soi được.

CD-15 · Key Takeaways, và chuỗi phụ thuộc của các chặng (SRC-660) ​

Chỉ đạo chủ dự án 2026-08-31: "Bổ sung Key Takeaways vào cuối các Lesson, và Units."

Takeaway không phải tóm tắt. Tóm tắt kể lại bài đã nói gì; takeaway nói điều learner MANG ĐI, dùng được ở chỗ khác kể cả khi đã quên bài này tên là gì. Đó cũng là chỗ model rơi vào mặc định, vì kể lại thì chỉ cần đọc, còn nói điều mang đi được thì phải hiểu bài dùng vào việc gì — nên cổng rejectTakeaways chặn ba dấu hiệu: mở đầu bằng lối kể lại, chép nguyên văn câu hỏi cốt lõi, và hai takeaway trùng nhau.

Hai bảng riêng (curriculum_lesson_takeaways, curriculum_unit_takeaways, migration 0185) vì hai hạng khác nhau: của một bài là điều đọng lại sau một buổi; của một unit là điều còn lại sau khi quên hết các bài. Một bảng chung có cột phân loại thì mọi truy vấn phải nhớ lọc, quên một lần là trộn hai hạng vào nhau.

Vị trí: cuối trang Unit và trang Lesson trên ielts.nemo12.com, và đầu chặng 4 trên trang học — chặng 4 chính là cuối bài, và điều đáng mang đi nên tới trước chỗ tự viết ra mình nhận thấy gì.

Hai chiều dịch, hai prompt ​

Nội dung ở tầng Course đi theo hai chiều dịch ngược nhau, và gộp chúng làm một là hỏng:

ChiềuLo phần nàoPromptDấu hiệu "chưa dịch"
Anh → Việtchủ dự án viết (tên khoá, Big Idea, câu hỏi)b21.translate-vi_vi = _en
Việt → Anhxưởng sinh (key concept, skill, takeaway, ví dụ)curriculum.translate-en_en IS NULL

Mỗi chiều có cái bẫy riêng. Chiều sang Việt: chữ Hán chèn vào, Viết Hoa Từng Từ theo lối tiếng Anh. Chiều sang Anh: dịch cả thuật ngữ tiếng Anh vốn đang nằm trong câu tiếng Việt, và nở một nhãn ngắn thành cả câu giải thích.

Chặng translate-en đánh địa chỉ dòng bằng rowid, không bằng khoá chính: mấy bảng này có khoá ghép (curriculum_unit_concepts là unit_id, kind, seq), nên UPDATE ... WHERE unit_id = ? sẽ ghi cùng một bản dịch đè lên mọi dòng của unit ấy — bảng vẫn đầy, chữ vẫn có, chỉ là sai.

Prompt phải cho model THẤY khuôn JSON, không tả bằng lời ​

Bốn prompt của xưởng cùng hỏng một kiểu trong ngày 2026-08-31: prompt tả hình dạng bằng lời ("mỗi phần tử đủ ba ô", "mỗi mục kèm một câu") và model trả về sai hình dạng — mảng chuỗi thay vì mảng object, hoặc đúng ngược nhau giữa hai trường. Cả bốn đều trượt schema, bị runPrompt trả về lỗi, và không sinh được gì suốt nhiều nhịp cron.

Cách chữa rẻ và chắc: dán một khuôn JSON thật vào prompt, có dữ liệu mẫu đúng miền. Cùng bài học với prompt dịch b21.translate-vi (SRC-642): model bắt chước ví dụ mạnh hơn nghe lời dặn. Đây là luật cho mọi prompt mới của xưởng.

Chuỗi phụ thuộc giữa các chặng, và một lỗi im lặng ​

Bốn chặng (checks, pitfalls, examples, takeaways) lấy Lesson Outcome làm đầu vào và continue khi bài không có outcome nào. Mạch 12 khoá nạp từ spec chủ dự án, mà spec đặt outcome ở tầng Unit — nên 201 lesson không có outcome, và bốn chặng ấy lặng lẽ bỏ qua toàn bộ 201 bài mỗi nhịp cron, không để lại một dòng lý do nào. Nhìn từ ngoài: nội dung mãi không xuất hiện, sổ lý do trống trơn, mọi cổng đều xanh.

Chặng lesson-outcomes sinh ra để gỡ đúng chỗ ấy, và nó đứng trước bốn chặng kia trong danh sách. Bài học rộng hơn: một chặng bỏ qua việc phải ghi lý do, không thì trạng thái "không có gì để làm" và "không làm được" trông y hệt nhau.

CD-17 · Cụm bài đọc của tầng luyện đọc IELTS (SRC-783) ​

Chỉ đạo chủ dự án 2026-09-16: ielts.nemo12.com có một tầng bài tập để thử nghiệm và để trao đổi với team, bắt đầu bằng luyện đọc. Hình dạng do chủ dự án đặt:

TầngRàng buộc
Unitnhiều cụm bài đọc
Cụmkhoảng 50 từ vựng quanh một lĩnh vực + 10 bài đọc
Bài đọc30 câu hỏi thuộc 10 nhóm, mỗi nhóm 3 câu khác nhau

Mười nhóm: Main Idea · Detail · Evidence · Inference · Vocabulary in Context · Reference · Author's Purpose · Tone · Organisation · Summary.

Vì sao gom thành cụm chứ không rải chủ đề mỗi bài một nơi. Chủ dự án nói thẳng chỗ này: passage thứ hai KHÔNG đổi sang lĩnh vực mới mà viết lại cùng một trường từ vựng bằng một cách viết khác. Nhờ vậy learner gặp lại cùng một vốn từ và cùng mười thao tác nhận thức nhiều lần, thay vì mỗi bài phải dựng lại bối cảnh từ đầu. Đây cũng là lý do câu hỏi của một bài nằm CẠNH bài đó, không tách sang trang khác: cái đang luyện là thao tác quay lại văn bản.

Lưu ra JSON files, không vào D1 (chỉ đạo cùng ngày). Chỗ này là nơi thử nghiệm, nội dung còn thay mỗi ngày; sửa file rồi deploy nhanh hơn và để lại vết review rõ hơn một lần seed. Mỗi cụm là một thư mục trong apps/learn/src/ielts/data/reading/: cluster.json giữ phần chung và 50 từ vựng, mỗi bài đọc một file p<seq>.json. Một bài một file vì mỗi cụm sẽ lên tới 10 bài: thêm bài là thêm file, hai phiên soạn hai bài khác nhau chạm hai file khác nhau (luật nhiều-phiên-song-song).

Đáp án lưu bằng chỉ số trong mảng options, không bằng chữ "B" — đổi thứ tự lựa chọn là việc thường xuyên, còn một đáp án ghi "B" thì im lặng sai sau mỗi lần đổi. Mỗi câu kèm một lời giải tiếng Việt nói cách tìm ra đáp án, không chỉ nói đáp án là gì.

Khuôn dữ liệu bằng máy: apps/learn/src/ielts/data/schema.ts. Trang: apps/learn/src/ielts/Reading.tsx (/reading, /reading/<cụm>, /reading/<cụm>/passages/<n>), chấm theo TỪNG NHÓM kỹ năng để kết quả đọc ra là "yếu ở suy luận" chứ không phải "sai câu 17". Chỗ trao đổi với team nằm ngay dưới mỗi bài (apps/learn/src/ielts/TeamNotes.tsx); chưa có backend nên ghi chú ở localStorage kèm nút chép ra JSON để dán vào repo — muốn trao đổi thời gian thực thì đường đúng là một route trong workers/api.

Đợt đầu (2026-09-16): 3 cụm × 3 bài = 270 câu. Bảy bài còn lại của mỗi cụm lấp dần.

CD-17b · Lĩnh vực của learner, và kho từ của lĩnh vực (SRC-784) ​

Chỉ đạo 2026-09-16: "Mỗi learner được chọn ra 1 domain chính (lĩnh vực) mà họ yêu thích, lưu vào local storage, và luôn hiển thị ở đâu đó. Các bài reading cần được lọc ra để liên quan với domain đó, và các bài listening cũng vậy." Và: "Khi learner đã chọn 1 domain, cần có chỗ xem word families và lexical chính, sắp xếp theo độ phổ biến hoặc độ khó để học dần."

Một danh mục lĩnh vực cho MỌI kỹ năng — apps/learn/src/ielts/data/domains.ts, tám lĩnh vực. Reading và listening đọc cùng bộ mã; nếu mỗi kỹ năng tự đặt danh mục riêng thì "lĩnh vực của tôi" mang hai nghĩa khác nhau ở hai trang. Mã tiếng Anh (đi vào JSON và localStorage nên là định danh kỹ thuật), nhãn tiếng Việt. Mã chỉ được THÊM, không sửa: sửa mã là làm hỏng lựa chọn đã lưu trên máy người học.

Danh mục cố ý ngắn. Tám lĩnh vực đủ phủ các trường chủ đề IELTS hay gặp mà mỗi lĩnh vực vẫn có nhiều cụm; chia hai mươi ngăn thì lọc theo lĩnh vực biến thành lọc mất gần hết nội dung.

Lựa chọn hiện ở header của mọi trang, không nằm trong một trang cài đặt: nó quyết định learner nhìn thấy nội dung nào nên phải ở trong tầm mắt và đổi được ngay tại chỗ đang đứng. Lọc không xoá cụm ngoài lĩnh vực, chỉ lùi chúng xuống sau một nút — lọc là để đỡ phải chọn, không phải để cấm.

Kho từ (apps/learn/src/ielts/data/lexicon/<domain>.json, trang /lexicon): họ từ chứ không phải danh sách từ rời, vì learner thường đã biết pollute mà vẫn kẹt khi cần pollutant hay heavily polluted — một họ mở ra bốn chỗ dùng trong cùng một bài viết. Xếp ba bậc theo độ phổ biến giảm dần, không xếp theo bảng chữ cái: bảng chữ cái là thứ tự để TRA, còn học dần cần một thứ tự mà học xong bậc 1 đã dùng được ngay. Mỗi họ có collocation và một câu ví dụ lấy từ chính bài đọc của lĩnh vực ấy.

CD-17c · Đánh dấu vàng và hai mươi từ có sẵn nghĩa (SRC-785) ​

Chỉ đạo 2026-09-17: "Cho phép user được high-light vài từ trong đoạn thành màu vàng ở nền, để đánh dấu. Trong mỗi bài đọc, có khoảng 20 từ là hệ thống đã chuẩn bị sẵn giải nghĩa."

Luật phân chia cử chỉ phải nói được bằng một câu: bấm vào từ thường thì bật/tắt nền vàng; bấm vào từ có gạch chân thì hiện nghĩa đã soạn (trong bảng nghĩa có luôn nút đánh dấu). Không dùng thao tác bôi đen cho việc thứ hai: trên điện thoại bôi đen bằng ngón tay là vật lộn với chính trình duyệt.

Dấu vàng lưu theo chữ của từ, không theo vị trí trong đoạn — cùng một từ xuất hiện ba lần thì cả ba chỗ cùng vàng (đúng điều learner muốn khi đánh dấu một từ mới: thấy nó quay lại ở đâu), và sửa một dấu phẩy trong bài không làm lệch toàn bộ dấu của người học.

Bảng nghĩa hiện ngay dưới bài, không phải popup nổi đè lên chữ: learner đang đọc dở một câu, che câu ấy đi để giải nghĩa một từ trong chính nó là tự phá việc mình vừa giúp.

Hai mươi mục nghĩa của mỗi bài nằm trong trường glossary của file bài đọc, và phải xuất hiện nguyên văn trong paragraphs — trang dò chuỗi để tô, nên một mục sai chính tả sẽ lặng lẽ không bao giờ hiện ra. scripts/audit-ielts-content.mjs (trong npm run check:code) bắt đúng chỗ đó, cùng với 30 câu / 10 nhóm / 3 câu mỗi nhóm, đáp án nằm trong options, và domain có trong danh mục.

CD-17d · Hai cột, và đúng một câu hỏi mỗi lúc (SRC-786) ​

Chỉ đạo 2026-09-17: "Trình bày lại để bên trái là bài đọc, bên phải là câu hỏi. Mỗi thời điểm chỉ có đúng 1 câu hỏi được hiển thị thôi."

Ba mươi câu xếp dọc dưới bài buộc learner cuộn qua cuộn lại, và mỗi lần cuộn là một lần mất chỗ đang đọc. Bài đứng yên bên trái, câu hỏi thay nhau bên phải thì thao tác "quay lại đoạn 3 để kiểm chứng" chỉ còn là liếc sang — mà đó đúng là thao tác cả mười nhóm câu hỏi đang luyện.

Một câu mỗi lúc còn cắt được cái nhìn trộm: thấy sẵn phương án của câu sau là thấy sẵn một phần câu trả lời, rõ nhất ở nhóm evidence và summary nơi nhiều câu soi vào cùng một đoạn.

Thanh ba mươi ô trên đầu cột phải là chỗ duy nhất thấy được toàn cảnh (trắng chưa làm, xanh đã chọn, xanh lá đúng, đỏ sai) và bấm thẳng tới câu bất kỳ. Một câu mỗi lúc mà không có thanh này thì learner mất hẳn cảm giác mình đang ở đâu.

Chấm từng câu chứ không chấm từng nhóm như bản đầu: khi trên màn chỉ có một câu thì nút "chấm cả nhóm" chấm những câu người học không nhìn thấy.

Trên màn hẹp không có trái phải: bài nằm trên, câu hỏi nằm dưới, kèm một lối tắt xuống thẳng câu hỏi, và vệt breadcrumb rút còn nhánh cuối để tiêu đề bài không bị đẩy khỏi màn.

CD-17e · Đọc bài thành tiếng qua AI Gateway (SRC-787) ​

Chỉ đạo 2026-09-17: "Hệ thống gọi vào API, rồi từ đó gọi vào AI Gateway của Cloudflare, để sinh ra audio files, để đọc chính cái bài reading lên. Cho phép đọc toàn bộ, hoặc là đọc từng đoạn."

Đường đi: trình duyệt → GET /v1/public/ielts/reading/{cluster}/{seq}/audio?paragraph=N&voice=… → env.AI.run với gateway (AS-10.1.1, cùng đường mọi lượt gọi model khác) → PCM ghép thành WAV → R2 CONTENT. Model và hàm đọc dùng lại của bài chép chính tả (modules/dictation/tts.ts), không dựng đường thứ hai.

Endpoint nhận MÃ BÀI, không nhận chữ. Nhận chữ tự do từ trình duyệt là mở một dịch vụ đọc thành tiếng miễn phí cho cả internet trên hoá đơn của mình. Nhận mã bài thì tập nội dung sinh ra được là hữu hạn và đã biết trước.

Khoá R2 mang băm của chính đoạn chữ, cùng mã bài và giọng. Sửa một chữ trong bài là khoá đổi và file mới được sinh — không có cảnh audio cũ đọc bản chữ đã sửa, mà cũng không phải nhớ xoá cache.

Một đoạn một file, kể cả khi đọc cả bài: "đọc toàn bộ" ở phía trình duyệt là phát lần lượt các file đoạn. Lượt chờ đầu tiên chỉ là một đoạn (vài giây thay vì gần một phút, và không chạm hạn của một request Cloudflare); file đoạn dùng lại cho cả hai chế độ; và khi đang đọc cả bài vẫn biết đang ở đoạn nào để tô sáng đúng đoạn ấy.

Nội dung bài đọc dời về content/ielts-reading/ vì từ nay nó có hai người dùng: app ielts đọc bằng import.meta.glob, worker API đọc bằng import tĩnh (esbuild không có glob) khai trong modules/ieltsReading/content.ts. Để nội dung trong src/ của một app rồi cho worker với tay sang là dựng một phụ thuộc ngược giữa hai workspace. Thư mục content/ ở gốc repo đã là chỗ của loại dữ liệu ấy (content/dictation/).

CD-17f · Tầng luyện nghe, lọc theo cùng lĩnh vực (SRC-789) ​

Chỉ đạo 2026-09-16 đòi listening cũng lọc theo lĩnh vực; 2026-09-17 chủ dự án chọn hướng dựng tầng nghe ngay trong ielts.nemo12.com thay vì gắn domain cho kho "Nghe & chép lại" bên learn. Lý do: kho ấy toàn chủ đề phim hoạt hình, gắn domain vào đó thì gần như cả kho rơi vào một lĩnh vực và bộ lọc không có việc gì để làm.

Ngữ liệu ở content/ielts-listening/, cùng danh mục domain với bài đọc (CD-17b) nên một lựa chọn của learner lọc được cả hai kỹ năng. Mỗi cụm nghe cố ý trùng lĩnh vực và trùng vốn từ với cụm bài đọc: nghe lại chính những từ vừa đọc là bước chuyển từ nhận mặt chữ sang nhận ra âm, và nó rẻ hơn nhiều so với học một vốn từ thứ hai.

Mỗi bài nghe 10 câu: 2 gist · 3 detail · 2 note completion (điền từ) · 2 inference · 1 attitude. Điền từ chấm bằng so khớp chuỗi đã chuẩn hoá với danh sách cách viết được chấp nhận (accept), không chấm bằng model: một bài luyện phải cho cùng một kết quả ở mọi lần chạy.

Bản chữ bị giấu cho tới khi đã chấm hết câu hỏi. Nghe mà nhìn được chữ thì đang luyện đọc. Mở sớm một câu là mở cho cả bài, vì mọi câu đều nằm trong cùng một đoạn tiếng.

Một file cho cả bài (khác bài đọc, nơi mỗi đoạn một file): người ta nghe một mạch rồi mới trả lời, cắt nhỏ ra là bỏ mất phần khó nhất của kỹ năng này. Đổi lại lượt sinh đầu tiên lâu hơn, nên sau mỗi lần thêm bài mới thì gọi trước một lượt cho mỗi bài để learner luôn gặp bản đã có ở R2.

Bài hội thoại khai turns — người nói của từng câu — và API đọc hai giọng khác phái trong cùng chất giọng. Khai tường minh chứ không suy ra bằng chỉ số chẵn lẻ: sẽ có ngày hai câu liền nhau thuộc cùng một người, và lúc ấy quy tắc chẵn lẻ đổi giọng giữa chừng mà không ai nhận ra cho tới lúc nghe.

CD-17g · Bài khởi động: 3 tới 5 câu, đúng 3 câu hỏi (SRC-794) ​

Chỉ đạo 2026-09-17: "Tạo ra các bài reading dạng nhỏ, chỉ tầm 3-5 câu. Và đi kèm với nó cũng là 3 câu hỏi thôi. Để learners có thể dễ dàng khởi động, mà không thấy bị quá áp lực."

Đây là một LOẠI NỘI DUNG RIÊNG, không phải bài đọc rút ngắn. Khuôn của bài đọc (30 câu, 10 nhóm, 20 từ có sẵn nghĩa) chính là thứ tạo ra cái áp lực mà dạng này sinh ra để tránh; để chung một kiểu dữ liệu là mời người soạn sau "bổ sung cho đủ". Nội dung ở content/ielts-warmup/, mỗi bài một file phẳng.

Không thuộc cụm nào, chỉ gắn domain. Learner mở bài khởi động khi chưa muốn cam kết vào một mạch mười bài; bắt họ chọn cụm trước là dựng lại đúng rào cản ấy. Bộ lọc lĩnh vực (CD-17b) vẫn áp dụng.

Ràng buộc, do scripts/audit-ielts-content.mjs thi hành: 3 tới 5 câu, đúng 3 câu hỏi, ba nhóm kỹ năng khác nhau (ba câu cùng hỏi chi tiết thì learner luyện một thao tác mà tưởng đã khởi động xong), đúng một đáp án mỗi câu (dạng chọn nhiều làm người mới chùn tay và thuộc về bài dài), và mọi từ trong bảng nghĩa phải xuất hiện nguyên văn. Cổng chặn chiều PHÌNH RA, không chặn chiều ngắn lại.

Trang /warmup mở thẳng một bài, không có danh sách: một danh sách ba mươi bài là một danh sách ba mươi việc chưa làm. Ba câu hỏi hiện cùng lúc và chấm một lần (ở bài dài, mỗi lúc một câu là để cắt cái nhìn trộm; ở đây không có gì để trộm). Không lưu điểm, không đếm chuỗi ngày — đúng hai thứ ấy biến một việc nhẹ thành một nghĩa vụ. Chấm xong: lời giải, một nút sang bài khác, và một lối đi sang bài dài cho ai đã sẵn sàng.