on master help sign in
Recover direct program initializer context
26bf7a7iko
README.md+1−1
@@ -44,7 +44,7 @@ tools/hoon --raw --cord src=tests/golden/foo/source.jibb 'tree:(golden /a/b/jibb
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-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.
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 focused `tools/type-program-main-test` checks the narrow closed, subscription-free `main` slice and its shared fake-ship fixture; it does not run an island or claim runtime watchability.
47+The focused `tools/type-program-main-test` checks the narrow closed, subscription-free `main` slice and its shared fake-ship fixture. `tools/type-program-init-test` checks transactional initializer recovery for a synthetic direct program, including exact exported and imported types and rejection boundaries. Neither runs an island or claims runtime watchability.
48
48
49### The doc's examples
49### The doc's examples
50
50
docs/compiler.md+2
@@ -130,6 +130,8 @@ A two-item tuple with an explicit term, null or loobean head can receive payload
130
130
131A full ordinary module may export a narrow checked program `main` only as a direct, unqualified `(program init update view subs)` call with four simple wing arguments, modulo transparent grouping. The canonical prepared prelude must supply both the `program` value and mold. The ordinary source-backed program fit and all normal mold, value and request-graph checks complete first. The inferred `main` must be closed and invariantly match an instantiated `program` mold from that prelude. The initializer must have a closed gate scheme; its data and model contain no open variables and share the existing 256-node gate-free budget, with `%yes` required for both. The named subscription gate must syntactically return null through transparent casts, groups and definition-free bodies. Arbitrary or aliased mains, API/store kinds, gates or unknowns in data/model, and nonempty subscriptions fail closed. This retains source and graph evidence and permits ordinary downstream imports; it neither executes the program nor proves runtime watchability.
131A full ordinary module may export a narrow checked program `main` only as a direct, unqualified `(program init update view subs)` call with four simple wing arguments, modulo transparent grouping. The canonical prepared prelude must supply both the `program` value and mold. The ordinary source-backed program fit and all normal mold, value and request-graph checks complete first. The inferred `main` must be closed and invariantly match an instantiated `program` mold from that prelude. The initializer must have a closed gate scheme; its data and model contain no open variables and share the existing 256-node gate-free budget, with `%yes` required for both. The named subscription gate must syntactically return null through transparent casts, groups and definition-free bodies. Arbitrary or aliased mains, API/store kinds, gates or unknowns in data/model, and nonempty subscriptions fail closed. This retains source and graph evidence and permits ordinary downstream imports; it neither executes the program nor proves runtime watchability.
132
132
133+When only that program's initializer and `main` are unresolved, a bounded transactional retry can derive the initializer's expected gate from the resolved update, view and subscription components. It instantiates all schemes above the greatest variable ID in the module and prelude, reuses the source-backed positional fit and stable replay, and leaves only the initializer's data variable open. The named initializer must be a direct gate whose transparent body is a tuple ending in null. Its own sample fixes data; ordinary inference, product and whole-gate fits, pending-tag and finalization checks, and a fresh ordinary `main` inference must all succeed before the ordinary kind and graph checks publish anything. Aliases, non-main libraries, simultaneous unresolved subscriptions, nonempty subscriptions and unrelated pending tags decline.
134+
133Each case's canonical API identity and source-derived schema travel across imports in a nonrecursive graph certificate containing the exact source bundle, prelude, reserved scope and trusted reader results. Cached interfaces must match those inputs and cannot hide an active ancestor; unknown legacy entries are rebuilt from their unique supplied source. Request-bearing closures are limited to 256 paths and requests. Closed gate samples can also fit when an unnamed input slot corresponds to a named one, provided products are identical and nested value faces and ambiguous cell tails remain intact. This is type inference only: request lowering, runtime schema validation and value watchability proofs are not implemented.
135Each case's canonical API identity and source-derived schema travel across imports in a nonrecursive graph certificate containing the exact source bundle, prelude, reserved scope and trusted reader results. Cached interfaces must match those inputs and cannot hide an active ancestor; unknown legacy entries are rebuilt from their unique supplied source. Request-bearing closures are limited to 256 paths and requests. Closed gate samples can also fit when an unnamed input slot corresponds to a named one, provided products are identical and nested value faces and ambiguous cell tails remain intact. This is type inference only: request lowering, runtime schema validation and value watchability proofs are not implemented.
134
136
135`+golden-types-with-prelude` accepts case-local Jibb module sources alongside `/sur` and mark results and the vendored prelude source. It resolves reachable ordinary library modules in dependency order, caching completed interfaces per invocation and exporting supported closed value schemes, direct generic unions, and simple or nonrecursive generic mold aliases whose bodies the fragment supports. It detects missing sources and cycles and rejects a dependency if its interface cannot be inferred by the fragment. Qualified wings can also read nested fields of an imported value, instantiating that value’s scheme independently at each use; missing, ambiguous and non-record fields remain unsupported.
137`+golden-types-with-prelude` accepts case-local Jibb module sources alongside `/sur` and mark results and the vendored prelude source. It resolves reachable ordinary library modules in dependency order, caching completed interfaces per invocation and exporting supported closed value schemes, direct generic unions, and simple or nonrecursive generic mold aliases whose bodies the fragment supports. It detects missing sources and cycles and rejects a dependency if its interface cannot be inferred by the fragment. Qualified wings can also read nested fields of an imported value, instantiating that value’s scheme independently at each use; missing, ambiguous and non-record fields remain unsupported.
docs/development.md+2
@@ -92,6 +92,7 @@ git clone https://github.com/urbit/tools /root/src/tools
92| `tools/type-todo-api-test` | Exercises the actual todo API through the real Hoon readers and partial checker |
92| `tools/type-todo-api-test` | Exercises the actual todo API through the real Hoon readers and partial checker |
93| `tools/type-direct-gate-test` | Checks a synthetic source-backed program report and direct gate provenance under eval and on the ship |
93| `tools/type-direct-gate-test` | Checks a synthetic source-backed program report and direct gate provenance under eval and on the ship |
94| `tools/type-program-main-test` | Checks the narrow closed subscription-free program-main interface, downstream import and rejection guards under eval and on the ship |
94| `tools/type-program-main-test` | Checks the narrow closed subscription-free program-main interface, downstream import and rejection guards under eval and on the ship |
95+| `tools/type-program-init-test` | Checks transactional direct-program initializer recovery, exact exported/imported types and fail-closed boundaries under eval and on the ship |
95| `tools/type-closed-gate-guards-test` | Checks closed gate sample labels and face uncertainty under eval and on the ship |
96| `tools/type-closed-gate-guards-test` | Checks closed gate sample labels and face uncertainty under eval and on the ship |
96| `tools/type-constructor-fit-guards-test` | Checks constructor-case uncertainty and known mismatches under eval and on the ship |
97| `tools/type-constructor-fit-guards-test` | Checks constructor-case uncertainty and known mismatches under eval and on the ship |
97| `tools/type-nested-union-guards-test` | Checks nested tagged-union case selection and uncertainty under eval and on the ship |
98| `tools/type-nested-union-guards-test` | Checks nested tagged-union case selection and uncertainty under eval and on the ship |
@@ -141,6 +142,7 @@ tools/type-todo-partial-test # unchanged todo partial report and reader fa
141tools/type-todo-api-test # real todo API partial inference and reader guards pass
142tools/type-todo-api-test # real todo API partial inference and reader guards pass
142tools/type-direct-gate-test # direct gate source and provenance guards pass
143tools/type-direct-gate-test # direct gate source and provenance guards pass
143tools/type-program-main-test # closed program-main interface and rejection guards pass
144tools/type-program-main-test # closed program-main interface and rejection guards pass
145+tools/type-program-init-test # transactional direct-program initializer context guards pass
144tools/type-generic-recursion-test # source-backed recursive identities and provenance
146tools/type-generic-recursion-test # source-backed recursive identities and provenance
145tools/type-generic-construction-test # source-backed recursive construction and bounds
147tools/type-generic-construction-test # source-backed recursive construction and bounds
146tools/type-generic-pattern-test # source-backed recursive patterns and bounds
148tools/type-generic-pattern-test # source-backed recursive patterns and bounds
docs/status.md+5−3
@@ -43,7 +43,7 @@ A separate source-backed analysis can prove one named mold gate-free, report a d
43
43
44The partial checker can also match a directly named, checked root gate against a generic gate sample in a direct, unshadowed source-backed prelude call. It uses the written two-slot sample layouts to preserve nested record faces, then requires the complete call samples to be closed and tag-free and repeats the fit under the final substitution. The proof falls back to existing inference for unavailable or ambiguous source layouts, local or dynamic gates, aliases, recursive placeholders and open generic caller types. It preserves written-capital checks and projection evidence; it does not add `program`, check islands or prove request watchability. Prepared prelude source and interface remain a trusted pair.
44The partial checker can also match a directly named, checked root gate against a generic gate sample in a direct, unshadowed source-backed prelude call. It uses the written two-slot sample layouts to preserve nested record faces, then requires the complete call samples to be closed and tag-free and repeats the fit under the final substitution. The proof falls back to existing inference for unavailable or ambiguous source layouts, local or dynamic gates, aliases, recursive placeholders and open generic caller types. It preserves written-capital checks and projection evidence; it does not add `program`, check islands or prove request watchability. Prepared prelude source and interface remain a trusted pair.
45
45
46−A narrow full-module path now checks direct four-wing `(program init update view subs)` definitions named `main`. It requires the canonical prepared `program` value and mold, reuses ordinary source-backed program fitting, and publishes only after all ordinary module and request-graph checks. The inferred `main` must be closed and invariantly match the instantiated `program` mold. Initializer data and model must be closed and gate-free with `%yes` verdicts inside a shared 256-node budget, and `subs` must syntactically return null through transparent forms. Aliases, arbitrary mains, API/store kinds, gate-bearing or unknown data/model, mismatched programs and nonempty subscriptions remain rejected. Checked interfaces retain source evidence and support ordinary downstream imports; no program execution or runtime watchability is claimed.
46+A narrow full-module path now checks direct four-wing `(program init update view subs)` definitions named `main`. It requires the canonical prepared `program` value and mold, reuses ordinary source-backed program fitting, and publishes only after all ordinary module and request-graph checks. The inferred `main` must be closed and invariantly match the instantiated `program` mold. Initializer data and model must be closed and gate-free with `%yes` verdicts inside a shared 256-node budget, and `subs` must syntactically return null through transparent forms. Aliases, arbitrary mains, API/store kinds, gate-bearing or unknown data/model, mismatched programs and nonempty subscriptions remain rejected. Checked interfaces retain source evidence and support ordinary downstream imports; no program execution or runtime watchability is claimed. A transactional extension can recover a direct initializer whose transparent tuple body ends in null when update, view and subs are already resolved. It derives the expected gate through the ordinary positional program fit with fresh IDs and stable replay, then re-infers the actual initializer and `main` under all ordinary finalization and kind checks. Non-main libraries, aliases, nonempty or simultaneously unresolved subscriptions, and unrelated pending tags remain rejected.
47
47
48The API path analyzer can retain its source, complete prepared prelude, reader results and resolved dependencies as evidence, and classify a unique declaration as watchable, not watchable or unknown. It does not yet prove the provenance of request values or check island subscriptions. Prepared artifacts and reader results remain trusted host inputs.
48The API path analyzer can retain its source, complete prepared prelude, reader results and resolved dependencies as evidence, and classify a unique declaration as watchable, not watchable or unknown. It does not yet prove the provenance of request values or check island subscriptions. Prepared artifacts and reader results remain trusted host inputs.
49
49
@@ -96,7 +96,7 @@ What the plan asks for, and where it is:
96Besides the plan's list:
96Besides the plan's list:
97
97
98- 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.
98- 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.
99−- The 659-case corpus passed under `urbit eval` in 90.4 s while other checks were running. The fake ship passed all 707 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 86.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.
99+- The 659-case corpus passed under `urbit eval` in 92.8 s while other checks were running. The fake ship passed all 708 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 93.1 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.
100- `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.
100- `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.
101- 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.
101- 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.
102- 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).
102- 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).
@@ -211,7 +211,8 @@ Besides the plan's list:
211| b5cdc80 | 2026-10-31 | Preserve full-module overlap source evidence |
211| b5cdc80 | 2026-10-31 | Preserve full-module overlap source evidence |
212| ab6fdc1 | 2026-10-31 | Add source-backed text conversion wrappers |
212| ab6fdc1 | 2026-10-31 | Add source-backed text conversion wrappers |
213| aa277c9 | 2026-10-31 | Recover prepared tuple initializers in partial reports |
213| aa277c9 | 2026-10-31 | Recover prepared tuple initializers in partial reports |
214−| This change | 2026-10-31 | Check narrow closed subscription-free program mains |
214+| b4703e7 | 2026-11-01 | Check narrow closed subscription-free program mains |
215+| This change | 2026-11-01 | Recover narrow direct-program initializer contexts |
215
216
216## Checking it
217## Checking it
217
218
@@ -250,6 +251,7 @@ tools/type-ask-guards-test # ask source and bootstrap guards
250tools/type-proj-guards-test # projection evidence and scope guards
251tools/type-proj-guards-test # projection evidence and scope guards
251tools/type-module-scope-test # module and prelude scope fixture
252tools/type-module-scope-test # module and prelude scope fixture
252tools/type-program-main-test # closed program-main interface and rejection guards
253tools/type-program-main-test # closed program-main interface and rejection guards
254+tools/type-program-init-test # transactional direct-program initializer context guards
253tools/hoon check-spans-test # prints <<>> when the span checker works
255tools/hoon check-spans-test # prints <<>> when the span checker works
254tools/testdata/selftest # the tools themselves
256tools/testdata/selftest # the tools themselves
255tools/doc-blocks docs/spec # the doc's examples are golden cases
257tools/doc-blocks docs/spec # the doc's examples are golden cases
jibb-dev/lib/jibb.hoon+182−17
@@ -10237,6 +10237,29 @@
10237 (resolve-groups-core ds molds globals externals surs mark-externals marks jimports reserved-molds at prelude ~)
10237 (resolve-groups-core ds molds globals externals surs mark-externals marks jimports reserved-molds at prelude ~)
10238::
10238::
10239
10239
10240++$ iadded-definition
10241+ [env=ienv checked=(map term def) artifacts=(list iwidth-definition)]
10242+++ add-supported-result
10243+ |= [d=def result=iresult initial=istate env=ienv checked=(map term def) artifacts=(list iwidth-definition)]
10244+ ^- (unit iadded-definition)
10245+ ?> ?=(%value -.d)
10246+ ?: ?=(%| -.result) ~
10247+ =. state.p.result (promote-restricted-numbers state.p.result env)
10248+ =. state.p.result (default-hole-numbers holes.state.p.result holes.initial state.p.result env !(itype-has-gate (itype-normalize typ.p.result sub.state.p.result)))
10249+ ?^ (unresolved-hole holes.state.p.result holes.initial state.p.result) ~
10250+ ?: (constrained-capitals caps.state.p.result sub.state.p.result) ~
10251+ =/ typ=itype (default-decimals (itype-normalize typ.p.result sub.state.p.result))
10252+ ?: |((pending-tags tags.state.p.result sub.state.p.result) (itype-has-tag typ)) ~
10253+ ?: (unsupported-atom-vars typ caps.state.p.result binders.state.p.result sub.state.p.result) ~
10254+ =/ vars=(list @ud) (unique-type-vars (itype-vars typ))
10255+ ?: (gth (lent vars) 26) ~
10256+ =/ finalized=(unit (list iwprojection))
10257+ (width-finalize projections.state.p.result sub.state.p.result vars)
10258+ ?~ finalized ~
10259+ =? artifacts ?=(^ u.finalized)
10260+ [[name.d val.d typ sub.state.p.result (flop u.finalized)] artifacts]
10261+ =? checked |(?=(%gate -.val.d) ?=(%gate-wide -.val.d)) (~(put by checked) name.d d)
10262+ `[[[name.d [typ vars]] env] checked artifacts]
10240++ add-supported-defs-core
10263++ add-supported-defs-core
10241 |= [ds=(list def) all-defs=(list def) checked=(map term def) heads=(unit igate-prelude-evidence) env=ienv molds=imolds globals=(list term) externals=iexternals surs=(list term) mark-externals=imark-externals marks=(list term) jimports=ijimports reserved-molds=(list term) at=path prelude=(unit ifile) artifacts=(list iwidth-definition) index=(unit [at=path source=@t prelude=ifile shapes=(map term shape)])]
10264 |= [ds=(list def) all-defs=(list def) checked=(map term def) heads=(unit igate-prelude-evidence) env=ienv molds=imolds globals=(list term) externals=iexternals surs=(list term) mark-externals=imark-externals marks=(list term) jimports=ijimports reserved-molds=(list term) at=path prelude=(unit ifile) artifacts=(list iwidth-definition) index=(unit [at=path source=@t prelude=ifile shapes=(map term shape)])]
10242 ^- [env=ienv artifacts=(list iwidth-definition)]
10265 ^- [env=ienv artifacts=(list iwidth-definition)]
@@ -10253,23 +10276,10 @@
10253 =. initial (reserve-def-caps val.d initial)
10276 =. initial (reserve-def-caps val.d initial)
10254 =/ result=iresult (infer-fragment val.d env initial)
10277 =/ result=iresult (infer-fragment val.d env initial)
10255 =? result ?=(%| -.result) (infer-recursive-gate d env initial)
10278 =? result ?=(%| -.result) (infer-recursive-gate d env initial)
10256− ?: ?=(%| -.result) $(ds t.ds)
10279+ =/ added=(unit iadded-definition)
10257− =. state.p.result (promote-restricted-numbers state.p.result env)
10280+ (add-supported-result d result initial env checked artifacts)
10258− =. state.p.result (default-hole-numbers holes.state.p.result holes.initial state.p.result env !(itype-has-gate (itype-normalize typ.p.result sub.state.p.result)))
10259− ?^ (unresolved-hole holes.state.p.result holes.initial state.p.result) $(ds t.ds)
10260− ?: (constrained-capitals caps.state.p.result sub.state.p.result) $(ds t.ds)
10261− =/ typ=itype (default-decimals (itype-normalize typ.p.result sub.state.p.result))
10262− ?: |((pending-tags tags.state.p.result sub.state.p.result) (itype-has-tag typ)) $(ds t.ds)
10263− ?: (unsupported-atom-vars typ caps.state.p.result binders.state.p.result sub.state.p.result) $(ds t.ds)
10264− =/ vars=(list @ud) (unique-type-vars (itype-vars typ))
10265− ?: (gth (lent vars) 26) $(ds t.ds)
10266− =/ finalized=(unit (list iwprojection))
10267− (width-finalize projections.state.p.result sub.state.p.result vars)
10268− ?~ finalized $(ds t.ds)
10281+ ?~ added $(ds t.ds)
10269− =? artifacts ?=(^ u.finalized)
10282+ $(ds t.ds, env env.u.added, checked checked.u.added, artifacts artifacts.u.added)
10270− [[name.d val.d typ sub.state.p.result (flop u.finalized)] artifacts]
10271− =? checked |(?=(%gate -.val.d) ?=(%gate-wide -.val.d)) (~(put by checked) name.d d)
10272− $(ds t.ds, env [[name.d [typ vars]] env], checked checked)
10273::
10283::
10274++ resolve-groups-core
10284++ resolve-groups-core
10275 |= [ds=(list def) molds=imolds globals=(list term) externals=iexternals surs=(list term) mark-externals=imark-externals marks=(list term) jimports=ijimports reserved-molds=(list term) at=path prelude=(unit ifile) index=(unit [at=path source=@t prelude=ifile shapes=(map term shape)])]
10285 |= [ds=(list def) molds=imolds globals=(list term) externals=iexternals surs=(list term) mark-externals=imark-externals marks=(list term) jimports=ijimports reserved-molds=(list term) at=path prelude=(unit ifile) index=(unit [at=path source=@t prelude=ifile shapes=(map term shape)])]
@@ -12466,6 +12476,19 @@
12466 ?. ?=([@ ~] names.e) ~
12476 ?. ?=([@ ~] names.e) ~
12467 `i.names.e
12477 `i.names.e
12468::
12478::
12479+++ program-main-args
12480+ |= d=def
12481+ ^- (unit (list expr))
12482+ ?. ?=(%value -.d) ~
12483+ |-
12484+ ?: ?=(%group -.val.d) $(val.d inner.val.d)
12485+ ?. ?=(%call -.val.d) ~
12486+ =/ head=(unit term) (program-main-wing head.val.d)
12487+ ?~ head ~
12488+ ?. =(%program u.head) ~
12489+ ?. ?=([* * * * ~] args.val.d) ~
12490+ `args.val.d
12491+::
12469++ program-main-parts
12492++ program-main-parts
12470 |= d=def
12493 |= d=def
12471 ^- (unit [init=term update=term view=term subs=term])
12494 ^- (unit [init=term update=term view=term subs=term])
@@ -12510,6 +12533,141 @@
12510 * |
12533 * |
12511 ==
12534 ==
12512::
12535::
12536+++ program-transparent
12537+ |= e=expr
12538+ ^- expr
12539+ ?- -.e
12540+ %group $(e inner.e)
12541+ %cast $(e val.e)
12542+ %body ?~(defs.e $(e final.e) e)
12543+ * e
12544+ ==
12545+++ program-init-tuple-null
12546+ |= d=def
12547+ ^- ?
12548+ ?. ?=(%value -.d) |
12549+ ?. |(?=(%gate -.val.d) ?=(%gate-wide -.val.d)) |
12550+ =/ body=expr
12551+ ?- -.val.d
12552+ %gate body.val.d
12553+ %gate-wide body.val.d
12554+ * !!
12555+ ==
12556+ =. body (program-transparent body)
12557+ ?. ?=(%tuple -.body) |
12558+ ?~ items.body |
12559+ (program-empty-null val:(rear items.body))
12560+::
12561+:: Recover only the initializer of an already recognized direct program main.
12562+:: The derived call is evidence for an ordinary init/main retry, never an
12563+:: interface to publish on its own. Any failure returns the original resolution.
12564+++ program-init-context
12565+ |= [main=def parts=[init=term update=term view=term subs=term] ds=(list def) resolution=iresolved initial=istate]
12566+ ^- (unit iresolved)
12567+ =/ env=ienv env.resolution
12568+ ?^ (ienv-lookup %main env) ~
12569+ ?^ (ienv-lookup init.parts env) ~
12570+ =/ update=(unit ischeme) (ienv-lookup update.parts env)
12571+ =/ view=(unit ischeme) (ienv-lookup view.parts env)
12572+ =/ subs=(unit ischeme) (ienv-lookup subs.parts env)
12573+ ?~ update ~
12574+ ?~ view ~
12575+ ?~ subs ~
12576+ =/ inits=(list def)
12577+ (skim ds |=(d=def &(?=(%value -.d) =(init.parts name.d))))
12578+ ?. ?=([* ~] inits) ~
12579+ =/ init-def=def i.inits
12580+ ?> ?=(%value -.init-def)
12581+ ?. (program-init-tuple-null init-def) ~
12582+ =/ args=(unit (list expr)) (program-main-args main)
12583+ ?~ args ~
12584+ ?~ prelude.initial ~
12585+ =/ program=(unit ischeme) (ienv-lookup %program values.u.prelude.initial)
12586+ ?~ program ~
12587+ =/ heads=(unit igate-prelude-evidence) (direct-prelude-evidence ds prelude.initial)
12588+ ?~ heads ~
12589+ =/ written=(unit def) (~(get by gates.u.heads) %program)
12590+ ?~ written ~
12591+ =/ written-sample=(unit sample) (direct-gate-sample u.written)
12592+ ?~ written-sample ~
12593+ ?. ?=(%cell -.u.written-sample) ~
12594+ ?~ items.u.written-sample ~
12595+ =/ checked=(map term def) (direct-checked-gates ds env)
12596+ =/ templates=ienv
12597+ (turn molds.u.prelude.initial |=(x=[name=term template=ischeme] [name.x template.x]))
12598+ =/ scanned=(unit dgscan)
12599+ (dg-all-env-ids (weld env (weld values.u.prelude.initial templates)) 32.768 ~)
12600+ ?~ scanned ~
12601+ =. next.initial (dg-next-id ids.u.scanned 0)
12602+ =/ instance=[typ=itype state=istate] (instantiate-scheme u.program initial)
12603+ ?. ?=(%fn -.typ.instance) ~
12604+ ?. ?=(%cell -.sample.typ.instance) ~
12605+ =/ expected-init=(unit itype)
12606+ (direct-slot-body hed.sample.typ.instance (direct-sample-name i.items.u.written-sample))
12607+ ?~ expected-init ~
12608+ ?. ?=(%fn -.u.expected-init) ~
12609+ ?. ?=(%var -.sample.u.expected-init) ~
12610+ =/ data=@ud id.sample.u.expected-init
12611+ =/ init-var=itype [%var next.state.instance]
12612+ =/ st=istate state.instance(next +(next.state.instance))
12613+ =/ up=[typ=itype state=istate] (instantiate-scheme u.update st)
12614+ =/ vw=[typ=itype state=istate] (instantiate-scheme u.view state.up)
12615+ =/ sb=[typ=itype state=istate] (instantiate-scheme u.subs state.vw)
12616+ =. st state.sb(gate-defs checked, head-evidence heads)
12617+ =/ actual=itype [%cell init-var [%cell typ.up [%cell typ.vw typ.sb]]]
12618+ =/ fit=ifit
12619+ (direct-positional-fit u.args items.u.written-sample actual sample.typ.instance env st sub.st next.st)
12620+ ?. ?=(%ok -.fit) ~
12621+ =/ actual-final=itype (itype-normalize actual sub.fit)
12622+ =/ expected-final=itype (itype-normalize sample.typ.instance sub.fit)
12623+ =/ open=(list @ud)
12624+ (unique-type-vars (weld (itype-vars actual-final) (itype-vars expected-final)))
12625+ ?. (levy open |=(n=@ud =(data n))) ~
12626+ ?: |((itype-has-tag actual-final) (itype-has-tag expected-final)) ~
12627+ =/ replay=ifit
12628+ (direct-positional-fit u.args items.u.written-sample actual sample.typ.instance env st sub.fit next.fit)
12629+ ?. ?=(%ok -.replay) ~
12630+ ?. &(=(sub.fit sub.replay) =(next.fit next.replay)) ~
12631+ =/ expected=itype (itype-normalize u.expected-init sub.fit)
12632+ ?. ?=(%fn -.expected) ~
12633+ =. st st(sub sub.fit, next next.fit)
12634+ =/ init-state=istate (reserve-def-caps val.init-def st)
12635+ =/ inferred=iresult (infer-fragment val.init-def env init-state)
12636+ =? inferred ?=(%| -.inferred) (infer-recursive-gate init-def env init-state)
12637+ ?: ?=(%| -.inferred) ~
12638+ ?. ?=(%fn -.typ.p.inferred) ~
12639+ =/ data-fit=ifit
12640+ (itype-fit sample.typ.p.inferred sample.expected sub.state.p.inferred next.state.p.inferred)
12641+ ?. ?=(%ok -.data-fit) ~
12642+ =/ closed=itype (itype-normalize expected sub.data-fit)
12643+ ?. ?=(%fn -.closed) ~
12644+ :: Resolve the ordinary tuple cast first, then check the complete gate.
12645+ :: General function fit remains unchanged; only this recovered candidate
12646+ :: receives the derived result context before its whole-type cast fit.
12647+ =/ product-fit=ifit
12648+ (itype-fit product.typ.p.inferred product.closed sub.data-fit next.data-fit)
12649+ ?. ?=(%ok -.product-fit) ~
12650+ =/ product=itype
12651+ (itype-merge-faces product.typ.p.inferred product.closed sub.product-fit)
12652+ =/ actual-cast=itype [%fn sample.typ.p.inferred product]
12653+ =/ cast=ifit
12654+ (itype-fit actual-cast closed sub.product-fit next.product-fit)
12655+ ?. ?=(%ok -.cast) ~
12656+ =/ merged=itype (itype-merge-faces actual-cast closed sub.cast)
12657+ =/ adjusted=iresult
12658+ [%& merged state.p.inferred(sub sub.cast, next next.cast)]
12659+ =/ added=(unit iadded-definition)
12660+ (add-supported-result init-def adjusted init-state env checked artifacts.resolution)
12661+ ?~ added ~
12662+ =/ recovered=(unit ischeme) (ienv-lookup init.parts env.u.added)
12663+ ?~ recovered ~
12664+ ?. ?=(~ vars.u.recovered) ~
12665+ ?. ?=(~ (itype-vars typ.u.recovered)) ~
12666+ =/ completed=[env=ienv artifacts=(list iwidth-definition)]
12667+ (add-supported-defs-core ~[main] ds checked.u.added heads env.u.added molds.initial globals.initial externals.initial surs.initial mark-externals.initial marks.initial jimports.initial reserved-molds.initial at.initial prelude.initial artifacts.u.added grec-index.initial)
12668+ ?~ (ienv-lookup %main env.completed) ~
12669+ `[env.completed grouped.resolution artifacts.completed]
12670+::
12513++ program-main-closed
12671++ program-main-closed
12514 |= [parts=[init=term update=term view=term subs=term] ds=(list def) env=ienv prelude=(unit ifile)]
12672 |= [parts=[init=term update=term view=term subs=term] ds=(list def) env=ienv prelude=(unit ifile)]
12515 ^- ?
12673 ^- ?
@@ -12627,6 +12785,13 @@
12627 (resolve-groups defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude)
12785 (resolve-groups defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude)
12628 (resolve-groups-core defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude index)
12786 (resolve-groups-core defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude index)
12629 =/ env=ienv env.resolution
12787 =/ env=ienv env.resolution
12788+ =/ recovered=(unit iresolved)
12789+ ?~ main ~
12790+ ?~ main-parts ~
12791+ (program-init-context u.main u.main-parts defs.mod resolution state)
12792+ =. env ?~(recovered env env.u.recovered)
12793+ =. artifacts.resolution
12794+ ?~(recovered artifacts.resolution artifacts.u.recovered)
12630 =. env
12795 =. env
12631 ?: (module-values-complete defs.mod env) env
12796 ?: (module-values-complete defs.mod env) env
12632 ?: |(?=([%ui %stores *] at) ?=(^ imports.mod) ?=(^ prelude) ?=(^ prelude-values) ?=(^ prelude-molds)) env
12797 ?: |(?=([%ui %stores *] at) ?=(^ imports.mod) ?=(^ prelude) ?=(^ prelude-values) ?=(^ prelude-molds)) env
tests/lib/jibb-program-init.hoonnew file+135
@@ -0,0 +1,135 @@
1+:: Transactional direct-program initializer context, without UI execution.
2+/+ jibb
3+/* prelude %jibb /lib/jibb/prelude/jibb
4+/* internal %jibb /lib/jibb/internal/jibb
5+/* initializer %txt /tests/type-program-main/initializer/txt
6+/* initializer-consumer %txt /tests/type-program-main/initializer-consumer/txt
7+/* initializer-unfaced %txt /tests/type-program-main/initializer-unfaced/txt
8+/* initializer-error %txt /tests/type-program-main/initializer-error/txt
9+/* initializer-earlier %txt /tests/type-program-main/initializer-earlier/txt
10+/* initializer-model %txt /tests/type-program-main/initializer-model/txt
11+/* initializer-message %txt /tests/type-program-main/initializer-message/txt
12+/* initializer-generic %txt /tests/type-program-main/initializer-generic/txt
13+/* initializer-missing %txt /tests/type-program-main/initializer-missing/txt
14+/* initializer-tag %txt /tests/type-program-main/initializer-tag/txt
15+/* initializer-no-main %txt /tests/type-program-main/initializer-no-main/txt
16+/* initializer-subs %txt /tests/type-program-main/initializer-subs/txt
17+|%
18+++ text
19+ |= lines=wain
20+ ^- @t
21+ (rap 3 (turn lines |=(line=@t (cat 3 line '\0a'))))
22+::
23+++ program-init-prepared
24+ |= [public=@t private=@t]
25+ ^- (unit iprelude:jibb)
26+ =/ extra=@t '\0a+$ element |$ [M] [%node item=M]\0a+$ program |$ [D X M]\0a [init=$-(D X) update=$-([M X] [X (list (cmd M))]) view=$-(X (element M)) subs=$-(X (list (sub M)))]\0a++ program |= [init=$-(D X) update=$-([M X] [X (list (cmd M))]) view=$-(X (element M)) subs=$-(X (list (sub M)))]\0a ^- (program D X M) [init update view subs]\0a'
27+ (prepare-prelude-with-internal:jibb (cat 3 public extra) private)
28+::
29+++ program-init-detailed
30+ |= [at=path src=@t modules=jbundle:jibb prepared=iprelude:jibb]
31+ ^- jfile-detailed-result:jibb
32+ (infer-jibb-file-detailed:jibb at src ~ ~ modules ~[at] values.prepared molds.prepared ~ `iface.prepared)
33+::
34+++ program-init-legacy
35+ |= [at=path src=@t modules=jbundle:jibb prepared=iprelude:jibb]
36+ ^- jfile-result:jibb
37+ (infer-jibb-file:jibb at src ~ ~ modules ~[at] values.prepared molds.prepared ~ `iface.prepared)
38+::
39+++ program-init-positive
40+ |= [at=path src=@t downstream=(unit @t) prepared=iprelude:jibb]
41+ ^- (list tape)
42+ =/ detailed=jfile-detailed-result:jibb (program-init-detailed at src ~ prepared)
43+ ?: ?=(%| -.detailed) ~["contextual direct program init was rejected"]
44+ =/ checked=ifile:jibb iface.p.detailed
45+ =/ legacy=jfile-result:jibb (program-init-legacy at src ~ prepared)
46+ ?: ?=(%| -.legacy) ~["legacy adapter rejected contextual init"]
47+ ?. =(values.checked values.iface.p.legacy) ~["contextual structured and legacy values differ"]
48+ =/ init=(unit ischeme:jibb) (ienv-lookup:jibb %init values.checked)
49+ =/ main=(unit ischeme:jibb) (ienv-lookup:jibb %main values.checked)
50+ ?~ init ~["contextual init interface is missing"]
51+ ?~ main ~["contextual main interface is missing"]
52+ ?. ?=(~ vars.u.init) ~["contextual init interface is not closed"]
53+ =/ expected=tape "$-((list @t) [xs=(list @t) [draft=@t error=(unit @t)]])"
54+ ?. =((show-itype:jibb typ.u.init ~) expected) ~["contextual init interface type differs"]
55+ ?. ?=(~ vars.u.main) ~["contextual main interface is not closed"]
56+ =/ fields=(list itype:jibb) (record-fields-named:jibb %init typ.u.main ~)
57+ ?. =(fields ~[typ.u.init]) ~["contextual main initializer field differs"]
58+ ?~ source.checked ~["contextual program source evidence is missing"]
59+ ?. =(u.source.checked src) ~["contextual program source evidence differs"]
60+ ?~ graph.checked ~["contextual program request graph is missing"]
61+ ?~ downstream ~
62+ =/ consumer-at=path /tests/program-main/initializer-consumer/jibb
63+ =/ imported=jfile-detailed-result:jibb
64+ (program-init-detailed consumer-at u.downstream ~[[at src]] prepared)
65+ ?: ?=(%| -.imported) ~["downstream contextual initializer import was rejected"]
66+ =/ use=(unit ischeme:jibb) (ienv-lookup:jibb %imported values.iface.p.imported)
67+ ?~ use ~["downstream contextual initializer is missing"]
68+ ?. =((show-itype:jibb typ.u.use ~) expected) ~["downstream contextual initializer type differs"]
69+ ?. =(u.use u.init) ~["downstream contextual initializer scheme differs"]
70+ ~
71+::
72+++ program-init-negative
73+ |= [label=@t at=path src=@t boundary=@t prepared=iprelude:jibb]
74+ ^- (list tape)
75+ =/ detailed=jfile-detailed-result:jibb (program-init-detailed at src ~ prepared)
76+ ?: ?=(%& -.detailed) ~[(weld (trip label) ": structured check accepted")]
77+ ?. ?=(~ overlap.p.detailed) ~[(weld (trip label) ": unexpected overlap evidence")]
78+ ?. =(message.p.detailed boundary) ~[(weld (trip label) ": rejected at the wrong boundary")]
79+ =/ legacy=jfile-result:jibb (program-init-legacy at src ~ prepared)
80+ ?: ?=(%& -.legacy) ~[(weld (trip label) ": legacy check accepted")]
81+ ?. =(p.legacy boundary) ~[(weld (trip label) ": legacy boundary differs")]
82+ ~
83+::
84+++ program-init-negative-cases
85+ |= [cases=(list [label=@t at=path src=@t boundary=@t]) prepared=iprelude:jibb]
86+ ^- (list tape)
87+ ?~ cases ~
88+ %+ weld
89+ (program-init-negative label.i.cases at.i.cases src.i.cases boundary.i.cases prepared)
90+ $(cases t.cases)
91+::
92+++ program-init-errors
93+ |= [public=@t private=@t island=@t downstream=@t unfaced=@t negatives=(list @t)]
94+ ^- (list tape)
95+ =/ prepared=(unit iprelude:jibb) (program-init-prepared public private)
96+ ?~ prepared ~["synthetic program prelude did not prepare for contextual init"]
97+ =/ at=path /tests/program-main/initializer/jibb
98+ =/ positives=(list tape)
99+ %+ weld
100+ (program-init-positive at island `downstream u.prepared)
101+ (program-init-positive /tests/program-main/initializer-unfaced/jibb unfaced ~ u.prepared)
102+ ?. =(9 (lent negatives)) ~["contextual negative fixture count differs"]
103+ =/ definitions=@t (crip "module definitions need unsupported inference: {(spud at)}")
104+ =/ cases=(list [label=@t at=path src=@t boundary=@t])
105+ :~ ['incompatible error field' at (snag 0 negatives) definitions]
106+ ['earlier tuple mismatch' at (snag 1 negatives) definitions]
107+ ['inconsistent model' at (snag 2 negatives) definitions]
108+ ['inconsistent message' at (snag 3 negatives) definitions]
109+ ['missing/generic data sample' at (snag 4 negatives) definitions]
110+ ['missing initializer' at (snag 5 negatives) definitions]
111+ ['unrelated pending tag' at (snag 6 negatives) definitions]
112+ ['non-main same source' at (snag 7 negatives) definitions]
113+ ['init and subs unresolved' at (snag 8 negatives) definitions]
114+ :- 'API path'
115+ [/ui/api/program-main/jibb island 'module kind needs unsupported inference: /ui/api/program-main/jibb']
116+ :- 'store path'
117+ [/ui/stores/program-main/jibb island 'module kind needs unsupported inference: /ui/stores/program-main/jibb']
118+ ==
119+ (weld positives (program-init-negative-cases cases u.prepared))
120+::
121+++ test-program-init
122+ ^- tang
123+ =/ negatives=(list @t)
124+ :~ (text initializer-error)
125+ (text initializer-earlier)
126+ (text initializer-model)
127+ (text initializer-message)
128+ (text initializer-generic)
129+ (text initializer-missing)
130+ (text initializer-tag)
131+ (text initializer-no-main)
132+ (text initializer-subs)
133+ ==
134+ (turn (program-init-errors prelude internal (text initializer) (text initializer-consumer) (text initializer-unfaced) negatives) |=(reason=tape leaf+reason))
135+--
tests/type-program-main/initializer-consumer.txtnew file+2
@@ -0,0 +1,2 @@
1+/= island /tests/program-main/initializer
2+++ imported init.main.island
tests/type-program-main/initializer-earlier.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts=(list @t) [ts ~zod ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-error.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=@t]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts=(list @t) [ts "" ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-generic.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts [ts "" ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-message.txtnew file+13
@@ -0,0 +1,13 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5++$ other
6+ %start
7+ %stop
8+++ main (program init update view subs)
9+++ init |= ts=(list @t) [ts "" ~]
10+++ update |= [msg=other state=model]
11+ ^- [model (list (cmd other))] [state ~]
12+++ view |= state=model ^- (element message) [%node %start]
13+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-missing.txtnew file+9
@@ -0,0 +1,9 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ update |= [msg=message state=model]
7+ ^- [model (list (cmd message))] [state ~]
8+++ view |= state=model ^- (element message) [%node %start]
9+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-model.txtnew file+11
@@ -0,0 +1,11 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ other [xs=(list @t) draft=@t error=(unit @t) extra=@ud]
3++$ message
4+ %start
5+ %stop
6+++ main (program init update view subs)
7+++ init |= ts=(list @t) [ts "" ~]
8+++ update |= [msg=message state=other]
9+ ^- [other (list (cmd message))] [state ~]
10+++ view |= state=model ^- (element message) [%node %start]
11+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-no-main.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ direct (program init update view subs)
6+++ init |= ts=(list @t) [ts "" ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer-subs.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts=(list @t) [ts "" ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state ~
tests/type-program-main/initializer-tag.txtnew file+13
@@ -0,0 +1,13 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts=(list @t) [ts "" ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model ^- (list (sub message)) ~
11+++ orphan
12+ ~& %unrelated
13+ 0
tests/type-program-main/initializer-unfaced.txtnew file+10
@@ -0,0 +1,10 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts=(list @t) [ts "" ~]
7+++ update |= input=[message model]
8+ ^- [model (list (cmd message))] [[~ "" ~] ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model ^- (list (sub message)) ~
tests/type-program-main/initializer.txtnew file+12
@@ -0,0 +1,12 @@
1++$ model [xs=(list @t) draft=@t error=(unit @t)]
2++$ message
3+ %start
4+ %stop
5+++ main (program init update view subs)
6+++ init |= ts=(list @t) [ts "" ~]
7+++ update |= [msg=message state=model]
8+ ^- [model (list (cmd message))] [state ~]
9+++ view |= state=model ^- (element message) [%node %start]
10+++ subs |= state=model
11+ ^- (list (sub message))
12+ (~)
tools/testdata/ship-selftest+6−1
@@ -325,6 +325,7 @@ def generator_checks(tmp):
325 'tests/lib/jibb-direct-gate-guards.hoon',
325 'tests/lib/jibb-direct-gate-guards.hoon',
326 'tests/lib/jibb-direct-gate-source.hoon',
326 'tests/lib/jibb-direct-gate-source.hoon',
327 'tests/lib/jibb-program-main.hoon',
327 'tests/lib/jibb-program-main.hoon',
328+ 'tests/lib/jibb-program-init.hoon',
328 'tests/lib/jibb-todo-api.hoon',
329 'tests/lib/jibb-todo-api.hoon',
329 'tests/lib/jibb-todo-partial.hoon',
330 'tests/lib/jibb-todo-partial.hoon',
330 'tests/lib/jibb-constructor-fit-guards.hoon',
331 'tests/lib/jibb-constructor-fit-guards.hoon',
@@ -399,7 +400,11 @@ def generator_checks(tmp):
399 check('program main sources and shared fixture are assembled',
400 check('program main sources and shared fixture are assembled',
400 {f'tests/type-program-main/{name}.txt' for name in (
401 {f'tests/type-program-main/{name}.txt' for name in (
401 'source', 'consumer', 'gate-model', 'gate-data', 'nonempty-subs',
402 'source', 'consumer', 'gate-model', 'gate-data', 'nonempty-subs',
402− 'mismatched-model', 'arbitrary-main', 'alias-main', 'open-message')} <= set(normal.files))
403+ 'mismatched-model', 'arbitrary-main', 'alias-main', 'open-message',
404+ 'initializer', 'initializer-consumer', 'initializer-unfaced',
405+ 'initializer-error', 'initializer-earlier', 'initializer-model',
406+ 'initializer-message', 'initializer-generic', 'initializer-missing',
407+ 'initializer-tag', 'initializer-no-main', 'initializer-subs')} <= set(normal.files))
403 check('todo partial golden and reused sources are assembled',
408 check('todo partial golden and reused sources are assembled',
404 {'tests/type-todo-partial/expected.txt', 'tests/type-gate-free/todo.txt',
409 {'tests/type-todo-partial/expected.txt', 'tests/type-gate-free/todo.txt',
405 'tests/type-api-paths/api.txt'} <= set(normal.files))
410 'tests/type-api-paths/api.txt'} <= set(normal.files))
tools/type-program-init-testnew file+49
@@ -0,0 +1,49 @@
1+#!/usr/bin/env python3
2+"""Run transactional direct-program initializer context checks under eval."""
3+from pathlib import Path
4+import argparse
5+import subprocess
6+import sys
7+import tempfile
8+
9+root = Path(__file__).resolve().parent.parent
10+parser = argparse.ArgumentParser(description=__doc__)
11+parser.add_argument('--lib', default=str(root / 'jibb-dev/lib/jibb.hoon'))
12+args = parser.parse_args()
13+
14+def body(name):
15+ text = (root / 'tests/lib' / name).read_text()
16+ return text[text.index('\n|%\n') + 1:]
17+
18+names = ('initializer', 'initializer-consumer', 'initializer-unfaced',
19+ 'initializer-error', 'initializer-earlier', 'initializer-model',
20+ 'initializer-message', 'initializer-generic', 'initializer-missing',
21+ 'initializer-tag', 'initializer-no-main', 'initializer-subs')
22+expression = ('=/ jibb .\n=/ prelude=@t prelude-text\n'
23+ '=/ internal=@t internal-text\n' +
24+ ''.join('=/ ' + name + '=wain (to-wain:format ' + name + '-text)\n'
25+ for name in names) +
26+ '=/ suite\n' + body('jibb-program-init.hoon') +
27+ '\n=/ negatives=(list @t)\n :~ (text:suite initializer-error)\n'
28+ ' (text:suite initializer-earlier)\n (text:suite initializer-model)\n'
29+ ' (text:suite initializer-message)\n (text:suite initializer-generic)\n'
30+ ' (text:suite initializer-missing)\n (text:suite initializer-tag)\n'
31+ ' (text:suite initializer-no-main)\n (text:suite initializer-subs)\n ==\n'
32+ '=/ failures=(list tape) (program-init-errors:suite prelude internal (text:suite initializer) (text:suite initializer-consumer) (text:suite initializer-unfaced) negatives)\n'
33+ '^- @t\n?~ failures \'program initializer checks passed\'\n'
34+ '(of-wain:format (turn failures crip))\n')
35+with tempfile.TemporaryDirectory(prefix='jibb-program-init-') as tmp:
36+ program = Path(tmp) / 'program-init.hoon'
37+ program.write_text(expression)
38+ command = [str(root / 'tools/hoon'), '--lib', args.lib, '--raw', '-f', str(program),
39+ '--cord', 'prelude-text=' + str(root / 'jibb-dev/lib/jibb/prelude.jibb'),
40+ '--cord', 'internal-text=' + str(root / 'jibb-dev/lib/jibb/internal.jibb')]
41+ for name in names:
42+ command += ['--cord', name + '-text=' + str(root / 'tests/type-program-main' / (name + '.txt'))]
43+ result = subprocess.run(command, stdout=subprocess.PIPE)
44+if result.returncode:
45+ sys.exit(result.returncode)
46+if result.stdout != b'program initializer checks passed\n':
47+ sys.stderr.buffer.write(result.stdout)
48+ sys.exit(1)
49+print('transactional direct-program initializer context guards passed')