Skip to content

SDK: let an action read a field of an output it built - #225

Open
robknight wants to merge 1 commit into
sdk-set-guardfrom
sdk-output-field-read
Open

SDK: let an action read a field of an output it built#225
robknight wants to merge 1 commit into
sdk-set-guardfrom
sdk-output-field-read

Conversation

@robknight

@robknight robknight commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Previously this did not compile:

var pick = action.output("Pick");
pick.set([["durability", 100]]);
action.st_gt(pick.durability, 0);

An output's script-final dict is normally rendered as initials.pick, and a field read is rendered as <dict>.<field>. Together they came out as initials.pick.durability, which anchors twice. Podlang has no syntax for that, so the module failed to compile.

The io sides already handle this case. When compute_wildcard_needs sees a field read there, it keeps the dict as a plain wildcard and pins it with an ArrayContains clause. This adds the same mechanism for the initials record, allowing the pattern above to compile.


Stack created with GitHub Stacks CLIGive Feedback 💬

`collapsed_at` collapsed an Output's script-final form into
`initials.<var>` unconditionally, so a body field read of it rendered
`initials.<var>.<field>` -- anchoring twice, which podlang has no syntax for,
and the module failed to compile through `load_module(...).expect("compiles")`.
The io sides never had this problem: `compute_wildcard_needs` spots a field
read there and keeps the dict as a wildcard pinned by an `ArrayContains`
clause. The initials record just had no equivalent escape.

Give it one. `compute_wildcard_needs` now reports all three forms through a
`WildcardNeeds` struct, `initials_entries` carries a `needs_wildcard` per entry
(hence `EntryShape` rather than a bare name), `collapsed_at` honours it, and
both emitters pin the wildcard to the initials record entry. With a third form
to place, the pin clauses became one loop over the three on each side, which is
what keeps the rendered clauses and the proved statements in step; the shared
`initials_ts` gives the "one ts below max" rule a single home instead of the
three copies this would otherwise have needed. `initials_anchor` returns None
for a forced-open form so TxInsert's initial arg stays bound to the wildcard.

This only changes rendering for scripts that could not compile before, so no
plugin hashes move. It also drops the workaround in
`test_statement_surface_round_trips`, which had to route entry args through
two inputs to avoid the broken form.
@robknight
robknight force-pushed the sdk-output-field-read branch from 5af945f to 5496904 Compare August 21, 2026 09:09
@robknight
robknight requested a review from dhvanipa August 21, 2026 09:30
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