Repository navigation
feat(data): FX policy — data/fx.json, fx refresh, build recomputes every usd block (#12) - #68
Merged
Merged
Conversation
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.
Resolves #12 (part of #1).
What changed
data/fx.json(new):{base: "USD", date, source, rates}. This is the seed block frompricing.json, copied unchanged (2026-10-02), so no price moves in this PR beyond re-rounding.tools/fx.mjs(new,npm run fx [--out path]):roundSig(6 significant digits),toUsd(native ÷ rate;nulland"unknown"pass through; an unsupported currency throws),isSupportedCurrency,validateFx, andfxFromFrankfurter.https://api.frankfurter.app/latest?from=USDwith a descriptiveUser-Agent. That URL now redirects (301) toapi.frankfurter.dev/v1, andsourcerecords the URL it actually landed on.tools/build.mjs(new,npm run build, which used to be a "not implemented" stub):usd{}block on API offers and subscriptions from native values anddata/fx.json.blended_3to1comes from the unrounded natives and is rounded once.fx_rate_dateis set only on non-USD rows.fxblock intopricing.jsonand rebuildsderived.cheapest_provider_per_model.usd_*columns of the two CSV exports.fx.jsonbefore building.tools/validate.mjs: three new checks:currency "XYZ" has no rate in fx (unsupported; see docs/fx.md).usdfield must equal what the build computes, otherwiseis X, build computes Y …; run npm run build. This is what makes a hand-editedusdvalue fail CI.fxblock inpricing.jsonmust deep-equaldata/fx.json.docs/fx.md(new): the policy. It covers the source, one dated rate set per dataset,usd = native / rate, rounding to 6 significant digits applied once, unsupported currencies being refused, rows never mixing currencies, andusdblocks being build output only.docs/SCHEMA.mdandloops/README.md. The api-daily loop runsnpm run fx && npm run build; the loop prompt files themselves don't exist yet.package.json: only thebuildline changed, plus a newfxline.Data diff — please look at this
The seed
usdvalues were rounded to 6 decimal places. The issue asks for 6 significant digits, so this PR re-rounds them once:pricing.json: 117 changed lines, every one ausdnumber or aderived…blended_3to1_usdmirror. Examples:6.737957 → 6.73796,0.005966 → 0.00596605. If you strip theusdblocks and derived blends, the old and new documents are deep-equal. Nocheapest_offerwinner changed and no derived entry was added or removed.usd_*cells changed.openrouter/mistral-small-3.2-24b-instruct-2506. Its blend 0.1328125 is an exact tie at the last digit, which the old values rounded down androundSignow rounds up.The build writes
pricing.jsonbyte-stably: it keeps20.0-style number lexemes and the missing trailing newline. That avoids roughly 445 lines of formatting churn and makes re-runs idempotent.Acceptance
fx.jsonchanges exactly theusdblocks of rows in that currency. This is a unit test on fixtures plus a test over the real data (bump CHF → exactly the 4 CHF rows change). The reviewer also checked it by hand: bumping CNY 6.7046 → 7.2 changed exactly the 56 CNY rows and only their CSVusd_*cells. The derived ranking was recomputed, and 6 winners correctly flipped from-intlto-cnrows.tools/fx.test.mjsandtools/build.test.mjs.Verification
npm ci && npm run validate && npm testpasses (ok data/pricing.json, 44/44 tests).node tools/build.mjson the committed data is idempotent: a second run leavespricing.jsonand both CSVs byte-identical.fx.jsonrates were not checked before the build used them.Size and overlap
Size. The PR is over the soft ceiling: about 1,060 lines in 6 new files plus +352/−182 across 8 modified files, 14 files in total.
tools/build.mjsis 344 lines, spent roughly on:usdmath: ~40Overlap with sibling #14.
package.jsonis edited by both PRs, on different script lines. I didn't touchtools/README.md(held by #14), so itsbuild/fxrows still describe the old plan; a follow-up should add thefxrow there.Language. The tools are
.mjsto matchtools/validate.mjs; the issue named the filetools/fx.ts.Plan.
docs/plan.md§6 still lists "FX normalisation policy" as pending;docs/fx.mdnow covers it.🤖 Generated by Colonizer in a microVM
Co-Authored-By: Colonizer Settlers 331648616+colonizer-settlers@users.noreply.github.com