Repository navigation
Split pricing.json into per-provider/per-vendor fragments with a deterministic build (#10) - #64
Closed
ParallelEntrepreneur wants to merge 1 commit into
Closed
ParallelEntrepreneur wants to merge 1 commit into
ParallelEntrepreneur wants to merge 1 commit into
Conversation
4 tasks
Contributor
Author
|
Closing: keeping one data/pricing.json as the source of truth, with |
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.
What changed and why
One 1.4 MB
data/pricing.jsonmade every data PR conflict with every other and hid what changed. This PR splits the dataset into the layout the loops will edit, and adds a deterministic builder that regenerates the committed artefacts byte-for-byte.New source-of-truth fragments (hand-edited from now on):
data/offers/<provider_id>.json{"provider_id", "offers":[…]}— all 480 api_offers rows, sorted by iddata/plans/<vendor_id>.json{"vendor_id", "plans":[…]}— all 103 subscription rows, sorted by iddata/providers.jsondata/sources.jsondata/fx.jsondata/meta.jsonAll fragments: 2-space indent, trailing newline, LF; canonical formatting enforced by the validator.
Tooling:
tools/build.ts(npm run build, viavite-node): reads the fragments, reassembles the full document, validates it with the existingvalidateDocuments(exits 1 on any schema problem), then writesdist/pricing.json,dist/pricing_api.csv,dist/pricing_subscriptions.csv. Deterministic: no clock, no randomness, plain-code-unit sorts.countsandderived.cheapest_provider_per_modelare recomputed;generated_at= maxlast_verified_atover all rows (date-only values normalized toT00:00:00Z), never the wall clock.tools/split.ts: the one-off migration that produced the fragments from the seed; kept for the record, run once in this PR (re-running it today over the regenerated pricing.json is byte-idempotent — verified).tools/validate.mjs: now fragment-aware. Files are classified by path; shards are validated against wrapper schemas that$refthe existingschema/pricing.v1.json$defs(no schema change, no version bump), plus hand checks: filename ↔ owner id, row owner ids, strictly sorted ids, sources sort + duplicate-triple detection, canonical formatting. Defaultnpm run validatevalidates every fragment (one pool, cross-shard id uniqueness) anddata/pricing.json(separate pool), printingok <file>per file — 99 ok lines today. Exports and CLI shape unchanged.tools/validate.test.mjs12 → 24 tests; newtools/build.test.mjs(8 tests, 32 total). The key gate: the committeddata/pricing.jsonand both CSVs must be byte-equal to fresh build output —npm testfails if a generated file is hand-edited..github/workflows/ci.yml: thedatajob gains an explicitbuild reproduces the committed generated filesstep (npm run build+cmpof the three outputs), so CI fails when a generated file is edited by hand, per the acceptance criteria.data/README.md(new): what each file is, "editoffers/andplans/, never the generated files", the edit → build → copy → validate workflow, formatting/sort rules, thegenerated_atand derived rules.tools/README.mdupdated.Regenerated artefacts — what reviewers will see in the data diff
The rebuilt
data/pricing.jsonand CSVs are semantically identical to the seed (independently diffed: zero mismatches — same rows, same values, counts/derived/fx/conventions/research_notes deep-equal). The visible diffs are exactly:generated_at:2026-10-05T07:01:34Z→2026-10-05T00:00:00Z(derived rule, per the issue).20.0→20) and 404 CSV cells — rendering only, same values.cache_write_per_mtok→"unknown"with the prose preserved innotes; 5 plan rows with"formula"/"None"limit amounts →"unknown"). The JSON is the source of truth; the regenerated CSVs now match it cell-for-cell.The derived rule was reconstructed empirically and verified with zero mismatches against all 47 seed entries including all 20 tie groups: group offers by
model_slug; rankable rows are those with numericusd.blended_3to1; groups with ≥2 rankable rows;offers= numeric-row count; cheapest = min blended, tie → lexicographically smallest id.Verification
npm run validate→ exit 0,okfor all 98 fragments +data/pricing.json.npm test→ exit 0, 32/32.npm run buildtwice withdist/deleted between runs → identical sha256s for all three outputs;cmpvsdata/copies clean.cmpfail; unsorted shard, broken formatting, duplicate source triple → validator fails with the offending file/path.crates/files modified); CIdatajob steps run green locally via npm (10.9.0 restored in the sandbox).Size note (over the soft ceiling, deliberately)
9 code/doc files changed (split.ts, build.ts, build.test.mjs, validate.mjs, validate.test.mjs, package.json, ci.yml, data/README.md, tools/README.md) — within the 10-file ceiling — plus ~100 data files: 98 new fragments + 5 registries/meta + 3 regenerated artefacts. The per-provider/per-vendor file count is the point of the issue; the artefact diffs are the one-time normalization described above.
For reviewers / sibling PRs
data/pricing.jsonand will conflict textually. After this lands, their content edits belong indata/offers/anthropic.json,data/providers.jsonanddata/plans/<vendor_id>.json;derivedandcountsare build-owned, so manual recomputes should be dropped. Both were notified with the layout and rules.data/meta.jsonis an addition beyond the issue's named files (carries document-level data the build needs); alternatives considered were hardcoding it in build.ts (rejected — it's data) — happy to rename/rehome if the maintainer prefers.sources[].part/research_noteskeys keep the historical batch names (api_western.json, …) verbatim — stable-data rules; renaming was deliberately not done.data/offers/,data/plans/,data/sources.json; this PR implements it (plusproviders.json/fx.json/meta.json, which the issue specifies and the plan predates).Closes #10
🤖 Generated by Colonizer in a microVM
Co-Authored-By: Colonizer Settlers 331648616+colonizer-settlers@users.noreply.github.com