Pyth template completion, MCP token-bloat fix, honest 404s for /v1 - #1
Open
92Infinitus92 wants to merge 10 commits into
Open
Pyth template completion, MCP token-bloat fix, honest 404s for /v1#192Infinitus92 wants to merge 10 commits into
92Infinitus92 wants to merge 10 commits into
Conversation
The pyth-price-feed-v2 template exposed only feed_id and price, so scenarios could not express staleness or confidence-band cases that lending/PMM logic actually reads. Adds the remaining PriceFeedMessage fields (conf, exponent, publish_time, prev_publish_time, ema_price, ema_conf) and posted_slot as template properties, and extends llm_context with field semantics, a staleness recipe, and the Surfnet clock rules (timeTravel takes milliseconds, the simulated clock only moves forward). Covered by a forging unit test against a real 134-byte PriceUpdateV2 account: all eight writable fields change to values that differ from the fixture's, bytes before price are asserted untouched, trailing padding is preserved.
absoluteTimestamp is consumed in milliseconds while the Clock sysvar exposes seconds, and jumps are forward-only; the doc comment said neither, which cost a debugging session to rediscover empirically.
get_override_templates inlined every constant option (hundreds of price feeds,
duplicated across templates), producing a ~1.86 MB payload that overflowed LLM
context windows and TPM limits. Constants are now summarized as
{label, description, optionsCount} — 85x smaller measured — and the new
search_constant_options tool resolves concrete values via case-insensitive
search with stable sorted paging (MAX_SEARCH_RESULTS) and self-correcting
errors for unknown template ids or constants. The str:///override_templates
resource shares the same serialization through compact_template_json, so both
MCP surfaces stay compact.
Adds the first tests of the mcp crate: tool error paths, case-insensitive
matching, truncation reporting, and a guarantee that no template leaks inlined
options.
…llback
The studio SPA catch-all answered any unknown GET — including API misses like
GET /v1/scenarios/{id}, which has never existed — with index.html and HTTP 200.
Clients then failed deep in JSON parsing ("Unexpected token '<'") instead of
seeing a clean 404, which is how a tag-wiping frontend bug shipped unnoticed.
Unknown /v1/* paths now get {"error":"not found"} with 404; page routes and
static assets keep the SPA fallback.
Route registration moved into configure_api, shared between the server and the
new HTTP test, so the load-bearing registration order (real endpoints before
the /v1 catch-all scope) is asserted on the exact code production runs.
Collaborator
Review feedback: the guard's default_service is method-agnostic, but the test only exercised GET. A POST to an unknown /v1 path now asserts the JSON 404 too.
92Infinitus92
marked this pull request as ready for review
August 5, 2026 06:46
failfmi
reviewed
Aug 5, 2026
failfmi
reviewed
Aug 5, 2026
Constant options carry their value as a string, so Raydium amm_config_index never derived its PDA and the override was skipped with only a log line.
The search tool asked for template_id while its payload returns templateId. A test covers both the schema a model reads and the deserializer behind it.
failfmi
self-requested a review
August 6, 2026 10:03
failfmi
previously approved these changes
Aug 6, 2026
Six documented fields were snake_case while the wire is camelCase. fetch_before_use was the harmful one: it is serde(default), so a client following the docs got HTTP 200 and an override stored with fetchBeforeUse false — no fresh fetch, and a skip when the account was not already in the SVM.
92Infinitus92
force-pushed
the
feat/pyth-price-feed-fields
branch
from
August 6, 2026 10:52
77db914 to
e052847
Compare
failfmi
self-requested a review
August 6, 2026 10:52
Collaborator
Author
|
Re-signed the branch — every commit is GPG-verified now. Nothing else changed: the tree hash is identical to the previous tip, The hashes referenced in the threads above moved: |
The registerScenario schema omitted the required tags and typed account as a string, so a request following it failed deserialization. The clock cheatcodes were missing from the catalog the MCP tool points models at, and the EpochInfo examples showed snake_case. The Pyth staleness workflow now says how to read the simulated clock, since pauseClock returns no timestamp.
failfmi
approved these changes
Aug 6, 2026
bakasura980
approved these changes
Aug 6, 2026
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.
Four changes, one commit each:
and posted_slot are now overridable, so scenarios can express staleness and
confidence cases. Unit-tested against a real PriceUpdateV2 account.
inlines hundreds of constant options (1.86 MB → 22 KB; it overflowed LLM
context and TPM limits). The new search_constant_options tool resolves
values on demand. First tests in the mcp crate. The /v1/scenarios/templates
HTTP endpoint (studio dropdowns) intentionally keeps full data.
HTTP 200, which masked client/API mismatches as JSON parse errors. Route
registration is shared between server and test via configure_api.
forward-only — neither was documented.
Testing: cli 19/19, mcp 5/5, core pyth 3/3; fmt and clippy clean; live
e2e against a running surfnet.
Open questions
tool parameter?
UIs must not depend on it.
older MCP tools, dead Arc app_data in cli/http, HEAD 404s on GET routes)?
Greptile Summary
This PR bundles four focused changes: expanding the Pyth
PriceUpdateV2override template from 2 to 9 fields, shrinking MCP template payloads 85× by summarising constant options and adding an on-demandsearch_constant_optionstool, returning proper JSON 404s for unknown/v1/*paths, and correctingsurfnet_timeTraveldocs (milliseconds, forward-only).conf,exponent,publish_time,prev_publish_time,ema_price,ema_conf, andposted_slot; a detailed LLM-context block guides staleness-scenario construction. All 8 fields are covered by a new round-trip test.compact_template_json(shared between theget_override_templatestool and the MCP resource handler), introducessearch_constant_optionsfor on-demand option lookup, and adds 5 unit tests. The HTTP/v1/scenarios/templatesendpoint is intentionally left with full data.web::scope("/v1").default_service(…)catch-all inside a sharedconfigure_apihelper; the test covers GET, POST, and a known-good path.Confidence Score: 5/5
Important Files Changed
compact_template_jsonhelper (eliminates the two duplicate inline-mapping blocks), newsearch_constant_optionstool with error handling for unknown template/constant, and 5 tests covering schema shape, case-insensitive search, truncation, and error paths. Logic is sound; metadata is included verbatim in results (flagged in a previous comment).configure_apiso the route graph is shared between the live server and tests. Adds the/v1scope default-service 404 handler and a test that validates GET, POST, and a known-good route (200). Routing order is correct: specific resources registered before the scope win in actix-web's trie matcher.pyth_price_update_v2_fixture(), refactors the import block, and addstest_get_forged_account_data_overrides_all_pyth_price_feed_fieldsthat round-trips all 8 template fields through the forge path and decodes the result. Tests are thorough and pin against the real byte layout.PdaSeed::U16BeRefto accept decimal strings (needed when MCP tools pass config indices as JSON strings). Three new tests cover the happy path, rejection of out-of-range/non-numeric strings, and rejection of non-integer JSON types.Sequence Diagram
sequenceDiagram participant LLM as LLM Client participant MCP as MCP Server participant Registry as TemplateRegistry LLM->>MCP: get_override_templates() MCP->>Registry: registry.all() Registry-->>MCP: Vec of OverrideTemplate Note over MCP: compact_template_json - constants summarised as optionsCount, options array omitted MCP-->>LLM: templates with id, properties, constants summary, llmContext LLM->>MCP: search_constant_options(templateId, query) MCP->>Registry: find template by id Registry-->>MCP: OverrideTemplate Note over MCP: iterate constants sorted, case-insensitive match, cap at MAX_SEARCH_RESULTS=20 MCP-->>LLM: results with value field, totalMatches, truncated LLM->>MCP: create_scenario(templateId, values with resolved feed_id) MCP->>MCP: POST surfnet_registerScenario MCP-->>LLM: success with studioUrlReviews (8): Last reviewed commit: "docs: make the cheatcode catalog match w..." | Re-trigger Greptile