on master help sign in
Recover prepared tuple initializers in reports
aa277c9iko
README.md+1−1
@@ -42,7 +42,7 @@ tools/hoon '(golden /a/b/jibb (crip "++ main view"))'
42tools/hoon --raw --cord src=tests/golden/foo/source.jibb 'tree:(golden /a/b/jibb src)'
42tools/hoon --raw --cord src=tests/golden/foo/source.jibb 'tree:(golden /a/b/jibb src)'
43```
43```
44
44
45−`tools/testdata/selftest` tests both tools against a stub library, and `tools/doc-blocks` against Markdown it writes. `tools/importer-test` compares the partial Hoon importer's fixture projections against their golden file. `tools/type-import-test`, `tools/type-import-overlap-test`, `tools/type-import-structural-test`, `tools/type-union-source-test`, `tools/type-union-alias-overlap-test`, `tools/type-full-overlap-test`, `tools/type-generic-recursion-test`, `tools/type-generic-construction-test`, `tools/type-generic-pattern-test`, `tools/type-deferred-test`, `tools/type-deferred-resolver-test`, `tools/type-deferred-context-test`, `tools/type-empty-test`, `tools/type-cell-branch-test`, `tools/type-tlon-test`, `tools/type-mark-test`, `tools/type-poke-test` and `tools/type-api-paths-test` check importer/checker, prelude and partial API path analysis boundaries under eval; the ship suite runs the same fixtures.
45+`tools/testdata/selftest` tests both tools against a stub library, and `tools/doc-blocks` against Markdown it writes. `tools/importer-test` compares the partial Hoon importer's fixture projections against their golden file. `tools/type-import-test`, `tools/type-import-overlap-test`, `tools/type-import-structural-test`, `tools/type-union-source-test`, `tools/type-union-alias-overlap-test`, `tools/type-full-overlap-test`, `tools/type-generic-recursion-test`, `tools/type-generic-construction-test`, `tools/type-generic-pattern-test`, `tools/type-deferred-test`, `tools/type-deferred-prepared-test`, `tools/type-deferred-resolver-test`, `tools/type-deferred-context-test`, `tools/type-empty-test`, `tools/type-cell-branch-test`, `tools/type-tlon-test`, `tools/type-mark-test`, `tools/type-poke-test` and `tools/type-api-paths-test` check importer/checker, prelude and partial API path analysis boundaries under eval; the ship suite runs the same fixtures.
46
46
47### The doc's examples
47### The doc's examples
48
48
docs/compiler.md+4−2
@@ -190,7 +190,7 @@ Note 4 has examples of each.
190
190
191Starting `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).
191Starting `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).
192
192
193−The experimental deferred constructor path can close a small import-free library transaction when ordinary resolution stalls. It retries definitions whose earlier attempts failed from their original states, retaining only successful attempts. A transaction with at most 64 definitions makes at most 4,096 attempts; it stops after a pass with no progress. This bounds the new attempt count, not each attempt's parsing, type walks or ordinary inference. Deferred definitions are restricted to simple one-component wings, literals, static strings, gates, transparent groups and empty bodies, calls, casts and a restricted boolean branch. 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.
193+The experimental deferred constructor path can close a small import-free library transaction when ordinary resolution stalls. It retries definitions whose earlier attempts failed from their original states, retaining only successful attempts. A transaction with at most 64 definitions makes at most 4,096 attempts; it stops after a pass with no progress. This bounds the new attempt count, not each attempt's parsing, type walks or ordinary inference. Deferred definitions are restricted to simple one-component wings, literals, static strings, gates, transparent groups and empty bodies, calls, casts and a restricted boolean branch. 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-prelude recovery, imports, recursive groups, unresolved holes or written capitals, and new projection actions remain outside this full-module path. `%grec` in the constraint or freshness scan is conservatively unsupported. This is not an island-kind, runtime, or watchability check.
194
194
195An 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.
195An 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.
196
196
@@ -198,6 +198,8 @@ In an isolated diagnostic with the real todo API and reader inputs, this cell co
198
198
199A deferred boolean branch must use both distinct literal loobean patterns. Its subject is unified with `?`; the arms are inferred in source order without contextual retry. Equal normalized arm types are retained directly. When both written arms are direct literals that each created their own unbound pending tag, the checker can instead retain two source-owned fit obligations to a shared, monomorphic result variable. A later definition may close that variable; replay uses the ordinary literal fit, requires a closed atomic target or a union of direct constant/cell cases, and rejects faced targets and faced union cases. It replays all edges under the final substitution without adding bindings or fresh IDs. This does not support deferred list literals, union-pattern reachability, arbitrary branch expressions or prepared-prelude/imported modules. It does not establish request watchability.
199A deferred boolean branch must use both distinct literal loobean patterns. Its subject is unified with `?`; the arms are inferred in source order without contextual retry. Equal normalized arm types are retained directly. When both written arms are direct literals that each created their own unbound pending tag, the checker can instead retain two source-owned fit obligations to a shared, monomorphic result variable. A later definition may close that variable; replay uses the ordinary literal fit, requires a closed atomic target or a union of direct constant/cell cases, and rejects faced targets and faced union cases. It replays all edges under the final substitution without adding bindings or fresh IDs. This does not support deferred list literals, union-pattern reachability, arbitrary branch expressions or prepared-prelude/imported modules. It does not establish request watchability.
200
200
201+With the caller's unchanged prepared prelude, the partial report can also recover a narrow import-free, non-main ordinary library initializer. A direct tuple literal may retain one source-owned fit obligation for each newly created pending literal until a later exact result cast closes them. A separate bounded candidate screen admits a direct tuple even without a constructor call. The prepared transaction requires exact agreement among the supplied interface, value inventory and reserved molds, and retains the API, store, import and `main` exclusions. It only adds recovered entries to the partial report: the ordinary full-module resolver does not publish them. Wrong unit or draft fields, unrelated pending tags and mold-name collisions fail closed; without the later final cast, the initializer remains not checked. This does not add list-literal deferral or import-aware recovery.
202+
201−Before a fallback, the checker screens the already parsed source for a direct single-constructor call beneath groups, gates, casts or bodies without local definitions. The screen visits at most 64 AST nodes per definition and rejects sources with more than 64 definitions or 65,536 bytes. A transaction is attempted at most once per resolver or report invocation and holds at most 64 pending edges. These limits do not bound the initial parsing, ordinary resolution, normalization, or total work across separate analyses. On the pre-recursive-index snapshot, startup-inclusive synthetic 1,000-gate comparisons had baseline/candidate user times of 25.97/29.30 seconds and 26.30/27.46 seconds in reverse order. These are limited shared-load measurements, not production benchmarks. The trimmed source-backed and direct-guard fixture passed in 28.13 seconds wall and 27.53 seconds user on one run after screening; its cases include parse-success checks in the same transaction source pass. The outer resolver and reporter each parse independently, and a fallback currently parses the source again.
203+Before the no-prepared-prelude fallback, the checker screens the already parsed source for a direct single-constructor call beneath groups, gates, casts or bodies without local definitions. The screen visits at most 64 AST nodes per definition and rejects sources with more than 64 definitions or 65,536 bytes. A transaction is attempted at most once per resolver or report invocation and holds at most 64 pending edges. These limits do not bound the initial parsing, ordinary resolution, normalization, or total work across separate analyses. On the pre-recursive-index snapshot, startup-inclusive synthetic 1,000-gate comparisons had baseline/candidate user times of 25.97/29.30 seconds and 26.30/27.46 seconds in reverse order. These are limited shared-load measurements, not production benchmarks. The trimmed source-backed and direct-guard fixture passed in 28.13 seconds wall and 27.53 seconds user on one run after screening; its cases include parse-success checks in the same transaction source pass. The outer resolver and reporter each parse independently, and a fallback currently parses the source again.
202
204
203A single sequential, startup-inclusive comparison against checkpoint `c96597d` measured user CPU for an unrelated stalled library at 25.04 seconds baseline and 26.32 seconds with the screened fallback; an incompatible constructor took 25.72 and 27.16 seconds; a direct constructor that the baseline declined and the candidate resolved took 24.46 and 26.79 seconds. These are small shared-load measurements, not a production benchmark. The screen was separately checked with a trapping fallback: the unrelated source skipped it, while the eligible conflicting source reached it.
205A single sequential, startup-inclusive comparison against checkpoint `c96597d` measured user CPU for an unrelated stalled library at 25.04 seconds baseline and 26.32 seconds with the screened fallback; an incompatible constructor took 25.72 and 27.16 seconds; a direct constructor that the baseline declined and the candidate resolved took 24.46 and 26.79 seconds. These are small shared-load measurements, not a production benchmark. The screen was separately checked with a trapping fallback: the unrelated source skipped it, while the eligible conflicting source reached it.
docs/development.md+3−1
@@ -83,6 +83,7 @@ git clone https://github.com/urbit/tools /root/src/tools
83| `tools/type-deferred-test` | Checks the bounded source-owned deferred inference transaction under eval and on the ship |
83| `tools/type-deferred-test` | Checks the bounded source-owned deferred inference transaction under eval and on the ship |
84| `tools/type-deferred-resolver-test` | Checks deferred resolution, report consistency and atomic failure under eval and on the ship |
84| `tools/type-deferred-resolver-test` | Checks deferred resolution, report consistency and atomic failure under eval and on the ship |
85| `tools/type-deferred-context-test` | Checks deferred source order and literal branch contexts under eval and on the ship |
85| `tools/type-deferred-context-test` | Checks deferred source order and literal branch contexts under eval and on the ship |
86+| `tools/type-deferred-prepared-test` | Checks prepared-prelude tuple initializer recovery, exact partial reports and fail-closed guards under eval and on the ship |
86| `tools/type-cell-branch-test` | Checks closed-cell branch context, rollback and bounded retry screens under eval and on the ship |
87| `tools/type-cell-branch-test` | Checks closed-cell branch context, rollback and bounded retry screens under eval and on the ship |
87| `tools/type-generic-alias-test` | Runs public/private generic union alias and provenance guards under eval and on the ship |
88| `tools/type-generic-alias-test` | Runs public/private generic union alias and provenance guards under eval and on the ship |
88| `tools/type-positional-face-guards-test` | Runs positional-call and nested-face guards under eval and on the ship |
89| `tools/type-positional-face-guards-test` | Runs positional-call and nested-face guards under eval and on the ship |
@@ -144,6 +145,7 @@ tools/type-generic-pattern-test # source-backed recursive patterns and boun
144tools/type-deferred-test # source-owned deferred inference guards
145tools/type-deferred-test # source-owned deferred inference guards
145tools/type-deferred-resolver-test # resolver consistency and failure guards
146tools/type-deferred-resolver-test # resolver consistency and failure guards
146tools/type-deferred-context-test # deferred source-order and branch guards
147tools/type-deferred-context-test # deferred source-order and branch guards
148+tools/type-deferred-prepared-test # prepared initializer reports and failure guards
147tools/type-cell-branch-test # contextual branch rollback and bounds
149tools/type-cell-branch-test # contextual branch rollback and bounds
148tools/type-closed-gate-guards-test # closed gate fit guards pass
150tools/type-closed-gate-guards-test # closed gate fit guards pass
149tools/type-constructor-fit-guards-test # constructor fit guards pass
151tools/type-constructor-fit-guards-test # constructor fit guards pass
@@ -214,4 +216,4 @@ Write `source.jibb` and `about.txt` by hand, run `tools/golden --update --case <
214
216
215A 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.
217A 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.
216
218
217−`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.
219+`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. `tools/type-deferred-prepared-test` checks the separate partial-report-only prepared-prelude route, direct tuple-literal obligations, exact report types and its wrong-field, unrelated-tag, mold-collision and no-final-cast controls. These checks do not establish island-kind or watchability support.
docs/status.md+7−3
@@ -31,6 +31,8 @@ A bounded local source proof recognizes a narrow class of generic-alias union ca
31
31
32The checker can experimentally discharge a narrowly scoped direct-constructor constraint while resolving an import-free library without a prepared prelude. It preserves independent generalized schemes and publishes only after all source molds, values, and recorded constraints close. API/store paths, `main`, imports, prepared preludes, recursive groups, open constraints, projection actions, and `%grec` in the constraint graph remain unsupported by this route. The fallback also declines source shapes outside its bounded direct-call screen. It does not yet typecheck the unchanged todo island or establish watchability.
32The checker can experimentally discharge a narrowly scoped direct-constructor constraint while resolving an import-free library without a prepared prelude. It preserves independent generalized schemes and publishes only after all source molds, values, and recorded constraints close. API/store paths, `main`, imports, prepared preludes, recursive groups, open constraints, projection actions, and `%grec` in the constraint graph remain unsupported by this route. The fallback also declines source shapes outside its bounded direct-call screen. It does not yet typecheck the unchanged todo island or establish watchability.
33
33
34+A prepared-prelude partial report can recover a narrow import-free, non-main ordinary library initializer by deferring source-owned literals in a direct tuple until a later exact result cast. The prepared interface and declared-name inventories must agree exactly. API/store paths, `main` and imports remain excluded, and the ordinary full-module resolver does not publish the recovered interface. Wrong field types, unrelated tags and mold collisions fail closed; a no-final-cast control remains unchecked. `tools/type-deferred-prepared-test` checks the exact recovered types and unchanged `partial inference; module not checked` disclaimer under eval and on the ship. List-literal deferral and import-aware recovery remain unsupported.
35+
34Closed cell context can now flow through a bounded loobean branch while preserving the inferred value faces and original failed-inference behavior. Open or structurally uncertain substitutions and nested retry shapes remain unsupported. This does not by itself provide the missing text and UI prelude definitions, cross-definition context, island-kind checks, or watchability evidence needed by the unchanged todo island.
36Closed cell context can now flow through a bounded loobean branch while preserving the inferred value faces and original failed-inference behavior. Open or structurally uncertain substitutions and nested retry shapes remain unsupported. This does not by itself provide the missing text and UI prelude definitions, cross-definition context, island-kind checks, or watchability evidence needed by the unchanged todo island.
35
37
36The internal prelude defines a transparent generic `ask` with pure, agent and store cases, re-exported alongside the Jibb-written `pure` gate. The partial checker infers supported constructors and exhaustive matches. Agent and store receivers operate on raw nouns; their fields do not prove schema validity or watchability. The public prelude now defines the documented source-backed `sub` union; supported `%watch` payloads retain the public `(ask M)` type. Constructing a `sub` does not prove that its request is watchable. Request lowering, checked decoding, runtime validation and island watch checking remain unimplemented.
38The internal prelude defines a transparent generic `ask` with pure, agent and store cases, re-exported alongside the Jibb-written `pure` gate. The partial checker infers supported constructors and exhaustive matches. Agent and store receivers operate on raw nouns; their fields do not prove schema validity or watchability. The public prelude now defines the documented source-backed `sub` union; supported `%watch` payloads retain the public `(ask M)` type. Constructing a `sub` does not prove that its request is watchable. Request lowering, checked decoding, runtime validation and island watch checking remain unimplemented.
@@ -61,7 +63,7 @@ The prelude has Jibb-written curried `lead` and `late` pair constructors, inferr
61
63
62The 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.
64The 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.
63
65
64−The experimental deferred constructor transaction conservatively declines tuples, most 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. It can retry source definitions after later dependencies become available, and a two-arm boolean branch can retain separately owned literal-result obligations until a later closed context resolves them. Faced targets or union cases, list literals and general union-pattern branches remain unsupported.
66+The experimental deferred constructor transaction conservatively declines general structural tuple fits, most 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. It can retry source definitions after later dependencies become available, and a two-arm boolean branch can retain separately owned literal-result obligations until a later closed context resolves them. Faced targets or union cases, list literals and general union-pattern branches remain unsupported.
65
67
66The 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 shared guard runs under eval and on the ship.
68The 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 shared guard runs under eval and on the ship.
67
69
@@ -92,7 +94,7 @@ What the plan asks for, and where it is:
92Besides the plan's list:
94Besides the plan's list:
93
95
94- 659 golden cases: 439 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.
96- 659 golden cases: 439 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.
95−- The 659-case corpus passed under `urbit eval` in 103.2 s while other checks were running. The fake ship passed all 705 tests, including the source-overlap, structural-overlap, generic-union source and alias-overlap, full-module overlap, deferred-context, 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 99.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.
97+- The 659-case corpus passed under `urbit eval` in 98.7 s while other checks were running. The fake ship passed all 706 tests, including the source-overlap, structural-overlap, generic-union source and alias-overlap, full-module overlap, deferred-context, 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 94.2 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.
96- `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.
98- `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.
97- 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.
99- 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.
98- 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).
100- 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).
@@ -205,7 +207,8 @@ Besides the plan's list:
205| b93a94b | 2026-10-31 | Prove local generic-alias union tags and add successor |
207| b93a94b | 2026-10-31 | Prove local generic-alias union tags and add successor |
206| 2826c93 | 2026-10-31 | Report generic-alias overlaps and retain deferred branch contexts |
208| 2826c93 | 2026-10-31 | Report generic-alias overlaps and retain deferred branch contexts |
207| b5cdc80 | 2026-10-31 | Preserve full-module overlap source evidence |
209| b5cdc80 | 2026-10-31 | Preserve full-module overlap source evidence |
208−| This change | 2026-10-31 | Add source-backed text conversion wrappers |
210+| ab6fdc1 | 2026-10-31 | Add source-backed text conversion wrappers |
211+| This change | 2026-10-31 | Recover prepared tuple initializers in partial reports |
209
212
210## Checking it
213## Checking it
211
214
@@ -235,6 +238,7 @@ tools/type-generic-pattern-test # source-proven recursive pattern guards
235tools/type-deferred-test # source-owned deferred inference guards
238tools/type-deferred-test # source-owned deferred inference guards
236tools/type-deferred-resolver-test # resolver consistency and failure guards
239tools/type-deferred-resolver-test # resolver consistency and failure guards
237tools/type-deferred-context-test # deferred source-order and branch guards
240tools/type-deferred-context-test # deferred source-order and branch guards
241+tools/type-deferred-prepared-test # prepared initializer reports and failure guards
238tools/type-empty-test # empty molds and coverage guards
242tools/type-empty-test # empty molds and coverage guards
239tools/type-cell-branch-test # branch context and rollback guards
243tools/type-cell-branch-test # branch context and rollback guards
240tools/type-positional-face-guards-test # positional sample face guards
244tools/type-positional-face-guards-test # positional sample face guards
jibb-dev/lib/jibb.hoon+121−8
@@ -8435,7 +8435,10 @@
8435 =/ traced=iresult $(e val.e)
8435 =/ traced=iresult $(e val.e)
8436 ?: ?=(%| -.traced) traced
8436 ?: ?=(%| -.traced) traced
8437 $(e then.e, state state.p.traced)
8437 $(e then.e, state state.p.traced)
8438+ %tuple
8439+ ?: &(?=(^ defer.state) ?=(^ prelude.state))
8440+ (dg-infer-tuple-items items.e env state)
8438− %tuple (infer-simple-items items.e env state)
8441+ (infer-simple-items items.e env state)
8439 %body
8442 %body
8440 ?~ defs.e $(e final.e)
8443 ?~ defs.e $(e final.e)
8441 =/ local-names=(list term) (global-value-names defs.e)
8444 =/ local-names=(list term) (global-value-names defs.e)
@@ -9241,6 +9244,8 @@
9241 |= [e=expr expected=itype env=ienv state=istate context=span]
9244 |= [e=expr expected=itype env=ienv state=istate context=span]
9242 ^- iresult
9245 ^- iresult
9243 ?: &(?=(^ defer.state) ?=(%branch -.e)) (infer-fragment e env state)
9246 ?: &(?=(^ defer.state) ?=(%branch -.e)) (infer-fragment e env state)
9247+ ?: &(?=(^ defer.state) ?=(^ prelude.state) ?=(%tuple -.e))
9248+ (infer-fragment e env state)
9244 ?: ?=(%pair -.e) $(e (pair-as-cell e))
9249 ?: ?=(%pair -.e) $(e (pair-as-cell e))
9245 ?: ?=(%group -.e) $(e inner.e)
9250 ?: ?=(%group -.e) $(e inner.e)
9246 ?: &(?=(%body -.e) ?=(~ defs.e)) $(e final.e)
9251 ?: &(?=(%body -.e) ?=(~ defs.e)) $(e final.e)
@@ -12658,7 +12663,7 @@
12658 ?: ?=(%| -.js) (of-wain:format ~['partial inference; module not checked' p.js])
12663 ?: ?=(%| -.js) (of-wain:format ~['partial inference; module not checked' p.js])
12659 =/ scope-values=(list term)
12664 =/ scope-values=(list term)
12660 (weld prelude-values (weld (collect-sur-imports imports.p.parsed) (collect-mark-imports imports.p.parsed)))
12665 (weld prelude-values (weld (collect-sur-imports imports.p.parsed) (collect-mark-imports imports.p.parsed)))
12661− (golden-types-in-context file src externals mark-externals resolved.p.js scope-values prelude-molds iface)
12666+ (golden-types-in-context-core file src externals mark-externals resolved.p.js scope-values prelude-molds iface prepared)
12662::
12667::
12663:: +golden-types-with-marks: supply declared mark types separately from /sur
12668:: +golden-types-with-marks: supply declared mark types separately from /sur
12664:: entries, as [mark result] with the result from +read-mark:jibb-import.
12669:: entries, as [mark result] with the result from +read-mark:jibb-import.
@@ -12689,6 +12694,10 @@
12689++ golden-types-in-context
12694++ golden-types-in-context
12690 |= [file=path src=@t externals=iexternals mark-externals=imark-externals jimports=ijimports prelude-values=(list term) reserved-molds=(list term) prelude=(unit ifile)]
12695 |= [file=path src=@t externals=iexternals mark-externals=imark-externals jimports=ijimports prelude-values=(list term) reserved-molds=(list term) prelude=(unit ifile)]
12691 ^- @t
12696 ^- @t
12697+ (golden-types-in-context-core file src externals mark-externals jimports prelude-values reserved-molds prelude ~)
12698+++ golden-types-in-context-core
12699+ |= [file=path src=@t externals=iexternals mark-externals=imark-externals jimports=ijimports prelude-values=(list term) reserved-molds=(list term) prelude=(unit ifile) prepared=(unit iprelude)]
12700+ ^- @t
12692 =. reserved-molds (weld reserved-molds (turn jimports |=(j=[face=term interface=ifile] face.j)))
12701 =. reserved-molds (weld reserved-molds (turn jimports |=(j=[face=term interface=ifile] face.j)))
12693 =/ parsed (parse file src)
12702 =/ parsed (parse file src)
12694 ?: ?=(%| -.parsed) (show-error src p.parsed)
12703 ?: ?=(%| -.parsed) (show-error src p.parsed)
@@ -12708,19 +12717,27 @@
12708 =/ eligible=?
12717 =/ eligible=?
12709 ?& ?=(~ imports.p.parsed)
12718 ?& ?=(~ imports.p.parsed)
12710 ?=(~ jimports)
12719 ?=(~ jimports)
12711− ?=(~ prelude)
12712− ?=(~ prelude-values)
12713− ?=(~ reserved-molds)
12714 !?=([%ui %api *] file)
12720 !?=([%ui %api *] file)
12715 !?=([%ui %stores *] file)
12721 !?=([%ui %stores *] file)
12716 !(lien (global-value-names ds) |=(n=term =(n %main)))
12722 !(lien (global-value-names ds) |=(n=term =(n %main)))
12717− (module-scope-valid p.parsed ~ ~)
12718 !(module-values-complete ds env)
12723 !(module-values-complete ds env)
12719 (lte (met 3 src) 65.536)
12724 (lte (met 3 src) 65.536)
12720 (lte (lent ds) 64)
12725 (lte (lent ds) 64)
12721− (dg-source-candidate ds 64)
12726+ ?| &(?=(~ prepared) ?=(~ prelude) ?=(~ prelude-values) ?=(~ reserved-molds) (module-scope-valid p.parsed ~ ~) (dg-source-candidate ds 64))
12727+ ?& ?=(^ prepared)
12728+ ?=(^ prelude)
12729+ =(u.prelude iface.u.prepared)
12730+ =(prelude-values values.u.prepared)
12731+ =(reserved-molds molds.u.prepared)
12732+ (module-scope-valid p.parsed values.u.prepared molds.u.prepared)
12733+ (dg-prepared-candidate ds 64)
12734+ ==
12735+ ==
12722 ==
12736 ==
12723− =/ transaction=(unit dgcommit) ?:(eligible (dg-root-source file src) ~)
12737+ =/ transaction=(unit dgcommit)
12738+ ?. eligible ~
12739+ ?~ prepared (dg-root-source file src)
12740+ (dg-root-prepared file src u.prepared)
12724 =. recovered
12741 =. recovered
12725 ?~ transaction ~
12742 ?~ transaction ~
12726 ?. &((module-values-complete ds env.u.transaction) (dg-interface-safe env.u.transaction)) ~
12743 ?. &((module-values-complete ds env.u.transaction) (dg-interface-safe env.u.transaction)) ~
@@ -13006,6 +13023,31 @@
13006 [%& result st(next +(next.st), obligations [ex ey obligations.st])]
13023 [%& result st(next +(next.st), obligations [ex ey obligations.st])]
13007 [%& typ.p.left state.p.right]
13024 [%& typ.p.left state.p.right]
13008::
13025::
13026+:: A direct tuple literal may wait for a later exact result context.
13027+:: Each pending literal retains its source tag and its own fit obligation.
13028+++ dg-infer-tuple-items
13029+ |= [items=(list item) env=ienv state=istate]
13030+ ^- iresult
13031+ ?~ items [%| ["empty cell is not supported by partial inference" ~]]
13032+ =/ head=iresult (infer-fragment val.i.items env state)
13033+ ?: ?=(%| -.head) head
13034+ =/ typ=itype typ.p.head
13035+ =/ st=istate state.p.head
13036+ =/ adjusted=(unit [typ=itype state=istate])
13037+ ?. (dg-owned-arm-literal val.i.items typ tags.st sub.st next.state) `[typ st]
13038+ ?: (gth (lent obligations.st) 63) ~
13039+ =/ pending=itype [%var next.st]
13040+ =/ edge=dgo [typ pending (span-of val.i.items) at.i.items]
13041+ `[pending st(next +(next.st), obligations [edge obligations.st])]
13042+ ?~ adjusted [%| ["deferred tuple context needs unsupported inference" ~]]
13043+ =. typ typ.u.adjusted
13044+ =. st state.u.adjusted
13045+ =. typ ?~(face.i.items typ [%face u.face.i.items typ])
13046+ ?~ t.items [%& typ st]
13047+ =/ tail=iresult $(items t.items, state st)
13048+ ?: ?=(%| -.tail) tail
13049+ [%& [%cell typ typ.p.tail] state.p.tail]
13050+::
13009:: Deferred inference uses only source forms whose successful fit sites are
13051:: Deferred inference uses only source forms whose successful fit sites are
13010:: guarded below; a shared source-node budget bounds this screen.
13052:: guarded below; a shared source-node budget bounds this screen.
13011++ dg-safe-expressions
13053++ dg-safe-expressions
@@ -13015,6 +13057,13 @@
13015 =/ first=(unit @ud) (dg-safe-expression i.todo fuel)
13057 =/ first=(unit @ud) (dg-safe-expression i.todo fuel)
13016 ?~ first ~
13058 ?~ first ~
13017 $(todo t.todo, fuel u.first)
13059 $(todo t.todo, fuel u.first)
13060+++ dg-safe-items
13061+ |= [items=(list item) fuel=@ud]
13062+ ^- (unit @ud)
13063+ ?~ items `fuel
13064+ =/ first=(unit @ud) (dg-safe-expression val.i.items fuel)
13065+ ?~ first ~
13066+ $(items t.items, fuel u.first)
13018++ dg-safe-expression
13067++ dg-safe-expression
13019 |= [e=expr fuel=@ud]
13068 |= [e=expr fuel=@ud]
13020 ^- (unit @ud)
13069 ^- (unit @ud)
@@ -13032,6 +13081,7 @@
13032 $(e final.e, fuel fuel)
13081 $(e final.e, fuel fuel)
13033 %gate $(e body.e, fuel fuel)
13082 %gate $(e body.e, fuel fuel)
13034 %gate-wide $(e body.e, fuel fuel)
13083 %gate-wide $(e body.e, fuel fuel)
13084+ %tuple (dg-safe-items items.e fuel)
13035 %branch
13085 %branch
13036 ?. (dg-boolean-patterns e) ~
13086 ?. (dg-boolean-patterns e) ~
13037 ?> ?=(^ arms.e)
13087 ?> ?=(^ arms.e)
@@ -13171,6 +13221,28 @@
13171 ?: (dg-direct-source val.i.ds 64) &
13221 ?: (dg-direct-source val.i.ds 64) &
13172 $(ds t.ds, fuel (dec fuel))
13222 $(ds t.ds, fuel (dec fuel))
13173::
13223::
13224+++ dg-prepared-source
13225+ |= [e=expr fuel=@ud]
13226+ ^- ?
13227+ ?: (dg-direct-source e fuel) &
13228+ ?: =(0 fuel) |
13229+ ?+ -.e |
13230+ %group $(e inner.e, fuel (dec fuel))
13231+ %gate $(e body.e, fuel (dec fuel))
13232+ %gate-wide $(e body.e, fuel (dec fuel))
13233+ %cast $(e val.e, fuel (dec fuel))
13234+ %body ?~(defs.e $(e final.e, fuel (dec fuel)) |)
13235+ %tuple &
13236+ ==
13237+++ dg-prepared-candidate
13238+ |= [ds=(list def) fuel=@ud]
13239+ ^- ?
13240+ ?~ ds |
13241+ ?: =(0 fuel) |
13242+ ?. ?=(%value -.i.ds) $(ds t.ds, fuel (dec fuel))
13243+ ?: (dg-prepared-source val.i.ds 64) &
13244+ $(ds t.ds, fuel (dec fuel))
13245+::
13174++ dg-interface-safe
13246++ dg-interface-safe
13175 |= [env=ienv]
13247 |= [env=ienv]
13176 ^- ?
13248 ^- ?
@@ -13216,6 +13288,47 @@
13216 (dg-stage defs base base st ~ 64)
13288 (dg-stage defs base base st ~ 64)
13217 ::
13289 ::
13218 [& (transact)]
13290 [& (transact)]
13291+:: The caller supplies the trusted prepared prelude. This transaction is
13292+:: only report evidence; the ordinary module resolver does not publish it.
13293+++ dg-root-prepared
13294+ |= [at=path src=@t prepared=iprelude]
13295+ ^- (unit dgcommit)
13296+ ?: ?=([%ui %api *] at) ~
13297+ ?: ?=([%ui %stores *] at) ~
13298+ ?: (gth (met 3 src) 65.536) ~
13299+ =/ parsed (parse at src)
13300+ ?: ?=(%| -.parsed) ~
13301+ ?^ imports.p.parsed ~
13302+ ?. (module-scope-valid p.parsed values.prepared molds.prepared) ~
13303+ ?^ (duplicate-defs defs.p.parsed) ~
13304+ =/ defs=(list def) defs.p.parsed
13305+ ?: (gth (lent defs) 64) ~
13306+ ?: (lien (global-value-names defs) |=(n=term =(n %main))) ~
13307+ ?. (dg-prepared-candidate defs 64) ~
13308+ =/ local-molds=imolds (collect-simple-molds defs)
13309+ =/ globals=(list term) (weld values.prepared (global-value-names defs))
13310+ =/ iface=ifile iface.prepared
13311+ =/ prelude=(unit ifile) `iface
13312+ =/ resolution=iresolved
13313+ (resolve-groups defs local-molds globals ~ ~ ~ ~ ~ molds.prepared at prelude)
13314+ ?^ grouped.resolution ~
13315+ ?^ artifacts.resolution ~
13316+ =/ base=ienv env.resolution
13317+ =/ templates=ienv
13318+ (turn molds.iface |=(x=[name=term template=ischeme] [name.x template.x]))
13319+ =/ all-env=ienv (weld base (weld values.iface templates))
13320+ =/ free=(unit dgscan) (dg-env all-env ~ 32.768 ~)
13321+ ?~ free ~
13322+ ?^ ids.u.free ~
13323+ =/ all=(unit dgscan) (dg-all-env-ids all-env 32.768 ~)
13324+ ?~ all ~
13325+ =/ fresh=@ud (dg-next-id ids.u.all 0)
13326+ =/ st=istate *istate
13327+ =. st st(next fresh, defer `~, molds local-molds, globals globals, at at, reserved-molds molds.prepared, prelude prelude, top-molds (turn local-molds |=(m=[name=term body=shape] name.m)), in-mold |, jrec-fuel 256)
13328+ =/ checked-molds=(each imold-types @t) (module-mold-types local-molds st)
13329+ ?: ?=(%| -.checked-molds) ~
13330+ (dg-stage defs base base st ~ 64)
13331+::
13219++ dg-all-env-ids
13332++ dg-all-env-ids
13220 |= [env=ienv fuel=@ud ids=(list @ud)]
13333 |= [env=ienv fuel=@ud ids=(list @ud)]
13221 ^- (unit dgscan)
13334 ^- (unit dgscan)
tests/lib/jibb-deferred-prepared.hoonnew file+114
@@ -0,0 +1,114 @@
1+:: Prepared-prelude initializer recovery remains a partial report only.
2+/+ jibb
3+/* prelude %jibb /lib/jibb/prelude/jibb
4+/* internal %jibb /lib/jibb/internal/jibb
5+/* good %txt /tests/type-deferred-prepared/good/txt
6+/* tuple-only %txt /tests/type-deferred-prepared/tuple-only/txt
7+/* wrong-unit %txt /tests/type-deferred-prepared/wrong-unit/txt
8+/* wrong-draft %txt /tests/type-deferred-prepared/wrong-draft/txt
9+/* unrelated-tag %txt /tests/type-deferred-prepared/unrelated-tag/txt
10+/* mold-collision %txt /tests/type-deferred-prepared/mold-collision/txt
11+/* no-final-cast %txt /tests/type-deferred-prepared/no-final-cast/txt
12+/* no-prelude %txt /tests/type-deferred-prepared/no-prelude/txt
13+/* main-source %txt /tests/type-deferred-prepared/main/txt
14+/* imported %txt /tests/type-deferred-prepared/imported/txt
15+/* expected %txt /tests/type-deferred-prepared/expected/txt
16+/* expected-control %txt /tests/type-deferred-prepared/expected-control/txt
17+/* expected-tuple-only %txt /tests/type-deferred-prepared/expected-tuple-only/txt
18+|%
19+++ text
20+ |= lines=wain
21+ ^- @t
22+ (rap 3 (turn lines |=(line=@t (cat 3 line '\0a'))))
23+++ check-prepared
24+ |= [where=path source=wain valid=?]
25+ ^- tang
26+ ?~ source ~[leaf+"source fixture missing"]
27+ =/ src=@t (text source)
28+ =/ parsed (parse:jibb where src)
29+ ?: ?=(%| -.parsed) ~[leaf+"source does not parse"]
30+ =/ prepared=(unit iprelude:jibb) (prepare-prelude-with-internal:jibb prelude internal)
31+ ?~ prepared ~[leaf+"prelude unavailable"]
32+ =/ recovered=? ?=(^ (dg-root-prepared:jibb where src u.prepared))
33+ ?. =(valid recovered) ~[leaf+"prepared initializer transaction result changed"]
34+ ~
35+++ check-no-prelude
36+ ^- tang
37+ =/ at=path /ui/prepared/jibb
38+ =/ src=@t (text no-prelude)
39+ ?: ?=(^ (dg-root-source:jibb at src))
40+ ~[leaf+"no-prelude source transaction recovered tuple initializer"]
41+ =/ legacy=jfile-result:jibb
42+ (infer-jibb-file:jibb at src ~ ~ ~ ~[at] ~ ~ ~ ~)
43+ ?: ?=(%& -.legacy) ~[leaf+"no-prelude resolver published recovered tuple initializer"]
44+ ~
45+++ check-ordinary
46+ ^- tang
47+ =/ prepared=(unit iprelude:jibb) (prepare-prelude-with-internal:jibb prelude internal)
48+ ?~ prepared ~[leaf+"prelude unavailable"]
49+ =/ at=path /ui/prepared/jibb
50+ =/ ordinary=jfile-result:jibb
51+ (infer-jibb-file:jibb at (text good) ~ ~ ~ ~[at] values.u.prepared molds.u.prepared ~ `iface.u.prepared)
52+ ?: ?=(%& -.ordinary) ~[leaf+"ordinary full-module path published recovered initializer"]
53+ ~
54+++ check-report
55+ |= [source=wain wanted=wain]
56+ ^- tang
57+ ?~ source ~[leaf+"report source fixture missing"]
58+ ?~ wanted ~[leaf+"expected report fixture missing"]
59+ =/ prepared=(unit iprelude:jibb) (prepare-prelude-with-internal:jibb prelude internal)
60+ ?~ prepared ~[leaf+"prelude unavailable"]
61+ =/ report=@t (golden-types-with-prepared-prelude:jibb /ui/prepared/jibb (text source) ~ ~ ~ prepared)
62+ =/ report-lines=wain (to-wain:format (cat 3 report '\0a'))
63+ ?~ report-lines ~[leaf+"prepared report is empty"]
64+ ?. =('partial inference; module not checked' i.report-lines)
65+ ~[leaf+"partial disclaimer changed"]
66+ ?. =(report-lines wanted) ~[leaf+"prepared report differs from exact recovered types"]
67+ ~
68+++ check-prepared-binding
69+ ^- tang
70+ =/ prepared=(unit iprelude:jibb) (prepare-prelude-with-internal:jibb prelude internal)
71+ ?~ prepared ~[leaf+"prelude unavailable"]
72+ =/ at=path /ui/prepared/jibb
73+ =/ src=@t (text good)
74+ =/ pre=(unit ifile:jibb) `iface.u.prepared
75+ =/ report
76+ |= [vals=(list term) ms=(list term) p=(unit ifile:jibb) prep=(unit iprelude:jibb)]
77+ ^- @t
78+ (golden-types-in-context-core:jibb at src ~ ~ ~ vals ms p prep)
79+ =/ vals=(list term) values.u.prepared
80+ =/ ms=(list term) molds.u.prepared
81+ ?: =((report vals ms pre prepared) (report vals ms pre ~))
82+ ~[leaf+"exact prepared binding did not recover the initializer"]
83+ ?. =((report ~ ms pre prepared) (report ~ ms pre ~))
84+ ~[leaf+"mismatched value inventory reached prepared recovery"]
85+ ?. =((report vals ~ pre prepared) (report vals ~ pre ~))
86+ ~[leaf+"mismatched mold inventory reached prepared recovery"]
87+ ?. =((report vals ms ~ prepared) (report vals ms ~ ~))
88+ ~[leaf+"mismatched prelude interface reached prepared recovery"]
89+ ~
90+++ test-prepared
91+ ^- tang
92+ =/ at=path /ui/prepared/jibb
93+ =/ checks=(list tang)
94+ :~ (check-prepared at good &)
95+ (check-prepared at tuple-only &)
96+ (check-prepared at no-prelude &)
97+ (check-prepared at wrong-unit |)
98+ (check-prepared at wrong-draft |)
99+ (check-prepared at unrelated-tag |)
100+ (check-prepared at mold-collision |)
101+ (check-prepared at no-final-cast |)
102+ (check-prepared at main-source |)
103+ (check-prepared at imported |)
104+ (check-prepared /ui/api/prepared/jibb good |)
105+ (check-prepared /ui/stores/prepared/jibb good |)
106+ check-no-prelude
107+ check-ordinary
108+ check-prepared-binding
109+ (check-report good expected)
110+ (check-report tuple-only expected-tuple-only)
111+ (check-report no-final-cast expected-control)
112+ ==
113+ (zing checks)
114+--
tests/type-deferred-prepared/expected-control.txtnew file+7
@@ -0,0 +1,7 @@
1+partial inference; module not checked
2++$ model: not checked
3++$ message: cases proven disjoint; mold not checked
4+++ initial: `~` needs context in partial inference
5+++ send: $-($-(@t A) $-(@t A))
6+++ first: call constraint is not supported by partial inference
7+++ fixed: name is not available to partial inference
tests/type-deferred-prepared/expected-tuple-only.txtnew file+4
@@ -0,0 +1,4 @@
1+partial inference; module not checked
2++$ model: not checked
3+++ final: $-((list @t) [(list @t) [@t (unit @t)]])
4+++ initial: $-((list @t) [(list @t) [@t (unit @t)]])
tests/type-deferred-prepared/expected.txtnew file+8
@@ -0,0 +1,8 @@
1+partial inference; module not checked
2++$ model: not checked
3++$ message: cases proven disjoint; mold not checked
4+++ final: $-((list @t) [(list @t) [@t (unit @t)]])
5+++ initial: $-((list @t) [(list @t) [@t (unit @t)]])
6+++ send: $-($-(@t A) $-(@t A))
7+++ first: $-(@t message)
8+++ fixed: $-(@t message)
tests/type-deferred-prepared/good.txtnew file+9
@@ -0,0 +1,9 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
6+++ initial |= xs=(list @t) [xs "" ~]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%got)
9+++ fixed ^- $-(@t message) first
tests/type-deferred-prepared/imported.txtnew file+11
@@ -0,0 +1,11 @@
1+/= other /ui/other
2+
3++$ model [xs=(list @t) draft=@t error=(unit @t)]
4++$ message
5+ [%got value=@t]
6+ [%other value=@p]
7+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
8+++ initial |= xs=(list @t) [xs "" ~]
9+++ send |= f=$-(@t A) f
10+++ first (send |=%got)
11+++ fixed ^- $-(@t message) first
tests/type-deferred-prepared/main.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
6+++ initial |= xs=(list @t) [xs "" ~]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%got)
9+++ fixed ^- $-(@t message) first
10+++ main initial
tests/type-deferred-prepared/mold-collision.txtnew file+9
@@ -0,0 +1,9 @@
1++$ list [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
6+++ initial |= xs=(list @t) [xs "" ~]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%got)
9+++ fixed ^- $-(@t message) first
tests/type-deferred-prepared/no-final-cast.txtnew file+8
@@ -0,0 +1,8 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ initial |= xs=(list @t) [xs "" ~]
6+++ send |= f=$-(@t A) f
7+++ first (send |=%got)
8+++ fixed ^- $-(@t message) first
tests/type-deferred-prepared/no-prelude.txtnew file+9
@@ -0,0 +1,9 @@
1++$ maybe
2+ %none
3+ [%some value=@t]
4++$ model [draft=@t error=maybe]
5+++ final ^- $-(@t [@t maybe]) initial
6+++ initial |= draft=@t [draft %none]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%some)
9+++ fixed ^- $-(@t maybe) first
tests/type-deferred-prepared/tuple-only.txtnew file+3
@@ -0,0 +1,3 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
3+++ initial |= xs=(list @t) [xs "" ~]
tests/type-deferred-prepared/unrelated-tag.txtnew file+11
@@ -0,0 +1,11 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
6+++ initial |= xs=(list @t) [xs "" ~]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%got)
9+++ fixed ^- $-(@t message) first
10+
11+++ unresolved |= x=@t %dangling
tests/type-deferred-prepared/wrong-draft.txtnew file+9
@@ -0,0 +1,9 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
6+++ initial |= xs=(list @t) [xs ~zod ~]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%got)
9+++ fixed ^- $-(@t message) first
tests/type-deferred-prepared/wrong-unit.txtnew file+9
@@ -0,0 +1,9 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ [%got value=@t]
4+ [%other value=@p]
5+++ final ^- $-((list @t) [(list @t) @t (unit @t)]) initial
6+++ initial |= xs=(list @t) [xs "" %absent]
7+++ send |= f=$-(@t A) f
8+++ first (send |=%got)
9+++ fixed ^- $-(@t message) first
tools/testdata/ship-selftest+6
@@ -334,6 +334,7 @@ def generator_checks(tmp):
334 'tests/lib/jibb-deferred.hoon',
334 'tests/lib/jibb-deferred.hoon',
335 'tests/lib/jibb-deferred-resolver.hoon',
335 'tests/lib/jibb-deferred-resolver.hoon',
336 'tests/lib/jibb-deferred-context.hoon',
336 'tests/lib/jibb-deferred-context.hoon',
337+ 'tests/lib/jibb-deferred-prepared.hoon',
337 'tests/lib/jibb-cell-branch.hoon'}
338 'tests/lib/jibb-cell-branch.hoon'}
338 <= normal_tests, sorted(normal_tests))
339 <= normal_tests, sorted(normal_tests))
339 check('generic recursion source and golden are assembled',
340 check('generic recursion source and golden are assembled',
@@ -383,6 +384,11 @@ def generator_checks(tmp):
383 {f'tests/type-deferred-context/{name}.txt' for name in (
384 {f'tests/type-deferred-context/{name}.txt' for name in (
384 'rich', 'plain', 'simple', 'missing', 'wrong', 'duplicate',
385 'rich', 'plain', 'simple', 'missing', 'wrong', 'duplicate',
385 'dangling', 'collision-early', 'collision-late', 'report')} <= set(normal.files))
386 'dangling', 'collision-early', 'collision-late', 'report')} <= set(normal.files))
387+ check('prepared initializer sources and exact reports are assembled',
388+ {f'tests/type-deferred-prepared/{name}.txt' for name in (
389+ 'good', 'tuple-only', 'wrong-unit', 'wrong-draft', 'unrelated-tag',
390+ 'mold-collision', 'no-final-cast', 'no-prelude', 'main',
391+ 'imported', 'expected', 'expected-control', 'expected-tuple-only')} <= set(normal.files))
386 check('cell branch sources are assembled',
392 check('cell branch sources are assembled',
387 {'tests/type-cell-branch/good.txt', 'tests/type-cell-branch/bad.txt'}
393 {'tests/type-cell-branch/good.txt', 'tests/type-cell-branch/bad.txt'}
388 <= set(normal.files))
394 <= set(normal.files))
tools/type-deferred-prepared-testnew file+49
@@ -0,0 +1,49 @@
1+#!/usr/bin/env python3
2+"""Evaluate prepared-prelude initializer recovery and report guards."""
3+from pathlib import Path
4+import argparse, subprocess, sys, tempfile
5+root = Path(__file__).resolve().parent.parent
6+p = argparse.ArgumentParser(description=__doc__)
7+p.add_argument('--lib', default=str(root/'jibb-dev/lib/jibb.hoon'))
8+p.add_argument('--hoon', default=str(root/'tools/hoon'))
9+a = p.parse_args()
10+core = (root / 'tests/lib/jibb-deferred-prepared.hoon').read_text()
11+core = core[core.index('\n|%\n') + 1:]
12+names = ['good', 'tuple-only', 'wrong-unit', 'wrong-draft', 'unrelated-tag', 'mold-collision',
13+ 'no-final-cast', 'no-prelude', 'main', 'imported', 'expected', 'expected-control',
14+ 'expected-tuple-only']
15+bindings = ''.join('=/ '+('main-source' if n == 'main' else n)+'=wain (to-wain:format '+n+'-text)\n' for n in names)
16+at = '/ui/prepared/jibb'
17+checks = ['(check-prepared:suite %s %s %s)' % (where, source, valid)
18+ for where, source, valid in (
19+ (at, 'good', '&'), (at, 'tuple-only', '&'), (at, 'no-prelude', '&'),
20+ (at, 'wrong-unit', '|'), (at, 'wrong-draft', '|'),
21+ (at, 'unrelated-tag', '|'), (at, 'mold-collision', '|'),
22+ (at, 'no-final-cast', '|'), (at, 'main-source', '|'),
23+ (at, 'imported', '|'),
24+ ('/ui/api/prepared/jibb', 'good', '|'),
25+ ('/ui/stores/prepared/jibb', 'good', '|'))]
26+checks += ['check-no-prelude:suite', 'check-ordinary:suite', 'check-prepared-binding:suite',
27+ '(check-report:suite good expected)', '(check-report:suite tuple-only expected-tuple-only)',
28+ '(check-report:suite no-final-cast expected-control)']
29+with tempfile.TemporaryDirectory(prefix='jibb-deferred-prepared-') as d:
30+ f = Path(d) / 'report.hoon'
31+ for check in checks:
32+ program = ('=/ jibb .\n' + bindings + '=/ suite\n' + core +
33+ "\n^- @t\n=/ checked=tang " + check + "\n?~ checked 'prepared deferred inference guards passed'\n(crip \"{<checked>}\")\n")
34+ f.write_text(program)
35+ cmd = [a.hoon, '--lib', a.lib, '--raw', '-f', str(f),
36+ '--cord', 'prelude='+str(root/'jibb-dev/lib/jibb/prelude.jibb'),
37+ '--cord', 'internal='+str(root/'jibb-dev/lib/jibb/internal.jibb')]
38+ for n in names:
39+ fixture = root/'tests/type-deferred-prepared'/(n+'.txt')
40+ if not fixture.is_file() or fixture.stat().st_size == 0:
41+ sys.exit('missing or empty fixture: '+str(fixture))
42+ cmd.extend(['--cord', n+'-text='+str(fixture)])
43+ got = subprocess.run(cmd, stdout=subprocess.PIPE)
44+ if got.returncode:
45+ sys.exit(got.returncode)
46+ if got.stdout != b'prepared deferred inference guards passed\n':
47+ sys.stderr.write(got.stdout.decode(errors='replace'))
48+ sys.exit(1)
49+print('prepared deferred inference guards passed')