Two iterative tightenings on Document::validate after the R1
fixes landed in 3d291ec8.
# R2 CONCERN-1: empty-pages document silently passed validate
`Document::validate` previously gated the active_page_index
range check on `!pages.is_empty()`, so a `Document { pages:
vec![], active_page_index: 99, ... }` returned `Ok(())` —
inconsistent with the implicit "every Document has at least one
page" invariant that Document::empty() and Document::sample()
both establish.
Fix:
- `validate()` now treats `pages.is_empty()` as the FIRST
violation it returns. Empty pages is itself an invariant
violation — `Document::empty()` is the constructor for the
default single-page shape.
- `active_page_index` range check now fires unconditionally.
New test `document_validate_catches_empty_pages` covers two
sub-cases:
- `pages: vec![], active_page_index: 0` → Err("pages is empty")
- `pages: vec![], active_page_index: 99` → Err (empty check
fires first, range check short-circuited)
# R3 CONCERN: empty-vs-range ordering not asserted
The R2 second sub-case only asserted `.is_err()` without
proving WHICH violation fired first. Strengthened to:
- assert error contains "pages is empty"
- assert error does NOT contain "active_page_index"
Both asserts carry failure messages so a future regression
points at the cause.
Test count: 34 lib + 21 widgets_static + 6 jian + 4
render_backend = 65 shell-core tests passing.
R4 GO from codex.