on master help sign in
Keep deferred call fits stable across substitutions
341bcb4iko
docs/compiler.md+1−1
@@ -188,7 +188,7 @@ Note 4 has examples of each.
188
188
189Starting `urbit eval` and building the library takes about 8 s. A 2,000-line module of 400 definitions then parses in about a second. Loops over definitions, arms, lines and items are tail calls, so a long module grows no stack; nesting costs a few stack frames a level, and 100,000 nested brackets still parse (note 3).
189Starting `urbit eval` and building the library takes about 8 s. A 2,000-line module of 400 definitions then parses in about a second. Loops over definitions, arms, lines and items are tail calls, so a long module grows no stack; nesting costs a few stack frames a level, and 100,000 nested brackets still parse (note 3).
190
190
191−The experimental deferred constructor path can close a small import-free library transaction when ordinary resolution stalls. It accepts only a direct constructor callback with a closed input, records its pending fit under the source-owned inference state, and generalizes each definition against the live environment and pending constraints. Before publication it discharges and replays every edge, rejects unresolved tags or changed replay state, and checks that all molds and values are complete. The reporter reads the committed schemes for definitions added by the transaction. API and store paths, `main`, prepared preludes, imports, recursive groups, unresolved holes or written capitals, and new projection actions remain outside this path. `%grec` in the constraint or freshness scan is conservatively unsupported. This is not an island-kind, runtime, or watchability check.
191+The experimental deferred constructor path can close a small import-free library transaction when ordinary resolution stalls. Deferred definitions are restricted to simple one-component wings, literals, static strings, gates, transparent groups and empty bodies, calls and casts. Each successful call or cast fit must have exactly equal normalized operands so later substitutions cannot invalidate a face check. A multi-argument call also needs closed argument, sample and product types because positional face checks depend on slot boundaries and whether the result can be a cell. Other fits fail closed. A 512-node screen bounds visited expression nodes and a separate 512-node scan bounds each stability check; neither bounds mold shapes, string-piece checks, parsing, normalization, lookup, or total repeated inference. It accepts only a direct constructor callback with a closed input, records its pending fit under the source-owned inference state, and generalizes each definition against the live environment and pending constraints. Before publication it discharges and replays every edge, rejects unresolved tags or changed replay state, and checks that all molds and values are complete. The reporter reads the committed schemes for definitions added by the transaction. API and store paths, `main`, prepared preludes, imports, recursive groups, unresolved holes or written capitals, and new projection actions remain outside this path. `%grec` in the constraint or freshness scan is conservatively unsupported. This is not an island-kind, runtime, or watchability check.
192
192
193An expected cell type can supply context to both arms of a loobean branch. This slice first retains any ordinary inference that already fits. Otherwise it retries from the original state only when a syntax screen excludes nested branches, casts, gates and local bodies, and a substitution screen excludes structural bindings. Both arms must fit, their normalized results and the expected type must be closed, their result types must match, and both fits must replay without changing the final substitution or fresh-ID counter. A successful retry retains the original arm type and its written faces; a failed retry returns the original inference result. The source and substitution screens each visit at most 512 entries. This permits at most one extra attempt for an eligible branch; the screens do not bound preexisting inference, type walks, list construction, or work across separate analyses.
193An expected cell type can supply context to both arms of a loobean branch. This slice first retains any ordinary inference that already fits. Otherwise it retries from the original state only when a syntax screen excludes nested branches, casts, gates and local bodies, and a substitution screen excludes structural bindings. Both arms must fit, their normalized results and the expected type must be closed, their result types must match, and both fits must replay without changing the final substitution or fresh-ID counter. A successful retry retains the original arm type and its written faces; a failed retry returns the original inference result. The source and substitution screens each visit at most 512 entries. This permits at most one extra attempt for an eligible branch; the screens do not bound preexisting inference, type walks, list construction, or work across separate analyses.
194
194
docs/development.md+1−1
@@ -203,4 +203,4 @@ Write `source.jibb` and `about.txt` by hand, run `tools/golden --update --case <
203
203
204A short subject in the imperative, then a body that says what changed and why, wrapped at 72 columns, as in `git log`. Each commit leaves every check passing.
204A short subject in the imperative, then a body that says what changed and why, wrapped at 72 columns, as in `git log`. Each commit leaves every check passing.
205
205
206−`tools/type-deferred-test` exercises the bounded, source-owned constructor transaction and low-level freshness/replay guards. `tools/type-deferred-resolver-test` checks the experimental import-free library resolver, report consistency, and atomic failure. These checks do not establish island-kind or watchability support.
206+`tools/type-deferred-test` exercises the bounded, source-owned constructor transaction and low-level freshness/replay guards. `tools/type-deferred-resolver-test` checks the experimental import-free library resolver, report consistency, atomic failure, and that both source orders of a late face constraint decline. These checks do not establish island-kind or watchability support.
docs/status.md+5−2
@@ -57,6 +57,8 @@ The prelude has Jibb-written curried `lead` and `late` pair constructors, inferr
57
57
58The prelude also has a Jibb-written `zing` that concatenates homogeneous lists via `weld`. Its focused golden infers empty, nested text, ship, generic and gate-element lists and reports a non-list error; the same golden passes on the ship. A Hoon translation agrees with Hoon `zing` on selected finite inputs, not on Jibb execution. Hoon’s raw helper additionally accepts heterogeneous noun lists, which the Jibb signature does not express. Backend lowering and jet recognition remain unverified.
58The prelude also has a Jibb-written `zing` that concatenates homogeneous lists via `weld`. Its focused golden infers empty, nested text, ship, generic and gate-element lists and reports a non-list error; the same golden passes on the ship. A Hoon translation agrees with Hoon `zing` on selected finite inputs, not on Jibb execution. Hoon’s raw helper additionally accepts heterogeneous noun lists, which the Jibb signature does not express. Backend lowering and jet recognition remain unverified.
59
59
60+The experimental deferred constructor transaction conservatively declines tuples, branches, field reads, nonidentical successful call/cast fits, and multi-argument calls with open argument, sample or result types. This prevents a later substitution from invalidating an earlier face-propagation check; cases requiring deferred structural fits remain unsupported. Focused regression checks exercise both source orders and independent polymorphism.
61+
60The checked inference slice now represents `!!`, proves empty cell positions and filters proven-empty union cases. List and unit payload arms whose elements are empty are rejected as unreachable; fixed opaque cases fail closed when reachability is unknown. The new shared guard covers checked interfaces, partial diagnostics and proof budgets. Its evaluator is run separately; ship verification remains pending.
62The checked inference slice now represents `!!`, proves empty cell positions and filters proven-empty union cases. List and unit payload arms whose elements are empty are rejected as unreachable; fixed opaque cases fail closed when reachability is unknown. The new shared guard covers checked interfaces, partial diagnostics and proof budgets. Its evaluator is run separately; ship verification remains pending.
61
63
62An eval and ship fixture now reports partial inference for the unchanged todo island with its real API and Hoon readers. It verifies that the source fixtures match `my-app` and exercises missing or duplicate imports; the report does not claim the module or island has been checked. The prelude also has a Jibb-written recursive `lent` whose supported generic calls infer `@ud`. Execution and shape-based jet recognition remain future backend work. Nested union tests check equal runtime nouns, different nested tags, empty fields and unknown inhabitation.
64An eval and ship fixture now reports partial inference for the unchanged todo island with its real API and Hoon readers. It verifies that the source fixtures match `my-app` and exercises missing or duplicate imports; the report does not claim the module or island has been checked. The prelude also has a Jibb-written recursive `lent` whose supported generic calls infer `@ud`. Execution and shape-based jet recognition remain future backend work. Nested union tests check equal runtime nouns, different nested tags, empty fields and unknown inhabitation.
@@ -84,7 +86,7 @@ What the plan asks for, and where it is:
84Besides the plan's list:
86Besides the plan's list:
85
87
86- 656 golden cases: 436 that parse and 220 that fail, each failure at a stated line and column. One failing case has an unclear expectation (corpus question 3). The newer type-output cases exercise only the partial inference fragment. Each case's `about.txt` quotes the doc's words it tests.
88- 656 golden cases: 436 that parse and 220 that fail, each failure at a stated line and column. One failing case has an unclear expectation (corpus question 3). The newer type-output cases exercise only the partial inference fragment. Each case's `about.txt` quotes the doc's words it tests.
87−- The 656-case corpus passed under `urbit eval` in 127.7 s while other checks were running. The fake ship passed all 697 tests, including the source-overlap, structural-overlap, generic-recursion, generic-construction, generic-pattern, deferred-inference, empty-mold and cell-branch fixtures, importer, importer/checker and mark/checker bridges, module scope, unification, hole, qath, ask, default-wrapper importer, projection, arithmetic, generic-alias, positional-face, API-evidence, request, closed-gate, todo API, constructor, sub, nested-union, gate-free and direct-gate guards and the unchanged todo report. Desk sync took 133.7 s while other checks were running. The importer golden compares 221 projections; `tools/clay-fixtures` builds the example Hoon fixtures through Clay, checks a recursive Ford import's origin, and passes Clay-built types through the Clay-built importer and partial checker.
89+- The 656-case corpus passed under `urbit eval` in 166.9 s while other checks were running. The fake ship passed all 697 tests, including the source-overlap, structural-overlap, generic-recursion, generic-construction, generic-pattern, deferred-inference, empty-mold and cell-branch fixtures, importer, importer/checker and mark/checker bridges, module scope, unification, hole, qath, ask, default-wrapper importer, projection, arithmetic, generic-alias, positional-face, API-evidence, request, closed-gate, todo API, constructor, sub, nested-union, gate-free and direct-gate guards and the unchanged todo report. Desk sync took 233.8 s while other checks were running. The importer golden compares 221 projections; `tools/clay-fixtures` builds the example Hoon fixtures through Clay, checks a recursive Ford import's origin, and passes Clay-built types through the Clay-built importer and partial checker.
88- `tools/testdata/selftest` (22 checks), `tools/testdata/ship-selftest` and `tools/testdata/clay-fixtures-selftest` test the tools themselves; the last checks temporary Clay fixture cleanup and signal handling without a ship.
90- `tools/testdata/selftest` (22 checks), `tools/testdata/ship-selftest` and `tools/testdata/clay-fixtures-selftest` test the tools themselves; the last checks temporary Clay fixture cleanup and signal handling without a ship.
89- Two independent audits before 7c739b7, one of which compared the library with a reference parser written in Python from the doc over about 19,000 generated programs. Before ab797a9, a second Python parser, written from the decisions, agreed with the library on 8,000 generated programs and 900 hand-written probes.
91- Two independent audits before 7c739b7, one of which compared the library with a reference parser written in Python from the doc over about 19,000 generated programs. Before ab797a9, a second Python parser, written from the decisions, agreed with the library on 8,000 generated programs and 900 hand-written probes.
90- Speed: starting `urbit eval` and building the library takes about 8 s. After that, a 2,000-line module of 400 definitions parses in about a second. Loops over definitions, arms, lines and items grow no stack; nesting costs a few stack frames a level, and 100,000 nested brackets still parse (library section 3).
92- Speed: starting `urbit eval` and building the library takes about 8 s. After that, a 2,000-line module of 400 definitions parses in about a second. Loops over definitions, arms, lines and items grow no stack; nesting costs a few stack frames a level, and 100,000 nested brackets still parse (library section 3).
@@ -192,7 +194,8 @@ Besides the plan's list:
192| d9d51e6 | 2026-10-31 | Check source-proven recursive tree construction |
194| d9d51e6 | 2026-10-31 | Check source-proven recursive tree construction |
193| 30b0a9e | 2026-10-31 | Match source-proven recursive tree cases |
195| 30b0a9e | 2026-10-31 | Match source-proven recursive tree cases |
194| 72d85ab | 2026-10-31 | Add bounded deferred inference and expand runtime equality coverage |
196| 72d85ab | 2026-10-31 | Add bounded deferred inference and expand runtime equality coverage |
195−| This change | 2026-10-31 | Check empty molds and propagate closed cell context into branches |
197+| 22f3788 | 2026-10-31 | Check empty molds and propagate closed cell context into branches |
198+| This change | 2026-10-31 | Keep deferred fits stable under later substitutions |
196
199
197## Checking it
200## Checking it
198
201
jibb-dev/lib/jibb.hoon+55
@@ -8529,6 +8529,8 @@
8529 =/ nested=(unit idiag) (nested-missing-tag val.e typ.p.value typ.u.target sub.state.p.value next.state.p.value at.shape.e)
8529 =/ nested=(unit idiag) (nested-missing-tag val.e typ.p.value typ.u.target sub.state.p.value next.state.p.value at.shape.e)
8530 ?^ nested [%| u.nested]
8530 ?^ nested [%| u.nested]
8531 [%| ["cast mold and expression type do not unify" ~[[at.shape.e (site-type-note "cast mold" typ.u.target sub.state.p.value)] [(span-of val.e) (site-type-note "expression" typ.p.value sub.state.p.value)]]]]
8531 [%| ["cast mold and expression type do not unify" ~[[at.shape.e (site-type-note "cast mold" typ.u.target sub.state.p.value)] [(span-of val.e) (site-type-note "expression" typ.p.value sub.state.p.value)]]]]
8532+ ?: &(?=(^ defer.state.p.value) !(dg-stable-fit typ.p.value typ.u.target sub.fit))
8533+ [%| ["deferred cast fit needs stable inference" ~]]
8532 =/ merged=itype (itype-merge-faces typ.p.value typ.u.target sub.fit)
8534 =/ merged=itype (itype-merge-faces typ.p.value typ.u.target sub.fit)
8533 [%& merged state.p.value(sub sub.fit, next next.fit)]
8535 [%& merged state.p.value(sub sub.fit, next next.fit)]
8534 %crash [%& [%var next.state] state(next +(next.state))]
8536 %crash [%& [%var next.state] state(next +(next.state))]
@@ -8857,6 +8859,8 @@
8857 =/ arg-at=span ?~(bad whole-args at.u.bad)
8859 =/ arg-at=span ?~(bad whole-args at.u.bad)
8858 =/ arg-type=itype ?~(bad typ.p.arg typ.u.bad)
8860 =/ arg-type=itype ?~(bad typ.p.arg typ.u.bad)
8859 [%| ["call's sample and argument types do not unify" ~[[(span-of head.e) (site-type-note "called gate" ht sub.st)] [arg-at (site-type-note "argument" arg-type sub.st)]]]]
8861 [%| ["call's sample and argument types do not unify" ~[[(span-of head.e) (site-type-note "called gate" ht sub.st)] [arg-at (site-type-note "argument" arg-type sub.st)]]]]
8862+ ?: &(?=(^ defer.st) !(dg-stable-call-fit typ.p.arg sample.ht product.ht sub.fit ?=(^ t.args.e)))
8863+ [%| ["deferred call fit needs stable inference" ~]]
8860 =/ face-asym=?
8864 =/ face-asym=?
8861 ?^ direct |
8865 ?^ direct |
8862 ?^ t.args.e (itype-positional-face-asym args.e typ.p.arg sample.ht sub.fit)
8866 ?^ t.args.e (itype-positional-face-asym args.e typ.p.arg sample.ht sub.fit)
@@ -12589,6 +12593,56 @@
12589 ?~ rest ~
12593 ?~ rest ~
12590 `[[name.i.env [normalized vars.s]] u.rest]
12594 `[[name.i.env [normalized vars.s]] u.rest]
12591::
12595::
12596+:: Deferred inference uses only source forms whose successful fit sites are
12597+:: guarded below; a shared source-node budget bounds this screen.
12598+++ dg-safe-expressions
12599+ |= [todo=(list expr) fuel=@ud]
12600+ ^- (unit @ud)
12601+ ?~ todo `fuel
12602+ =/ first=(unit @ud) (dg-safe-expression i.todo fuel)
12603+ ?~ first ~
12604+ $(todo t.todo, fuel u.first)
12605+++ dg-safe-expression
12606+ |= [e=expr fuel=@ud]
12607+ ^- (unit @ud)
12608+ ?: =(0 fuel) ~
12609+ =. fuel (dec fuel)
12610+ ?+ -.e ~
12611+ ?(%lit %ctor) `fuel
12612+ %wing ?:(?=([@ ~] names.e) `fuel ~)
12613+ %str
12614+ ?. (levy pieces.e |=(p=piece ?=(%text -.p))) ~
12615+ `fuel
12616+ %group $(e inner.e, fuel fuel)
12617+ %body
12618+ ?^ defs.e ~
12619+ $(e final.e, fuel fuel)
12620+ %gate $(e body.e, fuel fuel)
12621+ %gate-wide $(e body.e, fuel fuel)
12622+ %cast $(e val.e, fuel fuel)
12623+ %call
12624+ =/ head=(unit @ud) $(e head.e, fuel fuel)
12625+ ?~ head ~
12626+ (dg-safe-expressions args.e u.head)
12627+ ==
12628+:: Exact normalized equality is preserved by all later substitutions.
12629+:: The bounded scan declines opaque types and oversized inputs.
12630+++ dg-stable-fit
12631+ |= [actual=itype expected=itype sub=isub]
12632+ ^- ?
12633+ ?~ (dg-scan ~[actual expected] sub 512 ~) |
12634+ =((itype-normalize actual sub) (itype-normalize expected sub))
12635+::
12636+:: A positional call peels sample-slot faces during its separate face check.
12637+:: Require its argument, sample and result closed so that check stays valid.
12638+++ dg-stable-call-fit
12639+ |= [actual=itype expected=itype product=itype sub=isub positional=?]
12640+ ^- ?
12641+ =/ checked=(unit dgscan) (dg-scan ~[actual expected product] sub 512 ~)
12642+ ?~ checked |
12643+ ?: &(positional ?=(^ ids.u.checked)) |
12644+ =((itype-normalize actual sub) (itype-normalize expected sub))
12645+::
12592++ dg-stage
12646++ dg-stage
12593 |= [ds=(list def) base=ienv env=ienv state=istate pending=(list dgo) fuel=@ud]
12647 |= [ds=(list def) base=ienv env=ienv state=istate pending=(list dgo) fuel=@ud]
12594 ^- (unit dgcommit)
12648 ^- (unit dgcommit)
@@ -12611,6 +12665,7 @@
12611 ?: ?=(%mold -.d) $(ds t.ds, fuel (dec fuel))
12665 ?: ?=(%mold -.d) $(ds t.ds, fuel (dec fuel))
12612 ?^ (ienv-lookup name.d base) $(ds t.ds, fuel (dec fuel))
12666 ?^ (ienv-lookup name.d base) $(ds t.ds, fuel (dec fuel))
12613 ?^ (ienv-lookup name.d env) ~
12667 ?^ (ienv-lookup name.d env) ~
12668+ ?~ (dg-safe-expression val.d 512) ~
12614 =/ local=istate (reserve-def-caps val.d state)
12669 =/ local=istate (reserve-def-caps val.d state)
12615 :: This first slice declines all written capitals and holes/projections.
12670 :: This first slice declines all written capitals and holes/projections.
12616 ?^ caps.local ~
12671 ?^ caps.local ~
tests/lib/jibb-deferred-resolver.hoon+27−1
@@ -7,6 +7,14 @@
7/* duplicate %txt /tests/type-deferred-resolver/duplicate/txt
7/* duplicate %txt /tests/type-deferred-resolver/duplicate/txt
8/* face %txt /tests/type-deferred-resolver/face/txt
8/* face %txt /tests/type-deferred-resolver/face/txt
9/* store %txt /tests/type-deferred-resolver/store/txt
9/* store %txt /tests/type-deferred-resolver/store/txt
10+/* stability-early %txt /tests/type-deferred-resolver/stability-early/txt
11+/* stability-late %txt /tests/type-deferred-resolver/stability-late/txt
12+/* stability-simple-early %txt /tests/type-deferred-resolver/stability-simple-early/txt
13+/* stability-simple-late %txt /tests/type-deferred-resolver/stability-simple-late/txt
14+/* stability-output-early %txt /tests/type-deferred-resolver/stability-output-early/txt
15+/* stability-output-late %txt /tests/type-deferred-resolver/stability-output-late/txt
16+/* stability-slot-early %txt /tests/type-deferred-resolver/stability-slot-early/txt
17+/* stability-slot-late %txt /tests/type-deferred-resolver/stability-slot-late/txt
10/* public %jibb /lib/jibb/prelude/jibb
18/* public %jibb /lib/jibb/prelude/jibb
11/* internal %jibb /lib/jibb/internal/jibb
19/* internal %jibb /lib/jibb/internal/jibb
12/* expected %txt /tests/type-deferred-resolver/expected/txt
20/* expected %txt /tests/type-deferred-resolver/expected/txt
@@ -83,5 +91,23 @@
83 ^- tang
91 ^- tang
84 =/ result=@t (resolver-report (text good) (text conflict) (text missing) (text hole) (text duplicate) (text face) (text store) public internal)
92 =/ result=@t (resolver-report (text good) (text conflict) (text missing) (text hole) (text duplicate) (text face) (text store) public internal)
85 ?. =((to-wain:format (cat 3 result '\0a')) expected) ~[leaf+"deferred resolver report differs"]
93 ?. =((to-wain:format (cat 3 result '\0a')) expected) ~[leaf+"deferred resolver report differs"]
86− ~
94+ =/ closed=itype:jibb [%cell [%face %foo [%atom %t]] [%atom %t]]
95+ =/ open=itype:jibb [%cell [%face %foo [%var 500]] [%atom %t]]
96+ =/ tag=itype:jibb [%tag 501 *lit:jibb |]
97+ ?. (dg-stable-call-fit:jibb closed closed [%atom %t] ~ &) ~[leaf+"closed positional fit declined"]
98+ ?: (dg-stable-call-fit:jibb open open [%atom %t] ~ &) ~[leaf+"open positional face accepted"]
99+ ?: (dg-stable-call-fit:jibb closed closed tag ~ &) ~[leaf+"pending positional result accepted"]
100+ ?. (dg-stable-call-fit:jibb open open [%atom %t] ~ |) ~[leaf+"equal single argument declined"]
101+ =/ samples=(list wain)
102+ ~[stability-early stability-late stability-simple-early stability-simple-late stability-output-early stability-output-late stability-slot-early stability-slot-late]
103+ |-
104+ ?~ samples ~
105+ ?~ i.samples ~[leaf+"deferred stability source missing"]
106+ =/ at=path /ui/stability/jibb
107+ =/ src=@t (text i.samples)
108+ =/ parsed (parse:jibb at src)
109+ ?: ?=(%| -.parsed) ~[leaf+"deferred stability source does not parse"]
110+ =/ result=jfile-result:jibb (infer-jibb-file:jibb at src ~ ~ ~ ~[at] ~ ~ ~ ~)
111+ ?: ?=(%& -.result) ~[leaf+"unstable deferred fit published an interface"]
112+ $(samples t.samples)
87--
113--
tests/type-deferred-resolver/about.txt+2
@@ -1,3 +1,5 @@
1source: docs/spec/grammar.md, Tag resolution: “A variable constrained by tag resolution, and any it mentions, doesn't generalize; it stays open until something in the module fixes it.”
1source: docs/spec/grammar.md, Tag resolution: “A variable constrained by tag resolution, and any it mentions, doesn't generalize; it stays open until something in the module fixes it.”
2
2
3Import-free, no-prelude ordinary library resolution: principal generalized result and matching report, with conflicting constructors, holes, duplicate bindings, nested faces and store kind rejected atomically. Resolved imports and the actual prepared prelude are also checked as fail-closed boundaries.
3Import-free, no-prelude ordinary library resolution: principal generalized result and matching report, with conflicting constructors, holes, duplicate bindings, nested faces and store kind rejected atomically. Resolved imports and the actual prepared prelude are also checked as fail-closed boundaries.
4+
5+Both source orders decline when a later substitution changes a previously checked face-propagation condition. Controls cover compound and direct calls, an unresolved result tag that becomes `*`, and an unresolved positional slot that becomes faced. Positive low-level checks preserve closed positional fits and equal single-argument fits with open variables.
tests/type-deferred-resolver/stability-early.txtnew file+6
@@ -0,0 +1,6 @@
1++$ single [%got value=@t]
2+++ request |= f=$-(@t A) f
3+++ accept |= pair=[A [foo=A]] pair
4+++ waiting (request |=%got)
5+++ wrapped (accept [waiting waiting])
6+++ reveal ^- $-(@t single) waiting
tests/type-deferred-resolver/stability-late.txtnew file+6
@@ -0,0 +1,6 @@
1++$ single [%got value=@t]
2+++ request |= f=$-(@t A) f
3+++ accept |= pair=[A [foo=A]] pair
4+++ waiting (request |=%got)
5+++ reveal ^- $-(@t single) waiting
6+++ wrapped (accept [waiting waiting])
tests/type-deferred-resolver/stability-output-early.txtnew file+9
@@ -0,0 +1,9 @@
1++$ single [%got value=@t]
2+++ send |= f=$-(@t A) f
3+++ pending (send |=%got)
4+++ finish ^- $-(@t single) pending
5+++ accept |= [foo=@t bar=@t] %idle
6+++ foo-value ^- [foo=@t] "a"
7+++ bar-value ^- [bar=@t] "b"
8+++ value (accept foo-value bar-value)
9+++ reveal ^- * value
tests/type-deferred-resolver/stability-output-late.txtnew file+9
@@ -0,0 +1,9 @@
1++$ single [%got value=@t]
2+++ send |= f=$-(@t A) f
3+++ pending (send |=%got)
4+++ finish ^- $-(@t single) pending
5+++ accept |= [foo=@t bar=@t] %idle
6+++ foo-value ^- [foo=@t] "a"
7+++ bar-value ^- [bar=@t] "b"
8+++ prior ^- * (accept foo-value bar-value)
9+++ value (accept foo-value bar-value)
tests/type-deferred-resolver/stability-simple-early.txtnew file+6
@@ -0,0 +1,6 @@
1++$ single [%got value=@t]
2+++ request |= f=$-(@t A) f
3+++ accept |= x=[foo=A] x
4+++ waiting (request |=%got)
5+++ wrapped (accept waiting)
6+++ reveal ^- $-(@t single) waiting
tests/type-deferred-resolver/stability-simple-late.txtnew file+6
@@ -0,0 +1,6 @@
1++$ single [%got value=@t]
2+++ request |= f=$-(@t A) f
3+++ accept |= x=[foo=A] x
4+++ waiting (request |=%got)
5+++ reveal ^- $-(@t single) waiting
6+++ wrapped (accept waiting)
tests/type-deferred-resolver/stability-slot-early.txtnew file+9
@@ -0,0 +1,9 @@
1++$ single [%got value=@t]
2+++ request |= f=$-(@t A) f
3+++ label |= x=A [foo=x]
4+++ accept |= x=[[foo=A] @t] x
5+++ pending (request |=%got)
6+++ first (pending "hello")
7+++ labeled (label first)
8+++ value (accept labeled "b")
9+++ finish ^- $-(@t single) pending
tests/type-deferred-resolver/stability-slot-late.txtnew file+9
@@ -0,0 +1,9 @@
1++$ single [%got value=@t]
2+++ request |= f=$-(@t A) f
3+++ label |= x=A [foo=x]
4+++ accept |= x=[[foo=A] @t] x
5+++ pending (request |=%got)
6+++ first (pending "hello")
7+++ labeled (label first)
8+++ finish ^- $-(@t single) pending
9+++ value (accept labeled "b")
tools/testdata/ship-selftest+5−1
@@ -353,7 +353,11 @@ def generator_checks(tmp):
353 check('deferred transaction and resolver sources are assembled',
353 check('deferred transaction and resolver sources are assembled',
354 {'tests/type-deferred/nested-src.txt', 'tests/type-deferred/principal-src.txt',
354 {'tests/type-deferred/nested-src.txt', 'tests/type-deferred/principal-src.txt',
355 'tests/type-deferred/expected.txt', 'tests/type-deferred-resolver/good.txt',
355 'tests/type-deferred/expected.txt', 'tests/type-deferred-resolver/good.txt',
356− 'tests/type-deferred-resolver/store.txt', 'tests/type-deferred-resolver/expected.txt'}
356+ 'tests/type-deferred-resolver/store.txt', 'tests/type-deferred-resolver/expected.txt',
357+ 'tests/type-deferred-resolver/stability-early.txt', 'tests/type-deferred-resolver/stability-late.txt',
358+ 'tests/type-deferred-resolver/stability-simple-early.txt', 'tests/type-deferred-resolver/stability-simple-late.txt',
359+ 'tests/type-deferred-resolver/stability-output-early.txt', 'tests/type-deferred-resolver/stability-output-late.txt',
360+ 'tests/type-deferred-resolver/stability-slot-early.txt', 'tests/type-deferred-resolver/stability-slot-late.txt'}
357 <= set(normal.files))
361 <= set(normal.files))
358 check('cell branch sources are assembled',
362 check('cell branch sources are assembled',
359 {'tests/type-cell-branch/good.txt', 'tests/type-cell-branch/bad.txt'}
363 {'tests/type-cell-branch/good.txt', 'tests/type-cell-branch/bad.txt'}
tools/type-deferred-resolver-test+1−1
@@ -8,7 +8,7 @@ p.add_argument('--lib', default=str(root / 'jibb-dev/lib/jibb.hoon'))
8a = p.parse_args()
8a = p.parse_args()
9core = (root / 'tests/lib/jibb-deferred-resolver.hoon').read_text()
9core = (root / 'tests/lib/jibb-deferred-resolver.hoon').read_text()
10core = core[core.index('\n|%\n') + 1:]
10core = core[core.index('\n|%\n') + 1:]
11−names = ['good', 'conflict', 'missing', 'hole', 'duplicate', 'face', 'store', 'public', 'internal']
11+names = ['good', 'conflict', 'missing', 'hole', 'duplicate', 'face', 'store', 'stability-early', 'stability-late', 'stability-simple-early', 'stability-simple-late', 'stability-output-early', 'stability-output-late', 'stability-slot-early', 'stability-slot-late', 'public', 'internal']
12bindings = ''.join('=/ '+n+'=wain (to-wain:format '+n+'-text)\n' for n in names if n not in ('public', 'internal'))
12bindings = ''.join('=/ '+n+'=wain (to-wain:format '+n+'-text)\n' for n in names if n not in ('public', 'internal'))
13bindings += ''.join('=/ '+n+'=@t '+n+'-text\n' for n in ('public', 'internal'))
13bindings += ''.join('=/ '+n+'=@t '+n+'-text\n' for n in ('public', 'internal'))
14program = ('=/ jibb .\n' + bindings + '=/ expected=wain (to-wain:format expected-text)\n=/ suite\n' + core +
14program = ('=/ jibb .\n' + bindings + '=/ expected=wain (to-wain:format expected-text)\n=/ suite\n' + core +