1. Generation marks empty quizzes as Completed/available. Quiz 6a53cdfdc31783225d731df6 (sample-PDF book 6a53cdfdc31783225d731df5) finished as:
⏭️ Page 4/6 not found in database, skipping (may have failed during extraction) (pages 4–6)
Quiz generation completed ... Total questions: 0
Sent BookProcessingNotification: Stage=Completed
Zero questions should be a FAILED/flagged generation, not Completed — and the page-count mismatch (quiz believed 6 pages; extraction stored 3 for this book) deserves its own look: the same sample PDF (identical SHA256) was uploaded several times tonight; the page expectations appear to have come from a different upload's record.
2. The attempt flow lets an empty quiz start. StartQuizAttemptCommand happily creates an attempt against Questions.Count == 0, and the player degenerates to instant expiry + auto-complete 0/0.
Proposed fixes
QuizGeneration: if total questions == 0 → mark quiz Failed (ErrorMessage='no questions generated'), do NOT surface as takeable; notification severity Warning not success.
API: StartQuizAttemptCommand validator rejects quizzes with no questions (422) — belt for whatever braces miss.
Investigate the page-count source for the mismatch (likely cross-upload contamination via duplicate-SHA books).
Frontend (spikersoft-angular): show 'quiz unavailable' state instead of starting an empty quiz — minor, backend guards make it unreachable.
Healthy-path control: quiz 6a53cff5c31783225d731dfc generated 'Total questions: 2' at 17:33:53 the same evening — generation itself works on books with adequate content.
Related: tonight's pipeline work #497/#500; the affected book was a thin 3-page sample PDF.
## Symptom (prod, 2026-07-12 17:34 UTC)
Taking a generated quiz: UI shows started, then immediately 'time expired' and ends. Seq shows the whole attempt lasted 3 seconds:
17:34:43 StartQuizAttemptCommand completed (30ms)
17:34:46 Completing quiz attempt 6a53d033a41ad80628b1667a
Completed quiz attempt: 0/0 (0%)
## Root cause chain (two layers)
**1. Generation marks empty quizzes as Completed/available.** Quiz 6a53cdfdc31783225d731df6 (sample-PDF book 6a53cdfdc31783225d731df5) finished as:
⏭️ Page 4/6 not found in database, skipping (may have failed during extraction) (pages 4–6)
Quiz generation completed ... Total questions: 0
Sent BookProcessingNotification: Stage=Completed
Zero questions should be a FAILED/flagged generation, not Completed — and the page-count mismatch (quiz believed 6 pages; extraction stored 3 for this book) deserves its own look: the same sample PDF (identical SHA256) was uploaded several times tonight; the page expectations appear to have come from a different upload's record.
**2. The attempt flow lets an empty quiz start.** StartQuizAttemptCommand happily creates an attempt against Questions.Count == 0, and the player degenerates to instant expiry + auto-complete 0/0.
## Proposed fixes
- QuizGeneration: if total questions == 0 → mark quiz Failed (ErrorMessage='no questions generated'), do NOT surface as takeable; notification severity Warning not success.
- API: StartQuizAttemptCommand validator rejects quizzes with no questions (422) — belt for whatever braces miss.
- Investigate the page-count source for the mismatch (likely cross-upload contamination via duplicate-SHA books).
- Frontend (spikersoft-angular): show 'quiz unavailable' state instead of starting an empty quiz — minor, backend guards make it unreachable.
Healthy-path control: quiz 6a53cff5c31783225d731dfc generated 'Total questions: 2' at 17:33:53 the same evening — generation itself works on books with adequate content.
Related: tonight's pipeline work #497/#500; the affected book was a thin 3-page sample PDF.
Fix up in spikersoft-backend PR #231 (worker Failed-state + StartQuizAttempt guard + 400 mapping + 3 xUnit tests — details on the PR). The page-count-mismatch investigation (pages 4–6 'not found', suspected duplicate-SHA cross-contamination) is deliberately NOT in this PR — keeping this ticket's scope to the takeable-empty-quiz defect; happy to spin the mismatch into its own ticket if it reproduces on distinct files.
Fix up in spikersoft-backend PR #231 (worker Failed-state + StartQuizAttempt guard + 400 mapping + 3 xUnit tests — details on the PR). The page-count-mismatch investigation (pages 4–6 'not found', suspected duplicate-SHA cross-contamination) is deliberately NOT in this PR — keeping this ticket's scope to the takeable-empty-quiz defect; happy to spin the mismatch into its own ticket if it reproduces on distinct files.
Second code layer landed: PR #233 — the true mechanism of the zero-question quiz was the fixed pagesToSkip=3 making a 3-page book start at page 4 (its whole content skipped). New ComputePageWindow skips min(3, half-the-book); 11 window theories in a new QuizGeneration.Tests project. With #231 (fail-state + start guard) + #233 (window), the user-facing defect is fully covered. The remaining page-count-inflation anomaly (6 pages on a 3-pager; one book linking 570 pages) is now #509 with tonight's evidence — it needs Mongo inspection. Suggest closing this ticket once #231+#233 merge; #509 carries the data thread.
Second code layer landed: **PR #233** — the true mechanism of the zero-question quiz was the fixed `pagesToSkip=3` making a 3-page book start at page 4 (its whole content skipped). New `ComputePageWindow` skips min(3, half-the-book); 11 window theories in a new QuizGeneration.Tests project. With #231 (fail-state + start guard) + #233 (window), the user-facing defect is fully covered. The remaining page-count-inflation anomaly (6 pages on a 3-pager; one book linking 570 pages) is now **#509** with tonight's evidence — it needs Mongo inspection. Suggest closing this ticket once #231+#233 merge; #509 carries the data thread.
Fixed across three merged PRs and deployed via CI: #231 (0-question generations marked Failed + StartQuizAttempt guard + 400 mapping), #233 (page window no longer skips past small books — the true zero-question mechanism), #234 (the duplicate-upload page-merge that inflated the count in the first place). The broken UI state is unreachable: Failed quizzes leave the list, empty starts are rejected server-side, small books quiz their real content. Closing.
Fixed across three merged PRs and deployed via CI: #231 (0-question generations marked Failed + StartQuizAttempt guard + 400 mapping), #233 (page window no longer skips past small books — the true zero-question mechanism), #234 (the duplicate-upload page-merge that inflated the count in the first place). The broken UI state is unreachable: Failed quizzes leave the list, empty starts are rejected server-side, small books quiz their real content. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Symptom (prod, 2026-07-12 17:34 UTC)
Taking a generated quiz: UI shows started, then immediately 'time expired' and ends. Seq shows the whole attempt lasted 3 seconds:
Root cause chain (two layers)
1. Generation marks empty quizzes as Completed/available. Quiz 6a53cdfdc31783225d731df6 (sample-PDF book 6a53cdfdc31783225d731df5) finished as:
Zero questions should be a FAILED/flagged generation, not Completed — and the page-count mismatch (quiz believed 6 pages; extraction stored 3 for this book) deserves its own look: the same sample PDF (identical SHA256) was uploaded several times tonight; the page expectations appear to have come from a different upload's record.
2. The attempt flow lets an empty quiz start. StartQuizAttemptCommand happily creates an attempt against Questions.Count == 0, and the player degenerates to instant expiry + auto-complete 0/0.
Proposed fixes
Healthy-path control: quiz 6a53cff5c31783225d731dfc generated 'Total questions: 2' at 17:33:53 the same evening — generation itself works on books with adequate content.
Related: tonight's pipeline work #497/#500; the affected book was a thin 3-page sample PDF.
Fix up in spikersoft-backend PR #231 (worker Failed-state + StartQuizAttempt guard + 400 mapping + 3 xUnit tests — details on the PR). The page-count-mismatch investigation (pages 4–6 'not found', suspected duplicate-SHA cross-contamination) is deliberately NOT in this PR — keeping this ticket's scope to the takeable-empty-quiz defect; happy to spin the mismatch into its own ticket if it reproduces on distinct files.
Second code layer landed: PR #233 — the true mechanism of the zero-question quiz was the fixed
pagesToSkip=3making a 3-page book start at page 4 (its whole content skipped). NewComputePageWindowskips min(3, half-the-book); 11 window theories in a new QuizGeneration.Tests project. With #231 (fail-state + start guard) + #233 (window), the user-facing defect is fully covered. The remaining page-count-inflation anomaly (6 pages on a 3-pager; one book linking 570 pages) is now #509 with tonight's evidence — it needs Mongo inspection. Suggest closing this ticket once #231+#233 merge; #509 carries the data thread.Fixed across three merged PRs and deployed via CI: #231 (0-question generations marked Failed + StartQuizAttempt guard + 400 mapping), #233 (page window no longer skips past small books — the true zero-question mechanism), #234 (the duplicate-upload page-merge that inflated the count in the first place). The broken UI state is unreachable: Failed quizzes leave the list, empty starts are rejected server-side, small books quiz their real content. Closing.