_global/price-parser-repair
Repair a broken pricing-page parser in tools/bin/price-watch after a provider redesigns its page, and open a draft PR. Runs only after a human has settled what the price actually is.
Repair a pricing-page parser
tools/bin/price-watch reads each provider's published pricing page and compares
it to orchestrator/src/rates/<provider>.json. When a provider restructures that
page the parser stops being able to read it, the rate is marked disputed, and an
entry is opened in countries/_global/decisions.md.
This task fixes the parser. It never decides what a price is. A human settles that in the register first; you are repairing the deterministic path so the next weekly check does not need a human at all.
Before you start
Read the register: countries/_global/decisions.md. Find the open P- entry
naming the provider you were triggered for.
If its Status is not résolu, stop. Report that the price has not been
settled yet and do nothing else. A parser written to reproduce a number nobody has
confirmed is a parser that hard-codes a guess.
What to do
Fetch the page yourself and read its structure:
curl -sL "<the Source URL from the entry>" > /tmp/page.htmlOnly that URL. This task makes no other network calls.Run the parser as it stands and see how it fails:
price-watch check --provider <name> --no-llm --dry-runFix the parser function in
tools/bin/price-watch(parseDeepSeek,parseAnthropic, or a new one registered inPARSERS).Anchor on labels, never on position. The parser must find a value by the text next to it — the model's name, the row's caption — and return
nullwhen that text is absent. A parser that reads "the third number on the page" keeps working after a redesign and silently returns the wrong column, which is the single failure this whole tool exists to prevent. Returning nothing is a good outcome; guessing is not.Verify against the numbers the human accepted in the register:
price-watch check --provider <name> --no-llm --dry-runmust now read exactly those values, and reportokfor every model the entry did not dispute.Check you have not broken the other provider:
price-watch check --no-llm --dry-run— every other model must still sayok.
What you must not do
- Never edit a file under
orchestrator/src/rates/. Prices are applied byprice-watch applyafter a human accepts them, never by an agent, and never as a side effect of fixing a parser. If your parser only passes once you have changed a stored rate, your parser is wrong. - Never remove the
disputedmarker by hand — the next successfulcheckclears it on its own, which is the proof that the repair worked. - Never weaken
invariants()to make a value pass. That function is the only check that catches a plausible-but-wrong reading; loosening it to get a green result removes the guard that would have caught your own mistake.
Finishing
Open a draft PR with the parser change alone. In the description: the entry
id, what changed on the page, what the parser now anchors on, and the before/after
output of price-watch check.
This is code that decides what money costs, so it is reviewed by a human and
merged by a human. Append the usual dated entry to memory/journal.md: which
provider moved, what the page does now, and what the parser keys off — so the next
repair starts from what this one learned.