Skip to content

feat(tii): type-directed argument encoding to the TaggedArg wire form#36

Merged
scarmuega merged 1 commit into
mainfrom
feat/tagged-arg-encoder
Jun 22, 2026
Merged

feat(tii): type-directed argument encoding to the TaggedArg wire form#36
scarmuega merged 1 commit into
mainfrom
feat/tagged-arg-encoder

Conversation

@scarmuega

Copy link
Copy Markdown
Contributor

What

Parity with the Rust SDK: encodes an argument of an aggregate type (record, List, Map, Tuple, variant) into the TRP TaggedArg wire form. New tii/encode.ts, wired into intoResolveRequest.

One walk, not two paths

encode(param, value) is a single recursive walk over (type, value) — scalars are the leaf cases. A scalar leaf renders bare at the top level (resolver coerces via the flat TIR type) and tagged when nested; aggregates always render to their tagged structural form. Bare top-level scalars keep their pre-existing wire shape, so scalar-only protocols are unaffected.

Encoding rules

  • Record → positional struct fields in declared order, from the schema's required array (tx3c emits source order; properties is alphabetized and must not drive order).
  • Variantconstructor = the oneOf case index.
  • Map[key, value] pairs; keys are string leaves (the .tii erases the key type), pairs sorted.
  • Missing/extra field, wrong arity, unknown case → rejected before sending.

Breaking change

The record ParamType now carries ordered RecordField[] ([name, type]) instead of a Record<string, ParamType>, with a by-name field accessor. Coordinated breaking SDK change; version bump + publish are a separate release step.

Tests

Vector-driven over the shared cross-SDK oracle (tests/fixtures/wire-vectors.json, mirrored from sdk-spec): accept vectors encode byte-equal, reject vectors throw; plus the Meta field-order regression, top-level-bare vs nested-tagged, and an end-to-end intoResolveRequest check. npm run test:unit (150) + type-check green.

🤖 Generated with Claude Code

Mirror the Rust reference: marshal every arg through one recursive walk
over (ParamType, value) in `tii/encode.ts`, wired into
`intoResolveRequest`. A scalar leaf renders bare at the top level (the
resolver coerces it via the flat type) and tagged when nested in an
aggregate; aggregates (list/tuple/map/record/variant) render to the
self-describing tagged form. No separate scalar/aggregate path.

Records map the user's by-name object to positional `struct` fields in
declared (`required`-array) order; variants resolve the case index from
the `oneOf` ordering; map keys are `string` leaves, pairs sorted. Ill-
shaped values are rejected before sending.

BREAKING: the `record` ParamType now carries ordered `RecordField[]`
(`[name, type]`) instead of a name->type object, with a by-name `field`
accessor.

Tests drive the shared cross-SDK oracle (accept + reject vectors).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scarmuega scarmuega merged commit cee15bf into main Jun 22, 2026
3 checks passed
@scarmuega scarmuega deleted the feat/tagged-arg-encoder branch June 22, 2026 15:59
@scarmuega scarmuega mentioned this pull request Jun 22, 2026
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