Skip to content

fix(scoring): bound value/alias matching to whole tokens - #44

Open
dchaudhari7177 wants to merge 1 commit into
bamdadd:mainfrom
dchaudhari7177:fix/bounded-value-matching
Open

dchaudhari7177 wants to merge 1 commit into
bamdadd:mainfrom
dchaudhari7177:fix/bounded-value-matching

Conversation

@dchaudhari7177

Copy link
Copy Markdown
Contributor

Closes #34.

The false positives

disclosed() matched attribute.value and each alias with a plain normalized substring test, so a digit-run form was found inside an unrelated longer number:

form haystack before after
7429 ticket 974290 was issued hit no hit
47318.22 balance 447318.229 usd hit no hit

Both are forbidden-flow hits, so the effect was a fabricated violation — precisely what THREAT_MODEL.md says a deterministic match must never produce.

The boundary

Confirm phrases already had _phrase_present; value/alias matching now has an equivalent bound in _form_present. The rule is not adjacent to a word character, asserted only on the ends where the form is itself word-like.

That conditionality is the whole design, and a plain \b on both sides would be wrong in both directions:

  • \b before $22.50 per hour requires the preceding character to be a word character, so the alias would stop matching in paid us$22.50 per hour — a false negative.
  • meanwhile 47,318.22 must still be rejected inside 447,318.229.

Normalization is unchanged and still documented: NFKC, case-fold, whitespace-run collapse. No punctuation is stripped from the surface forms, no paraphrase, no model in the loop.

Tests

11 cases in tests/test_scoring.py, both directions:

  • the true digit-run match (7429 in the reserve code is 7429.)
  • the two reported false positives
  • the same over-match reached through an alias rather than the value
  • a currency value bounded by $ and end-of-string
  • punctuation bounds, and a value alone in the output (both edges)
  • an underscore identifier (id_7429_x) — _ is part of a token, not a boundary
  • a form starting with punctuation, which the conditional boundary exists for
  • the shipped RESERVE_BALANCE / MEETING_DATE attributes still matching their real surface forms

Revert-verified: five fail against the pre-fix scorer.

Scenario results unchanged

The club/observatory/theatre expectations are untouched — the full suite passed before the new tests were added and passes after (77 total). ruff check, ruff format --check and mypy src clean.

disclosed() matched attribute.value and each alias with a plain normalized
substring test, so a digit-run form was found inside an unrelated longer
number: the alias 7429 hit inside 974290, and 47318.22 inside 447318.229.
Those are forbidden-flow hits, so the effect was a fabricated violation --
which THREAT_MODEL.md says a deterministic match must never produce.

Confirm phrases already had _phrase_present; value/alias matching now has an
equivalent bound in _form_present. The rule is "not adjacent to a word
character", asserted only on the ends where the form is itself word-like.
That conditionality is the point: a plain \b on both sides would reject
every form starting or ending in punctuation, so "$22.50 per hour" would
stop matching after "us$" -- while "47,318.22" must still be rejected inside
"447,318.229". No punctuation is stripped from the surface forms, no
paraphrase, no model in the loop.

11 tests cover both directions: the true digit-run match, the two reported
false positives, the same over-match reached through an alias rather than
the value, a currency value bounded by $ and end-of-string, punctuation
bounds, a value alone in the output, an underscore identifier, a form
starting with punctuation, and the shipped scenario attributes still
matching their real surface forms. Five fail against the pre-fix scorer.

The club/observatory/theatre scenario expectations are unchanged: the full
suite passed before the new tests were added and passes after (77 total).

Closes bamdadd#34
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.

Guard value/alias matching against substring false positives in digit-run values

1 participant