[Bug][Backend][Quiz] GET /api/Quiz 500s — Quiz.DegradedPageNumbers (#559) & UnvalidatedQuestionDropCount (#564) are required non-nullable, so pre-deploy quizzes fail to materialize
#606
Both are non-nullable, so the MongoDB EF Core provider's compiled shaper treats them as REQUIRED and throws when a BSON document written before those deploys lacks the element. Same class of outage as the ArtStudio #369 schema-evolution rule. Any quiz missing DegradedPageNumbers also predates #564, so fixing only the reported field would just move the 500 onto UnvalidatedQuestionDropCount.
Fix
Per the #369 rule: declare both post-original properties nullable and normalize absence in the accessors (empty list / 0) so old documents materialize and new writes keep populating them (next save heals the document). Add a FakeMongoClientWrapper legacy-document regression test (real shaper) plus a schema-evolution guard asserting only original-era Quiz fields may be required. No data backfill required, though a one-time $set on old quizzes would also resolve it.
## Symptom
GET /api/Quiz (GetAllQuizzesQuery) returns 500 in production:
```
System.InvalidOperationException: Document element is missing for required non-nullable property 'DegradedPageNumbers'.
```
A single legacy quiz document poisons the whole paginated list query — any caller whose collection contains one pre-#559 quiz gets a 500.
## Root cause
`SpikerSoft.Data/Mongos/Quiz.cs` added two properties AFTER the original schema (2025-11-14):
- `DegradedPageNumbers` (`List<int>`) in #559
- `UnvalidatedQuestionDropCount` (`int`) in #564
Both are non-nullable, so the MongoDB EF Core provider's compiled shaper treats them as REQUIRED and throws when a BSON document written before those deploys lacks the element. Same class of outage as the ArtStudio #369 schema-evolution rule. Any quiz missing `DegradedPageNumbers` also predates #564, so fixing only the reported field would just move the 500 onto `UnvalidatedQuestionDropCount`.
## Fix
Per the #369 rule: declare both post-original properties nullable and normalize absence in the accessors (empty list / 0) so old documents materialize and new writes keep populating them (next save heals the document). Add a FakeMongoClientWrapper legacy-document regression test (real shaper) plus a schema-evolution guard asserting only original-era Quiz fields may be required. No data backfill required, though a one-time `$set` on old quizzes would also resolve it.
Resolved in spikersoft-backend PR #311 (merged to master). Quiz.DegradedPageNumbers (#559) and Quiz.UnvalidatedQuestionDropCount (#564) were non-nullable properties added after the schema existed, so the EF-Mongo shaper threw Document element is missing for required non-nullable property on legacy quizzes, 500-ing GET /api/Quiz. Made both nullable with normalizing accessors per the #369 schema-evolution rule; added 4 legacy-document tests via the real shaper. Deployed + verified (no deser errors in API logs; endpoint healthy). The QuizGeneration worker shares the same Quiz.cs fix and picks it up on its next image deploy. Closing.
Resolved in spikersoft-backend PR #311 (merged to `master`). `Quiz.DegradedPageNumbers` (#559) and `Quiz.UnvalidatedQuestionDropCount` (#564) were non-nullable properties added after the schema existed, so the EF-Mongo shaper threw `Document element is missing for required non-nullable property` on legacy quizzes, 500-ing `GET /api/Quiz`. Made both nullable with normalizing accessors per the #369 schema-evolution rule; added 4 legacy-document tests via the real shaper. Deployed + verified (no deser errors in API logs; endpoint healthy). The QuizGeneration worker shares the same `Quiz.cs` fix and picks it up on its next image deploy. 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
GET /api/Quiz (GetAllQuizzesQuery) returns 500 in production:
A single legacy quiz document poisons the whole paginated list query — any caller whose collection contains one pre-#559 quiz gets a 500.
Root cause
SpikerSoft.Data/Mongos/Quiz.csadded two properties AFTER the original schema (2025-11-14):DegradedPageNumbers(List<int>) in [Bug][Backend][Quality] Quiz pages whose LLM output fails JSON parsing silently contribute 0 questions (WRN only) — quizzes ship smaller than requested (#559)UnvalidatedQuestionDropCount(int) in [Bug][Backend][Quality] QuizGenerationService validation is fail-open — if the validation LLM call throws, the unvalidated question ships in the quiz (#564)Both are non-nullable, so the MongoDB EF Core provider's compiled shaper treats them as REQUIRED and throws when a BSON document written before those deploys lacks the element. Same class of outage as the ArtStudio #369 schema-evolution rule. Any quiz missing
DegradedPageNumbersalso predates #564, so fixing only the reported field would just move the 500 ontoUnvalidatedQuestionDropCount.Fix
Per the #369 rule: declare both post-original properties nullable and normalize absence in the accessors (empty list / 0) so old documents materialize and new writes keep populating them (next save heals the document). Add a FakeMongoClientWrapper legacy-document regression test (real shaper) plus a schema-evolution guard asserting only original-era Quiz fields may be required. No data backfill required, though a one-time
$seton old quizzes would also resolve it.Resolved in spikersoft-backend PR #311 (merged to
master).Quiz.DegradedPageNumbers(#559) andQuiz.UnvalidatedQuestionDropCount(#564) were non-nullable properties added after the schema existed, so the EF-Mongo shaper threwDocument element is missing for required non-nullable propertyon legacy quizzes, 500-ingGET /api/Quiz. Made both nullable with normalizing accessors per the #369 schema-evolution rule; added 4 legacy-document tests via the real shaper. Deployed + verified (no deser errors in API logs; endpoint healthy). The QuizGeneration worker shares the sameQuiz.csfix and picks it up on its next image deploy. Closing.