Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
d74e13a
Detect explicitly labelled customer, employee and person record IDs
Naoray Oct 10, 2026
a942c48
Assign record identifier test binaries to CI shards
Naoray Oct 10, 2026
86062c8
Clarify the serialized JSON boundary for labelled record IDs
Naoray Oct 10, 2026
bec5f7c
Keep opaque identifier punctuation inside the complete value
Naoray Oct 10, 2026
82f72ea
Capture escaped slashes in labelled record identifiers
Naoray Oct 10, 2026
10393bf
Include labelled record identifiers in core class inventory
Naoray Oct 10, 2026
3ffb649
Add person-linked record identifier benchmark cells
Naoray Oct 10, 2026
6eb7bcf
Merge current main into labelled record identifiers
Naoray Oct 10, 2026
cf9924f
Keep generic corpus assertions compatible with record identifier decoys
Naoray Oct 10, 2026
00cc1f2
Reject prose placeholders after person-linked identifier labels
Naoray Oct 10, 2026
d39df06
Refresh comparison page current generator version
Naoray Oct 10, 2026
807c0ed
Allow pinned rulepack-path appends for mechanism ablations
Naoray Oct 10, 2026
84240c0
Export exact rulepack subsets for record identifier mechanism evidence
Naoray Oct 10, 2026
395c128
Re-measure release history on person-linked identifier cells
Naoray Oct 10, 2026
8091c94
Recognize German person and contact record ID labels
Naoray Oct 10, 2026
215b859
Disclose the short numeric repeat benchmark limit
Naoray Oct 10, 2026
8a8621c
Add record identifier scalar syntax benchmark cells
Naoray Oct 10, 2026
0b74e2a
Merge current main into record identifier syntax benchmark
Naoray Oct 10, 2026
f1a1ef0
Give JSON scalar counterweights distinct tool turns
Naoray Oct 10, 2026
577ed4a
Bind placeholder rejection to the captured value quote
Naoray Oct 10, 2026
b19263f
Merge current main before scalar syntax measurements
Naoray Oct 10, 2026
56b20a2
Document distinct tool-turn scalar cases
Naoray Oct 10, 2026
96500ef
Reject unquoted capture guards on non-regex matchers
Naoray Oct 10, 2026
f7b1084
Publish scalar record ID historical measurements
Naoray Oct 10, 2026
3116563
Integrate current benchmark validation tooling
Naoray Oct 10, 2026
778ed6a
Prepare exact record ID rule ablation inputs
Naoray Oct 10, 2026
7f316a9
Integrate value-specific quote guards and exact rule ablation
Naoray Oct 10, 2026
034dfaa
Integrate independently measured scalar-syntax harness
Naoray Oct 10, 2026
d19d964
Resume scanning after rejected person-ID placeholders
Naoray Oct 10, 2026
33d90b9
Merge benchmark scalar-syntax coverage from main
Naoray Oct 10, 2026
bc7d2cd
Record failed record-ID gain comparisons
Naoray Oct 10, 2026
d9e7051
Merge main for generator v16 record-ID gain
Naoray Oct 11, 2026
bfabbac
Record passing generator v16 record-ID gains
Naoray Oct 11, 2026
ccf6d3f
Merge main with the private source snapshot cap fix
Naoray Oct 11, 2026
c8ef338
Merge value ownership benchmark before runtime repair
Naoray Oct 11, 2026
b40bf2c
Reproduce grouped personal identifier ownership leaks
Naoray Oct 11, 2026
6e3b76f
Judge grouped personal identifiers by their owned field value
Naoray Oct 11, 2026
da4ee39
Reproduce quoted personal scalar suffix exposure
Naoray Oct 11, 2026
cb00664
Preserve entire quoted personal field scalars
Naoray Oct 11, 2026
594b88b
Reproduce adjacent labelled field swallowing and repeat leaks
Naoray Oct 11, 2026
3178053
Stop owned identifiers before multiword assignment labels
Naoray Oct 11, 2026
a29e102
Verify owned record spans and public assignment controls
Naoray Oct 11, 2026
002e442
Verify quoted record ownership, guard audit, and CRM authority
Naoray Oct 11, 2026
ebce706
Document field-owned scanning and regenerate public rule exports
Naoray Oct 11, 2026
6324074
Bind fresh value-ownership benchmark evidence
Naoray Oct 11, 2026
7fdd590
Specify complete record identifier boundaries and public controls
Naoray Oct 12, 2026
6c58d6b
Merge current benchmark and collision coverage into labelled record i…
Naoray Oct 12, 2026
7987a21
Keep terminal prose punctuation outside record identifier values
Naoray Oct 12, 2026
80f075d
Specify legacy identifier ownership at complete next-field cues
Naoray Oct 12, 2026
5c868c6
Stop speculative identifier extensions at complete next-field cues
Naoray Oct 12, 2026
53e2aeb
Specify fail-closed serialized scalar bounds and audit reasons
Naoray Oct 12, 2026
3d0f1b5
Observe serialized boundary limits through the public pipeline seam
Naoray Oct 12, 2026
5f02cb4
Own raw serialized record scalars through bounded quote contexts
Naoray Oct 12, 2026
13eb59c
Admit opening newlines only inside quoted record scalars
Naoray Oct 12, 2026
5aceceb
Protect tab-grouped record identifiers and reject schema placeholders
Naoray Oct 12, 2026
f3f1e38
Specify complete uncertain repeats across turns and signed snapshots
Naoray Oct 12, 2026
4c9c6f2
Preserve typed field-owned repeat seeds through sessions and snapshots
Naoray Oct 12, 2026
75e03d6
Validate repeat metadata inside authenticated modern snapshot envelopes
Naoray Oct 12, 2026
dc450ad
Document conditional snapshot migration and complete record ownership
Naoray Oct 12, 2026
f5e91ca
Clarify conditional snapshot versions in the public export contract
Naoray Oct 12, 2026
91ce16a
Merge current semantic verification coverage into record ownership fixes
Naoray Oct 12, 2026
21a2088
Recognize complete adjacent licence labels
Naoray Oct 12, 2026
5d16f1b
Cover legacy public metadata and unclaimed private tails
Naoray Oct 12, 2026
a86c197
Keep unverified legacy identifier tails conservatively owned
Naoray Oct 12, 2026
86973fc
Exercise complete raw Unicode licence tails and prose controls
Naoray Oct 12, 2026
3004db4
Protect complete raw Unicode identifier tails conservatively
Naoray Oct 12, 2026
d2aa4b1
Test lowercase action boundaries and complete connector expiry
Naoray Oct 12, 2026
7df0220
Keep conservative cue connectors scoped to accepted value groups
Naoray Oct 12, 2026
6cde643
Use the direct ASCII predicate for conservative Unicode cues
Naoray Oct 12, 2026
4700a22
Test conservative legacy prefix repeats and retained seed geometry
Naoray Oct 12, 2026
22ac20f
Retain one typed uncertainty prefix for conservative legacy cue owners
Naoray Oct 12, 2026
40cdc0d
Document conservative legacy repeat evidence and snapshot compatibility
Naoray Oct 12, 2026
07af8ee
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 12, 2026
1810669
Recognize complete private labels when locating conservative prefix s…
Naoray Oct 12, 2026
1f07f2e
Prove scanner wrappers cannot lower repeat precision floors
Naoray Oct 12, 2026
5176075
Keep scanner wrapper prefixes within existing repeat precision floors
Naoray Oct 12, 2026
ceee36d
Merge current main and preserve both snapshot metadata contracts
Naoray Oct 22, 2026
cded2b5
Merge adjacent-token restore and shared matcher fixes from main
Naoray Oct 22, 2026
ab8e1a4
Bound quoted identifier scalars before following structure
Naoray Oct 22, 2026
d1d03fd
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 22, 2026
ac86977
Publish fresh labelled identifier gain evidence
Naoray Oct 22, 2026
342b845
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 22, 2026
6e4f5ba
Measure private suffixes inside unterminated identifier values
Naoray Oct 22, 2026
8039d27
Require boundary proof before releasing unterminated identifier suffixes
Naoray Oct 22, 2026
e2936ce
Pin the expanded malformed-scalar corpus and its historical inputs
Naoray Oct 22, 2026
1e10fcb
Refresh the comparison page generator version note
Naoray Oct 22, 2026
47f11b5
Refresh labelled identifier boundary gain evidence
Naoray Oct 23, 2026
e9c3726
Keep unfinished record values private across serialized strings
Naoray Oct 23, 2026
e73e53a
Ignore quoted field content when finding enclosing strings
Naoray Oct 23, 2026
26a51f4
Publish enclosing-string boundary gain evidence
Naoray Oct 23, 2026
a656574
Separate concurrent unreleased changelog entries
Naoray Oct 23, 2026
20ff2b0
Preserve complete quote dialects inside serialized record fields
Naoray Oct 23, 2026
25cd70a
Publish quote-dialect record ownership gain evidence
Naoray Oct 23, 2026
d1889ce
Protect labelled values across CSV cells and Unicode wrappers
Naoray Oct 23, 2026
c5ef1ba
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 23, 2026
cdf6ec9
Own labelled values behind unfamiliar and escaped wrappers
Naoray Oct 23, 2026
97e8e88
Keep empty unquoted fields separate from following assignments
Naoray Oct 23, 2026
e113a59
Honor verified CSV and SQL scopes through serialized strings
Naoray Oct 23, 2026
63f30c8
Bound partial decoded cells by their enclosing source string
Naoray Oct 23, 2026
7818579
Preserve private ownership through JSON Unicode wrapper escapes
Naoray Oct 23, 2026
f621387
Keep opaque wrapper benchmark values partition disjoint
Naoray Oct 23, 2026
e99c969
Retain encoded field ownership through unfinished JSON streams
Naoray Oct 23, 2026
53e1f66
Exclude escaped prose quotes from JSON enclosure openers
Naoray Oct 23, 2026
90d112a
Preserve multiline SQL ownership after preceding records
Naoray Oct 24, 2026
58d907c
Merge current main into the labelled record ID branch
Naoray Oct 24, 2026
05d04b5
Merge current main into labelled identifier fixes
Naoray Oct 25, 2026
8f63672
Prepare labelled identifier mechanism captures
Naoray Oct 25, 2026
cf67c6f
Reuse scalar enclosure scans across labelled fields
Naoray Oct 25, 2026
0b8245f
Reuse bounded prefix checkpoints for unresolved literals
Naoray Oct 25, 2026
5bf2530
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 25, 2026
b454af0
Share JSON validity proofs across sibling scalar contexts
Naoray Oct 25, 2026
c4a6e8c
Reuse ancestor validation and record break indexes
Naoray Oct 25, 2026
61cf30d
Count record-boundary scans in scaling checks
Naoray Oct 25, 2026
18e0024
Refresh invocation inventory for labelled record rules
Naoray Oct 25, 2026
48cff89
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 25, 2026
da4ffb7
Handle missing enclosed ID values and index unclosed wrapper scans
Naoray Oct 25, 2026
80a6fa4
Verify missing JSON values independently in scanner differential
Naoray Oct 25, 2026
f04603e
Protect JSON label-cell values and share quote-boundary events
Naoray Oct 25, 2026
1d0a123
Record compiled scanner mutations and restored source hashes
Naoray Oct 25, 2026
9f9ad91
Include scanner proof fixtures in the full CI input audit
Naoray Oct 25, 2026
f01798b
Use neutral sibling fixture and targeted scanner mutation probes
Naoray Oct 25, 2026
08b49d1
Record targeted default-feature scanner mutation results
Naoray Oct 25, 2026
b017196
Merge main into labelled record ID work
Naoray Oct 26, 2026
5d34d3d
Protect labelled IDs in embedded JSON and bound repeat sweeps
Naoray Oct 26, 2026
f551f5a
Record embedded JSON and bounded sweep mutation evidence
Naoray Oct 26, 2026
47629b2
Merge remote-tracking branch 'origin/main' into feat/labelled-record-ids
Naoray Oct 26, 2026
19a5608
Preserve JSON structure in labelled record ownership and repeats
Naoray Oct 26, 2026
01b23b9
Keep labelled repeats outside partial JSON escapes
Naoray Oct 26, 2026
d3d26d3
Record JSON ownership and repeat mutation evidence
Naoray Oct 26, 2026
993ba35
Share decoded whitespace rules across label and repeat scanning
Naoray Oct 26, 2026
3f0cca5
Refresh mutation evidence for shared whitespace scanning
Naoray Oct 26, 2026
60af203
Make generated JSON region vectors explicit for clippy
Naoray Oct 26, 2026
d009181
Pin mutation receipts to clippy-clean scanner tests
Naoray Oct 26, 2026
f84b4d3
Bound decoded repeat patterns while preserving legacy prefix contracts
Naoray Oct 26, 2026
4993630
Probe trailing-padding repeat eligibility after decoded fallback
Naoray Oct 26, 2026
fa3dfc2
Clarify field-scalar and legacy repeat eligibility
Naoray Oct 26, 2026
e00ab4e
Retain bounded exact spellings when Unicode folding expands patterns
Naoray Oct 26, 2026
5034953
Preserve exact collision-family matching for scalar repeat seeds
Naoray Oct 26, 2026
385b77b
Record complete decoded repeat and scalar mutation evidence
Naoray Oct 26, 2026
a8054aa
Preserve JSON structure across mixed record ID carriers
Naoray Oct 26, 2026
20f4fc8
Cover payload prefixes and zero-width label-tail mutations
Naoray Oct 26, 2026
e8ff847
Use explicit single-range collections in JSON ownership
Naoray Oct 26, 2026
2b59c22
Keep empty array values from suppressing later record IDs
Naoray Oct 26, 2026
2fc1eb0
Record mixed-carrier invariants and compiled mutation evidence
Naoray Oct 26, 2026
ab01b84
Constrain record IDs and preserve lexical carrier syntax
Naoray Oct 26, 2026
b06a1a3
Preserve padded base64 IDs without consuming attribute syntax
Naoray Oct 26, 2026
73b7e6c
Check header ownership before independent value guards
Naoray Oct 26, 2026
76dcf3e
Import scanner ownership helpers in the header test
Naoray Oct 26, 2026
9e48029
Preserve unquoted HTML carriers and pin decoded ownership
Naoray Oct 26, 2026
c259602
Share markup syntax gates across record detection and repeats
Naoray Oct 26, 2026
fe4af64
Keep decoded JSON data eligible for markup-safe repeats
Naoray Oct 26, 2026
af22270
Require field context and a real closing quote for padded IDs
Naoray Oct 26, 2026
204562a
Record lexical carrier checks and compiled mutation evidence
Naoray Oct 26, 2026
3b42363
Pin CRM label suffix and quoted wrapper CI regressions
Naoray Oct 26, 2026
30ab82e
Use the public cleaning helper in the CRM regression
Naoray Oct 26, 2026
62e7bf0
Preserve CRM label suffixes and quoted wrapper contents under CI guards
Naoray Oct 26, 2026
536cc05
Register scanner carriers and reference evidence in full CI inputs
Naoray Oct 26, 2026
5fbf92a
Check integration mutation execution and exact owned byte ranges
Naoray Oct 26, 2026
670f355
Record CI regression mutation evidence and verification boundaries
Naoray Oct 26, 2026
76f1928
Refresh detached probe lock and cap named Rust gates at two jobs
Naoray Oct 26, 2026
e60fcbf
Merge main daemon v2 with labelled record provenance and pin allocati…
Naoray Oct 26, 2026
e87f6ce
Charge record provenance and decoded sweep allocations within daemon …
Naoray Oct 26, 2026
34fe4b6
Pin daemon stabilization when record repeat provenance changes
Naoray Oct 26, 2026
3b226cd
Advance daemon stabilization when repeat ownership changes and probe …
Naoray Oct 26, 2026
0f83b17
Record integrated session and sweep mutation evidence
Naoray Oct 26, 2026
bdcfb74
Pin record identifier markup and code boundary regressions
Naoray Oct 26, 2026
845f95b
Constrain markup gates to closed attributes and retain labelled ID va…
Naoray Oct 26, 2026
c3effda
Pin strict tag grammar and labelled identifier exceptions with mutations
Naoray Oct 26, 2026
6c13e14
Keep legacy scanner grammar frozen while extending record ID starts
Naoray Oct 26, 2026
273beba
Extend code type counterweights and wrapper mutation checks
Naoray Oct 27, 2026
ca26a19
Preserve wrapped SQL schema expressions across statement lines
Naoray Oct 27, 2026
048d875
Recognize SQL schema statements inside labelled tool output
Naoray Oct 27, 2026
ac5c9fe
Reject attributes on closing tags when establishing markup context
Naoray Oct 27, 2026
1171bcb
Retain each reported non-tag input alongside the generated ownership …
Naoray Oct 27, 2026
67742b7
Limit hash-led record IDs to the initial value position
Naoray Oct 27, 2026
8b1d53d
Keep hash support out of the shared legacy value grammar
Naoray Oct 27, 2026
a78bed2
Keep code carrier counterweights in the documented test fixture scope
Naoray Oct 27, 2026
3f6891c
Document the fixture boundary without an inert allow marker
Naoray Oct 27, 2026
3e7d9bc
Register code counterweights in the full CI input inventory
Naoray Oct 27, 2026
129bcf9
Add both-sided record ID rule boundary generators and review probes
Naoray Oct 27, 2026
a190609
Make all review probes reproducible and declare generator inputs
Naoray Oct 27, 2026
a1a5575
Constrain record ID vetoes to lexical references and established carr…
Naoray Oct 27, 2026
62faad8
Cover component and HTML fragment grammar boundaries
Naoray Oct 27, 2026
4fd55f4
Preserve case-insensitive HTML fragments without SQL keyword attributes
Naoray Oct 27, 2026
6b7538b
End schema ownership veto at the matching column-list close
Naoray Oct 27, 2026
50949b8
Pin valid semicolon HTML fragments and diagnose remaining SQL context
Naoray Oct 27, 2026
98171dd
Recognize complete ALTER ADD COLUMN carriers across tool-output prefixes
Naoray Oct 27, 2026
df9d057
Index SQL source and statement delimiters for bounded context checks
Naoray Oct 27, 2026
53d5104
Pin each HTML evidence predicate independently with counterexamples
Naoray Oct 27, 2026
072e409
Make paired-tag counterweights independent of fragment evidence
Naoray Oct 27, 2026
3dceafc
Simplify optional SQL source predicate for clippy
Naoray Oct 27, 2026
0e912cf
Cover standard SVG and MathML tag names in primary and repeat paths
Naoray Oct 27, 2026
d0635bc
Use standard SVG and MathML vocabularies for tag evidence
Naoray Oct 27, 2026
9897f87
Normalize the MathML index typo before emitting element names
Naoray Oct 27, 2026
2b57336
Pin Unicode hash IDs and character-count boundaries
Naoray Oct 27, 2026
d03e1cf
Test SQL parameter boundaries with quoted and qualified table names
Naoray Oct 27, 2026
90ef06f
Preserve Unicode hash IDs and quoted SQL parameter carriers
Naoray Oct 27, 2026
e987063
Pin grouped prose IDs next to SQL keyword boundaries
Naoray Oct 27, 2026
3389b81
Scope DML keyword stops to SQL carriers and preserve grouped prose IDs
Naoray Oct 27, 2026
eeb578d
Pin seeded semicolon HTML and paired SQL-keyword non-tags
Naoray Oct 27, 2026
c441706
Reject SQL-keyword attribute lookalikes even with a matching closer
Naoray Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
retain their keys and punctuation. Generic `token` keys remain outside the
code-field rule; ambiguous password metadata stays fail-closed. Whole Argon2
encodings no longer split at an inner postal-code candidate (#824).
- Protect explicitly labelled customer, employee and person/member record identifiers
in English/German prose, JSON and logs with exact reversible value capture.
Generic record, order, invoice, issue, build and tracking IDs remain outside these rules.

- Plain-text session files on macOS/Linux clear and verify their extended ACL
before any restore-key bytes are written, including overwrite replacements.
ACL failures and unsupported platforms (including Windows) refuse
Expand Down Expand Up @@ -111,6 +115,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
A new mapping invalidates the cache. Ambiguous runs now return the distinct
`AmbiguousTokenRun` error, whose display and debug output contain no tokens
or manifest values.
- Cross-class identifier trimming discards repeat seeds that extend beyond the
shortened owner, preserving fail-closed validation without refusing valid
mixed licence and card inputs.

- Preserve first-value repeats when a complete private or unknown cue remains
inside a conservative legacy identifier owner, including raw NFC/NFD licence
labels. One typed prefix seed retains the owned tail and existing length floor;
conservative protection of public prefix copies remains a measured cost.

- Labelled customer, employee and member IDs preserve terminal prose punctuation,
stop at complete next-field cues, and protect raw quoted scalars through nested
serialization, initial newlines and tab groups. Single and triple delimiters
retain doubled quotes and complete multiline values. Unicode opening
punctuation, typographic quotes, paired brackets and backticks preserve whole
private scalars. Complete CSV cells and enclosing SQL literals distinguish
doubled delimiters from JSON escaping. Unpaired scalars inside CSV and SQL
literals retain embedded line breaks and literal backslashes. Every close search stays
inside its enclosing serialized string, preserving later public fields.
JSON record-separator escapes retain the following person-label cue.
Unterminated values end before an enclosing serialized string
close, at an unescaped record line break, or at input end. Key-looking private
suffixes stay protected, and enclosing JSON remains parseable. Unclassified
quote runs retain nonempty ownership. Conservative tab prefixes protect repeats
under unchanged length floors, including later session turns; their public-byte
cost is disclosed in benchmark evidence.
- Legacy grouped identifier extensions stop at positively recognized complete
operational metadata cues without trimming their original regex capture.
Private and unknown tails retain conservative ownership until an independent
recognizer supplies existing boundary proof. Unicode groups and complete
licence connectors retain their original bytes.
- `gaze-proxy` no longer restores a value captured from a JSON document with its
JSON escapes. A name captured as `Robert \"Bob\" Smith` from a JSON text block
or JSON tool result now reaches Anthropic `tool_use.input` as
Expand Down Expand Up @@ -145,6 +179,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Signed session snapshots with deterministic repeat-seed metadata use envelope
v8. JSON source spelling alone retains v7; ordinary snapshots remain v6. New
readers restore v2–v8. Older readers reject v8 rather than silently dropping
repeat protection; upgrade all readers before exchanging these snapshots.
- **Breaking:** context JSON requires a top-level object. Positional arrays of
zero through six fields are rejected with `PolicyConfig` by
`gaze clean --context-json` and daemon clean frames. Replace positional input
Expand All @@ -153,9 +191,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **Snapshot contract.** `Session` records each token's source spelling and
adds `source_spelling` and `restore_strict_decoded_text_with_provenance`. A
manifest holding a JSON-escaped value exports as `session_blob` envelope v7,
which v0.17 and older refuse with `InvalidSnapshotVersion(7)`. Other
manifests still export as v6.
manifest holding a JSON-escaped value exports as `session_blob` envelope v7
unless repeat metadata requires v8. Readers on v0.17 and older refuse both
versions. Manifests without either metadata path still export as v6.

### Benchmark

Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ The browser-MITM project is separate (formerly in-tree `debug-proxy`).
[`docs/explanation/detection/validator-veto.md`](docs/explanation/detection/validator-veto.md).
- Repeat-value sweep: after resolve and before the safety net, uncovered copies of rule-found values
(this document's winners + session manifest entries with a non-learned evidence tier) join the
pool and it is resolved again; NER/safety-net values never propagate. `session_blob` is v6
(per-entry evidence tier). Contract:
pool and it is resolved again; NER/safety-net values never propagate. `session_blob` uses v6 for ordinary values, v7 for JSON source spelling alone, and v8 when
deterministic repeat-seed metadata is present (per-entry evidence plus authenticated seed offsets),
including entries that also retain JSON source spelling. Older readers reject unsupported versions. Contract:
[`docs/explanation/detection/manifest-sweep.md`](docs/explanation/detection/manifest-sweep.md).
- Collision-family policy: cross-class recognizer rivalries declare `[recognizers.collision]` or
`[policy.custom_recognizers.collision]` metadata and compile into `FamilyPolicyTable`.
Expand Down
34 changes: 31 additions & 3 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,45 @@ process that writes one.

A session now records whether each value was captured inside a JSON string
literal in its escaped spelling. A manifest that holds such a value exports as
envelope version 7. Every other manifest still exports as version 6.
envelope version 7 unless it also carries repeat metadata (version 8).
Manifests without either metadata path still export as version 6.

- A v0.17 or older reader refuses a v7 blob with `InvalidSnapshotVersion(7)`.
It fails closed; nothing is restored.
- This release imports v2 to v7 blobs. Older blobs restore exactly as before;
their values read as plain text.
- This release imports v2 to v8 blobs. Older blobs restore exactly as before;
values without spelling metadata read as plain text.

`gaze-proxy` restores such a value into Anthropic `tool_use.input` as the value
its escapes spell, not with literal backslashes. Text blocks and other
plain-text destinations still receive the bytes the client sent.

### Action required: conditional `session_blob` version 8

Field-owned record identifiers now retain exact scalar whitespace and conservative
repeat prefixes for ambiguous tab groups and complete cues
inside conservative legacy owners. Legacy prefixes never shorten the original
capture or declare the next field public. Their ordinary length floor is unchanged.
A signed snapshot with this metadata uses envelope v8. JSON source spelling alone
retains v7. Ordinary snapshots remain v6. Readers supporting only v7 and earlier
reject v8 with `InvalidSnapshotVersion(8)`.

Upgrade every reader before importing newly written v8 snapshots. The new reader
imports and restores v2–v8 without re-tokenizing old manifests. Seed offsets bind
to the existing owner value. Import rejects invalid geometry, missing deterministic
evidence, and seed metadata in an older envelope. Whole-value ownership and
strict restore remain intact. Conservative prefix matches can protect public
bytes and retain the existing repeat-length floors.

Single and triple ASCII quote delimiters retain raw content, including doubled
quotes and complete multiline scalars. Every closing-quote search stops before
the enclosing serialized string's close at every representable depth.
Unterminated or inconsistent values end at the nearest enclosing serialized
string close (excluded, with escape depth preserved), an unescaped LF/CRLF/CR
record boundary, or input end. Key-looking text and container punctuation inside
the unfinished value remain private; a following assignment alone is no boundary.
Unclassified quoting keeps nonempty ownership through that safe boundary. Unquoted tab grouping
retains its existing conservative public-column cost.

---

## v0.16.x → v0.17.0
Expand Down
22 changes: 19 additions & 3 deletions anvil.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ checks:
inputs: *rust-inputs
toolchain: *rust-tools
commands:
- cargo clippy --workspace --all-features --all-targets -- -D warnings
- env CARGO_BUILD_JOBS=2 nice -n 10 cargo clippy --workspace --all-features --all-targets -- -D warnings
fast:
description: Format and lint before full verification
reusable: true
Expand All @@ -69,7 +69,7 @@ checks:
toolchain: *rust-tools
commands:
- cargo fmt --all -- --check
- cargo clippy --workspace --all-features --all-targets -- -D warnings
- env CARGO_BUILD_JOBS=2 nice -n 10 cargo clippy --workspace --all-features --all-targets -- -D warnings
test:
description: Workspace tests, with at least one executed test
expensive: true
Expand All @@ -78,7 +78,7 @@ checks:
toolchain: *rust-tools
commands:
- python3 -m unittest discover -s scripts/anvil -p 'test_test_*.py'
- python3 scripts/anvil/test_nonempty.py cargo test --workspace --all-features
- python3 scripts/anvil/test_nonempty.py env CARGO_BUILD_JOBS=2 nice -n 10 cargo test --workspace --all-features
feature-matrix:
expensive: true
locks: [workspace-build]
Expand Down Expand Up @@ -114,3 +114,19 @@ checks:
commands:
- cargo fmt --all -- --check
- env CARGO_BUILD_JOBS=2 GAZE_DISABLE_OS_KEYSTORE=1 nice -n 10 python3 scripts/gate/os-keystore-mutation-probe.py --focused

record-id-focused:
description: Focused labelled-record JSON and sweep regression tests
inputs: *rust-inputs
toolchain: *rust-tools
commands:
- env CARGO_BUILD_JOBS=2 nice -n 10 cargo test -p gaze-recognizers --lib
- env CARGO_BUILD_JOBS=2 nice -n 10 cargo test -p gaze-pii --lib
- env CARGO_BUILD_JOBS=2 nice -n 10 cargo test -p gaze-cli --test record_ids
- env CARGO_BUILD_JOBS=2 nice -n 10 cargo test -p gaze-cli --test daemon_reversible record_ids
record-id-mutations:
description: Compiled mutations for record ownership and repeat protection
inputs: *rust-inputs
toolchain: *rust-tools
commands:
- env CARGO_BUILD_JOBS=2 nice -n 10 python3 scripts/verify_record_id_scanner_mutations.py
8 changes: 8 additions & 0 deletions crates/gaze-assembly/src/detector_wiring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub(crate) fn register_rulepack_recognizers(
pattern_template,
capture_groups,
complete_labelled_value,
labelled_value_mode,
} => {
let pattern =
lower_regex_pattern(&recognizer.id, pattern, pattern_template, locale_vocab)?;
Expand Down Expand Up @@ -182,7 +183,14 @@ pub(crate) fn register_rulepack_recognizers(
.as_ref()
.and_then(|context| context.reject_match_regex.as_deref()),
)?
.with_unquoted_capture_rejection(
recognizer
.context
.as_ref()
.and_then(|context| context.reject_unquoted_capture_regex.as_deref()),
)?
.with_complete_labelled_value(complete_labelled_value)
.with_labelled_value_mode(labelled_value_mode)
.with_locale_basis(recognizer.locale_basis)
.with_validator_on_fail(
recognizer
Expand Down
95 changes: 95 additions & 0 deletions crates/gaze-cli/tests/daemon_reversible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,3 +728,98 @@ fn context_requests_keep_resident_ner_and_its_learned_evidence_tier() {
"caller-known rule evidence must propagate"
);
}

#[test]
fn padded_record_ids_keep_repeat_protection_on_second_daemon_turn() {
let dir = tempdir().unwrap();
let policy = dir.path().join("policy.toml");
fs::write(&policy, "[session]\nscope = \"conversation\"\n[policy.rulepacks]\nbundled = [\"core\"]\n[[rule]]\nkind = \"default\"\naction = \"tokenize\"\n").unwrap();
let mut daemon = Daemon::start(&policy);
for (index, padding) in [" ".repeat(32), "\u{00a0}".repeat(16), "\\t".repeat(32)]
.into_iter()
.enumerate()
{
let session = format!("padded-record-{index}");
let opened = daemon.request(json!({"version":1,"op":"open","session_id":session}));
assert_eq!(opened["op"], "open", "{opened}");
let text = format!(r#"{{"customerId":"SYN731284{padding}"}}"#);
let first =
daemon.request(json!({"version":1,"op":"clean","session_id":session,"text":text}));
assert!(
!first["clean_text"].as_str().unwrap().contains("SYN731284"),
"{first}"
);
let next = daemon.request(json!({"version":1,"op":"clean","session_id":session,"text":"Follow-up about SYN731284"}));
assert!(
!next["clean_text"].as_str().unwrap().contains("SYN731284"),
"{next}"
);
}
}

#[test]
fn mixed_record_ids_keep_json_structure_on_second_daemon_turn() {
let dir = tempdir().unwrap();
let policy = dir.path().join("policy.toml");
fs::write(&policy, "[session]\nscope = \"conversation\"\n[policy.rulepacks]\nbundled = [\"core\"]\n[[rule]]\nkind = \"default\"\naction = \"tokenize\"\n").unwrap();
let mut daemon = Daemon::start(&policy);
let mut checked = 0;
for (index, (seed, text, encoded)) in [
(
"customerId: 731284",
r#"{"731284":true,"total":731284,"copy":"731284"}"#,
false,
),
(
"Customer ID = 731284",
r#"{\"731284\":true,\"total\":731284,\"copy\":\"731284\"}"#,
true,
),
(
r#"{"customerId":"SYN\u0037\u0033\u0031\u0032\u0038\u0034"}"#,
r#"{"copy":"SYN731284"}"#,
false,
),
(
r#"{"customerId":"SYN731284"}"#,
r#"{"copy":"SYN\u0037\u0033\u0031\u0032\u0038\u0034"}"#,
false,
),
]
.into_iter()
.enumerate()
{
let session = format!("mixed-record-{index}");
let opened = daemon.request(json!({"version":1,"op":"open","session_id":session}));
assert_eq!(opened["op"], "open", "{opened}");
let first =
daemon.request(json!({"version":1,"op":"clean","session_id":session,"text":seed}));
assert!(first["clean_text"].is_string(), "{first}");
let input = format!("log: {text}");
let next =
daemon.request(json!({"version":1,"op":"clean","session_id":session,"text":input}));
let clean = next["clean_text"].as_str().unwrap();
let body = clean.strip_prefix("log: ").unwrap();
let decoded = if encoded {
serde_json::from_str::<String>(&format!("\"{body}\"")).unwrap()
} else {
body.to_owned()
};
let parsed: Value = serde_json::from_str(&decoded).unwrap();
if index < 2 {
assert_eq!(parsed["731284"], true);
assert_eq!(parsed["total"], 731284);
assert_ne!(parsed["copy"], "731284");
} else {
assert!(
!clean.contains("SYN731284") && !clean.contains(r"SYN\u0037"),
"{clean}"
);
}
let restored =
daemon.request(json!({"version":1,"op":"restore","session_id":session,"text":clean}));
assert_eq!(restored["text"], input, "{restored}");
checked += 1;
}
assert_eq!(checked, 4);
}
Loading
Loading