feat: add lexical-mutation corpus generator - #14
Merged
Conversation
Adds a lexical lane alongside the crypto fixture lanes: a deterministic generator for synthetic term-matching benchmark corpora, built from an immutable anchor plus a seed-derived body so every generated string stays visibly synthetic. Changes: - Add internal/lexmatrix: grammar, transform library covering fourteen mutation classes, surface rendering with byte-span answer keys, deterministic seeded generation, and fail-closed cell accounting - Split output into a sterile plane (opaque identifiers, coordinates and digests) and a protected plane (term values and source artifacts) - Refuse to record a positive case whose rendered variant is identical to the unmutated term, and reject a term value that collides with another - Build a corpus alongside its target and swap it in once complete, so an interrupted run leaves the previous corpus intact - Add cmd/synthcorpus-lexgen and wire it into make build - Give each generator its own output-root ownership marker, so --force can only replace a root its own lane created; document the marker kind as the authorization attribute and the tool field as provenance only - Add docs/lexical-matrix.md covering grammar, matrix, floors and planes - Gate both shipped binaries' version identity in the release checklist Generated by Claude Opus 5 via Claude Code under supervision of @3leapsdave Co-Authored-By: Claude Opus 5 <noreply@3leaps.net> Role: devlead Committer-of-Record: @3leapsdave
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a lexical lane alongside the existing crypto fixture lanes: a deterministic generator for synthetic term-matching benchmark corpora.
Grammar
Every term is an immutable
zzlxanchor followed by a seed-derived base32 body. Transforms only ever touch body scalars, so a mutated variant is still greppable as synthetic. Two shapes are deliberate exceptions, both documented: common-word decoys, where an ordinary word is the whole point of the control, and below-policy-length terms, which are too short to hold a full anchor.The matrix
Seven surfaces with per-surface transform classes and severity mixes — 49 required cells, six of which carry a pinned severity rather than the surface rotation. Unicode classes, vowel-drop, and truncation outside
snake_caseare implemented but sit outside the required matrix behind--include-extensions.Population floors are enforced inside generation: a run that cannot meet them fails rather than emitting a thin corpus. A default run produces 721 cases — 588 positives, 49 negative controls, and 84 below-policy-length cases.
Output planes
Generation writes a sterile plane (opaque identifiers, answer-key coordinates, digests) and a protected plane (term values and the artifacts a detector scans). The fixture set references the protected manifest by SHA-256 alone.
docs/lexical-matrix.mdstates plainly that this is a handling boundary rather than a confidentiality control: generation is deterministic from a seed the sterile plane carries, so the protected plane is reconstructible by anyone with this source.Correctness guards
Ownership markers
Each generator now owns a distinct output-root marker, so
--forcecan only replace a root its own lane created and a corpus holding no key material is no longer labelled with the marker that locates key-bearing roots. The marker kind is the authorization attribute; the tool field is provenance only. A corpus is built alongside its target and swapped in once complete, so an interrupted run leaves the previous one intact.Verification
make check-allless the decernor contract lane, which needs a binary at the pinned commit on the running host. Package coverage 87.0%, CLI 80.9%. Determinism verified across separate processes: identical seed produces byte-identical output trees.🤖 Generated with Claude Code