From e3996d88bf68bed0c17e11b7763f27325d5be4b0 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Sat, 22 Aug 2026 02:12:29 +0100 Subject: [PATCH] fix(pricing): content-digest snapshot instead of a wall-clock date MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generated pricing_data_gen.go header used to stamp today's date on every `make pricing-sync` run, so a re-run against genuinely unchanged upstream data still touched the file and produced a spurious daily diff with nothing real to review. The header now records a short SHA-256 digest of the FETCHED bytes instead — identical upstream data always reproduces a byte-identical generated file. Folded review minor. --- pricing_data_gen.go | 5 +++-- tools/pricing-sync/main.go | 36 ++++++++++++++++++++++++++++----- tools/pricing-sync/main_test.go | 30 +++++++++++++++++++++++---- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/pricing_data_gen.go b/pricing_data_gen.go index d68dffa..f2b4f3f 100644 --- a/pricing_data_gen.go +++ b/pricing_data_gen.go @@ -4,8 +4,9 @@ package traefikllmgateway // model_prices_and_context_window.json — DO NOT EDIT. // // Source: https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json -// Snapshot: 2026-08-22, 236 entries kept (pruned from 3111 upstream entries — -// see tools/pricing-sync/main.go's own doc comment for the exact pruning +// Source digest: sha256:0e8d23239c27 +// 236 entries kept (pruned from 3111 upstream entries — see +// tools/pricing-sync/main.go's own doc comment for the exact pruning // rule and bare-id collision resolution). // // Regenerate with: make pricing-sync diff --git a/tools/pricing-sync/main.go b/tools/pricing-sync/main.go index 2a7e786..1a33128 100644 --- a/tools/pricing-sync/main.go +++ b/tools/pricing-sync/main.go @@ -92,6 +92,8 @@ package main import ( "context" + "crypto/sha256" + "encoding/hex" "encoding/json" "fmt" "go/format" @@ -272,7 +274,7 @@ func run() error { } src, err := renderGoSource(table, sourceMeta{ - snapshot: time.Now().UTC().Format("2006-01-02"), + sourceDigest: contentDigest(data), totalUpstream: totalUpstream, kept: len(table), }) @@ -450,9 +452,32 @@ func providerPriorityIndex(provider string) int { return len(providerPriority) } -// sourceMeta is renderGoSource's header-comment material. +// contentDigestLen is how many leading hex characters of the SHA-256 +// digest contentDigest keeps — enough to be a stable, practically +// collision-free content fingerprint for a header comment, without +// printing a full 64-character hash nobody reads in full. +const contentDigestLen = 12 + +// contentDigest returns a short SHA-256 fingerprint of data, hex +// encoded — the generated file's snapshot label (review fix, folded +// minor), so a `make pricing-sync` re-run against UNCHANGED upstream +// bytes reproduces an identical file, with no diff at all, rather than a +// wall-clock date bumping every run regardless of whether the data +// itself changed. +func contentDigest(data []byte) string { + sum := sha256.Sum256(data) + return hex.EncodeToString(sum[:])[:contentDigestLen] +} + +// sourceMeta is renderGoSource's header-comment material. sourceDigest is +// a short content hash of the FETCHED upstream bytes (review fix, +// folded minor), not a wall-clock date: a date-stamped header made every +// `make pricing-sync` run touch the generated file even when the +// upstream data had not changed at all, producing a spurious daily diff +// with nothing real to review. A content hash changes only when the +// underlying data actually changes. type sourceMeta struct { - snapshot string + sourceDigest string totalUpstream int kept int } @@ -476,8 +501,9 @@ func renderGoSource(table map[string]builtinEntry, meta sourceMeta) (string, err fmt.Fprintf(&b, "// model_prices_and_context_window.json — DO NOT EDIT.\n") fmt.Fprintf(&b, "//\n") fmt.Fprintf(&b, "// Source: %s\n", litellmSourceURL) - fmt.Fprintf(&b, "// Snapshot: %s, %d entries kept (pruned from %d upstream entries —\n", meta.snapshot, meta.kept, meta.totalUpstream) - fmt.Fprintf(&b, "// see tools/pricing-sync/main.go's own doc comment for the exact pruning\n") + fmt.Fprintf(&b, "// Source digest: sha256:%s\n", meta.sourceDigest) + fmt.Fprintf(&b, "// %d entries kept (pruned from %d upstream entries — see\n", meta.kept, meta.totalUpstream) + fmt.Fprintf(&b, "// tools/pricing-sync/main.go's own doc comment for the exact pruning\n") fmt.Fprintf(&b, "// rule and bare-id collision resolution).\n") fmt.Fprintf(&b, "//\n") fmt.Fprintf(&b, "// Regenerate with: make pricing-sync\n") diff --git a/tools/pricing-sync/main_test.go b/tools/pricing-sync/main_test.go index b18e3ad..adad3e9 100644 --- a/tools/pricing-sync/main_test.go +++ b/tools/pricing-sync/main_test.go @@ -168,13 +168,13 @@ func TestParseAndPrune_Golden(t *testing.T) { // TestRenderGoSource_ValidSortedGo asserts renderGoSource produces // syntactically valid, gofmt-canonical Go source (parseable by go/ // parser) whose entries appear in sorted key order, and that its header -// documents the pruning provenance (source URL, snapshot, counts). +// documents the pruning provenance (source URL, content digest, counts). func TestRenderGoSource_ValidSortedGo(t *testing.T) { table := map[string]builtinEntry{ "zzz-model": {ContextTokens: 1, InputCostPerMTokMicroUSD: 1, OutputCostPerMTokMicroUSD: 1}, "aaa-model": {ContextTokens: 2, InputCostPerMTokMicroUSD: 2, OutputCostPerMTokMicroUSD: 2}, } - src, err := renderGoSource(table, sourceMeta{snapshot: "2026-08-22", totalUpstream: 3111, kept: 2}) + src, err := renderGoSource(table, sourceMeta{sourceDigest: "deadbeefcafe", totalUpstream: 3111, kept: 2}) if err != nil { t.Fatalf("renderGoSource: %v", err) } @@ -188,8 +188,8 @@ func TestRenderGoSource_ValidSortedGo(t *testing.T) { if !strings.Contains(src, litellmSourceURL) { t.Error("generated source missing source URL provenance comment") } - if !strings.Contains(src, "2026-08-22") || !strings.Contains(src, "3111") { - t.Error("generated source missing snapshot date / upstream count provenance comment") + if !strings.Contains(src, "deadbeefcafe") || !strings.Contains(src, "3111") { + t.Error("generated source missing source-digest / upstream count provenance comment") } if got, want := strings.Index(src, `"aaa-model"`), strings.Index(src, `"zzz-model"`); got == -1 || want == -1 || got > want { t.Errorf(`entries not sorted: index("aaa-model")=%d, index("zzz-model")=%d, want aaa before zzz`, got, want) @@ -242,3 +242,25 @@ func TestApplyNamingBridges_DoesNotOverwriteExistingEntry(t *testing.T) { t.Errorf(`table["MiniMax-M2.1-highspeed"] = %+v, want %+v (its own direct LiteLLM entry, not the bridged duplicate)`, got, want) } } + +// TestContentDigest covers the review-fix replacement for a wall-clock +// snapshot date: identical bytes must always produce an identical +// digest (the whole point — a `make pricing-sync` re-run against +// unchanged upstream data must reproduce a byte-identical file, with no +// spurious diff), different bytes must produce a different digest, and +// the digest is always exactly contentDigestLen hex characters. +func TestContentDigest(t *testing.T) { + a := contentDigest([]byte(`{"gpt-5":{}}`)) + b := contentDigest([]byte(`{"gpt-5":{}}`)) + c := contentDigest([]byte(`{"gpt-5":{"changed":true}}`)) + + if a != b { + t.Errorf("contentDigest is not deterministic: %q != %q for identical input", a, b) + } + if a == c { + t.Errorf("contentDigest(%q) == contentDigest(%q) = %q, want different digests for different input", `{"gpt-5":{}}`, `{"gpt-5":{"changed":true}}`, a) + } + if len(a) != contentDigestLen { + t.Errorf("len(contentDigest(...)) = %d, want %d", len(a), contentDigestLen) + } +}