Skip to content

feat: support Codama root-node IDLs and variable discriminators#114

Merged
adiman9 merged 16 commits into
mainfrom
codama-parsing
Jun 17, 2026
Merged

feat: support Codama root-node IDLs and variable discriminators#114
adiman9 merged 16 commits into
mainfrom
codama-parsing

Conversation

@adiman9

@adiman9 adiman9 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add fallback parsing for Codama rootNode IDLs in arete-idl
  • convert Codama programs, accounts, instructions, errors, and defined types into IdlSpec
  • fix macro codegen/parser generation for variable-length and embedded account discriminators
  • add targeted tests for Codama parsing and discriminator handling
  • keep the arete-a4-sdk changes formatting-only

Why

Some Steel/Codama-generated IDLs are emitted as Codama root-node JSON rather than the legacy format arete-idl expects today. Those IDLs also use discriminator patterns that are not always 8-byte Anchor-style discriminators. This branch teaches the IDL layer and generated parsers to accept those layouts without regressing the existing path.

What Changed

arete-idl

  • parse_idl_content now falls back to deserializing a Codama root node when direct IdlSpec parsing fails
  • maps Codama program metadata, instructions, accounts, defined types, and errors into the internal IdlSpec
  • derives account discriminators from the accountDiscriminator enum when present
  • derives instruction discriminants from the synthetic discriminator argument default value and removes that field from emitted args
  • supports number, public key, string, defined type links, arrays, fixed-size types, structs, and fieldless enums in the Codama conversion path
  • records Codama metadata as spec: "codama" and origin: "codama-rootNode"

arete-macros

  • generated account parsers now use starts_with(...) instead of assuming an 8-byte discriminator slice
  • account matching is sorted by discriminator length descending so shorter prefixes do not mask longer ones
  • generated account decoders detect when the payload itself starts with an embedded discriminator field and deserialize from the full buffer instead of skipping bytes first

rust/arete-a4-sdk

  • rustfmt-only reformat of the auth-related files included in the branch
  • no functional behavior changes in the SDK portion of this PR

Constraints

  • Codama enums with payload fields are still rejected because arete-idl only models fieldless enums today
  • the Codama conversion path currently expects root-node shaped JSON and looks for account discriminators in a defined type named accountDiscriminator

Testing

  • cargo test -p arete-idl -p arete-macros -p arete-a4-sdk

@vercel

vercel Bot commented Jun 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
arete-docs Ready Ready Preview, Comment Jun 17, 2026 9:34pm

Request Review

@greptile-apps

greptile-apps Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Codama rootNode IDL parsing to arete-idl and fixes macro code generation for variable-length and embedded account discriminators. It also brings gRPC connection management improvements, negative caching for token resolvers, and type name deduplication to the interpreter generators.

  • arete-idl: adds a fallback parse path that deserializes Codama root-node JSON and maps it to IdlSpec; errors from both parsers are now surfaced together; CodamaTypeNode/CodamaCountNode gain #[serde(other)] catch-alls so unknown node kinds produce clear errors.
  • arete-macros: account parser switches from a fixed 8-byte slice match to starts_with(...) sorted by discriminator length; code gen detects embedded discriminator structs and skips the skip-bytes step; generated gRPC connection loop gains exponential backoff, keepalive, and a semaphore-gated resolver concurrency cap.
  • interpreter: Rust/TypeScript generators add name-collision deduplication for resolved struct types; runtime_resolvers gains per-path profiling and negative-cache handling for token metadata misses.

Confidence Score: 5/5

The change is safe to merge. All correctness concerns raised in earlier review rounds have been addressed — discriminant extraction now errors on missing defaults, account discriminator lookups return errors when the map is non-empty but an account is absent, and both parser errors are surfaced together. Resolver mutations are still combined with primary mutations in a single batch before emission.

The IDL parsing, macro codegen, and runtime changes are well-structured, each new code path is covered by targeted tests, and the previous blocking concerns have been resolved. The embedded-discriminator heuristic is sound for Steel/Codama naming conventions, and the gRPC backoff and resolver semaphore additions improve resilience without introducing new data-path risks.

arete-macros/src/codegen/vixen_runtime.rs — largest surface area of new generated runtime code; worth a second read on the ManagedYellowstoneGrpcSource SourceTrait implementation and the async_resolver_order counter lifetime.

Important Files Changed

Filename Overview
arete-idl/src/parse.rs Adds Codama root-node fallback parsing with all previous-thread concerns addressed: both errors propagated, Unknown catch-alls added, discriminator misses now return errors, discriminant extraction validates numeric default_value.
arete-macros/src/idl_parser_gen.rs Replaces fixed 8-byte discriminator slice match with starts_with() sorted by length descending; min-length check relaxed to data.is_empty(); well-tested with the new parsers test module.
arete-macros/src/idl_codegen.rs Adds embedded-discriminator detection via field-name/type heuristic and routes borsh/bytemuck deserialization to the full buffer for those accounts; tests confirm both detection and decode path.
arete-macros/src/codegen/vixen_runtime.rs Large addition: ManagedYellowstoneGrpcSource, exponential backoff, keepalive, resolver semaphore, and async_resolver_order counter; resolver mutations are still combined with primary mutations in a single batch preserving the no-duplicate-frames guarantee.
interpreter/src/runtime_resolvers.rs Adds per-stage profiling, negative-cache handling for token metadata misses, and UpdateContext propagation; logic is clean and the context is always restored after apply.
interpreter/src/vm.rs Adds retry tracking, per-entry TTL, and negative caching for resolver entries; in_flight/queued state transitions look consistent across take, restore, and schedule_retry paths.
interpreter/src/rust.rs Type-name deduplication via build_resolved_type_name_map; field_type_to_rust still returns base type (underscore-prefixed map param intentionally unused); tests confirm no regression on existing generated types.
interpreter/src/typescript.rs Mirrors the Rust name-deduplication pattern; resolved_type_to_interface_name rebuilds the name map on every call, though impact is limited to code generation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[parse_idl_content] -->|try| B[serde_json: IdlSpec]
    B -->|Ok| C[IdlSpec returned]
    B -->|Err: IdlSpec error| D[try Codama fallback]
    D -->|serde_json: CodamaRoot| E{kind == rootNode?}
    E -->|No| F[Return error]
    E -->|Yes| G[Extract accountDiscriminator\nfrom defined_types]
    G --> H[codama_account_to_idl\nfor each account]
    G --> I[codama_instruction_to_idl\nfor each instruction]
    G --> J[codama_defined_type_to_idl\nfor each defined type]
    H --> K[Lookup discriminator\nfrom HashMap]
    K -->|found| L[vec discriminator byte]
    K -->|not found, map non-empty| M[Return Err - missing variant]
    K -->|map empty| N[vec empty - Anchor fallback]
    I --> O[Find discriminator arg\nwith numberValueNode default]
    O -->|found| P[SteelDiscriminant with value]
    O -->|missing default| Q[Return Err - cannot determine]
    L & P & J --> R[IdlSpec assembled]
    D -->|Err: Codama error| S[Both errors surfaced]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[parse_idl_content] -->|try| B[serde_json: IdlSpec]
    B -->|Ok| C[IdlSpec returned]
    B -->|Err: IdlSpec error| D[try Codama fallback]
    D -->|serde_json: CodamaRoot| E{kind == rootNode?}
    E -->|No| F[Return error]
    E -->|Yes| G[Extract accountDiscriminator\nfrom defined_types]
    G --> H[codama_account_to_idl\nfor each account]
    G --> I[codama_instruction_to_idl\nfor each instruction]
    G --> J[codama_defined_type_to_idl\nfor each defined type]
    H --> K[Lookup discriminator\nfrom HashMap]
    K -->|found| L[vec discriminator byte]
    K -->|not found, map non-empty| M[Return Err - missing variant]
    K -->|map empty| N[vec empty - Anchor fallback]
    I --> O[Find discriminator arg\nwith numberValueNode default]
    O -->|found| P[SteelDiscriminant with value]
    O -->|missing default| Q[Return Err - cannot determine]
    L & P & J --> R[IdlSpec assembled]
    D -->|Err: Codama error| S[Both errors surfaced]
Loading

Reviews (10): Last reviewed commit: "fix: surface errors for unsupported Coda..." | Re-trigger Greptile

Comment thread arete-idl/src/parse.rs Outdated
Comment thread arete-idl/src/parse.rs
Comment thread arete-idl/src/parse.rs
Comment thread arete-idl/src/parse.rs
Comment thread arete-idl/src/parse.rs Outdated
Comment thread arete-macros/src/codegen/vixen_runtime.rs Outdated
Comment thread interpreter/src/rust.rs Outdated
…lent fallbacks

- Include Codama parse error alongside IdlSpec error in fallback message
  (was discarded by |_| closure, leaving users with misleading errors)
- Error when a Codama account is missing from a non-empty
  accountDiscriminator map instead of silently falling back to an
  unmatchable 8-byte Anchor hash
- Error when a discriminator argument lacks a numeric default_value
  instead of silently leaving discriminant=None, which could cause
  discriminant collisions in generated parsers
- Add #[serde(other)] Unknown catch-all variants to CodamaTypeNode and
  CodamaCountNode so unmodelled node kinds produce clear unsupported
  errors instead of opaque deserialization failures
@adiman9 adiman9 merged commit 1ffcf84 into main Jun 17, 2026
11 checks passed
@adiman9 adiman9 deleted the codama-parsing branch June 17, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant