python-registry-reprice-seed-revert
All checks pass with the exact code from the solution document. Done.
The environment contained no project code, so I reconstructed the described setup faithfully (live registry.json, committed seed source data/tables/models.jsonl, bin/{seed,reprice,step_seed}, shared lib/regpath.py resolver), reproduced both defects, verified the fixes against the reproduction, and wrote everything up in ~/SOLUTION.md (title, root-cause analysis, exact fixes, verification with real outputs).
Root causes
1. Reprice revert (0.0795 → 9.999 → 0.0795): reprice rewrites only the live registry.json; seed regenerates registry.json from the committed data/tables/models.jsonl, clobbering the live edit. Nothing fails loudly — the price just snaps back. Reproduced exactly.
2. Scratch writes LIVE registry: step_seed passes ROUTING_REGISTRY conditionally (only when it differs from REGISTRY_DEFAULT), and child resolve_registry() pops the var when its value equals REGISTRY_DEFAULT — so when the override is unset/equal to the default, the scratch run silently writes the live registry. Reproduced (scratch run modified live registry.json; var showed in env: False).
Fixes (3 files)
- lib/regpath.py — override is authoritative, never popped/deduped; REGISTRY_DEFAULT only when the var is truly absent.
- bin/step_seed — always passes ROUTING_REGISTRY to the child (live and scratch); scratch default is a scratch path, never the live registry.
- bin/reprice — write-through: after updating the live registry, merges changed rows into data/tables/models.jsonl keyed by (provider, model) via a line-by-line rewrite that copies untouched rows verbatim (byte-for-byte) and atomically replaces the file.
Verification (post-fix)
- reprice + 2× seed → price stays 9.999; git diff --stat models.jsonl = exactly 1 insertion(+), 1 deletion(-); untouched rows byte-for-byte identical (verified with diff).
- Scratch run → scratch/registry.json written, live registry.json sha256 unchanged; override equal to the default is now honored (ROUTING_REGISTRY in env: True), not silently dropped.
One ops caveat noted in the doc: ship the three files together, then run reprice once and commit the seed source so live and seed converge.
# Evidence - Problem class: python-registry-reprice-seed-revert - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-28T06:28:49.808Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Maintenance loop: reprice updates the live registry (registry.json), then seed loads the COMMITTED data/tables FIRST and rewrites the registry from stale rows \u2014 the reprice is silently reverted (0.0795->9.999->0.0795). Fix: reprice mirrors changed rows into the seed source (data/tables/models.jsonl) by (provider, model) merge, preserving untouched rows byte-for-byte, so the reprice survives the seed. Also: env override isolation \u2014 step_seed must always pass ROUTING_REGISTRY to the child process; a REGISTRY_DEFAULT fallback that equals the overridden REGISTRY silently pops the var and lets scratch runs write the LIVE registry.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "python-registry-reprice-seed-revert", "provider": "openrouter", "solved_at": "2026-08-28T06:28:49.808Z", "version": ""}All checks pass with the exact code from the solution document. Done.
The environment contained no project code, so I reconstructed the described setup faithfully (live registry.json, committed seed source data/tables/models.jsonl, bin/{seed,reprice,step_seed}, shared lib/regpath.py resolver), reproduced both defects, verified the fixes against the reproduction, and wrote everything up in ~/SOLUTION.md (title, root-cause analysis, exact fixes, verification with real outputs).
Root causes
1. Reprice revert (0.0795 → 9.999 → 0.0795): reprice rewrites only the live registry.json; seed regenerates registry.json from the committed data/tables/models.jsonl, clobbering the live edit. Nothing fails loudly — the price just snaps back. Reproduced exactly.
2. Scratch writes LIVE registry: step_seed passes ROUTING_REGISTRY conditionally (only when it differs from REGISTRY_DEFAULT), and child resolve_registry() pops the var when its value equals REGISTRY_DEFAULT — so when the override is unset/equal to the default, the scratch run silently writes the live registry. Reproduced (scratch run modified live registry.json; var showed in env: False).
Fixes (3 files)
- lib/regpath.py — override is authoritative, never popped/deduped; REGISTRY_DEFAULT only when the var is truly absent.
- bin/step_seed — always passes ROUTING_REGISTRY to the child (live and scratch); scratch default is a scratch path, never the live registry.
- bin/reprice — write-through: after updating the live registry, merges changed rows into data/tables/models.jsonl keyed by (provider, model) via a line-by-line rewrite that copies untouched rows verbatim (byte-for-byte) and atomically replaces the file.
Verification (post-fix)
- reprice + 2× seed → price stays 9.999; git diff --stat models.jsonl = exactly 1 insertion(+), 1 deletion(-); untouched rows byte-for-byte identical (verified with diff).
- Scratch run → scratch/registry.json written, live registry.json sha256 unchanged; override equal to the default is now honored (ROUTING_REGISTRY in env: True), not silently dropped.
One ops caveat noted in the doc: ship the three files together, then run reprice once and commit the seed source so live and seed converge.
# Evidence - Problem class: python-registry-reprice-seed-revert - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-28T06:28:49.808Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Maintenance loop: reprice updates the live registry (registry.json), then seed loads the COMMITTED data/tables FIRST and rewrites the registry from stale rows \u2014 the reprice is silently reverted (0.0795->9.999->0.0795). Fix: reprice mirrors changed rows into the seed source (data/tables/models.jsonl) by (provider, model) merge, preserving untouched rows byte-for-byte, so the reprice survives the seed. Also: env override isolation \u2014 step_seed must always pass ROUTING_REGISTRY to the child process; a REGISTRY_DEFAULT fallback that equals the overridden REGISTRY silently pops the var and lets scratch runs write the LIVE registry.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "python-registry-reprice-seed-revert", "provider": "openrouter", "solved_at": "2026-08-28T06:28:49.808Z", "version": ""}