Skip to content

test: exhaustive Tier-3 gates for fold/slug/whitespace/dot/preset invariants - #524

Merged
raeq merged 1 commit into
mainfrom
test/exhaustive-tier3-gates
Jul 13, 2026
Merged

test: exhaustive Tier-3 gates for fold/slug/whitespace/dot/preset invariants#524
raeq merged 1 commit into
mainfrom
test/exhaustive-tier3-gates

Conversation

@raeq

@raeq raeq commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Follow-up to #523. When an invariant is local (decidable per code point or per small window) but guarded only by a random \PC* proptest, random generation merely samples the failure space — which is exactly how the confusables idempotency bug (#523) stayed hidden until an unlucky CI seed. These invariants are bounded and enumerable, so this adds deterministic exhaustive Tier-3 gates.

All #[ignore] (run by the --lib -- --ignored step wired in #523), ~11s combined in release. No production code changes — every gate passes, confirming the #523 fix plus the already-exhaustive case-fold / transliterate layers leave the higher-level transforms clean.

Gate Domain Guarantee
exhaustive_fold_case_invariants every code point fold_case is composition-free + per-code-point ⇒ single-code-point enumeration is a complete proof for all strings (idempotency, no residual ASCII uppercase, no drop, ASCII→ASCII)
exhaustive_slug_codomain every code point completely proves slugify_output_is_ascii + charset membership (a per-char codomain property)
exhaustive_collapse_whitespace every code point in a run + all patterns over {SPACE, NBSP, x} to len 7 collapse/trim state machine (whitespace handled uniformly)
exhaustive_collapse_dot_sequences all dot patterns over {., a} to len 12 + every non-dot code point dot-collapse machine (no .., idempotent, single-dot preserved)
exhaustive_preset_idempotency every code point (#498 class) + every BMP base × combining diacritical U+0300–036F (#523 class) canonicalize / sort_key / search_key / catalog_key / ml_normalize idempotency

The proptests stay for multi-cluster / long-range cases the bounded sweeps can't reach.

Assisted-by: Claude Code:claude-opus-4-8

Copilot AI review requested due to automatic review settings July 13, 2026 21:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds deterministic Tier-3 (#[ignore]) exhaustive test gates to prove key invariants for per-code-point or bounded-window transforms in the Rust core, reducing reliance on probabilistic \PC* proptests for classes of bugs like #523/#498.

Changes:

  • Add exhaustive idempotency/invariant gates for fold_case across all scalar values.
  • Add exhaustive codomain gate for slugify output charset across all scalar values.
  • Add exhaustive state-machine gates for whitespace collapsing, dot-sequence collapsing, and preset idempotency (single code point + BMP base×combining mark).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/whitespace.rs Adds Tier-3 exhaustive gate for collapse_whitespace idempotency + trimming/no-double-space invariants.
src/slugify.rs Adds Tier-3 exhaustive gate proving slug output is ASCII and within [a-z0-9-] for every code point.
src/presets.rs Adds Tier-3 exhaustive preset idempotency gate over all scalar values and BMP base×combining-diacritic pairs.
src/filename.rs Adds Tier-3 exhaustive gate for collapse_dot_sequences over dot patterns and all non-dot code points.
src/case_fold.rs Adds Tier-3 exhaustive gate validating fold_case invariants over every code point.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/presets.rs Outdated
Comment thread src/presets.rs Outdated
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…ariants

Follow-up to #523: where an invariant is *local* (decidable per code point or
per small window) but guarded only by a random `\PC*` proptest, random generation
merely samples the failure space — exactly how the confusables idempotency bug
hid for so long. These invariants are bounded and enumerable, so add deterministic
exhaustive Tier-3 gates (all `#[ignore]`, run by the `--lib -- --ignored` step
wired in #523; ~11s combined in release). No production code changes; all pass —
the confusables fix (#523) plus the already-exhaustive case-fold / transliterate
layers leave the higher-level transforms clean.

- case_fold (`exhaustive_fold_case_invariants`): every code point. fold_case is
  composition-free and per-code-point, so single-code-point enumeration is a
  *complete proof* for all strings — idempotency, no residual ASCII uppercase,
  no drop, ASCII-in⇒ASCII-out.
- slugify (`exhaustive_slug_codomain`): every code point. The slug charset is a
  per-code-point property, so this completely proves `output_is_ascii` and the
  charset-membership half of `output_charset` (separator *position* stays with
  the proptests).
- whitespace (`exhaustive_collapse_whitespace`): every code point in a run
  context + every pattern over {SPACE, NBSP, x} to length 7 — the collapse/trim
  state machine (uniform whitespace handling).
- filename (`exhaustive_collapse_dot_sequences`): every dot pattern over {., a}
  to length 12 + every non-dot code point preserved — the dot-collapse machine.
- presets (`exhaustive_preset_idempotency`): every code point (the #498 class) +
  every BMP base × combining diacritical U+0300–036F (the #523 class), for
  canonicalize / sort_key / search_key / catalog_key / ml_normalize.

Signed-off-by: Richard Quinn <quinn.richard@gmail.com>
Assisted-by: Claude Code:claude-opus-4-8
@raeq
raeq force-pushed the test/exhaustive-tier3-gates branch from d469c7d to 835fe72 Compare July 13, 2026 21:49
@raeq

raeq commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Both addressed in the latest push:

  • Corrected the doc estimate — it's ~1.1M scalars × 5 presets + ~7.1M BMP base×mark pairs × 2 presets, each checked twice (~40M preset calls), not "~7M".
  • Made idem a generic monomorphized helper (was &dyn Fn) so the inner loops pay no vtable dispatch.

@raeq
raeq merged commit 2acb9b6 into main Jul 13, 2026
21 checks passed
@raeq
raeq deleted the test/exhaustive-tier3-gates branch July 13, 2026 21:54
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants