fix: the price sweep only ever saw one of two gateways - #97
Merged
Conversation
This script exists to catch price drift, and it was blind to half of it. BASE was hardcoded to blockrun.ai, so every "verified live" claim it has ever made was a claim about one of two gateways. They do not agree. Probed 2026-08-07 across 45 routes: Base charges base + $0.001, Solana charges base + $0.000 — Solana adds no transaction fee at all, so 37 routes are cheaper there by exactly that amount. Eight more are not served on Solana at all: all six modal routes 503, defillama 404, and seedance-2.5@1080p 400 (that last one is the already-tracked gateway defect, a different cause). The gateways can diverge because they are separate deployments and TRANSACTION_FEE_USD is env-overridable in the gateway — the fee can move on one chain and not the other with nothing in this repo noticing. That is the same shape as a marketplace check that never reads the skills directory: the tool whose whole job is this class of bug could not see the case. Direction decides severity, so the two are counted separately: - Solana CHEAPER is safe for the budget gate. Estimators reserve the Base figure, so on Solana we over-reserve. Reported, not fatal. - Solana DEARER would mean every estimator under-reserves for anyone on that chain, which is exactly as fatal as a Base shortfall — `blockrun_wallet action:"chain"` lets one agent switch mid-session. It now exits 1. - NOT SERVED is reported per route, because a chain switch turns those calls into a 404/503 rather than a cheaper call. Both chains are probed concurrently per route, so covering the second gateway costs no wall-clock.
Neither tool had a chain guard, while price, video, image, speech, music and realface all do. sol.blockrun.ai does not serve either route family: every /v1/modal/* path 503s and /v1/defillama/* 404s (probed 2026-08-07 by the dual-chain sweep, all six modal probes plus defillama). So an agent that ran blockrun_wallet action:"chain" chain:"solana" earlier in the session got a raw 503 from blockrun_modal, which reads as "the sandbox service is down" — a plausible, wrong, unactionable conclusion that invites a retry loop against a backend that was never going to answer. The defi 404 is worse: it looks like a bad path, so the next move is to re-check the path rather than the chain. Both now say which it is and how to fix it, before the round trip, matching the wording the six tools that already guard use.
…w is gone Two defects, one sweep, both verified route by route against live 402 quotes rather than computed. PRICES. Every flat figure in the skills was base + $0.002, the per-transaction fee that has since gone back to $0.001 — so each was a tenth of a cent high, across eleven files. Agents read these to budget. Corrected against the `payment-required` header on each specific route, because subtracting $0.001 everywhere is wrong: several rows share a printed value while meaning different endpoints. That trap fired during this sweep — crypto-data's RPC rows went $0.0040 -> $0.0030 -> $0.0020 when a later rule re-matched the output of an earlier one, and only a per-route audit caught it. Two figures were wrong for reasons unrelated to the fee, and only probing found them: the modal CPU billing cliff stops being cheaper at 360s, not the 432s claimed (probed 300s $0.011000, 360s $0.011001, 361s $0.011028), and an 8s video clip is $0.421, not the $0.402 the table showed — its base is $0.42, not the $0.05/sec x 8 the per-second table implies. Prices are Base prices. Solana charges no transaction fee, so every figure runs $0.001 lower there, and blockrun_defi and blockrun_modal are not served on it at all. Rather than qualify eleven files with a caveat we intend to delete once the gateways agree, that is stated once in skills/blockrun — the entry point every agent loads first. DFLOW. skills/prediction-markets advertised dflow/trades and the two dflow/wallet/* paths. All three return "Unknown Predexon endpoint" 404 from the gateway itself — de-registered, not an upstream timeout. Removed from the description, the trigger list and the route table; endpoint count 58 -> 55; and from surf's coverage comparison, which claimed dFlow as a Predexon advantage. Also removed from src/tools/markets.ts, which listed the same three dead routes in the tool description — so the model was being told they exist on every call, not just when the skill loaded.
VickyXAI
added a commit
that referenced
this pull request
Aug 8, 2026
#97 established that the two gateways disagree and guarded the two affected tools in code, but the skills still described one catalog. An agent that ran blockrun_wallet action:"chain" chain:"solana" earlier in the session had no written way to know that two of the twenty tools stopped existing. Probed against both gateways 2026-08-07: - /v1/defillama/* is absent on sol.blockrun.ai — 404, which reads like a bad path, so the natural next move is to re-check the path rather than the chain. - /v1/modal/* is present but unconfigured there — 503 on all four sandbox actions. That reads like an outage, which invites retrying against a backend that was never going to answer. Both now say so where the tool is documented (crypto-data's defi section, the modal skill's opening) rather than only in the core skill, because that is where an agent is looking when it needs the answer. The core skill grows a short section on what action:"chain" actually changes — it repoints every paid call at a different deployment — with the coverage table and both llms.txt URLs, since each gateway's catalog quotes its own pricing convention. rules/wallet-and-payment.md carries the mechanics: why the budget gate reserves the Base figure on both chains (over-reserving on Solana is the safe direction) and that verify-prices fails the build if Solana ever becomes the dearer one.
VickyXAI
added a commit
that referenced
this pull request
Aug 8, 2026
…ma (0.39.0) (#96) * fix(video): tighten Seedance capability tables to token360's own schema (0.38.2) Sibling of blockrun#353 and blockrun-sol#133. Yesterday's 0.38.1 tightened the guards toward the gateway's tables; live probing (2026-08-07) shows those tables were themselves hand-typed drift. token360 publishes the answer — GET /v1/models/{id} → parameter_schema — and nobody had ever read it. Per-model truth, now enforced here: 2.0 = 480p/720p/1080p/4K in BOTH modes (the t2v/i2v split is gone; 540p/1K hard-reject upstream even image-conditioned), 1.5-pro = 480p/720p/1080p, 2.0-fast and 2.5 = 480p/720p. 360p/540p/1K leave the resolution enum and 9:21 leaves the ratio enum — no model lists them. Off-schema values that merely pass upstream validation (2.0-fast 1080p, 1.5-pro 540p) stay blocked: "passes validation" is not "renders", and 1.5-pro historically echoed 2K/4K, billed the tier, rendered 720p. All probes cost $0: token360 validates duration → resolution → ratio → other, so an invalid LATER parameter guarantees rejection after the one under test is judged, and a failed submit never creates a task or bills. RESOLUTION_TOKEN_FACTOR drops the unreachable tiers (the estimator throws on a missing key, so stale is loud, not a silent 720p-baseline reserve). The verify:prices matrix keeps 2.5@1080p as a fleet-consistency probe — the gateway still quotes $3.55 for a render token360 refuses until #353 deploys — and drops 2.0@360p, which this client can no longer express. 302 tests pass. Live gate: 0 under-reserving. * fix(review): the acceptance side was silently revertible, and one assertion matched itself Five-reviewer pass over this PR (testing, maintainability, api-contract, Claude adversarial, Codex). What survived verification: THE TESTS PINNED ONLY HALF THE TABLE — mutation-proven. Emptying 2.0-fast's resolution set left the suite green: every rejection was tested, almost no acceptance was, so an over-restrictive edit could brick a paid capability with no red test. And the first fix draft iterated the exported table in the test — mutating the table mutated the expectation, same two escapes. The acceptance sweep now hardcodes the expected pairs (the test IS the spec) and asserts deep-equality with the shipped table, both directions. A FOURTH VACUOUS ASSERTION, mutation-proven: `/seedance-2\.0/` intended to pin the advice pointer, but the message opens with "bytedance/seedance-2.0- fast", which contains the pattern — deleting the pointer entirely stayed green. Anchored on the note's phrasing now, and the note itself stops steering 1080p seekers to the $2.56 model when 1.5-pro renders it at $0.80. THE "BOTH MODES" CLAIM was carried by 360p — a value real callers can no longer send (it left the zod enum), tested on the one model whose set holds all four enum values. Re-adding an image-conditioned wide set in enum-valid values (the production-reachable bill-high/render-low trap) passed. Now pinned with 1080p/4K image-conditioned rejections per model; the 360p leg stays as labeled defense-in-depth. ASPECT_RATIO'S DESCRIPTION LIED (Codex): "Ignored by xAI/Sora" — the handler forwards it for every model and the gateway maps it to portrait/landscape on the per-second models. Description now says what happens. 0.38.2 -> 0.39.0 (api-contract): the enum removals are a deliberate breaking schema change and were shipping as a patch. CHANGELOG's justification also overclaimed — seedance-2.0 image-conditioned 360p DID produce billed output before this release; reworded to the real rationale (off-schema shapes can downscale while billing the requested tier). Comment sweep: "per generation mode" (the mode split this PR deleted), "cannot drift apart" (nothing mechanical enforces it — softened, and the probe matrix now covers each model's ceiling and floor tier so divergence shows up in the free 402 sweep: three new rows, including the only above-720p tier that had no live pin, 1.5-pro@1080p, charge $0.797311 vs reserve $0.798311), and a "2K" that never existed in this client. 303 tests, 6/6 mutations caught, live gate 0 under-reserving (16 video probes). * fix(review): round 3 — the round-2 fixes hold; their prose didn't A fresh-context regression hunt over 61e6993 (round 2's fix commit) plus a manual pass. The code survived: four new mutations against the acceptance table, the image-conditioned guard, the pointer note, and 2.5's set all went red; the probe rows estimate cleanly; the semver bump is consistent. What did not survive was the WORDS around the code — including one error round 2 introduced while fixing another: - The aspect_ratio describe (and CHANGELOG) said "Sora/Grok use it to pick portrait vs landscape". Grok doesn't: submitXAIVideo builds its body from model/prompt/image_url/duration only — the gateway never forwards aspect_ratio to xAI. Round 2 replaced "both ignore it" (false for Sora) with "both use it" (false for Grok). Third try states each model's truth. - The CHANGELOG's "previously accepted no-ops" was false for (Sora, 9:21): azureSoraSize treats 9:21 as a portrait trigger, so the removed value changed output orientation. 9:16 is the exact replacement, now said. - "302 tests pass" was stale by round 2's own commit (303). - The probe-matrix comment claimed floor+ceiling coverage per model while seedance-2.0@480p — after round 2, the only schema pair with no live pin — had no row. Added: charge $0.56874, reserve $0.56974, the fee gap. - video.ts's table comment described unmerged blockrun PR #353 in the present tense. Until it deploys, production runs the old wide tables and this client is the only gate — the comment now says so. 303 tests, live gate 0 under-reserving (17 video probes). * docs: record what #97 ships inside 0.39.0, and its dual-gateway view of the 2.5@1080p probe
VickyXAI
added a commit
that referenced
this pull request
Aug 8, 2026
#97 found the two gateways disagree on the transaction fee (Base $0.001, Solana $0.000) and framed it as an open decision, recommending "align the gateways". Owner decision (2026-08-08): the gap is DELIBERATE — Solana is meant to run ~$0.001 cheaper per call as an incentive to settle there. The sweep's advisory no longer tells the next maintainer to erase an intentional price difference; it states the policy and the one invariant that still matters: Solana DEARER than Base fails the gate, because agents can switch chains mid-session while every estimator reserves the Base figure. skills/blockrun's qualifier says "on purpose" instead of "currently", so nobody reads the gap as pending cleanup. No behavior changes — both surfaces are prose; the direction gate #97 shipped already encoded the right check.
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.
Started as the price sweep #91 deferred. Became three things, because probing the second gateway changed what the first two should say.
1.
verify:priceswas blind to half the surfaceBASEwas hardcoded toblockrun.ai. Every "verified live" claim this repo has made was a claim about one of two gateways — and they do not agree:Solana adds no transaction fee at all. Probed 2026-08-07 across 45 routes: 37 cheaper on Solana, 0 dearer, 8 not served there at all (all six
modalroutes 503,defillama404,seedance-2.5@1080p400 — that last is the already-tracked gateway defect).They can diverge because they are separate deployments and
TRANSACTION_FEE_USDis env-overridable in the gateway: the fee can move on one chain and not the other with nothing here noticing. Same shape as a marketplace check that never reads the skills directory — the tool whose whole job is this bug class could not see the case.Direction decides severity, so they are counted separately:
blockrun_wallet action:"chain"lets one agent switch mid-session. Exits 1.Both chains probe concurrently, so the second gateway costs no wall-clock.
2.
blockrun_defiandblockrun_modalhad no chain guardSix other tools do. On Solana, modal 503s and defi 404s — the 503 reads as "sandbox is down" (plausible, wrong, invites a retry loop) and the 404 reads as a bad path, so the next move is to re-check the path rather than the chain. Both now fail fast and name the fix.
3. The price sweep itself
Every flat figure across eleven skills was
base + $0.002— the fee that has since gone back to $0.001. Corrected route by route against the live 402, not by subtracting $0.001, because several rows share a printed value while meaning different endpoints. That trap fired mid-sweep: crypto-data's RPC rows went$0.0040 → $0.0030 → $0.0020when a later rule re-matched an earlier rule's output. Only a per-route audit caught it.Two figures were wrong for reasons unrelated to the fee, and only probing found them:
$0.011000, 360s$0.011001, 361s$0.011028).$0.05/sec × 8the per-second table implies.dFlow is removed: all three paths return
Unknown Predexon endpoint404 from the gateway itself — de-registered, not an upstream timeout. Gone from the description, triggers and route table (58 → 55 endpoints), from surf's coverage comparison, and fromsrc/tools/markets.ts, which was advertising the same three dead routes to the model on every call.On the one number the docs print
Prices in
skills/are Base prices. Rather than caveat eleven files with something we intend to delete once the gateways agree, that is stated once inskills/blockrun— the entry point every agent loads first. The open decision is whether to align the gateways (my recommendation: one number, since an agent can switch chains mid-session and a per-chain table doubles the drift surface this PR exists to shrink) or to keep them apart and qualify everywhere.Verification
npm run typecheck,npm run build, 302/302 tests,sync-brand-numbers --checkall green.npm run verify:prices→0 under-reserving, 0 Solana dearer, exits 0.