---
phase: 25.1
slug: parser-robustness-security-hardening
status: draft
nyquist_compliant: false
wave_0_complete: false
created: 2026-03-12
---

# Phase 25.1 — Validation Strategy

> Per-phase validation contract for feedback sampling during execution.

---

## Test Infrastructure

| Property | Value |
|----------|-------|
| **Framework** | Rust `#[test]` + proptest 1.9 + cargo-fuzz (libFuzzer) |
| **Config file** | none (proptest uses defaults; fuzz/Cargo.toml already configured) |
| **Quick run command** | `cargo test` |
| **Full suite command** | `just test-all` |
| **Fuzz run command** | `cargo +nightly fuzz run fuzz_ddl_parse -- -max_total_time=60` |

---

## Sampling Rate

- **After every task commit:** Run `cargo test`
- **Per wave merge:** Run `just test-all`
- **Phase gate:** `just test-all` green before `/gsd:verify-work`

---

## Requirements → Test Map

Phase 25.1 has no formal requirement IDs (cross-cutting quality concern).
Success criteria from ROADMAP.md map to tests as follows:

| Success Criterion | Behavior Under Test | Test Type | Command | Exists? |
|-------------------|---------------------|-----------|---------|---------|
| SC-1: token-based detection | `CREATE\tSEMANTIC\tVIEW` → `DdlKind::Create` | unit | `cargo test` | ❌ |
| SC-1: all 7 forms with tabs | each DdlKind detected correctly | proptest | `cargo test` | ❌ |
| SC-1: all 7 forms with newlines | each DdlKind detected correctly | proptest | `cargo test` | ❌ |
| SC-1: all 7 forms with mixed ws | each DdlKind detected correctly | proptest | `cargo test` | ❌ |
| SC-2: validate_and_rewrite round-trips | full rewrite succeeds with non-space ws | proptest | `cargo test` | ❌ |
| SC-3: very long input (1 MB) | returns PARSE_NOT_OURS in < 1 ms, no panic | unit | `cargo test` | ❌ |
| SC-3: null byte in view name | clean error, no panic | unit | `cargo test` | ❌ |
| SC-3: embedded semicolons in view name | safe output or clean error | unit | `cargo test` | ❌ |
| SC-3: Unicode homoglyphs | PARSE_NOT_OURS, no near-miss confusion | unit | `cargo test` | ❌ |
| SC-3: control characters in view name | clean error, no panic | unit | `cargo test` | ❌ |
| SC-3: fuzz detect_ddl_kind | no panic on arbitrary byte sequences | fuzz | `cargo +nightly fuzz run fuzz_ddl_parse` | ❌ |
| SC-3: fuzz validate_and_rewrite | no panic on arbitrary strings | fuzz | `cargo +nightly fuzz run fuzz_ddl_parse` | ❌ |
| SC-4: body_parser whitespace | arbitrary inter-token whitespace accepted | proptest | `cargo test` | ✅ (Phase 25) |
| SC-5: full suite | all tests pass | integration | `just test-all` | ✅ |

---

## Wave 0 Gaps (all new)

All tests in this phase are new. Wave 0 creates:

- [ ] `tests/parse_proptest.rs` — TEST-07: `proptest!` block with `arb_inter_keyword_ws` strategy (`[ \t\n\r]{1,4}`) covering all 7 DDL forms
- [ ] `tests/parse_proptest.rs` — TEST-08: `#[test]` block with adversarial unit tests (long string, null byte, semicolons in name, homoglyphs, control characters)
- [ ] `fuzz/fuzz_targets/fuzz_ddl_parse.rs` — fuzz target exercising `detect_semantic_view_ddl` and `validate_and_rewrite` on arbitrary byte sequences (registered in `fuzz/Cargo.toml`)

---

## Fuzz Target Design

The new `fuzz_ddl_parse` target should:

1. Accept raw `&[u8]` (arbitrary byte sequences, not just valid UTF-8)
2. Convert to `&str` via `std::str::from_utf8` — if invalid UTF-8, return early (not a crash)
3. Call `detect_semantic_view_ddl(query)` — assert no panic
4. If `PARSE_DETECTED`, call `validate_and_rewrite(query)` — assert no panic
5. If `Ok(Some(sql))`, assert the output SQL is non-empty and starts with `SELECT * FROM `

**Corpus seeds** (add to `fuzz/corpus/fuzz_ddl_parse/`):
- `CREATE SEMANTIC VIEW v (...)` — basic valid
- `CREATE\tSEMANTIC\tVIEW v (...)` — tab whitespace
- `CREATE SEMANTIC VIEW v\0bad (...)` — null byte
- `CREATE SEMANTIC VIEW ` + `A` * 10000 — long input
- `СREATE SEMANTIC VIEW v (...)` — Cyrillic homoglyph

---

## Nyquist Compliance Checklist

- [ ] Every success criterion has at least one automated test
- [ ] Fuzz target registered in fuzz/Cargo.toml
- [ ] Corpus seeds committed to fuzz/corpus/fuzz_ddl_parse/
- [ ] `cargo test` passes after Wave 1 code changes
- [ ] `just test-all` passes at phase gate
