complete the quiz path for grades 8 through 12, and close three gaps in the API contract

Content
-------
Every node in grades 8, 9, 10, 11 and 12 now holds a full four-question
quiz — 121 more questions, filling the two حسابان دوازدهم nodes in
فصل ۵: کاربردهای مشتق that were empty and the two ریاضی هشتم nodes that
were short. The repo's own seed guard was already failing on those two
empty nodes; it passes now.

Grades 3, 6 and 7 are the other team's books and were left alone. 39 of
their 145 nodes still hold fewer than four questions, but none is empty,
so every node on the map still plays.

An audit over all 1,593 questions in grades 8–12 found no structural
fault: no question with the wrong number of options, no question with
zero or two correct answers, no empty or duplicated option, no leftover
LaTeX, and no two identical questions inside one lesson.

Contract
--------
Three endpoints were missing or malformed in the OpenAPI schema, which
matters more than it looks: that schema is the contract the frontend
generates its client from, so a view missing there is a view the other
repo cannot call.

- NotificationMarkReadView was dropped from the schema entirely, because
  spectacular could not guess a request body for its PATCH and gives up
  on the whole view rather than the one field. It declares request=None.
- PaymentRedirectView was dropped for the same reason; it answers with a
  302 and no JSON body, which it now says.
- /api/health and /api/health/ collided on operationId and were emitted
  as health_retrieve and health_retrieve_2. The slash variant exists only
  for a monitor that calls it that way, so it is excluded from the schema.

`spectacular` now runs clean — no errors, no warnings.

Tidying
-------
Condensed the two longest comment blocks (18 and 14 lines) in
rag_verify_solutions and settings, keeping the measurement and the rule
and dropping the retelling. README gains the bulk question-authoring
workflow; the playbook's subagent section now points at the real tool
instead of describing the steps by hand.

458 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-22 03:49:32 +03:30
parent 82edd0ecb0
commit 6a6d0200d2
9 changed files with 2140 additions and 41 deletions

View File

@@ -170,8 +170,8 @@ actually connected without asking a human.
## Content: where it lives and how it gets to a server
`content/seed/` holds the whole curriculum and question bank as committed JSON —
`curriculum.json` (6 grades, 48 units, 230 nodes, 1,928 lessons) and `questions.json`
(1,441 multiple-choice questions). `deploy.sh` runs `seed_content` on every release, so a
`curriculum.json` (8 grades, 58 units, 263 nodes, 2,617 lessons) and `questions.json`
(2,463 multiple-choice questions). `deploy.sh` runs `seed_content` on every release, so a
fresh server fills itself with one command: **no Qdrant, no AI credit, no SSH session.**
`seed_content` is idempotent and never deletes. Questions bind to lessons **by title path**
@@ -243,7 +243,9 @@ reliably pull the final answer out of a solution and produced ~40% broken output
- Throttle rates need periodic review against real traffic.
- `DEV_MASTER_OTP` (`0000`) must stay gated behind `DEBUG` — never enabled in prod.
- No video content exists yet, though `Lesson.kind`/`video_url` can express it.
- 58 of 230 nodes still hold fewer than four questions; their verified chunks ran out.
- Grades 8–12 are fully covered: every node holds a four-question quiz. 39 of the 145
nodes in grades 3/6/7 (the other team's books) still hold fewer than four; none is
empty, so every node still plays.
- Kavenegar is unconfigured, so `POST /api/auth/otp/request` returns 503. With `DEBUG=0`
there is no way to log into the API without creating an `OTPCode` row in the admin
(`/admin/accounts/otpcode/add/`) — this is how to hand a tester a working login.
@@ -404,11 +406,7 @@ branch, no rendering anywhere. Do not build content for it without asking first.
کاربر تصمیمِ محصولی را گرفت و هر دو پایه ساخته شدند. `seed_curriculum_from_textbook`
اسکلت را رایگان ساخت — یازدهم ۵ فصل/۲۱ نود/۳۶۹ درس، دوازدهم ۵ فصل/۱۲ نود/۳۲۰ درس — و
سوال‌ها با subagentهای Sonnet نوشته شدند: **۵۵۹ سوال** (یازدهم ۳۲۲، دوازدهم ۲۳۷).
هر ۲۱ نودِ یازدهم آزمونِ کاملِ چهارسوالی دارند؛ از دوازدهم ۱۰ نود از ۱۲.
⚠️ **دو نودِ باقی‌مانده، هر دو در «فصل ۵: کاربردهای مشتق»** («جهت تقعر نمودار…» و
«رسم نمودار تابع»): سوال ندارند چون سقفِ هفتگیِ Sonnet وسطِ کار پر شد، نه چون داده کم
است. جفت‌هایشان آماده‌اند — دو دسته‌ی آخرِ همان اجرای `--export`.
هر ۳۳ نودِ هر دو پایه آزمونِ کاملِ چهارسوالی دارند.
`GRADE_STYLE` حالا برای یازدهم/دوازدهم رنگ دارد (فیروزه‌ای و نیلی، عمداً جدا از شش
پایه‌ی عمومی چون حسابان فقط کتابِ رشته‌ی ریاضی‌فیزیک است).
@@ -420,7 +418,7 @@ branch, no rendering anywhere. Do not build content for it without asking first.
عینِ همان PROMPTی که به مدلِ پولی می‌رفت می‌نویسد، تا کیفیتِ دو شاخه از هم جدا نیفتد.
خروجیِ subagent با `content.question_io` وارد می‌شود (فایلِ بد هیچ‌چیز نمی‌نویسد).
بازده روی ۶۳۰ ورودی: **۵۵۹ سوال، ۸۹٪** — بقیه عمداً رد شدند، بیشترشان مسئله‌هایی که
بازده روی ۷۷۸ ورودی: **۶۸۰ سوال، ۸۷٪** — بقیه عمداً رد شدند، بیشترشان مسئله‌هایی که
بدونِ شکلِ کتاب خودکفا نمی‌شوند. چند subagent خطایِ حسابِ خودِ کتاب را هم گرفتند
(راه‌حلی که √ را ۶ نوشته بود ولی ۶٫۵ بود؛ راه‌حلی که می‌گفت حد وجود ندارد درحالی‌که
داشت) — یعنی `solution_verdict='agrees'` تضمینِ کامل نیست، فقط فیلترِ اول است.