Skip to content

Standing differential regexp fuzzer + 12 new reject classes (TASK-54) - #40

Merged
claude-agent-ahrzb[bot] merged 1 commit into
masterfrom
task-54
Jul 27, 2026
Merged

Standing differential regexp fuzzer + 12 new reject classes (TASK-54)#40
claude-agent-ahrzb[bot] merged 1 commit into
masterfrom
task-54

Conversation

@claude-agent-ahrzb

Copy link
Copy Markdown

What

A standing differential fuzzer for the wave-B regexp engine, plus the reject-list additions its first deep run demanded. Stacked on #39 (task-53) — will retarget to master automatically when that merges.

  • tests/test_duckdb_regexp_fuzz.py — generates patterns from a grammar biased toward the divergence-prone axes (Perl classes in/out of char classes, inline flags, alternation, bounded repetition incl. the 1000-cap edge, escapes, Unicode properties, class edge shapes, options strings, replacement templates) and runs each through BOTH duckdb and DuckDBInferFn on a tiny table. Per-case contract: identical rows, OR engine build-time reject, OR both error; duck-errors-while-engine-serves and mismatches fail with seed + case index + SQL in the message. Fixed seed, REGEXP_FUZZ_SEED / REGEXP_FUZZ_N overrides, ~4s at the default N=250 (in the normal gate, no marker needed).

What it found (all fixed in retrans.rs, pinned in pins-waveB/fuzzer-task54.json + spec addendum)

First run: 122 divergences in 3k cases, 12 construct classes — including three silent wrong-answer shapes and one DuckDB self-inconsistency:

  1. \1-\9 outside a class — RE2 backref-reject vs rust octal(true) serve → reject
  2. Stacked quantifiers are a grammar, not a pair list ({2}*, ?*, *{2}, a???) → quantifier-state machine
  3. RE2's nested counted-repetition product cap at 1000 ((c{3,}..){1,999}) → reject past product
  4. {1, 3} spaced bounds — literal to RE2, repetition to rust (wrong answers) → reject
  5. --/&&/~~ in classes — RE2 literals/ranges vs rust set operations (wrong answers) → reject
  6. Non-POSIX [ in classes — rust nested classes (wrong answers) → reject
  7. POSIX [:...:] desynced the class tracker ([[:alpha:]\d] mis-rewrote) → fixed, consumed atomically
  8. Perl-class range endpoints ([a-\d], [\x08-\s]) → reject
  9. Ranges starting at class-leading ] ([]-Z]) → reject
  10. Anchor-only patterns ($\z, ^^): DuckDB's row path literal-optimizes to string equality (FALSE for 'hello') while its own constant fold says TRUE — unservable, reject
  11. (x){0} — rust erases the capture group, shifting group numbers and the rewrite pre-check → reject
  12. Rewrite templates: RE2's MaxSubmatch pre-check outranks the bad-escape consume quirk → translate_rewrite pre-scans

After fixes: zero divergences over 40k cases / 8 seeds.

Verification

  • uv run python scripts/gate.py green: 155 Rust + 802 py (corpus replay intact — the new rejects demote nothing that was matching)
  • clippy: no findings in retrans.rs
  • backlog: task-54 Done, all ACs checked

🤖 Generated with Claude Code

@claude-agent-ahrzb
claude-agent-ahrzb Bot changed the base branch from task-53 to master July 27, 2026 02:04
…t classes from its first deep run (TASK-54)

Grammar-biased duckdb-vs-engine fuzzer in the normal gate (~4s, fixed seed,
env-overridable). First deep run: 122 divergences in 3k cases; after the
retrans.rs fixes (reject list + POSIX class tracker + rewrite MaxSubmatch
pre-scan), zero divergences over 40k cases / 8 seeds. Pins:
pins-waveB/fuzzer-task54.json + spec addendum.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude-agent-ahrzb
claude-agent-ahrzb Bot merged commit 7418499 into master Jul 27, 2026
1 check passed
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.

1 participant