Skip to content

fix(monitors): do not truncate malformed price tokens in price_below - #172

Open
charan-rathore wants to merge 2 commits into
CopilotKit:mainfrom
charan-rathore:fix/price-token-boundaries
Open

charan-rathore wants to merge 2 commits into
CopilotKit:mainfrom
charan-rathore:fix/price-token-boundaries

Conversation

@charan-rathore

Copy link
Copy Markdown
Contributor

Problem

matchesPrice consumed a numeric prefix of malformed amounts: $1,00 and USD1,00 became 1, and $9.999 became 9.99. With a threshold of 10 those produce a false match and a notification for a page that never showed a real price under it.

Solution

Reject a match when the character right after it continues the numeric token (a digit or comma, or a decimal dot followed by a digit). Slash ($9.99/month) and sentence punctuation stay separators.

Relation to #16: that PR adds a price_above condition and touches the same matcher, but does not fix these numeric boundaries; this is not its feature implementation, and either order of merging should be a small rebase for the other.

Testing

Ran on Node 24.9.0 against the real browser-fixture/API/worker outcome path (controlled HTTP fixture, no live providers, no UI changed):

  • New regression file tests/monitor-price-token-boundaries.test.ts (7 cases): on current main the three malformed cases fail ($1,00, $9.999, USD 1,00 falsely match); with the fix all 7 pass.
  • Existing tests/monitor-price-spacing.test.ts (8 cases): all pass with the fix.
  • Root tsc --noEmit and Biome on the touched files are clean.

One honest limitation: full single-file runs of these test files stall in my environment after five or six fixture instances (the merged spacing file stalls the same way on clean main, so this is environmental, not from this change). I ran the files in --test-name-pattern chunks instead; every case in both files passed, each in 1-2 s. I did not get a full-file green run, and the broader suite was not run.

matchesPrice consumed a numeric prefix of malformed amounts: $1,00 and
USD1,00 became 1, and $9.999 became 9.99, so a threshold of 10 matched
and sent a notification for a page that never showed a real price under
it. Reject a match when the next character continues the numeric token
(digit or comma, or a decimal dot followed by a digit); slash and
sentence punctuation stay separators. Regression cases run the real
browser-fixture, API and worker outcome path.

Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com>

@NathanTarbert NathanTarbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @charan-rathore. Stopping "$1,000" from being read as "$1" is a good catch, and the lookahead does that. One case needs adjusting, because it now misses real prices.

A price followed by a comma no longer matches. The new lookahead (?![\d,]|\.\d) rejects any comma after the number, including a normal comma in a sentence. So "Now $9, was $20" only finds $20, and "Only $5," finds nothing. A watch for prices under $10 would never fire on that page. Rejecting a comma only when a digit follows it, as in (?!\d|,\d|\.\d), keeps the fix for "$1,000" and lets ordinary commas through. A couple of test cases like "Price: $9, limited time" and "$5, $20" would lock that in.

A related gap: a price with a letter after it still gets cut short. "$9M" and "$9k" still read as 9, so a watch for prices under 10 would fire on something worth 9 million. Requiring that the number isn't followed by a letter would cover those along with the punctuation cases.

The tests could also work a bit harder. The "$1,000,00" and "$1,000.00" cases come out the same with or without the fix, since both read as 1000, which isn't under 10. So they don't actually test the new check. A higher threshold, or a case like "$1,0", would make them meaningful. The new file is also mostly a copy of tests/monitor-price-spacing.test.ts, including the owner id price-spacing-user, and each case starts a whole browser. matchesPrice only works on a string, so exporting it would allow quick table tests of all these inputs, with one end-to-end case kept for the wiring. That would probably also fix the slow runs mentioned in the description. Last, the test title says "does not truncate malformed numeric tokens" for every case, including the valid ones that should match, so a failure on "$9.99/month" would show up under a misleading name.

…price_below

The malformed-token lookahead also rejected an ordinary comma after a
real price, so "Only $5," or "Price: $9, limited time" never matched and
a watch could not fire. A price with a magnitude letter still truncated:
$9M and $9k read as 9. Reject only a digit, a comma followed by a digit,
a decimal dot followed by a digit, or a trailing letter after the
amount.

Extract matchesPrice into apps/server/src/engine/price.ts and cover it
with fast table cases (comma sentences, lists, magnitude suffixes,
truncated groups); keep one browser-fixture case for the worker wiring.

Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com>
@charan-rathore

Copy link
Copy Markdown
Contributor Author

Thanks, both catches reproduce. The lookahead rejected an ordinary sentence comma, so "Only $5," and "Now $9, was $20" missed the real price, and "$9M" / "$9k" still truncated to 9. The lookahead now rejects only a digit, a comma followed by a digit, a decimal dot followed by a digit, or a trailing letter. I checked the full table against the old and new patterns: "$1,00", "$1,0", "$9.999", "USD 1,00" and "$1,000,00" stay rejected, "$9M"/"$9k" no longer match, and "$9.99/month" still does.

Good call on the tests. matchesPrice is now exported from apps/server/src/engine/price.ts, so the cases run as fast table tests with names that say what each pins, including "Price: $9, limited time" and "$5, $20". One browser-fixture case stays for the worker wiring, under its own owner id. The "$1,000,00" and "$1,000.00" entries now state what they actually check, and "$1,0" covers the truncated-group path.

16/16 table and wiring cases pass, tsc --noEmit is clean, biome is clean. One honest caveat: the neighboring monitor-price-spacing file gets killed partway through on this machine with and without this change (a memory limit here, not an assertion failure); every subtest that ran passed.

This branch has not been deployed

No deployments
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.

2 participants