Skip to content

feat(tii)!: interpret the full complex param-type model#18

Merged
scarmuega merged 2 commits into
mainfrom
feat/complex-param-types
Jun 12, 2026
Merged

feat(tii)!: interpret the full complex param-type model#18
scarmuega merged 2 commits into
mainfrom
feat/complex-param-types

Conversation

@scarmuega

Copy link
Copy Markdown
Contributor

Summary

Reworks ParamType to interpret every shape tx3c emits into the TII params schema, per the canonical model in the SDK spec's api-surface/args.md. The python-sdk slice of a cross-fleet complex-type parity effort (rust/go/python/web).

Changes

  • Flat str EnumParamKind + ParamType dataclass carrying element/field types (inner/elements/fields/cases/schema); adds UNIT/UTXO/ANY_ASSET/TUPLE/MAP/RECORD/VARIANT/UNKNOWN.
  • Trailing-name $ref matching across tii#/$defs/ and legacy core# forms (previously the tii# form degraded to a typeless custom); drops the latent string→ADDRESS default.
  • Never raises — unrecognized shapes become UNKNOWN; resolves #/components/schemas/<Name> refs (threaded through Protocol.invoke).
  • Protocol.invoke now also exposes party (Address) and environment-schema params, matching the reference SDK.

Tests

pytest — 62 pass (new test_param_type.py over the full canonical table incl. both ref forms, nested compounds, component resolution, never-raise fallbacks; existing tii suite green). ruff clean.

Validated against the shared fixture sdk-spec/test-vectors/complex-types/complex.tii via the full Protocol.invoke path (parties + env + tx params + component resolution).

Breaking change

ParamType changes from a str Enum to a dataclass; the kind discriminant moves to the new ParamKind enum. Needs a version bump per sdk-spec/release-policy.md.

🤖 Generated with Claude Code

Rework `ParamType` to interpret every shape `tx3c` emits into the TII params
schema, per the canonical model in the SDK spec's `api-surface/args.md`.

- Replace the flat `Enum` with a `ParamKind` + `ParamType` dataclass carrying
  element/field types (`inner`/`elements`/`fields`/`cases`/`schema`). Adds
  `UNIT`, `UTXO`, `ANY_ASSET`, `TUPLE`, `MAP`, `RECORD`, `VARIANT`, and
  `UNKNOWN` kinds.
- Match built-in scalar `$ref`s by trailing name so both the canonical
  `…/tii#/$defs/<Name>` and legacy `…/core#<Name>` forms resolve (previously the
  `tii#` form degraded to a typeless custom).
- `param_type_from_schema` never raises; unrecognized shapes become `UNKNOWN`.
- Drop the latent `string`→ADDRESS default.
- Resolve `#/components/schemas/<Name>` refs against the TII components table,
  threaded through `Protocol.invoke`.
- `Protocol.invoke` now also exposes party (Address) and environment-schema
  params, matching the reference SDK.

BREAKING CHANGE: `ParamType` changes from a `str` `Enum` to a dataclass; use the
new `ParamKind` enum for the kind discriminant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er invoke path

Behavior-preserving readability pass over the complex param-type interpreter,
mirroring the rust-sdk (#41) and go-sdk (#14) changes.

- Split param_type_from_schema into a thin dispatcher plus _ref_type /
  _array_type / _object_type helpers (joining the existing _variant_case /
  _core_kind_from_ref). Same fallbacks, recursion, and kind map.
- Remove InvalidParamTypeError: the interpreter no longer raises it once it
  became never-failing, leaving it dead. InvalidParamsSchemaError stays
  (protocol.py still raises it).
- Add test_invoke_interprets_complex_params + the shared complex.tii fixture
  to cover the Protocol.invoke path the unit tests can't reach: components
  threading, party->Address, environment params, and a resolved component-$ref
  Record and Variant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scarmuega

Copy link
Copy Markdown
Contributor Author

Pushed a behavior-preserving readability pass (1afc17d) — the same review we applied to rust-sdk #41 and go-sdk #14, against the four code-quality dimensions. No change to the kind map; all existing tests still pass.

1. Module cohesion — already good, no change. Unlike rust (where the interpreter was buried in mod.rs), Python already has a dedicated tii/param_type.py. Nothing to extract.

2. Function decomposition. param_type_from_schema was a ~90-line function with the $ref, array, and object arms inline. It's now a thin dispatcher delegating to _ref_type / _array_type / _object_type (joining the already-extracted _variant_case / _core_kind_from_ref). Same fallbacks, recursion, and kind map.

3. Dead-code removal. Once the interpreter became never-failing it stopped raising InvalidParamTypeError, leaving it dead — only the class def + export survived, referenced by no test. Removed it (and its two __init__ export lines). InvalidParamsSchemaError stays — protocol.py still raises it.

4. Integration coverage. test_param_type.py covers the interpreter well in isolation, but the Protocol.invoke path this PR added — threading components, party→Address, environment params — was untested against a real complex TII (test_tii.py used all-primitive transfer.tii). Added test_invoke_interprets_complex_params + the shared complex.tii fixture, asserting the compound kinds plus a resolved component-$ref Record (asset.policy → Bytes) and the 2-case Variant — the assertion that actually guards the components threading.

pytest -m "not e2e" → 68 passed; ruff check clean.

@scarmuega scarmuega merged commit 8d49bae into main Jun 12, 2026
3 checks passed
@scarmuega scarmuega deleted the feat/complex-param-types branch June 12, 2026 18:45
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