on master help sign in
Preserve full-module overlap source evidence
b5cdc80iko
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-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-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+1−1
@@ -66,7 +66,7 @@ Before the empty-capital optimization below, single sequential eval runs includi
66
66
67Restricted-number promotion only applies to written capital variables. If none are present, it returns immediately instead of traversing the environment. In one startup-inclusive pair of runs on 2,000 independent gates, output was byte-identical and user CPU fell from 71.67 to 38.26 seconds; wall time was 72.80 versus 51.66 seconds while other checks were running. This does not establish a bound for dependent modules or a complete-checker benchmark.
67Restricted-number promotion only applies to written capital variables. If none are present, it returns immediately instead of traversing the environment. In one startup-inclusive pair of runs on 2,000 independent gates, output was byte-identical and user CPU fell from 71.67 to 38.26 seconds; wall time was 72.80 versus 51.66 seconds while other checks were running. This does not establish a bound for dependent modules or a complete-checker benchmark.
68
68
69−A bounded source proof can also establish distinct literal heads when a union case is a one-hop application of a uniquely resolved local generic mold. It compares literal runtime nouns and checks the original mold normally before publishing an interface. The same source proof improves the partial report, which still says the mold is not checked. The new proof declines nested or qualified applications, opaque references, recursive-index states, holes and deferred obligations; other valid unions can remain unsupported. A 256-node source budget and a separate 256-entry inherited-state budget apply per attempt. They do not bound the existing pairwise union pass, parsing, atom or name sizes, or downstream checking. Prepared interfaces and inference state remain trusted inputs. `tools/type-union-source-test` and the shared ship guard exercise source resolution, reporting, rollback and these bounds. A separate positive witness can identify overlap in two-field, literal-headed cases when a unique one-hop local, one-parameter generic alias is applied to a concrete primitive payload. It compares the literal noun values and proves the payloads have a shared noun, so an empty or unknown payload is not a witness. The partial report identifies both original case sites; full-module inference still rejects these cases with its generic unsupported-mold error. This witness uses a shared 256-node source/pair budget per attempt; an unsupported earlier case may hide a later overlap. Existing pairwise union analysis, parsing, atom and name sizes, and downstream checking remain outside this budget. `tools/type-union-alias-overlap-test` checks the source proof and its two-site report.
69+A bounded source proof can also establish distinct literal heads when a union case is a one-hop application of a uniquely resolved local generic mold. It compares literal runtime nouns and checks the original mold normally before publishing an interface. The same source proof improves the partial report, which still says the mold is not checked. The new proof declines nested or qualified applications, opaque references, recursive-index states, holes and deferred obligations; other valid unions can remain unsupported. A 256-node source budget and a separate 256-entry inherited-state budget apply per attempt. They do not bound the existing pairwise union pass, parsing, atom or name sizes, or downstream checking. Prepared interfaces and inference state remain trusted inputs. `tools/type-union-source-test` and the shared ship guard exercise source resolution, reporting, rollback and these bounds. A separate positive witness can identify overlap in two-field, literal-headed cases when a unique one-hop local, one-parameter generic alias is applied to a concrete primitive payload. It compares the literal noun values and proves the payloads have a shared noun, so an empty or unknown payload is not a witness. The partial report identifies both original case sites. `infer-jibb-file-detailed` returns structured overlap evidence for the first failed mold, including the originating path, exact source, mold name and both case spans. Ordinary Jibb imports preserve a child’s evidence through source and cache checks; the legacy `infer-jibb-file` API remains a text-result adapter and renders both excerpts. Specialized API and prepared-prelude paths retain their existing generic or text-only error boundaries. This witness uses a shared 256-node source/pair budget per attempt; generic-wrapper parameter validation has a separate 256-entry cap. An unsupported earlier case may hide a later overlap. Existing pairwise union analysis, parsing, atom and name sizes, source-excerpt rendering, and downstream checking remain outside these budgets. `tools/type-union-alias-overlap-test` checks the source proof and partial report; `tools/type-full-overlap-test` checks the detailed and legacy full-module paths, source attribution and cache behavior.
70
70
71A single-arm cell pattern can bind two or more positions, with its last binder capturing the remaining tail. Duplicate and shadowed names are rejected. A definite non-cell spine fails; an intermediate union or collection that might contain a cell remains unsupported. For a known non-union cell, a separate one-arm rule also accepts structured patterns, including nested literal and wildcard positions, when the existing coverage proof establishes the whole pattern. It binds payloads with their original types and checks result context; unknown, partially covered, union or recursive spines stay unsupported.
71A single-arm cell pattern can bind two or more positions, with its last binder capturing the remaining tail. Duplicate and shadowed names are rejected. A definite non-cell spine fails; an intermediate union or collection that might contain a cell remains unsupported. For a known non-union cell, a separate one-arm rule also accepts structured patterns, including nested literal and wildcard positions, when the existing coverage proof establishes the whole pattern. It binds payloads with their original types and checks result context; unknown, partially covered, union or recursive spines stay unsupported.
72
72
docs/development.md+3−1
@@ -14,7 +14,7 @@ From the plan's Setup and ground rules, and from @iko:
14- **Push straight to `master`.** @iko reviews work in the project's chat, not in pull requests, so there are none. Run the checks below first.
14- **Push straight to `master`.** @iko reviews work in the project's chat, not in pull requests, so there are none. Run the checks below first.
15- **Keep docs/ current**: [status.md](status.md) when a milestone moves, [open-questions.md](open-questions.md) when a question is settled or found.
15- **Keep docs/ current**: [status.md](status.md) when a milestone moves, [open-questions.md](open-questions.md) when a question is settled or found.
16
16
17−The source-backed generic-union guard can be run under eval with `tools/type-union-source-test`; its `test-union-source` arm is also assembled for the fake ship. It checks a bounded partial inference slice, not general union completeness. `tools/type-union-alias-overlap-test` exercises the separate positive overlap witness and its shared ship test arm.
17+The source-backed generic-union guard can be run under eval with `tools/type-union-source-test`; its `test-union-source` arm is also assembled for the fake ship. It checks a bounded partial inference slice, not general union completeness. `tools/type-union-alias-overlap-test` exercises the separate positive overlap witness and its shared ship test arm. `tools/type-full-overlap-test` checks structured full-module overlap evidence and the legacy error text under eval; both of its test arms are assembled for the fake ship.
18
18
19## Setting up a machine
19## Setting up a machine
20
20
@@ -68,6 +68,7 @@ git clone https://github.com/urbit/tools /root/src/tools
68| `tools/type-import-structural-test` | Checks multi-case and nested Hoon union overlap witnesses under eval and on the ship |
68| `tools/type-import-structural-test` | Checks multi-case and nested Hoon union overlap witnesses under eval and on the ship |
69| `tools/type-union-source-test` | Checks bounded local generic-alias disjointness and state guards under eval and on the ship |
69| `tools/type-union-source-test` | Checks bounded local generic-alias disjointness and state guards under eval and on the ship |
70| `tools/type-union-alias-overlap-test` | Checks source-backed generic-alias overlap witnesses under eval and on the ship |
70| `tools/type-union-alias-overlap-test` | Checks source-backed generic-alias overlap witnesses under eval and on the ship |
71+| `tools/type-full-overlap-test` | Checks structured full-module overlap evidence and imported-source attribution |
71| `tools/type-tlon-test` | Runs the real Tlon presence source through the importer and partial checker, comparing `tests/type-tlon/expected.txt` under eval |
72| `tools/type-tlon-test` | Runs the real Tlon presence source through the importer and partial checker, comparing `tests/type-tlon/expected.txt` under eval |
72| `tools/type-import-diagnostic-test` | Compares the structured reader diagnostic bridge report under eval |
73| `tools/type-import-diagnostic-test` | Compares the structured reader diagnostic bridge report under eval |
73| `tools/type-mark-test` | Checks the partial checker’s mark import boundary against `tests/type-mark/expected.txt` under eval |
74| `tools/type-mark-test` | Checks the partial checker’s mark import boundary against `tests/type-mark/expected.txt` under eval |
@@ -122,6 +123,7 @@ tools/type-import-overlap-test # source-aware Hoon overlap and provenance co
122tools/type-import-structural-test # nested and multi-case Hoon overlap controls
123tools/type-import-structural-test # nested and multi-case Hoon overlap controls
123tools/type-union-source-test # local generic-alias union guards
124tools/type-union-source-test # local generic-alias union guards
124tools/type-union-alias-overlap-test # local generic-alias overlap diagnostics
125tools/type-union-alias-overlap-test # local generic-alias overlap diagnostics
126+tools/type-full-overlap-test # full-module overlap evidence
125tools/type-tlon-test # real Tlon importer/checker report matches
127tools/type-tlon-test # real Tlon importer/checker report matches
126tools/type-import-diagnostic-test # direct structured reader diagnostics match
128tools/type-import-diagnostic-test # direct structured reader diagnostics match
127tools/type-mark-test # mark/checker bridge golden report matches
129tools/type-mark-test # mark/checker bridge golden report matches
docs/status.md+5−3
@@ -27,7 +27,7 @@ The internal prelude also defines `qath` as a transparent recursive knot sequenc
27
27
28The checker also recognizes a limited source-proven generic recursive tree in an import-free defining module. Its nominal identity retains the defining path, mold name and type arguments, including across supported imports and aliases. With a known expected type it can construct supported tagged cases by checking one source-proven layer at a time. Flat matches with explicit tags or nonbinding catch-alls also work for these source-proven trees, as does a missing-case diagnostic for a supported single-arm match. At most 128 arms are screened per attempt; whole-case binders and nested patterns remain unsupported. Broader pattern matching, general structural fits and gate-free proof remain unsupported; this is not yet the prelude's `element` implementation or island checking. The source index uses fixed-shape checks during mold collection. Each construction or supported pattern attempt has 256 unfolding steps and at most 4,096 face and substitution visits per scan; pattern subject recognition and view validation can each scan separately. Parsing, other inference and retries remain outside those limits. A single startup-inclusive comparison of 1,000 ordinary gates produced identical reports and used 29.12 seconds of user CPU before the shared-resolver refactor and 28.55 seconds after it, with other work running; it is not a general performance bound.
28The checker also recognizes a limited source-proven generic recursive tree in an import-free defining module. Its nominal identity retains the defining path, mold name and type arguments, including across supported imports and aliases. With a known expected type it can construct supported tagged cases by checking one source-proven layer at a time. Flat matches with explicit tags or nonbinding catch-alls also work for these source-proven trees, as does a missing-case diagnostic for a supported single-arm match. At most 128 arms are screened per attempt; whole-case binders and nested patterns remain unsupported. Broader pattern matching, general structural fits and gate-free proof remain unsupported; this is not yet the prelude's `element` implementation or island checking. The source index uses fixed-shape checks during mold collection. Each construction or supported pattern attempt has 256 unfolding steps and at most 4,096 face and substitution visits per scan; pattern subject recognition and view validation can each scan separately. Parsing, other inference and retries remain outside those limits. A single startup-inclusive comparison of 1,000 ordinary gates produced identical reports and used 29.12 seconds of user CPU before the shared-resolver refactor and 28.55 seconds after it, with other work running; it is not a general performance bound.
29
29
30−A bounded local source proof recognizes a narrow class of generic-alias union cases with different literal heads, then applies the ordinary mold checks. Nested or qualified aliases and several open states remain unsupported, including a valid alias used during the deferred transaction; the partial report states that the mold itself has not been checked. `tools/type-union-source-test` exercises the source and state bounds and failure paths under eval and on the ship. A separate bounded witness now reports proven collisions between supported literal-headed aliases, with both original case sites; unknown payload intersections still decline. Full module failure remains generic, and the ship replay for this witness is pending.
30+A bounded local source proof recognizes a narrow class of generic-alias union cases with different literal heads, then applies the ordinary mold checks. Nested or qualified aliases and several open states remain unsupported, including a valid alias used during the deferred transaction; the partial report states that the mold itself has not been checked. `tools/type-union-source-test` exercises the source and state bounds and failure paths under eval and on the ship. A separate bounded witness now reports proven collisions between supported literal-headed aliases, with both original case sites; unknown payload intersections still decline. The detailed full-module result now carries the first failed mold’s source-bound overlap evidence, including through ordinary Jibb imports; the legacy text result renders both case excerpts. Specialized API and prelude paths remain limited. The shared guards pass under eval and on the ship.
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
@@ -90,7 +90,7 @@ What the plan asks for, and where it is:
90Besides the plan's list:
90Besides the plan's list:
91
91
92- 658 golden cases: 438 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.
92- 658 golden cases: 438 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.
93−- The 658-case corpus passed under `urbit eval` in 106.8 s while other checks were running. The fake ship passed all 702 tests, including the source-overlap, structural-overlap, generic-union source and alias-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 107.6 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.
93+- The 658-case corpus passed under `urbit eval` in 116.7 s while other checks were running. The fake ship passed all 704 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 107.6 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.
94- `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.
94- `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.
95- 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.
95- 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.
96- 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).
96- 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).
@@ -201,7 +201,8 @@ Besides the plan's list:
201| 22f3788 | 2026-10-31 | Check empty molds and propagate closed cell context into branches |
201| 22f3788 | 2026-10-31 | Check empty molds and propagate closed cell context into branches |
202| 341bcb4 | 2026-10-31 | Keep deferred fits stable under later substitutions |
202| 341bcb4 | 2026-10-31 | Keep deferred fits stable under later substitutions |
203| b93a94b | 2026-10-31 | Prove local generic-alias union tags and add successor |
203| b93a94b | 2026-10-31 | Prove local generic-alias union tags and add successor |
204−| This change | 2026-10-31 | Report generic-alias overlaps and retain deferred branch contexts |
204+| 2826c93 | 2026-10-31 | Report generic-alias overlaps and retain deferred branch contexts |
205+| This change | 2026-10-31 | Preserve full-module overlap source evidence |
205
206
206## Checking it
207## Checking it
207
208
@@ -216,6 +217,7 @@ tools/type-import-overlap-test # source-aware Hoon overlap and provenance fix
216tools/type-import-structural-test # structural overlap and multi-case source fixture
217tools/type-import-structural-test # structural overlap and multi-case source fixture
217tools/type-union-source-test # local generic-alias union guards
218tools/type-union-source-test # local generic-alias union guards
218tools/type-union-alias-overlap-test # local generic-alias overlap diagnostics
219tools/type-union-alias-overlap-test # local generic-alias overlap diagnostics
220+tools/type-full-overlap-test # full-module overlap evidence
219tools/type-tlon-test # the real Tlon reader/checker fixture
221tools/type-tlon-test # the real Tlon reader/checker fixture
220tools/type-mark-test # the mark/checker bridge fixture
222tools/type-mark-test # the mark/checker bridge fixture
221tools/type-poke-test # the source-backed poke/API fixture
223tools/type-poke-test # the source-backed poke/API fixture
jibb-dev/lib/jibb.hoon+89−24
@@ -11006,7 +11006,14 @@
11006+$ jbundle (list jsource)
11006+$ jbundle (list jsource)
11007+$ jcache (list [at=path iface=ifile])
11007+$ jcache (list [at=path iface=ifile])
11008+$ jfile-result (each [iface=ifile cache=jcache] @t)
11008+$ jfile-result (each [iface=ifile cache=jcache] @t)
11009+:: Overlap evidence retains the exact source that supplied its spans.
11010+:: Ordinary Jibb imports preserve this evidence through the resolver.
11011++$ jfile-overlap [file=path source=@t name=term cases=upair]
11012++$ jfile-failure [message=@t overlap=(unit jfile-overlap)]
11013++$ jfile-detailed-result (each [iface=ifile cache=jcache] jfile-failure)
11009+$ jimports-result (each [resolved=ijimports cache=jcache] @t)
11014+$ jimports-result (each [resolved=ijimports cache=jcache] @t)
11015+:: Preserve an imported overlap's original file and source across the graph.
11016++$ jimports-detailed-result (each [resolved=ijimports cache=jcache] jfile-failure)
11010::
11017::
11011:: Written record fields each have their own lexical record scope.
11018:: Written record fields each have their own lexical record scope.
11012+$ written-fields (map term span)
11019+$ written-fields (map term span)
@@ -11279,6 +11286,43 @@
11279 (skim defs.mod |=(d=def !&(?=(%mold -.d) =(%poke name.d))))
11286 (skim defs.mod |=(d=def !&(?=(%mold -.d) =(%poke name.d))))
11280 (module-scope-valid mod(defs remaining) prelude-values prelude-molds)
11287 (module-scope-valid mod(defs remaining) prelude-values prelude-molds)
11281::
11288::
11289+:: A detailed failure is attached only to the first mold that actually
11290+:: failed in this check, using that module's checked source mold table.
11291++$ imold-failure [message=@t overlap=(unit [name=term cases=upair])]
11292+:: Validate a generic wrapper without an unbounded duplicate-name pass.
11293+++ module-mold-params-valid
11294+ |= [vars=(list @t) seen=(set @t) fuel=@ud]
11295+ ^- ?
11296+ ?~ vars &
11297+ ?: =(0 fuel) |
11298+ ?: (~(has in:..zuse seen) i.vars) |
11299+ $(vars t.vars, seen (~(put in:..zuse seen) i.vars), fuel (dec fuel))
11300+++ module-mold-overlap
11301+ |= [m=[name=term body=shape] molds=imolds]
11302+ ^- (unit upair)
11303+ =/ sh=shape body.m
11304+ =/ valid=?
11305+ ?. ?=(%generic -.sh) &
11306+ ?~ vars.sh |
11307+ (module-mold-params-valid vars.sh *(set @t) 256)
11308+ ?. valid ~
11309+ =? sh ?=(%generic -.sh) body.sh
11310+ ?. ?=(%union -.sh) ~
11311+ (union-source-overlap cases.sh molds 256)
11312+++ module-mold-types-detail
11313+ |= [molds=imolds state=istate]
11314+ ^- (each imold-types imold-failure)
11315+ ?~ molds [%& ~]
11316+ =/ m=[name=term body=shape] i.molds
11317+ =/ t=(unit [template=ischeme state=istate])
11318+ (infer-mold-template body.m state(active [name.m active.state], in-mold &))
11319+ ?~ t
11320+ =/ overlap=(unit upair) (module-mold-overlap m molds.state)
11321+ [%| ['module mold needs unsupported inference' ?~(overlap ~ `[name.m u.overlap])]]
11322+ =. typ.template.u.t (label-direct-union typ.template.u.t body.m name.m state)
11323+ =/ rest=(each imold-types imold-failure) $(molds t.molds)
11324+ ?: ?=(%| -.rest) rest
11325+ [%& [[name.m template.u.t] p.rest]]
11282++ module-mold-types
11326++ module-mold-types
11283 |= [molds=imolds state=istate]
11327 |= [molds=imolds state=istate]
11284 ^- (each imold-types @t)
11328 ^- (each imold-types @t)
@@ -11627,33 +11671,40 @@
11627++ resolve-jibb-imports
11671++ resolve-jibb-imports
11628 |= [imports=(list import) externals=iexternals mark-externals=imark-externals modules=jbundle active=(list path) prelude-values=(list term) prelude-molds=(list term) cache=jcache prelude=(unit ifile)]
11672 |= [imports=(list import) externals=iexternals mark-externals=imark-externals modules=jbundle active=(list path) prelude-values=(list term) prelude-molds=(list term) cache=jcache prelude=(unit ifile)]
11629 ^- jimports-result
11673 ^- jimports-result
11674+ =/ result=jimports-detailed-result
11675+ (resolve-jibb-imports-detailed imports externals mark-externals modules active prelude-values prelude-molds cache prelude)
11676+ ?: ?=(%| -.result) [%| message.p.result]
11677+ [%& p.result]
11678+++ resolve-jibb-imports-detailed
11679+ |= [imports=(list import) externals=iexternals mark-externals=imark-externals modules=jbundle active=(list path) prelude-values=(list term) prelude-molds=(list term) cache=jcache prelude=(unit ifile)]
11680+ ^- jimports-detailed-result
11630 ?~ imports [%& [~ cache]]
11681 ?~ imports [%& [~ cache]]
11631 ?. ?=(%jibb -.i.imports) $(imports t.imports)
11682 ?. ?=(%jibb -.i.imports) $(imports t.imports)
11632 =/ at=path (weld path.i.imports `path`~[%jibb])
11683 =/ at=path (weld path.i.imports `path`~[%jibb])
11633 ?: =(at /lib/jibb/internal/jibb)
11684 ?: =(at /lib/jibb/internal/jibb)
11634− [%| 'the prelude internal module is private']
11685+ [%| ['the prelude internal module is private' ~]]
11635 ?: =(at /lib/jibb/primitives/jibb)
11686 ?: =(at /lib/jibb/primitives/jibb)
11636− [%| 'the prelude primitive interface is private']
11687+ [%| ['the prelude primitive interface is private' ~]]
11637 ?: (lien active |=(p=path =(p at)))
11688 ?: (lien active |=(p=path =(p at)))
11638− [%| (crip "import cycle at {(spud at)}")]
11689+ [%| [(crip "import cycle at {(spud at)}") ~]]
11639 =/ found=jbundle (skim modules |=(m=jsource =(at at.m)))
11690 =/ found=jbundle (skim modules |=(m=jsource =(at at.m)))
11640− ?~ found [%| (crip "module source missing: {(spud at)}")]
11691+ ?~ found [%| [(crip "module source missing: {(spud at)}") ~]]
11641− ?^ t.found [%| (crip "duplicate module sources: {(spud at)}")]
11692+ ?^ t.found [%| [(crip "duplicate module sources: {(spud at)}") ~]]
11642 =/ cached=(unit ifile) (find-jibb-cache at cache)
11693 =/ cached=(unit ifile) (find-jibb-cache at cache)
11643− =/ iface=jfile-result
11694+ =/ iface=jfile-detailed-result
11644 ?^ cached
11695 ?^ cached
11645− ?. =(at.u.cached at) [%| 'cached module identity needs unsupported inference']
11696+ ?. =(at.u.cached at) [%| ['cached module identity needs unsupported inference' ~]]
11646 ?~ graph.u.cached
11697 ?~ graph.u.cached
11647 :: A detached legacy interface has unknown evidence. Rebuild it
11698 :: A detached legacy interface has unknown evidence. Rebuild it
11648 :: against the current graph, without retaining any stale entry.
11699 :: against the current graph, without retaining any stale entry.
11649 =/ clean=jcache (skim cache |=(x=[at=path iface=ifile] !=(at.x at)))
11700 =/ clean=jcache (skim cache |=(x=[at=path iface=ifile] !=(at.x at)))
11650− (infer-jibb-file at source.i.found externals mark-externals modules [at active] prelude-values prelude-molds clean prelude)
11701+ (infer-jibb-file-detailed at source.i.found externals mark-externals modules [at active] prelude-values prelude-molds clean prelude)
11651 ?. (request-graph-reusable u.cached source.i.found externals mark-externals modules active prelude-values prelude-molds prelude)
11702 ?. (request-graph-reusable u.cached source.i.found externals mark-externals modules active prelude-values prelude-molds prelude)
11652− [%| 'cached module evidence needs unsupported inference']
11703+ [%| ['cached module evidence needs unsupported inference' ~]]
11653 [%& [u.cached cache]]
11704 [%& [u.cached cache]]
11654− (infer-jibb-file at source.i.found externals mark-externals modules [at active] prelude-values prelude-molds cache prelude)
11705+ (infer-jibb-file-detailed at source.i.found externals mark-externals modules [at active] prelude-values prelude-molds cache prelude)
11655 ?: ?=(%| -.iface) [%| p.iface]
11706 ?: ?=(%| -.iface) [%| p.iface]
11656− =/ rest=jimports-result $(imports t.imports, cache cache.p.iface)
11707+ =/ rest=jimports-detailed-result $(imports t.imports, cache cache.p.iface)
11657 ?: ?=(%| -.rest) rest
11708 ?: ?=(%| -.rest) rest
11658 [%& [[[face.i.imports iface.p.iface] resolved.p.rest] cache.p.rest]]
11709 [%& [[[face.i.imports iface.p.iface] resolved.p.rest] cache.p.rest]]
11659::
11710::
@@ -12390,17 +12441,25 @@
12390++ infer-jibb-file
12441++ infer-jibb-file
12391 |= [at=path src=@t externals=iexternals mark-externals=imark-externals modules=jbundle active=(list path) prelude-values=(list term) prelude-molds=(list term) cache=jcache prelude=(unit ifile)]
12442 |= [at=path src=@t externals=iexternals mark-externals=imark-externals modules=jbundle active=(list path) prelude-values=(list term) prelude-molds=(list term) cache=jcache prelude=(unit ifile)]
12392 ^- jfile-result
12443 ^- jfile-result
12444+ =/ out=jfile-detailed-result
12445+ (infer-jibb-file-detailed at src externals mark-externals modules active prelude-values prelude-molds cache prelude)
12446+ ?: ?=(%| -.out) [%| message.p.out]
12447+ [%& p.out]
12448+:: Returns structured root-source overlap evidence after the same full check.
12449+++ infer-jibb-file-detailed
12450+ |= [at=path src=@t externals=iexternals mark-externals=imark-externals modules=jbundle active=(list path) prelude-values=(list term) prelude-molds=(list term) cache=jcache prelude=(unit ifile)]
12451+ ^- jfile-detailed-result
12393 =/ parsed (parse at src)
12452 =/ parsed (parse at src)
12394− ?: ?=(%| -.parsed) [%| (crip "module source does not parse: {(spud at)}")]
12453+ ?: ?=(%| -.parsed) [%| [(crip "module source does not parse: {(spud at)}") ~]]
12395 =/ mod=module p.parsed
12454 =/ mod=module p.parsed
12396 =/ duplicate=(unit idiag) (duplicate-defs defs.mod)
12455 =/ duplicate=(unit idiag) (duplicate-defs defs.mod)
12397− ?^ duplicate [%| (show-duplicate-fields at src u.duplicate)]
12456+ ?^ duplicate [%| [(show-duplicate-fields at src u.duplicate) ~]]
12398 ?: ?=([%ui %api *] at)
12457 ?: ?=([%ui %api *] at)
12399 =/ iface=(unit ifile) (api-poke-interface at mod mark-externals prelude-values prelude-molds prelude)
12458 =/ iface=(unit ifile) (api-poke-interface at mod mark-externals prelude-values prelude-molds prelude)
12400 ?^ iface
12459 ?^ iface
12401 =/ checked=ifile u.iface(source `src, graph `[(silt `(list path)`~[at]) ~ modules prelude prelude-values prelude-molds externals mark-externals])
12460 =/ checked=ifile u.iface(source `src, graph `[(silt `(list path)`~[at]) ~ modules prelude prelude-values prelude-molds externals mark-externals])
12402 [%& [checked [[at checked] cache]]]
12461 [%& [checked [[at checked] cache]]]
12403− ?~ prelude [%| (crip "API module needs unsupported inference: {(spud at)}")]
12462+ ?~ prelude [%| [(crip "API module needs unsupported inference: {(spud at)}") ~]]
12404 =/ prepared=iprelude [u.prelude prelude-values prelude-molds]
12463 =/ prepared=iprelude [u.prelude prelude-values prelude-molds]
12405 =/ narrow=?
12464 =/ narrow=?
12406 ?. ?=([[%mark *] ~] imports.mod) |
12465 ?. ?=([[%mark *] ~] imports.mod) |
@@ -12410,21 +12469,21 @@
12410 ?: narrow
12469 ?: narrow
12411 =/ request=(each ione-request-interface @t)
12470 =/ request=(each ione-request-interface @t)
12412 (one-request-interface-graph at src externals mark-externals modules active cache `prepared)
12471 (one-request-interface-graph at src externals mark-externals modules active cache `prepared)
12413− ?: ?=(%| -.request) [%| (crip "API module needs unsupported inference: {(spud at)}")]
12472+ ?: ?=(%| -.request) [%| [(crip "API module needs unsupported inference: {(spud at)}") ~]]
12414 =/ checked=ifile iface.p.request
12473 =/ checked=ifile iface.p.request
12415 [%& [checked [[at checked] dependencies.paths.support.p.request]]]
12474 [%& [checked [[at checked] dependencies.paths.support.p.request]]]
12416 =/ multi=(each [iface=ifile cache=jcache] @t)
12475 =/ multi=(each [iface=ifile cache=jcache] @t)
12417 (multi-request-interface-graph at src externals mark-externals modules active cache `prepared)
12476 (multi-request-interface-graph at src externals mark-externals modules active cache `prepared)
12418− ?: ?=(%| -.multi) [%| (crip "API module needs unsupported inference: {(spud at)}")]
12477+ ?: ?=(%| -.multi) [%| [(crip "API module needs unsupported inference: {(spud at)}") ~]]
12419 [%& [iface.p.multi [[at iface.p.multi] cache.p.multi]]]
12478 [%& [iface.p.multi [[at iface.p.multi] cache.p.multi]]]
12420 ?. (module-scope-valid mod prelude-values prelude-molds)
12479 ?. (module-scope-valid mod prelude-values prelude-molds)
12421 ?: (pending-declared-poke at mod prelude-values prelude-molds)
12480 ?: (pending-declared-poke at mod prelude-values prelude-molds)
12422− [%| (crip "module kind or scope needs unsupported inference: {(spud at)}")]
12481+ [%| [(crip "module kind or scope needs unsupported inference: {(spud at)}") ~]]
12423− [%| (crip "module has conflicting names: {(spud at)}")]
12482+ [%| [(crip "module has conflicting names: {(spud at)}") ~]]
12424 =/ vals=(list term) (global-value-names defs.mod)
12483 =/ vals=(list term) (global-value-names defs.mod)
12425 ?: (lien vals |=(n=term =(n %main)))
12484 ?: (lien vals |=(n=term =(n %main)))
12426− [%| (crip "module kind needs unsupported inference: {(spud at)}")]
12485+ [%| [(crip "module kind needs unsupported inference: {(spud at)}") ~]]
12427− =/ js=jimports-result (resolve-jibb-imports imports.mod externals mark-externals modules active prelude-values prelude-molds cache prelude)
12486+ =/ js=jimports-detailed-result (resolve-jibb-imports-detailed imports.mod externals mark-externals modules active prelude-values prelude-molds cache prelude)
12428 ?: ?=(%| -.js) [%| p.js]
12487 ?: ?=(%| -.js) [%| p.js]
12429 =/ collected=grec-collected
12488 =/ collected=grec-collected
12430 ?^ imports.mod [(collect-simple-molds defs.mod) *(map term shape)]
12489 ?^ imports.mod [(collect-simple-molds defs.mod) *(map term shape)]
@@ -12449,8 +12508,14 @@
12449 ?: (lien molds |=(m=[name=term body=shape] =(%list name.m))) ~
12508 ?: (lien molds |=(m=[name=term body=shape] =(%list name.m))) ~
12450 `[at src u.prelude index]
12509 `[at src u.prelude index]
12451 =. grec-index.state index
12510 =. grec-index.state index
12452− =/ mts=(each imold-types @t) (module-mold-types molds state)
12511+ =/ mts=(each imold-types imold-failure) (module-mold-types-detail molds state)
12512+ ?: ?=(%| -.mts)
12453− ?: ?=(%| -.mts) [%| (crip "{(trip p.mts)}: {(spud at)}")]
12513+ ?~ overlap.p.mts [%| [(crip "{(trip message.p.mts)}: {(spud at)}") ~]]
12514+ =/ witness=[name=term cases=upair] u.overlap.p.mts
12515+ =/ first=@t (show-error src [at line.beg.first.cases.witness col.beg.first.cases.witness "first union case"])
12516+ =/ second=@t (show-error src [at line.beg.second.cases.witness col.beg.second.cases.witness "overlapping case"])
12517+ =/ msg=@t (of-wain:format ~[(crip "module mold {(trip name.witness)} has overlapping cases") first second])
12518+ [%| [msg `[at src name.witness cases.witness]]]
12454 =/ resolution=iresolved
12519 =/ resolution=iresolved
12455 ?~ index
12520 ?~ index
12456 (resolve-groups defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude)
12521 (resolve-groups defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude)
@@ -12467,10 +12532,10 @@
12467 ?: (dg-interface-safe env.u.transaction) env.u.transaction
12532 ?: (dg-interface-safe env.u.transaction) env.u.transaction
12468 env
12533 env
12469 ?. (module-values-complete defs.mod env)
12534 ?. (module-values-complete defs.mod env)
12470− [%| (crip "module definitions need unsupported inference: {(spud at)}")]
12535+ [%| [(crip "module definitions need unsupported inference: {(spud at)}") ~]]
12471 =/ initial=irequest-graph [(silt `(list path)`~[at]) ~ modules prelude prelude-values prelude-molds externals mark-externals]
12536 =/ initial=irequest-graph [(silt `(list path)`~[at]) ~ modules prelude prelude-values prelude-molds externals mark-externals]
12472 =/ graph=(unit irequest-graph) (request-graph-merge resolved.p.js initial (add 1 (lent resolved.p.js)))
12537 =/ graph=(unit irequest-graph) (request-graph-merge resolved.p.js initial (add 1 (lent resolved.p.js)))
12473− ?~ graph [%| 'module request evidence needs unsupported inference']
12538+ ?~ graph [%| ['module request evidence needs unsupported inference' ~]]
12474 =/ iface=ifile [env p.mts at ~ artifacts.resolution ~ `src graph]
12539 =/ iface=ifile [env p.mts at ~ artifacts.resolution ~ `src graph]
12475 [%& [iface [[at iface] cache.p.js]]]
12540 [%& [iface [[at iface] cache.p.js]]]
12476::
12541::
tests/lib/jibb-full-overlap-basic.hoonnew file+143
@@ -0,0 +1,143 @@
1+:: Source-bound full-module overlap diagnostics.
2+/+ jibb
3+/* same %txt /tests/type-full-overlap/same/txt
4+/* zero %txt /tests/type-full-overlap/zero/txt
5+/* unsupported %txt /tests/type-full-overlap/unsupported/txt
6+/* precedence %txt /tests/type-full-overlap/precedence/txt
7+/* duplicate %txt /tests/type-full-overlap/duplicate/txt
8+/* invalid %txt /tests/type-full-overlap/invalid/txt
9+/* distinct %txt /tests/type-full-overlap/distinct/txt
10+/* parent %txt /tests/type-full-overlap/parent/txt
11+/* child %txt /tests/type-full-overlap/child/txt
12+/* generic %txt /tests/type-full-overlap/generic/txt
13+/* duplicate-generic %txt /tests/type-full-overlap/duplicate-generic/txt
14+/* expected %txt /tests/type-full-overlap/expected-basic/txt
15+|%
16++$ overlap-evidence [file=path source=@t name=term cases=upair:jibb]
17++$ detailed-result
18+ (each [iface=ifile:jibb cache=jcache:jibb] [message=@t overlap=(unit overlap-evidence)])
19+++ source-pair
20+ |= [file=path source=@t name=term]
21+ ^- (unit upair:jibb)
22+ =/ parsed (parse:jibb file source)
23+ ?: ?=(%| -.parsed) ~
24+ =/ molds=imolds:jibb (collect-simple-molds:jibb defs.p.parsed)
25+ =/ found=(unit shape:jibb) (find-simple-mold:jibb name molds)
26+ ?~ found ~
27+ =/ sh=shape:jibb u.found
28+ =? sh ?=(%generic -.sh) body.sh
29+ ?. ?=(%union -.sh) ~
30+ ?~ cases.sh ~
31+ ?~ t.cases.sh ~
32+ `[at.i.cases.sh at.i.t.cases.sh %overlap]
33+++ source-witness
34+ |= [file=path source=@t name=term]
35+ ^- ?
36+ =/ parsed (parse:jibb file source)
37+ ?: ?=(%| -.parsed) |
38+ =/ molds=imolds:jibb (collect-simple-molds:jibb defs.p.parsed)
39+ =/ found=(unit shape:jibb) (find-simple-mold:jibb name molds)
40+ ?~ found |
41+ =/ sh=shape:jibb u.found
42+ =? sh ?=(%generic -.sh) body.sh
43+ ?. ?=(%union -.sh) |
44+ ?=(^ (union-source-overlap:jibb cases.sh molds 256))
45+++ detailed
46+ |= [file=path source=@t modules=jbundle:jibb]
47+ ^- detailed-result
48+ (infer-jibb-file-detailed:jibb file source ~ ~ modules ~[file] ~ ~ ~ ~)
49+++ expected-overlap
50+ |= [file=path source=@t name=term]
51+ ^- ?
52+ =/ expected=(unit upair:jibb) (source-pair file source name)
53+ ?~ expected |
54+ =/ result=detailed-result (detailed file source ~)
55+ ?: ?=(%& -.result) |
56+ ?~ overlap.p.result |
57+ =/ ev=overlap-evidence u.overlap.p.result
58+ ?& !=(0 message.p.result)
59+ =(file.ev file)
60+ =(source.ev source)
61+ =(name.ev name)
62+ =(cases.ev u.expected)
63+ =(%overlap relation.cases.ev)
64+ =(3 line.beg.first.cases.ev)
65+ =(3 col.beg.first.cases.ev)
66+ =(4 line.beg.second.cases.ev)
67+ =(3 col.beg.second.cases.ev)
68+ ==
69+++ plain-failure
70+ |= [file=path source=@t]
71+ ^- ?
72+ =/ parsed (parse:jibb file source)
73+ ?: ?=(%| -.parsed) |
74+ =/ result=detailed-result (detailed file source ~)
75+ ?: ?=(%& -.result) |
76+ &(!=(0 message.p.result) ?=(~ overlap.p.result))
77+++ run
78+ |= [same=@t zero=@t unsupported=@t precedence=@t duplicate=@t invalid=@t distinct=@t parent=@t child=@t generic=@t duplicate-generic=@t]
79+ ^- (list [@t ?])
80+ =/ root=path /ui/root/jibb
81+ =/ names256=(list @t) (turn (gulf 0 255) |=(n=@ud (scot %ud n)))
82+ =/ names257=(list @t) (turn (gulf 0 256) |=(n=@ud (scot %ud n)))
83+ =/ child-file=path /ui/child/jibb
84+ =/ good-parsed (parse:jibb root distinct)
85+ =/ good-result=detailed-result (detailed root distinct ~)
86+ =/ bad-parsed (parse:jibb root invalid)
87+ =/ bad-result=detailed-result (detailed root invalid ~)
88+ =/ invalid-clean=?
89+ ?: ?=(%& -.bad-parsed) |
90+ ?: ?=(%& -.bad-result) |
91+ &(!=(0 message.p.bad-result) ?=(~ overlap.p.bad-result))
92+ =/ legacy=jfile-result:jibb (infer-jibb-file:jibb root same ~ ~ ~ ~[root] ~ ~ ~ ~)
93+ =/ legacy-excerpts=?
94+ ?: ?=(%& -.legacy) |
95+ =/ lines=wain (to-wain:format p.legacy)
96+ &((lien lines |=(line=@t =(line '/ui/root.jibb:3:3: first union case'))) (lien lines |=(line=@t =(line '/ui/root.jibb:4:3: overlapping case'))))
97+ =/ imported=detailed-result (detailed root parent ~[[child-file child]])
98+ =/ child-pair=(unit upair:jibb) (source-pair child-file child %child-bad)
99+ =/ import-valid=?
100+ ?: ?=(%& -.imported) |
101+ ?: =(0 message.p.imported) |
102+ ?~ overlap.p.imported |
103+ ?~ child-pair |
104+ =/ ev=overlap-evidence u.overlap.p.imported
105+ ?& =(file.ev child-file)
106+ =(source.ev child)
107+ =(name.ev %child-bad)
108+ =(cases.ev u.child-pair)
109+ ==
110+ :~ ['256 generic parameters accepted by scan' (module-mold-params-valid:jibb names256 *(set @t) 256)]
111+ ['257 generic parameters exhaust scan' !(module-mold-params-valid:jibb names257 *(set @t) 256)]
112+ ['duplicate generic parameters fail scan' !(module-mold-params-valid:jibb ~['A' 'A'] *(set @t) 256)]
113+ ['same head has source-bound overlap' (expected-overlap root same %bad)]
114+ ['zero spelling has source-bound overlap' (expected-overlap root zero %bad)]
115+ ['generic wrapper has source-bound overlap' (expected-overlap root generic %bad)]
116+ ['duplicate generic parameters remain unstructured' (plain-failure root duplicate-generic)]
117+ ['unsupported remains unstructured' (plain-failure root unsupported)]
118+ ['later overlap exists in precedence source' (source-witness root precedence %bad)]
119+ ['earlier unsupported mold takes precedence' (plain-failure root precedence)]
120+ ['duplicate source parsed but rejects without overlap' (plain-failure root duplicate)]
121+ ['invalid source rejects without overlap' invalid-clean]
122+ ['distinct alias source parses and checks' &(?=(%& -.good-parsed) ?=(%& -.good-result))]
123+ ['parent itself has different positive overlap' (source-witness root parent %parent-bad)]
124+ ['legacy full-module error contains both excerpts' legacy-excerpts]
125+ ['import overlap retains exact child source' import-valid]
126+ ==
127+++ text
128+ |= lines=wain
129+ ^- @t
130+ (rap 3 (turn lines |=(line=@t (cat 3 line '\0a'))))
131+++ output
132+ |= [same=@t zero=@t unsupported=@t precedence=@t duplicate=@t invalid=@t distinct=@t parent=@t child=@t generic=@t duplicate-generic=@t]
133+ ^- @t
134+ =/ result=(list [@t ?]) (run same zero unsupported precedence duplicate invalid distinct parent child generic duplicate-generic)
135+ (of-wain:format (turn result |=(entry=[@t ?] (crip "{(trip -.entry)}: {?:(+.entry "ok" "BAD")}"))))
136+++ test-full-overlap-basic
137+ ^- tang
138+ ?~ expected ~[leaf+"expected output missing"]
139+ =/ actual=@t (output (text same) (text zero) (text unsupported) (text precedence) (text duplicate) (text invalid) (text distinct) (text parent) (text child) (text generic) (text duplicate-generic))
140+ ?. =((to-wain:format (cat 3 actual '\0a')) expected)
141+ ~[leaf+"full-module overlap output differs"]
142+ ~
143+--
tests/lib/jibb-full-overlap-graph.hoonnew file+126
@@ -0,0 +1,126 @@
1+:: Source-bound full-module overlap diagnostics.
2+/+ jibb
3+/* parent %txt /tests/type-full-overlap/parent/txt
4+/* child %txt /tests/type-full-overlap/child/txt
5+/* distinct %txt /tests/type-full-overlap/distinct/txt
6+/* expected %txt /tests/type-full-overlap/expected-graph/txt
7+|%
8++$ overlap-evidence [file=path source=@t name=term cases=upair:jibb]
9++$ detailed-result
10+ (each [iface=ifile:jibb cache=jcache:jibb] [message=@t overlap=(unit overlap-evidence)])
11+++ detailed
12+ |= [file=path source=@t modules=jbundle:jibb]
13+ ^- detailed-result
14+ (infer-jibb-file-detailed:jibb file source ~ ~ modules ~[file] ~ ~ ~ ~)
15+++ source-pair
16+ |= [file=path source=@t]
17+ ^- (unit upair:jibb)
18+ =/ parsed (parse:jibb file source)
19+ ?: ?=(%| -.parsed) ~
20+ =/ molds=imolds:jibb (collect-simple-molds:jibb defs.p.parsed)
21+ =/ found=(unit shape:jibb) (find-simple-mold:jibb %child-bad molds)
22+ ?~ found ~
23+ ?. ?=(%union -.u.found) ~
24+ ?~ cases.u.found ~
25+ ?~ t.cases.u.found ~
26+ `[at.i.cases.u.found at.i.t.cases.u.found %overlap]
27+++ failure-message
28+ |= [r=detailed-result expected-message=@t]
29+ ^- ?
30+ ?: ?=(%& -.r) |
31+ &(=(message.p.r expected-message) ?=(~ overlap.p.r))
32+++ run
33+ |= [parent=@t child=@t distinct=@t]
34+ ^- (list [@t ?])
35+ =/ root=path /ui/root/jibb
36+ =/ child-file=path /ui/child/jibb
37+ =/ good-parsed (parse:jibb child-file distinct)
38+ =/ parent-parsed (parse:jibb root parent)
39+ =/ child-parsed (parse:jibb child-file child)
40+ ?: ?=(%| -.good-parsed) ~[['BAD valid child parse' |]]
41+ ?: ?=(%| -.parent-parsed) ~[['BAD parent parse' |]]
42+ ?: ?=(%| -.child-parsed) ~[['BAD child parse' |]]
43+ =/ child-pair=(unit upair:jibb) (source-pair child-file child)
44+ ?~ child-pair ~[['BAD child pair' |]]
45+ =/ old=detailed-result (detailed child-file distinct ~)
46+ =/ cache-controls=[rebuilt=? stale=? source-bound=?]
47+ ?: ?=(%| -.old) [| | |]
48+ =/ previous=ifile:jibb iface.p.old
49+ =/ source-bound=?
50+ ?~ source.previous |
51+ ?~ graph.previous |
52+ ?& =(at.previous child-file)
53+ =(u.source.previous distinct)
54+ (request-graph-reusable:jibb previous distinct ~ ~ ~ ~ ~ ~ ~)
55+ !(request-graph-reusable:jibb previous child ~ ~ ~ ~ ~ ~ ~)
56+ ==
57+ =/ detached=ifile:jibb previous(graph ~)
58+ =/ rebuilt=detailed-result
59+ (infer-jibb-file-detailed:jibb root parent ~ ~ ~[[child-file child]] ~[root] ~ ~ ~[[child-file detached]] ~)
60+ =/ stale=detailed-result
61+ (infer-jibb-file-detailed:jibb root parent ~ ~ ~[[child-file child]] ~[root] ~ ~ ~[[child-file previous]] ~)
62+ =/ rebuilt-ok=?
63+ ?: ?=(%& -.rebuilt) |
64+ ?~ overlap.p.rebuilt |
65+ ?& =(file.u.overlap.p.rebuilt child-file)
66+ =(source.u.overlap.p.rebuilt child)
67+ =(name.u.overlap.p.rebuilt %child-bad)
68+ =(cases.u.overlap.p.rebuilt u.child-pair)
69+ ==
70+ =/ stale-ok=?
71+ ?: ?=(%& -.stale) |
72+ &(=(message.p.stale 'cached module evidence needs unsupported inference') ?=(~ overlap.p.stale))
73+ [rebuilt-ok stale-ok source-bound]
74+ =/ middle=@t (of-wain:format ~['/= leaf /ui/leaf' '+$ okay @t'])
75+ =/ leaf-file=path /ui/leaf/jibb
76+ =/ middle-parsed (parse:jibb child-file middle)
77+ =/ transitive=detailed-result
78+ (infer-jibb-file-detailed:jibb root parent ~ ~ ~[[child-file middle] [leaf-file child]] ~[root] ~ ~ ~ ~)
79+ =/ transitive-ok=?
80+ ?: ?=(%| -.middle-parsed) |
81+ ?: ?=(%& -.transitive) |
82+ ?~ overlap.p.transitive |
83+ ?& =(file.u.overlap.p.transitive leaf-file)
84+ =(source.u.overlap.p.transitive child)
85+ =(name.u.overlap.p.transitive %child-bad)
86+ =(cases.u.overlap.p.transitive u.child-pair)
87+ ==
88+ =/ clean-failure
89+ |= r=detailed-result
90+ ^- ?
91+ ?: ?=(%& -.r) |
92+ &(!=(0 message.p.r) ?=(~ overlap.p.r))
93+ =/ private-src=@t (of-wain:format ~['/= secret /lib/jibb/internal' '+$ good @t'])
94+ =/ cycle-src=@t (of-wain:format ~['/= mine /ui/root' '+$ good @t'])
95+ =/ private-parsed (parse:jibb root private-src)
96+ =/ cycle-parsed (parse:jibb root cycle-src)
97+ =/ private-result=detailed-result (detailed root private-src ~)
98+ =/ cycle-result=detailed-result (detailed root cycle-src ~)
99+ =/ duplicate-result=detailed-result (detailed root parent ~[[child-file child] [child-file child]])
100+ =/ missing-result=detailed-result (detailed root parent ~)
101+ :~ ['detached cache rebuild preserves child evidence' rebuilt.cache-controls]
102+ ['mismatched graph cache declines without evidence' stale.cache-controls]
103+ ['verified cache source binding' source-bound.cache-controls]
104+ ['private import declines before source proof' &(?=(%& -.private-parsed) (failure-message private-result 'the prelude internal module is private'))]
105+ ['active cycle declines before source proof' &(?=(%& -.cycle-parsed) (failure-message cycle-result (crip "import cycle at {(spud root)}")))]
106+ ['duplicate child sources decline without evidence' (clean-failure duplicate-result)]
107+ ['missing child source declines without evidence' (clean-failure missing-result)]
108+ ['transitive import retains leaf source' transitive-ok]
109+ ==
110+++ text
111+ |= lines=wain
112+ ^- @t
113+ (rap 3 (turn lines |=(line=@t (cat 3 line '\0a'))))
114+++ output
115+ |= [parent=@t child=@t distinct=@t]
116+ ^- @t
117+ =/ result=(list [@t ?]) (run parent child distinct)
118+ (of-wain:format (turn result |=(entry=[@t ?] (crip "{(trip -.entry)}: {?:(+.entry "ok" "BAD")}"))))
119+++ test-full-overlap-graph
120+ ^- tang
121+ ?~ expected ~[leaf+"expected output missing"]
122+ =/ actual=@t (output (text parent) (text child) (text distinct))
123+ ?. =((to-wain:format (cat 3 actual '\0a')) expected)
124+ ~[leaf+"full-module overlap output differs"]
125+ ~
126+--
tests/type-full-overlap/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: docs/spec/grammar.md, Molds: “Cases must differ as nouns”.
2+tests: Full-module overlap evidence retains the defining source and both case spans through ordinary Jibb imports, and legacy errors render the excerpts. Distinct cases check; duplicate names, stale caches, cycles, private imports and other unsupported inputs retain their own earlier errors. Specialized API and prelude paths remain outside this diagnostic slice.
3+expect: shared eval and ship guards
tests/type-full-overlap/child.txtnew file+4
@@ -0,0 +1,4 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ child-bad
3+ (tagged @t)
4+ [%wrapped @p]
tests/type-full-overlap/distinct.txtnew file+5
@@ -0,0 +1,5 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ good
3+ (tagged @t)
4+ [%other @p]
5+++ id |= x=good x
tests/type-full-overlap/duplicate-generic.txtnew file+4
@@ -0,0 +1,4 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ bad |$ [B B]
3+ (tagged @t)
4+ [%wrapped @p]
tests/type-full-overlap/duplicate.txtnew file+5
@@ -0,0 +1,5 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ tagged |$ [A] [%other A]
3++$ bad
4+ (tagged @t)
5+ [%wrapped @p]
tests/type-full-overlap/expected-basic.txtnew file+16
@@ -0,0 +1,16 @@
1+256 generic parameters accepted by scan: ok
2+257 generic parameters exhaust scan: ok
3+duplicate generic parameters fail scan: ok
4+same head has source-bound overlap: ok
5+zero spelling has source-bound overlap: ok
6+generic wrapper has source-bound overlap: ok
7+duplicate generic parameters remain unstructured: ok
8+unsupported remains unstructured: ok
9+later overlap exists in precedence source: ok
10+earlier unsupported mold takes precedence: ok
11+duplicate source parsed but rejects without overlap: ok
12+invalid source rejects without overlap: ok
13+distinct alias source parses and checks: ok
14+parent itself has different positive overlap: ok
15+legacy full-module error contains both excerpts: ok
16+import overlap retains exact child source: ok
tests/type-full-overlap/expected-graph.txtnew file+8
@@ -0,0 +1,8 @@
1+detached cache rebuild preserves child evidence: ok
2+mismatched graph cache declines without evidence: ok
3+verified cache source binding: ok
4+private import declines before source proof: ok
5+active cycle declines before source proof: ok
6+duplicate child sources decline without evidence: ok
7+missing child source declines without evidence: ok
8+transitive import retains leaf source: ok
tests/type-full-overlap/generic.txtnew file+4
@@ -0,0 +1,4 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ bad |$ [B]
3+ (tagged @t)
4+ [%wrapped @p]
tests/type-full-overlap/invalid.txtnew file+4
@@ -0,0 +1,4 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ bad
3+ (tagged @t
4+ [%wrapped @p]
tests/type-full-overlap/parent.txtnew file+5
@@ -0,0 +1,5 @@
1+/= lib /ui/child
2++$ tagged |$ [A] [%wrapped A]
3++$ parent-bad
4+ (tagged @t)
5+ [%wrapped @p]
tests/type-full-overlap/precedence.txtnew file+5
@@ -0,0 +1,5 @@
1++$ unresolved (missing @t)
2++$ tagged |$ [A] [%wrapped A]
3++$ bad
4+ (tagged @t)
5+ [%wrapped @p]
tests/type-full-overlap/same.txtnew file+4
@@ -0,0 +1,4 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ bad
3+ (tagged @t)
4+ [%wrapped @p]
tests/type-full-overlap/unsupported.txtnew file+4
@@ -0,0 +1,4 @@
1++$ tagged |$ [A] [%wrapped A]
2++$ bad |$ [A]
3+ (tagged A)
4+ [%wrapped @t]
tests/type-full-overlap/zero.txtnew file+4
@@ -0,0 +1,4 @@
1++$ zero |$ [A] [%.y A]
2++$ bad
3+ (zero @t)
4+ [%$ @p]
tools/testdata/ship-selftest+7
@@ -316,6 +316,8 @@ def generator_checks(tmp):
316 'tests/lib/jibb-empty.hoon',
316 'tests/lib/jibb-empty.hoon',
317 'tests/lib/jibb-union-source.hoon',
317 'tests/lib/jibb-union-source.hoon',
318 'tests/lib/jibb-union-alias-overlap.hoon',
318 'tests/lib/jibb-union-alias-overlap.hoon',
319+ 'tests/lib/jibb-full-overlap-basic.hoon',
320+ 'tests/lib/jibb-full-overlap-graph.hoon',
319 'tests/lib/jibb-api-evidence.hoon',
321 'tests/lib/jibb-api-evidence.hoon',
320 'tests/lib/jibb-ask-guards.hoon',
322 'tests/lib/jibb-ask-guards.hoon',
321 'tests/lib/jibb-request-guards.hoon',
323 'tests/lib/jibb-request-guards.hoon',
@@ -363,6 +365,11 @@ def generator_checks(tmp):
363 {f'tests/type-union-alias-overlap/{name}.txt' for name in (
365 {f'tests/type-union-alias-overlap/{name}.txt' for name in (
364 'positive', 'negative', 'nonzero', 'multi', 'opaque', 'wrong',
366 'positive', 'negative', 'nonzero', 'multi', 'opaque', 'wrong',
365 'duplicate', 'qualified', 'flag-source', 'expected')} <= set(normal.files))
367 'duplicate', 'qualified', 'flag-source', 'expected')} <= set(normal.files))
368+ check('full overlap source fixtures are assembled',
369+ {f'tests/type-full-overlap/{name}.txt' for name in (
370+ 'same', 'zero', 'unsupported', 'precedence', 'duplicate',
371+ 'invalid', 'distinct', 'parent', 'child', 'generic',
372+ 'duplicate-generic', 'expected-basic', 'expected-graph')} <= set(normal.files))
366 check('deferred transaction and resolver sources are assembled',
373 check('deferred transaction and resolver sources are assembled',
367 {'tests/type-deferred/nested-src.txt', 'tests/type-deferred/principal-src.txt',
374 {'tests/type-deferred/nested-src.txt', 'tests/type-deferred/principal-src.txt',
368 'tests/type-deferred/expected.txt', 'tests/type-deferred-resolver/good.txt',
375 'tests/type-deferred/expected.txt', 'tests/type-deferred-resolver/good.txt',
tools/type-full-overlap-testnew file+49
@@ -0,0 +1,49 @@
1+#!/usr/bin/env python3
2+"""Check source-bound full-module overlap evidence under eval."""
3+from pathlib import Path
4+import argparse
5+import difflib
6+import subprocess
7+import sys
8+import tempfile
9+
10+root = Path(__file__).resolve().parent.parent
11+parser = argparse.ArgumentParser(description=__doc__)
12+parser.add_argument('--lib', default=str(root / 'jibb-dev/lib/jibb.hoon'))
13+parser.add_argument('--update', action='store_true')
14+args = parser.parse_args()
15+fixture = root / 'tests/type-full-overlap'
16+cases = {
17+ 'basic': ['same', 'zero', 'unsupported', 'precedence', 'duplicate', 'invalid', 'distinct', 'parent', 'child', 'generic', 'duplicate-generic'],
18+ 'graph': ['parent', 'child', 'distinct'],
19+}
20+for kind, names in cases.items():
21+ source = (root / 'tests/lib' / f'jibb-full-overlap-{kind}.hoon').read_text()
22+ source = source[source.index('\n|%\n') + 1:]
23+ cords = [item for name in names for item in ('--cord', f'{name}-text={fixture / (name + ".txt")}')]
24+ expected = fixture / f'expected-{kind}.txt'
25+ if not args.update:
26+ cords += ['--cord', f'expected-text={expected}']
27+ bindings = ''.join(f'=/ {name}=wain (to-wain:format {name}-text)\n' for name in names)
28+ program = ('=/ jibb .\n' + bindings +
29+ ('=/ expected=wain ~\n' if args.update else '=/ expected=wain (to-wain:format expected-text)\n') +
30+ '=/ suite\n' + source + '\n=/ output=@t (output:suite ' +
31+ ' '.join(name + '-text' for name in names) + ')\n' +
32+ ('output\n' if args.update else
33+ f"=/ actual-test=tang test-full-overlap-{kind}:suite\n?~ actual-test output\n'BAD ship test arm'\n"))
34+ with tempfile.TemporaryDirectory(prefix='jibb-full-overlap-') as tmp:
35+ path = Path(tmp) / 'driver.hoon'
36+ path.write_text(program)
37+ result = subprocess.run([str(root / 'tools/hoon'), '--lib', args.lib, '--raw', '-f', str(path), *cords], stdout=subprocess.PIPE)
38+ if result.returncode:
39+ sys.exit(result.returncode)
40+ if any(line.startswith(b'BAD ') or line.endswith(b': BAD') for line in result.stdout.splitlines()):
41+ sys.stderr.write(f'{kind} overlap guard assertion failed:\n')
42+ sys.stderr.buffer.write(result.stdout)
43+ sys.exit(1)
44+ if args.update:
45+ expected.write_bytes(result.stdout)
46+ elif result.stdout != expected.read_bytes():
47+ sys.stderr.writelines(difflib.unified_diff(expected.read_text().splitlines(keepends=True), result.stdout.decode().splitlines(keepends=True), fromfile=str(expected), tofile='actual'))
48+ sys.exit(1)
49+print('source-bound full-module overlap guards passed')