on master help sign in
Check the unchanged cart store and basket

Add the approved store builder, validate declaration-aware store mains, and derive poke constructors and state requests with source-bound evidence. Prove direct store watches while rejecting store requests in page loads and enforcing request-graph bounds. Verify cart and basket through both full APIs with exact main and derived types, structural imports, and rejection controls under eval and on the ship. Multi-action declarations and runtime execution remain out of scope.

commit4bf477e2c4a093f7d2d6aa2bff1ce5858bd98e36 authoriko <mail@iko.soy> dateMon 2 Nov 2026, 05:51 (5 hours ago) parent0517053
26 files changed+887−89
unifiedsplit
README.md+2 docs/compiler.md+4 docs/development.md+2 docs/prelude-inventory.md+2 docs/spec/decisions.md+2−1 docs/spec/implementation-plan.md+1−1 docs/spec/overview.md+3−1 docs/status.md+5−2 jibb-dev/lib/jibb.hoon+458−32 jibb-dev/lib/jibb/prelude.jibb+5 tests/golden/types-prelude-ask/source.jibb+1−1 tests/golden/types-prelude-ask/tokens.txt+25−25 tests/golden/types-prelude-ask/tree.txt+11−11 tests/golden/types-prelude-ask/types.txt+1−1 tests/lib/jibb-store.hoon+261 tests/type-store/basket.txt+32 tests/type-store/cart.txt+13 tests/type-todo-full/alias.txt+2−2 tests/type-todo-full/ambiguous-mapper.txt+2−2 tests/type-todo-full/open-key.txt+2−2 tests/type-todo-full/wrong-message.txt+2−2 tests/type-todo-full/wrong-model.txt+2−2 tests/type-todo-full/wrong-result.txt+2−2 tests/type-todo-full/wrong-watch.txt+2−2 tools/testdata/ship-selftest+4 tools/type-store-test+41
README.md+2
@@ -48,6 +48,8 @@ The focused `tools/type-page-main-test` fully checks the byte-identical static a
4848
4949The focused `tools/type-theme-test` fully checks the byte-identical real theme against the exact prelude mold, including its exported type, structural downstream import, dark absent/present forms and malformed-field negatives under eval with a shared fake-ship arm. It does not check contrast, render themes or route fonts.
5050
51+The focused `tools/type-store-test` checks the byte-identical cart store and basket through detailed and legacy inference, exact main and derived schemes, structural imports, direct store watch evidence and rejection controls under eval with a shared fake-ship arm. It does not lower or execute stores, support multi-action declarations, or permit store requests in page loads.
52+
5153The 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. `tools/type-program-update-test` checks derived result context for an unannotated two-slot update, including a union/boolean branch, downstream types and fail-closed controls under eval with a shared fake-ship arm. `tools/type-program-watch-test` uses the real todo readers with synthetic program components to check one direct request value against merged API-source evidence and reject hand-built, indirect, parameterized, diff and ambiguous subscriptions. These are static checks only: they do not run an island or establish runtime watching. `tools/type-todo-full-test` additionally checks the byte-identical todo island through both full-module APIs, verifies its exact closed `main` type and structural downstream import, and runs rejection controls.
5254
5355### The doc's examples
docs/compiler.md+4
@@ -132,6 +132,10 @@ A full ordinary module may export a narrow checked program `main` only as a dire
132132
133133The same post-inference, post-request-graph kind boundary accepts a static `main` by instantiating its ordinary scheme, fitting it to canonical `(element !!)`, requiring the specialized result closed, and publishing that closed canonical scheme. Thus `main view` works when `view` is generic only in its element message. A data page must instead be a direct `(page load view)` call with simple wing arguments and a closed main type invariant against the instantiated canonical `page` mold. Its named load must be a direct gate whose transparent body is exactly `case.face reply`, with a simple wing or direct constructor reply. Page loads and direct program watches share the exact plain derived-member/request-evidence check: unique evidence in the selected interface's own graph, matching API source and inner case name, no typed path segments, diffs or scry. Page aliases, indirect or hand-built/pure/unknown requests, other main types and store paths fail closed. These are interface checks only, not rendering or runtime request claims.
134134
135+A store `main` is recognized only as a direct, unqualified `(store init update)` call with two simple wing arguments, modulo grouping, independently of its directory. Its module must declare exactly one ordinary `state` mold and one `+$ poke` whose body is one unqualified reference to a local ordinary action mold. The declaration is removed before ordinary mold/value inference and is not exported. `+store-main-closed` checks the canonical closed store main, exact init/state equality, and an invariant `$-([action state] state)` update after erasing only the two outer binder faces. It deliberately performs no gate-free-state check. The direct form can recover a missing main from checked components; aliases and hand-built records cannot.
136+
137+The store interface adds a derived `$-(action poke)` constructor and a generic `$-($-(state M) (ask M))` state request after validating the exact internal `poke` and `ask` representations. Derived names must not collide with values, imports or other derived names. Store request certificates are distinct from API certificates and retain the exact store path, source, state and action identities across graph merges. `+derived-store-request-member` requires the selected interface's unique state member and action constructor to match freshly derived canonical schemes and the same certificate to occur in both interface and consumer graphs. Store state is watchable by definition only after those checks; page loads continue to accept API evidence alone. Multi-action declarations, lowering and execution are outside this slice.
138+
135139When 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.
136140
137141A component-local recovery sequence handles a recognized direct program whose context-dependent definitions cannot resolve ordinarily. Update first derives its result from its inferred two-slot sample and canonical `cmd`/`list` templates. Subscription recovery then checks the same message/model relation and the canonical fourth slot. A narrow keyed-view proof finds exactly one direct `each (turn xs mapper)` site, derives the mapper from the actual `each` and `turn` schemes, and recovers the view before the existing initializer and ordinary `main` retries. Every recovered scheme must be closed and freshly allocated above the current environment and prelude IDs. A source screen skips doomed ordinary attempts only for this keyed shape and never skips final `main` inference; non-gate views and aliases decline without crashing. Final publication still requires all module definitions, the program-mold and gate-free checks, and request-value watchability.
docs/development.md+2
@@ -97,6 +97,7 @@ git clone https://github.com/urbit/tools /root/src/tools
9797| `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 |
9898| `tools/type-program-update-test` | Checks transactional direct-program update result recovery, union/boolean context, exact exported/imported types and fail-closed boundaries under eval and on the ship |
9999| `tools/type-program-watch-test` | Checks direct singleton request-value watchability against merged real-todo evidence, exact types/imports and rejection boundaries under eval and on the ship |
100+| `tools/type-store-test` | Checks the unchanged cart/basket through detailed and legacy inference, exact store/derived schemes, structural imports, source-bound state watch evidence and rejection guards under eval and on the ship |
100101| `tools/type-todo-full-test` | Fully checks the byte-identical todo island through real readers, exact main type, structural downstream import and rejection controls under eval and on the ship |
101102| `tools/type-closed-gate-guards-test` | Checks closed gate sample labels and face uncertainty under eval and on the ship |
102103| `tools/type-constructor-fit-guards-test` | Checks constructor-case uncertainty and known mismatches under eval and on the ship |
@@ -153,6 +154,7 @@ tools/type-program-main-test # closed program-main interface and rejectio
153154tools/type-program-init-test # transactional direct-program initializer context guards pass
154155tools/type-program-update-test # transactional direct-program update context guards pass
155156tools/type-program-watch-test # direct request-value watchability guards pass
157+tools/type-store-test # unchanged cart/basket, store evidence and rejection guards pass
156158tools/type-todo-full-test # byte-identical full todo, downstream import and rejection guards pass
157159tools/type-generic-recursion-test # source-backed recursive identities and provenance
158160tools/type-generic-construction-test # source-backed recursive construction and bounds
docs/prelude-inventory.md+2
@@ -10,6 +10,8 @@ The prelude also declares the generic `cmd` mold exactly as in Overview, Effects
1010
1111The public prelude now defines the UI `length`, `align`, `role`, `tone` and `attr` molds, a nonrecursive generic `element` union with one case per UI node, and the exact `program` and `page` records with their builders. Nested child, keyed-item and table payloads in the runtime union are erased to `*`; the public constructors retain typed children and independent key types, and `island` stores `[program data]` in its erased payload. The focused `types-prelude-ui` golden infers the complete union and constructor schemes, including static and message-bearing composition. Raw-constructor encapsulation, duplicate-attribute rejection, rendering, storage, navigation and execution are not established by this slice.
1212
13+The public prelude defines the approved generic `store` record `[init=S update=*]` and its builder, whose update argument is `$-([A S] S)` while the result exposes only `S`. Focused store coverage checks both exact schemes, the unchanged cart's closed main and derived state/action gates, and downstream structural imports. Store declaration checking and watch evidence are implemented; multi-action declarations, lowering and runtime execution are not.
14+
1315The public prelude also defines the exact `theme` mold: three space cords, five normal tone cords, `wide`, `lang` and `zone` cords, `(unit qath)` for `font`, and a unit containing the same five dark tone cords. The shared `type-theme` fixture fully checks the byte-identical real theme and its structural downstream import, including dark absent/present and malformed-field negatives. It does not implement contrast checking, rendering, routing or any other theme behavior.
1416
1517Hoon `+$` arms are marked **mold** below; `++` arms can be gates, doors or mold generators, and need individual inspection. Jibb's loobean `not` and Hoon's bitwise `not.bit` are distinct. Parser helpers outside 3g are excluded from the intended prelude except the specifically listed `slav` and `slaw`; the raw candidates below still need to be classified.
docs/spec/decisions.md+2−1
@@ -65,7 +65,7 @@ The choices behind the Language tab, made on 2026-10-23; a later date marks a re
6565| Page loading | `load` maps route parameters, `~` for none, to one `ask` or `pure`; pages render per request from a fresh scry of the path, or of its case's scry path; nothing is watched or kept | Decided 2026-10-29 |
6666| Compile targets | Nock on the ship, JavaScript in the browser | Decided |
6767| Optimizer | Basic lowering; holes later | Decided 2026-10-29 |
68−| Island `update` | In the browser | Decided |
68+| Island `update` | In the browser; returns the model and a list of commands, which the runtime processes one at a time in list order | Decided 2026-11-02 |
6969| Island `init` | Takes the page's data, returns the model | Decided 2026-10-29 |
7070| Island rendering | `view` re-runs on model changes; a keyed diff patches the DOM; holes later | Decided 2026-10-29 |
7171| Data crossing to the browser | No gates in island data or models | Decided 2026-10-29 |
@@ -73,6 +73,7 @@ The choices behind the Language tab, made on 2026-10-23; a later date marks a re
7373| Transactions | None; one poke per command | Decided |
7474| Reloads | Restart from the model the page is served with | Decided 2026-10-29 |
7575| Shared state | Stores: browser agents written like API files, with `state`, `+$ poke` and `(store init update)`; the store's `+$ poke` is a declaration, not a mold; derived gates provide poke constructors and state requests; one per page | Decided 2026-10-31 |
76+| Store builder | `+$ store |$ [S] [init=S update=*]`, with `++ store |= [init=S update=$-([A S] S)] ^- (store S) [init update]`: the builder checks action `A`, while `main` exposes only state `S`; the store kind check verifies `A` against the poke declaration | Decided 2026-11-01 |
7677| Subscriptions | By agent and path, shared per page; the first fact is full state, so no paths that need a scry path | Decided 2026-10-29 |
7778| Apps | One island under a catch-all route, given the path by `pure`; `%url` delivers the path on every change; in-section links act as `go`; focus moves to the first heading | Decided 2026-10-29 |
7879| Layout vocabulary | Jibb's elements and theme tokens; the stylesheet comes from the theme alone; chars and fill are inline; `[%fill n]` below 1 counts as 1 | Decided 2026-10-29 |
docs/spec/implementation-plan.md+1−1
@@ -73,7 +73,7 @@ For milestone 6. An island is one loop over one model: events become messages, `
7373- **Messages** come from controls, command replies, facts, timers and `%url`. *Proposed*: an island handles them one at a time, in arrival order.
7474- **Rendering**: a message changes the model when `update` returns a different noun; `view` then re-runs and a keyed diff patches the DOM. An unchanged model renders nothing. *Proposed*: the patch lands before the next message, so a crash in `view` belongs to one message.
7575- **Controls**: after every event, the control that fired is reset to the latest view, even when the model didn't change. A field's text is rewritten only when it differs from the screen, which keeps the caret and any IME composition.
76−- **Commands**: each reply arrives later as a new message, never inside the `update` that sent it. *Proposed*: commands run in list order, after the patch.
76+- **Commands**: an update may return several commands. The runtime processes them one at a time, in list order, after the patch. Each reply arrives later as a new message, never inside the `update` that sent it.
7777
7878| Control | Sends | When |
7979| --- | --- | --- |
docs/spec/overview.md+3−1
@@ -152,6 +152,8 @@ Loads and renders run in Nock.
152152 [%url reply=$-(path M)]
153153```
154154
155+An island's `update` returns `[model (list (cmd M))]`, so one message may produce several commands. The runtime processes the returned commands one at a time, in list order. A store's `update` consumes exactly one poke with the current state and returns the next state.
156+
155157- `poke`, `ask` and `qath` are transparent types defined in the internal prelude and re-exported normally. Derived gates and `pure` also construct requests. A derived poke constructor such as `(todo-action.todo [%add draft.m])` checks its value and supplies the agent and mark, so one island can poke several agents. The agent's mark rechecks on the ship; a nack's `tang` reaches the reply as text. Store constructors poke the store in the browser.
156158- A request such as `(todos.todo |=%got)` comes from a declared path or a store's `state`; its reply always gets full state. A path with diffs also takes a fold, `(changes.todo |=%got apply)`, which the runtime applies first. Facts are checked; a bad one crashes the reply, which counts as a crashed `update`.
157159- Islands read agents only by watching. A watch's first fact must be full state, so watching a request whose path case has a separate `scry=` path is a type error in an island. The checker must prove a request is watchable; unknown watchability is also a type error. The runtime acks facts, rewatches after a kick or a dropped connection and reseeds from the first fact; a refused watch shows the crash notice.
@@ -163,7 +165,7 @@ Inputs send a message per `input` event, and one per IME composition, so validat
163165
164166- `init` runs on the ship with the page's data and returns only the model, jammed into the page; the browser resumes from it at start. A reload starts from the model the page is served with.
165167- A crash in `update` drops the message, keeps the model and shows the standard notice.
166−- Stores share state between a page's islands. A store module, written like an API file, has `state`, `+$ poke` and `++ main (store init update)`, where `update` applies a poke. The store's `+$ poke` is a declaration, not a mold. Islands import it with `/=` and use its derived gates: a constructor per poke type, and `(state.cart |=%got)`, whose first fact is the current state and each later fact the next.
168+- Stores share state between a page's islands. A store module, written like an API file, has `state`, `+$ poke` and `++ main (store init update)`, where `update` applies a poke. The store's `+$ poke` is a declaration, not a mold. The builder is `+$ store |$ [S] [init=S update=*]` with `++ store |= [init=S update=$-([A S] S)] ^- (store S) [init update]`: it checks action `A`, while `main` exposes only state `S`; the store kind check verifies `A` against the declaration. Islands import it with `/=` and use its derived gates: a constructor per poke type, and `(state.cart |=%got)`, whose first fact is the current state and each later fact the next.
167169- A store runs in the browser from its `init` when its first island starts, and lasts as long as the page. Islands keep what they watch in their own models.
168170- An app is a page whose view is one island under a catch-all route; its `load` passes the path with `pure`. The island's `%url` subscription delivers the path at start and after every change, back and forward included. `go` pushes history, and `go` or `link` within the section changes the island without a reload. Focus then moves to the new view's first heading, which screen readers announce.
169171
docs/status.md+5−2
@@ -51,6 +51,8 @@ A narrow full-module path now checks direct four-wing `(program init update view
5151
5252Static and direct data-page `main` checking now completes the unchanged about page, blog index and todo index through the real Hoon readers. Static generic element mains specialize to closed canonical `(element !!)`; direct pages require a closed invariant `page` type and a direct plain derived-request load. Page loads reuse the strict source/member/evidence identity checks used by program watches, rejecting aliases, indirect/hand-built/pure/unknown requests, typed paths, diffs and store paths. The shared eval and ship fixture asserts exact main types and structural downstream imports. Rendering, runtime loading and request execution remain unimplemented.
5353
54+The prelude now has the approved `store` mold and action-checking builder. Direct two-wing store mains infer after removing the single local `+$ poke` declaration from ordinary molds and values; the final kind check requires one closed state mold, a direct local action reference, exact init/state and update relations, and no gate-free-state restriction. Stores export their ordinary state/action molds plus derived poke and state-request gates, never the poke declaration. Separate source-bound store certificates prove only the actual imported state member watchable; API evidence checks and page-load rejection remain intact. The unchanged cart and basket pass detailed and legacy checking with exact mains, derived schemes and structural imports, including non-keyed view and null-sample initializer recovery. Multi-action declarations, lowering and runtime execution remain unsupported.
55+
5456The component-local program recovery now covers update, subscriptions, one direct keyed `each`/`turn` mapper and its view, then the existing initializer and ordinary `main` path. Each recovered scheme is closed and freshly allocated; a keyed source screen avoids repeated doomed ordinary attempts without skipping final `main`, and non-gate views decline safely. Canonical `element` recursion and exact singleton-case list fits are narrowly guarded, with successful ordinary fits taking precedence. The byte-identical unchanged todo now passes both detailed and legacy full-module checks with an exact closed `main` type and structural downstream import. Wrong models, messages, results, mappers, keys, aliases, non-gate views and watches fail closed. This is static checking only: no Jibb execution or runtime watching is claimed.
5557
5658The 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. This remains declaration evidence rather than proof about an arbitrary request value. The narrow direct-program check above composes it with final value syntax, resolved imports and merged evidence for one plain request. Prepared artifacts and reader results remain trusted host inputs.
@@ -104,7 +106,7 @@ What the plan asks for, and where it is:
104106Besides the plan's list:
105107
106108- 660 golden cases: 440 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.
107−- The 660-case corpus passed under `urbit eval` in 96.8 s while other checks were running. The fake ship passed all 714 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 105.5 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.
109+- The 660-case corpus passed under `urbit eval` in 101.8 s while other checks were running. The fake ship passed all 715 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 104.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.
108110- `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.
109111- 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.
110112- 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).
@@ -226,7 +228,8 @@ Besides the plan's list:
226228| a163965 | 2026-11-01 | Recover direct-program update result contexts |
227229| 46748b0 | 2026-11-01 | Check the unchanged todo island through component recovery |
228230| 1e17d5f | 2026-11-01 | Check static and direct data-page mains |
229−| This change | 2026-11-01 | Add the theme mold and require explicit unit syntax |
231+| 0517053 | 2026-11-01 | Add the theme mold and require explicit unit syntax |
232+| This change | 2026-11-01 | Check the unchanged cart store and basket |
230233
231234## Checking it
232235
jibb-dev/lib/jibb.hoon+458−32
@@ -5623,10 +5623,14 @@
56235623:: of an arbitrary ask value. Reader graphs and source inputs are trusted.
56245624+$ irequest-evidence
56255625 [api-at=path name=term path=iapi-path-typed api-source=@t public-source=@t internal-source=@t prelude-values=(list term) prelude-molds=(list term) externals=iexternals marks=imark-externals]
5626+:: Store requests have their own source-bound evidence. In particular, an
5627+:: API path certificate cannot make a store state member watchable, or vice versa.
5628++$ istore-request-evidence
5629+ [store-at=path source=@t state=itype action-name=term action=itype]
56265630:: A unit distinguishes a verified empty closure from a detached legacy file.
56275631:: The opaque prelude is an exact trusted input, not a recursive interface mold.
56285632+$ irequest-graph
5629− [paths=(set path) requests=(list irequest-evidence) bundle-input=* prelude-input=* prelude-values=(list term) prelude-molds=(list term) externals=iexternals marks=imark-externals]
5633+ [paths=(set path) requests=(list irequest-evidence) stores=(list istore-request-evidence) bundle-input=* prelude-input=* prelude-values=(list term) prelude-molds=(list term) externals=iexternals marks=imark-externals]
56305634+$ ifile [values=ienv molds=imold-types at=path derived=(list iderived) elaborations=(list iwidth-definition) dependencies=(list iwidth-dependency) source=(unit @t) graph=(unit irequest-graph)]
56315635+$ ijimports (list [face=term interface=ifile])
56325636+$ icap [name=@t id=@ud at=span]
@@ -11676,6 +11680,25 @@
1167611680 =(externals.g externals)
1167711681 =(marks.g marks)
1167811682 ==
11683+++ request-graph-bounded
11684+ |= g=irequest-graph
11685+ ^- ?
11686+ =/ total=@ud (add (lent requests.g) (lent stores.g))
11687+ &((lte (lent ~(tap in:..zuse paths.g)) 256) (lte total 256))
11688+::
11689+++ store-graph-requests-add
11690+ |= [pending=(list istore-request-evidence) acc=(list istore-request-evidence) fuel=@ud]
11691+ ^- (unit (list istore-request-evidence))
11692+ ?~ pending `acc
11693+ ?: =(0 fuel) ~
11694+ =/ hit=(list istore-request-evidence)
11695+ (skim acc |=(x=istore-request-evidence =(store-at.x store-at.i.pending)))
11696+ ?^ hit
11697+ ?. ?=([* ~] hit) ~
11698+ ?. =(i.hit i.pending) ~
11699+ $(pending t.pending, fuel (dec fuel))
11700+ $(pending t.pending, acc [i.pending acc], fuel (dec fuel))
11701+::
1167911702++ request-graph-merge
1168011703 |= [imports=ijimports g=irequest-graph fuel=@ud]
1168111704 ^- (unit irequest-graph)
@@ -11696,8 +11719,13 @@
1169611719 =/ rs=(unit (list irequest-evidence))
1169711720 (request-graph-requests-add requests.cg requests.g (add 1 (lent requests.cg)))
1169811721 ?~ rs ~
11699− ?: &(?=(^ u.rs) |((gth (lent ~(tap in:..zuse merged)) 256) (gth (lent u.rs) 256))) ~
11700− $(imports t.imports, g g(paths merged, requests u.rs), fuel (dec fuel))
11722+ =/ ss=(unit (list istore-request-evidence))
11723+ (store-graph-requests-add stores.cg stores.g (add 1 (lent stores.cg)))
11724+ ?~ ss ~
11725+ =/ total=@ud (add (lent u.rs) (lent u.ss))
11726+ ?: &(?=(^ u.rs) |((gth (lent ~(tap in:..zuse merged)) 256) (gth total 256))) ~
11727+ ?: &(?=(^ u.ss) |((gth (lent ~(tap in:..zuse merged)) 256) (gth total 256))) ~
11728+ $(imports t.imports, g g(paths merged, requests u.rs, stores u.ss), fuel (dec fuel))
1170111729++ request-graph-reusable
1170211730 |= [f=ifile src=@t externals=iexternals marks=imark-externals modules=jbundle active=(list path) values=(list term) molds=(list term) prelude=(unit ifile)]
1170311731 ^- ?
@@ -12155,6 +12183,28 @@
1215512183:: Value watchability remains unproved even for a watchable declaration.
1215612184+$ ione-request-interface
1215712185 [support=iapi-support-evidence parts=iapi-request-parts iface=ifile]
12186+++ store-compatible-poke
12187+ |= prelude=iprelude
12188+ ^- (unit ischeme)
12189+ =/ public=ifile iface.prelude
12190+ ?. =(at.public /lib/jibb/prelude/jibb) ~
12191+ =/ poke=(unit ischeme) (find-jibb-mold %poke public)
12192+ ?~ poke ~
12193+ ?. ?=(%union -.typ.u.poke) ~
12194+ ?^ vars.u.poke ~
12195+ ?. =(origin.typ.u.poke `[/lib/jibb/internal/jibb %poke]) ~
12196+ ?: (itype-has-tag typ.u.poke) ~
12197+ =/ private=(list iwidth-dependency)
12198+ (skim dependencies.public |=(d=iwidth-dependency =(at.d /lib/jibb/internal/jibb)))
12199+ ?. ?=([* ~] private) ~
12200+ ?~ source.i.private ~
12201+ =/ agent-case=itype
12202+ [%cell [%const [%term %tas %agent '%agent']] [%cell [%face %agent [%atom %tas]] [%cell [%face %mark [%atom %tas]] [%face %payload [%noun ~]]]]]
12203+ =/ store-case=itype
12204+ [%cell [%const [%term %tas %store '%store']] [%cell [%face %module [%atom %t]] [%cell [%face %action [%atom %tas]] [%face %payload [%noun ~]]]]]
12205+ ?. =(cases.typ.u.poke ~[agent-case store-case]) ~
12206+ poke
12207+::
1215812208++ request-compatible-ask
1215912209 |= prelude=iprelude
1216012210 ^- (unit ischeme)
@@ -12251,7 +12301,7 @@
1225112301 ?~ source.i.private [%| 'request internal source needs unsupported inference']
1225212302 =/ req=irequest-evidence
1225312303 [file name.path.p p src u.source.public u.source.i.private values.prelude molds.prelude externals marks]
12254− =/ interface=ifile [~[[name.path.p scheme]] exports file ~ ~ ~ `src `[(silt `(list path)`~[file]) ~[req] modules `public values.prelude molds.prelude externals marks]]
12304+ =/ interface=ifile [~[[name.path.p scheme]] exports file ~ ~ ~ `src `[(silt `(list path)`~[file]) ~[req] ~ modules `public values.prelude molds.prelude externals marks]]
1225512305 [%& [support u.parts interface]]
1225612306:: Graph-aware request artifact; resolver use remains type-only.
1225712307++ one-request-interface-graph
@@ -12305,7 +12355,7 @@
1230512355 ?~ source.i.private [%| 'request internal source needs unsupported inference']
1230612356 =/ req=irequest-evidence
1230712357 [file name.path.p p src u.source.public u.source.i.private values.prelude molds.prelude externals marks]
12308− =/ interface=ifile [~[[name.path.p scheme]] exports file ~ ~ ~ `src `[(silt `(list path)`~[file]) ~[req] modules `public values.prelude molds.prelude externals marks]]
12358+ =/ interface=ifile [~[[name.path.p scheme]] exports file ~ ~ ~ `src `[(silt `(list path)`~[file]) ~[req] ~ modules `public values.prelude molds.prelude externals marks]]
1230912359 [%& [support u.parts interface]]
1231012360::
1231112361++ api-mark-exports
@@ -12474,7 +12524,7 @@
1247412524 [%| 'API exported molds need unsupported inference']
1247512525 =/ env=ienv (weld values.u.gates (weld values.u.poke values.support))
1247612526 =/ graph=irequest-graph
12477− [(silt `(list path)`~[file]) requests.u.gates modules `public values.prep molds.prep externals marks]
12527+ [(silt `(list path)`~[file]) requests.u.gates ~ modules `public values.prep molds.prep externals marks]
1247812528 =/ iface=ifile
1247912529 [env exports file derived.u.poke elaborations.support ~ `src `graph]
1248012530 [%& [iface dependencies.ev]]
@@ -12554,6 +12604,61 @@
1255412604 ?~ view ~
1255512605 `[u.load u.view]
1255612606::
12607+:: A store main is only the direct two-wing source call. The poke declaration
12608+:: is checked here, then removed before every ordinary mold/value inference pass.
12609+++ store-main-parts
12610+ |= d=def
12611+ ^- (unit [init=term update=term])
12612+ ?. ?=(%value -.d) ~
12613+ |-
12614+ ?: ?=(%group -.val.d) $(val.d inner.val.d)
12615+ ?. ?=(%call -.val.d) ~
12616+ =/ head=(unit term) (program-main-wing head.val.d)
12617+ ?~ head ~
12618+ ?. =(%store u.head) ~
12619+ ?. ?=([* * ~] args.val.d) ~
12620+ =/ args=(list expr) args.val.d
12621+ ?> ?=([* * ~] args)
12622+ =/ init=(unit term) (program-main-wing i.args)
12623+ =/ update=(unit term) (program-main-wing i.t.args)
12624+ ?~ init ~
12625+ ?~ update ~
12626+ `[u.init u.update]
12627+::
12628++$ istore-declaration [action=term defs=(list def)]
12629+++ store-declaration
12630+ |= [mod=module prelude-values=(list term) prelude-molds=(list term)]
12631+ ^- (unit istore-declaration)
12632+ =/ ds=(list def) defs.mod
12633+ =/ pokes=(list def)
12634+ (skim ds |=(d=def &(?=(%mold -.d) =(%poke name.d))))
12635+ ?. ?=([* ~] pokes) ~
12636+ =/ states=(list def)
12637+ (skim ds |=(d=def &(?=(%mold -.d) =(%state name.d))))
12638+ ?. ?=([* ~] states) ~
12639+ =/ poke=def i.pokes
12640+ =/ state=def i.states
12641+ ?> &(?=(%mold -.poke) ?=(%mold -.state))
12642+ ?: ?=(%generic -.shape.state) ~
12643+ ?. ?=(%ref -.shape.poke) ~
12644+ ?. ?=([@ ~] names.shape.poke) ~
12645+ =/ action=term i.names.shape.poke
12646+ =/ actions=(list def)
12647+ (skim ds |=(d=def &(?=(%mold -.d) =(action name.d))))
12648+ ?. ?=([* ~] actions) ~
12649+ =/ action-def=def i.actions
12650+ ?> ?=(%mold -.action-def)
12651+ ?: ?=(%generic -.shape.action-def) ~
12652+ =/ ordinary=(list def)
12653+ (skim ds |=(d=def !&(?=(%mold -.d) =(%poke name.d))))
12654+ ?. (module-scope-valid mod(defs ordinary) prelude-values prelude-molds) ~
12655+ =/ derived=(list term) ~[%state action]
12656+ ?: (lien derived |=(n=term =(n %proj))) ~
12657+ =/ outer=(list term)
12658+ (weld prelude-values (weld (global-value-names ordinary) (api-import-faces imports.mod)))
12659+ ?. (levy derived |=(n=term &((unique-value-name n derived) !(lien outer |=(x=term =(n x)))))) ~
12660+ `[action ordinary]
12661+::
1255712662++ program-empty-null
1255812663 |= e=expr
1255912664 ^- ?
@@ -13155,6 +13260,86 @@
1315513260 (program-single-case-fit i.args.actual-el i.args.expected-el sub.expected-check next.expected-check)
1315613261 case-fit
1315713262::
13263+:: A direct view without a keyed each/turn site still needs the message type
13264+:: from the checked update. Recover only that closed component; final main
13265+:: checking remains the canonical program-kind boundary.
13266+++ program-plain-view-context
13267+ |= [parts=[init=term update=term view=term subs=term] ds=(list def) resolution=iresolved initial=istate]
13268+ ^- (unit iresolved)
13269+ =/ env=ienv env.resolution
13270+ ?^ (ienv-lookup %main env) ~
13271+ ?^ (ienv-lookup view.parts env) ~
13272+ =/ relation=(unit [message=itype model=itype])
13273+ (program-update-relation update.parts ds env)
13274+ ?~ relation ~
13275+ =/ views=(list def)
13276+ (skim ds |=(d=def &(?=(%value -.d) =(view.parts name.d))))
13277+ ?. ?=([* ~] views) ~
13278+ =/ view-def=def i.views
13279+ ?> ?=(%value -.view-def)
13280+ =/ written-view=(unit sample) (direct-gate-sample view-def)
13281+ ?~ written-view ~
13282+ =/ body=expr
13283+ ?- -.val.view-def
13284+ %gate body.val.view-def
13285+ %gate-wide body.val.view-def
13286+ * !!
13287+ ==
13288+ =/ sites=(unit (list iview-site)) (program-view-sites body ~)
13289+ ?~ sites ~
13290+ ?^ u.sites ~
13291+ ?~ prelude.initial ~
13292+ ?~ (ienv-lookup %program values.u.prelude.initial) ~
13293+ =/ element=(unit ischeme) (find-jibb-mold %element u.prelude.initial)
13294+ ?~ element ~
13295+ =/ heads=(unit igate-prelude-evidence) (direct-prelude-evidence ds prelude.initial)
13296+ ?~ heads ~
13297+ ?~ (~(get by gates.u.heads) %program) ~
13298+ =/ checked=(map term def) (direct-checked-gates ds env)
13299+ =/ templates=ienv
13300+ (turn molds.u.prelude.initial |=(x=[name=term template=ischeme] [name.x template.x]))
13301+ =/ scanned=(unit dgscan)
13302+ (dg-all-env-ids (weld env (weld values.u.prelude.initial templates)) 32.768 ~)
13303+ ?~ scanned ~
13304+ =. next.initial (dg-next-id ids.u.scanned 0)
13305+ =/ view-state=istate (reserve-def-caps val.view-def initial)
13306+ =/ sam=isample-result (infer-sample u.written-view env view-state)
13307+ ?: ?=(%| -.sam) ~
13308+ =/ actual-model=itype (program-inferred-sample typ.p.sam u.written-view)
13309+ ?. ?=(~ (itype-vars actual-model)) ~
13310+ ?: (itype-has-tag actual-model) ~
13311+ =/ model-fit=ifit
13312+ (direct-invariant actual-model model.u.relation sub.state.p.sam next.state.p.sam)
13313+ ?. ?=(%ok -.model-fit) ~
13314+ =/ product=(unit itype) (template-apply u.element ~[message.u.relation])
13315+ ?~ product ~
13316+ =/ st=istate
13317+ state.p.sam(sub sub.model-fit, next next.model-fit, gate-defs checked, head-evidence heads)
13318+ =/ inferred=iresult
13319+ (infer-call-context-arg body u.product env.p.sam st (span-of body))
13320+ ?: ?=(%| -.inferred) ~
13321+ =/ product-fit=ifit
13322+ (itype-fit typ.p.inferred u.product sub.state.p.inferred next.state.p.inferred)
13323+ ?. ?=(%ok -.product-fit) ~
13324+ =/ merged-product=itype
13325+ (itype-merge-faces typ.p.inferred u.product sub.product-fit)
13326+ =/ actual-cast=itype [%fn typ.p.sam merged-product]
13327+ =/ closed=itype [%fn typ.p.sam u.product]
13328+ =/ cast=ifit
13329+ (itype-fit actual-cast closed sub.product-fit next.product-fit)
13330+ ?. ?=(%ok -.cast) ~
13331+ =/ merged=itype (itype-merge-faces actual-cast closed sub.cast)
13332+ =/ adjusted=iresult
13333+ [%& merged state.p.inferred(sub sub.cast, next next.cast)]
13334+ =/ added=(unit iadded-definition)
13335+ (add-supported-result view-def adjusted view-state env checked artifacts.resolution)
13336+ ?~ added ~
13337+ =/ recovered=(unit ischeme) (ienv-lookup view.parts env.u.added)
13338+ ?~ recovered ~
13339+ ?. ?=(~ vars.u.recovered) ~
13340+ ?. ?=(~ (itype-vars typ.u.recovered)) ~
13341+ `[env.u.added grouped.resolution artifacts.u.added]
13342+::
1315813343:: Recover exactly one direct keyed each/turn row mapper, then its view.
1315913344:: The prelude's own each and turn schemes determine the mapper gate: the
1316013345:: key is inferred from the mapper body, never selected by this recovery.
@@ -13377,6 +13562,88 @@
1337713562 ?. ?=(~ (itype-vars typ.u.recovered)) ~
1337813563 `[env.u.added grouped.resolution artifacts.u.added]
1337913564::
13565+++ program-init-null-sample
13566+ |= d=def
13567+ ^- ?
13568+ =/ written=(unit sample) (direct-gate-sample d)
13569+ ?~ written |
13570+ ?. ?=(%bare -.u.written) |
13571+ =/ sh=shape shape.u.written
13572+ ?. ?=(%const -.sh) |
13573+ =(%null form.lit.sh)
13574+::
13575+:: The tuple-ending-null initializer retry above intentionally keeps its own
13576+:: boundary. A direct null-sample initializer can instead receive the closed
13577+:: model already established by update, view and subscriptions.
13578+++ program-plain-init-context
13579+ |= [parts=[init=term update=term view=term subs=term] ds=(list def) resolution=iresolved initial=istate]
13580+ ^- (unit iresolved)
13581+ =/ env=ienv env.resolution
13582+ ?^ (ienv-lookup %main env) ~
13583+ ?^ (ienv-lookup init.parts env) ~
13584+ ?~ (ienv-lookup update.parts env) ~
13585+ ?~ (ienv-lookup view.parts env) ~
13586+ ?~ (ienv-lookup subs.parts env) ~
13587+ =/ relation=(unit [message=itype model=itype])
13588+ (program-update-relation update.parts ds env)
13589+ ?~ relation ~
13590+ =/ inits=(list def)
13591+ (skim ds |=(d=def &(?=(%value -.d) =(init.parts name.d))))
13592+ ?. ?=([* ~] inits) ~
13593+ =/ init-def=def i.inits
13594+ ?> ?=(%value -.init-def)
13595+ ?. (program-init-null-sample init-def) ~
13596+ =/ written=(unit sample) (direct-gate-sample init-def)
13597+ ?~ written ~
13598+ =/ body=expr
13599+ ?- -.val.init-def
13600+ %gate body.val.init-def
13601+ %gate-wide body.val.init-def
13602+ * !!
13603+ ==
13604+ ?~ prelude.initial ~
13605+ ?~ (ienv-lookup %program values.u.prelude.initial) ~
13606+ =/ heads=(unit igate-prelude-evidence) (direct-prelude-evidence ds prelude.initial)
13607+ ?~ heads ~
13608+ ?~ (~(get by gates.u.heads) %program) ~
13609+ =/ checked=(map term def) (direct-checked-gates ds env)
13610+ =/ templates=ienv
13611+ (turn molds.u.prelude.initial |=(x=[name=term template=ischeme] [name.x template.x]))
13612+ =/ scanned=(unit dgscan)
13613+ (dg-all-env-ids (weld env (weld values.u.prelude.initial templates)) 32.768 ~)
13614+ ?~ scanned ~
13615+ =. next.initial (dg-next-id ids.u.scanned 0)
13616+ =/ init-state=istate (reserve-def-caps val.init-def initial)
13617+ =/ sam=isample-result (infer-sample u.written env init-state)
13618+ ?: ?=(%| -.sam) ~
13619+ ?. ?=(~ (itype-vars typ.p.sam)) ~
13620+ ?: (itype-has-tag typ.p.sam) ~
13621+ =/ st=istate state.p.sam(gate-defs checked, head-evidence heads)
13622+ =/ inferred=iresult
13623+ (infer-call-context-arg body model.u.relation env.p.sam st (span-of body))
13624+ ?: ?=(%| -.inferred) ~
13625+ =/ product-fit=ifit
13626+ (itype-fit typ.p.inferred model.u.relation sub.state.p.inferred next.state.p.inferred)
13627+ ?. ?=(%ok -.product-fit) ~
13628+ =/ merged-product=itype
13629+ (itype-merge-faces typ.p.inferred model.u.relation sub.product-fit)
13630+ =/ actual-cast=itype [%fn typ.p.sam merged-product]
13631+ =/ closed=itype [%fn typ.p.sam model.u.relation]
13632+ =/ cast=ifit
13633+ (itype-fit actual-cast closed sub.product-fit next.product-fit)
13634+ ?. ?=(%ok -.cast) ~
13635+ =/ merged=itype (itype-merge-faces actual-cast closed sub.cast)
13636+ =/ adjusted=iresult
13637+ [%& merged state.p.inferred(sub sub.cast, next next.cast)]
13638+ =/ added=(unit iadded-definition)
13639+ (add-supported-result init-def adjusted init-state env checked artifacts.resolution)
13640+ ?~ added ~
13641+ =/ recovered=(unit ischeme) (ienv-lookup init.parts env.u.added)
13642+ ?~ recovered ~
13643+ ?. ?=(~ vars.u.recovered) ~
13644+ ?. ?=(~ (itype-vars typ.u.recovered)) ~
13645+ `[env.u.added grouped.resolution artifacts.u.added]
13646+::
1338013647:: Recover only the initializer of an already recognized direct program main.
1338113648:: The derived call is evidence for an ordinary init/main retry, never an
1338213649:: interface to publish on its own. Any failure returns the original resolution.
@@ -13484,6 +13751,23 @@
1348413751 ?. ?=(~ (itype-vars typ.u.recovered)) ~
1348513752 `[env.u.added grouped.resolution artifacts.u.added]
1348613753::
13754+++ store-derived-schemes
13755+ |= [prelude=ifile values=(list term) molds=(list term) state=itype action=itype]
13756+ ^- (unit [state=ischeme action=ischeme])
13757+ =/ prep=iprelude [prelude values molds]
13758+ =/ ask=(unit ischeme) (request-compatible-ask prep)
13759+ ?~ ask ~
13760+ =/ poke=(unit ischeme) (store-compatible-poke prep)
13761+ ?~ poke ~
13762+ ?^ (itype-vars state) ~
13763+ ?^ (itype-vars action) ~
13764+ ?: |((itype-has-tag state) (itype-has-tag action)) ~
13765+ =/ result=(unit itype) (template-apply u.ask ~[[%var 0]])
13766+ ?~ result ~
13767+ =/ request=ischeme [[%fn [%fn state [%var 0]] u.result] ~[0]]
13768+ =/ constructor=ischeme [[%fn action typ.u.poke] ~]
13769+ `[request constructor]
13770+::
1348713771++ program-subs-watch
1348813772 |= [d=def imports=ijimports graph=irequest-graph prelude=ifile]
1348913773 ^- ?
@@ -13518,7 +13802,9 @@
1351813802 =/ callback=expr (program-transparent i.args.request)
1351913803 ?. ?=(%ctor -.callback) |
1352013804 ?. ?=(%term form.tag.callback) |
13521− ?=(^ (derived-request-member case face imports graph prelude))
13805+ ?| ?=(^ (derived-request-member case face imports graph prelude))
13806+ ?=(^ (derived-store-request-member case face imports graph prelude))
13807+ ==
1352213808::
1352313809:: Exact derived-member and request-evidence identity, shared by direct
1352413810:: program watches and direct data-page loads. Only a plain request in the
@@ -13558,6 +13844,35 @@
1355813844 ?. =(product.typ.u.member u.result) ~
1355913845 member
1356013846::
13847+:: Store state is watchable by definition, but only the actual derived member
13848+:: of the uniquely selected source-bound store interface proves that fact.
13849+++ derived-store-request-member
13850+ |= [case=term face=term imports=ijimports graph=irequest-graph prelude=ifile]
13851+ ^- (unit ischeme)
13852+ ?. =(%state case) ~
13853+ =/ selected=(list [face=term interface=ifile])
13854+ (skim imports |=(j=[face=term interface=ifile] =(face face.j)))
13855+ ?. ?=([* ~] selected) ~
13856+ =/ iface=ifile interface.i.selected
13857+ =/ member=(unit ischeme) (ienv-lookup %state values.iface)
13858+ ?~ member ~
13859+ ?~ source.iface ~
13860+ =/ evidence=(list istore-request-evidence)
13861+ (skim stores.graph |=(r=istore-request-evidence =(store-at.r at.iface)))
13862+ ?. ?=([* ~] evidence) ~
13863+ =/ request=istore-request-evidence i.evidence
13864+ ?. =(u.source.iface source.request) ~
13865+ ?~ graph.iface ~
13866+ ?. (lien stores.u.graph.iface |=(r=istore-request-evidence =(r request))) ~
13867+ =/ derived=(unit [state=ischeme action=ischeme])
13868+ (store-derived-schemes prelude prelude-values.graph prelude-molds.graph state.request action.request)
13869+ ?~ derived ~
13870+ ?. =(u.member state.u.derived) ~
13871+ =/ constructor=(unit ischeme) (ienv-lookup action-name.request values.iface)
13872+ ?~ constructor ~
13873+ ?. =(u.constructor action.u.derived) ~
13874+ member
13875+::
1356113876++ program-main-context
1356213877 |= [main=def ds=(list def) resolution=iresolved initial=istate]
1356313878 ^- iresolved
@@ -13670,6 +13985,72 @@
1367013985 ?. ?=([* ~] subs) |
1367113986 |((program-subs-empty i.subs) (program-subs-watch i.subs imports graph u.prelude))
1367213987::
13988+:: The two outer sample faces are binder names, not part of the action/state
13989+:: relation. Leave every face inside either component untouched.
13990+++ store-update-unfaced
13991+ |= typ=itype
13992+ ^- itype
13993+ ?. ?=(%fn -.typ) typ
13994+ ?. ?=(%cell -.sample.typ) typ
13995+ =/ head=itype hed.sample.typ
13996+ =/ tail=itype tal.sample.typ
13997+ =? head ?=(%face -.head) body.head
13998+ =? tail ?=(%face -.tail) body.tail
13999+ typ(sample [%cell head tail])
14000+::
14001+:: The builder erases the action from main. Recover it only from the direct
14002+:: local poke declaration and check both ordinary components invariantly.
14003+++ store-main-closed
14004+ |= [parts=[init=term update=term] action=term env=ienv molds=imold-types prelude=(unit ifile)]
14005+ ^- (unit ischeme)
14006+ ?~ prelude ~
14007+ =/ builder=(unit ischeme) (ienv-lookup %store values.u.prelude)
14008+ ?~ builder ~
14009+ ?. ?=([@ @ ~] vars.u.builder) ~
14010+ =/ state-var=@ud i.vars.u.builder
14011+ =/ action-var=@ud i.t.vars.u.builder
14012+ ?: =(state-var action-var) ~
14013+ =/ builder-sample=itype
14014+ [%cell [%face %init [%var state-var]] [%face %update [%fn [%cell [%var action-var] [%var state-var]] [%var state-var]]]]
14015+ =/ builder-product=itype [%cell [%face %init [%var state-var]] [%face %update [%noun ~]]]
14016+ ?. =(typ.u.builder [%fn builder-sample builder-product]) ~
14017+ =/ store=(unit ischeme) (find-jibb-mold %store u.prelude)
14018+ ?~ store ~
14019+ ?. ?=([@ ~] vars.u.store) ~
14020+ ?. =(typ.u.store [%cell [%face %init [%var i.vars.u.store]] [%face %update [%noun ~]]]) ~
14021+ =/ state=(unit ischeme) (find-jibb-mold %state [~ molds /tmp ~ ~ ~ ~ ~])
14022+ ?~ state ~
14023+ =/ action-mold=(unit ischeme) (find-jibb-mold action [~ molds /tmp ~ ~ ~ ~ ~])
14024+ ?~ action-mold ~
14025+ ?. &(?=(~ vars.u.state) ?=(~ (itype-vars typ.u.state))) ~
14026+ ?. &(?=(~ vars.u.action-mold) ?=(~ (itype-vars typ.u.action-mold))) ~
14027+ =/ canonical=(unit itype) (template-apply u.store ~[typ.u.state])
14028+ ?~ canonical ~
14029+ =/ main=(unit ischeme) (ienv-lookup %main env)
14030+ =/ main-fit=(unit ifit)
14031+ ?~(main ~ `(direct-invariant typ.u.main u.canonical ~ 0))
14032+ =/ main-ok=?
14033+ ?~ main &
14034+ ?. ?=(~ vars.u.main) |
14035+ ?. ?=(~ (itype-vars typ.u.main)) |
14036+ ?~ main-fit |
14037+ ?=(%ok -.u.main-fit)
14038+ ?. main-ok ~
14039+ =/ init=(unit ischeme) (ienv-lookup init.parts env)
14040+ ?~ init ~
14041+ ?. ?=(~ vars.u.init) ~
14042+ ?. ?=(~ (itype-vars typ.u.init)) ~
14043+ =/ init-fit=ifit (direct-invariant typ.u.init typ.u.state ~ 0)
14044+ ?. ?=(%ok -.init-fit) ~
14045+ =/ update=(unit ischeme) (ienv-lookup update.parts env)
14046+ ?~ update ~
14047+ ?. ?=(~ vars.u.update) ~
14048+ ?. ?=(~ (itype-vars typ.u.update)) ~
14049+ =/ expected=itype [%fn [%cell typ.u.action-mold typ.u.state] typ.u.state]
14050+ =/ update-fit=ifit (direct-invariant (store-update-unfaced typ.u.update) expected ~ 0)
14051+ ?. ?=(%ok -.update-fit) ~
14052+ `[u.canonical ~]
14053+::
1367314054++ infer-jibb-file
1367414055 |= [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)]
1367514056 ^- jfile-result
@@ -13691,7 +14072,7 @@
1369114072 ?: ?=([%ui %api *] at)
1369214073 =/ iface=(unit ifile) (api-poke-interface at mod mark-externals prelude-values prelude-molds prelude)
1369314074 ?^ iface
13694− =/ checked=ifile u.iface(source `src, graph `[(silt `(list path)`~[at]) ~ modules prelude prelude-values prelude-molds externals mark-externals])
14075+ =/ checked=ifile u.iface(source `src, graph `[(silt `(list path)`~[at]) ~ ~ modules prelude prelude-values prelude-molds externals mark-externals])
1369514076 [%& [checked [[at checked] cache]]]
1369614077 ?~ prelude [%| [(crip "API module needs unsupported inference: {(spud at)}") ~]]
1369714078 =/ prepared=iprelude [u.prelude prelude-values prelude-molds]
@@ -13710,23 +14091,31 @@
1371014091 (multi-request-interface-graph at src externals mark-externals modules active cache `prepared)
1371114092 ?: ?=(%| -.multi) [%| [(crip "API module needs unsupported inference: {(spud at)}") ~]]
1371214093 [%& [iface.p.multi [[at iface.p.multi] cache.p.multi]]]
13713− ?. (module-scope-valid mod prelude-values prelude-molds)
13714− ?: (pending-declared-poke at mod prelude-values prelude-molds)
13715− [%| [(crip "module kind or scope needs unsupported inference: {(spud at)}") ~]]
13716− [%| [(crip "module has conflicting names: {(spud at)}") ~]]
13717− =/ vals=(list term) (global-value-names defs.mod)
1371814094 =/ main=(unit def) (program-main-def defs.mod)
1371914095 =/ main-parts=(unit [init=term update=term view=term subs=term])
1372014096 ?~(main ~ (program-main-parts u.main))
1372114097 =/ page-parts=(unit [load=term view=term])
1372214098 ?~(main ~ (page-main-parts u.main))
13723− ?: &(?=([%ui %stores *] at) ?=(^ main))
14099+ =/ store-parts=(unit [init=term update=term])
14100+ ?~(main ~ (store-main-parts u.main))
14101+ =/ declared=(unit istore-declaration)
14102+ ?~(store-parts ~ (store-declaration mod prelude-values prelude-molds))
14103+ ?: &(?=(^ store-parts) ?=(~ declared))
14104+ [%| [(crip "module kind or scope needs unsupported inference: {(spud at)}") ~]]
14105+ ?: &(?=([%ui %stores *] at) ?=(^ main) ?=(~ store-parts))
1372414106 [%| [(crip "module kind needs unsupported inference: {(spud at)}") ~]]
14107+ =/ ds=(list def) ?~(declared defs.mod defs.u.declared)
14108+ =/ checking=module mod(defs ds)
14109+ ?. (module-scope-valid checking prelude-values prelude-molds)
14110+ ?: (pending-declared-poke at mod prelude-values prelude-molds)
14111+ [%| [(crip "module kind or scope needs unsupported inference: {(spud at)}") ~]]
14112+ [%| [(crip "module has conflicting names: {(spud at)}") ~]]
14113+ =/ vals=(list term) (global-value-names ds)
1372514114 =/ js=jimports-detailed-result (resolve-jibb-imports-detailed imports.mod externals mark-externals modules active prelude-values prelude-molds cache prelude)
1372614115 ?: ?=(%| -.js) [%| p.js]
1372714116 =/ collected=grec-collected
13728− ?^ imports.mod [(collect-simple-molds defs.mod) *(map term shape)]
13729− (grec-collect-molds defs.mod)
14117+ ?^ imports.mod [(collect-simple-molds ds) *(map term shape)]
14118+ (grec-collect-molds ds)
1373014119 =/ molds=imolds molds.collected
1373114120 =/ globals=(list term) (weld prelude-values (weld (import-binding-names imports.mod) vals))
1373214121 =/ surs=(list term) (collect-sur-imports imports.mod)
@@ -13757,56 +14146,93 @@
1375714146 [%| [msg `[at src name.witness cases.witness]]]
1375814147 =/ resolution=iresolved
1375914148 ?~ index
13760− (resolve-groups defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude)
13761− (resolve-groups-core defs.mod molds globals externals surs mark-externals marks resolved.p.js reserved at prelude index)
14149+ (resolve-groups ds molds globals externals surs mark-externals marks resolved.p.js reserved at prelude)
14150+ (resolve-groups-core ds molds globals externals surs mark-externals marks resolved.p.js reserved at prelude index)
1376214151 =/ env=ienv env.resolution
1376314152 =/ recovered=iresolved
1376414153 ?~ main resolution
1376514154 ?~ main-parts resolution
1376614155 =/ updated=(unit iresolved)
13767− (program-update-context u.main u.main-parts defs.mod resolution state)
14156+ (program-update-context u.main u.main-parts ds resolution state)
1376814157 =/ with-update=iresolved ?~(updated resolution u.updated)
1376914158 =/ subscribed=(unit iresolved)
13770− (program-subs-context u.main-parts defs.mod with-update state)
14159+ (program-subs-context u.main-parts ds with-update state)
1377114160 =/ with-subs=iresolved ?~(subscribed with-update u.subscribed)
1377214161 =/ viewed=(unit iresolved)
13773− (program-view-context u.main-parts defs.mod with-subs state)
13774− =/ with-view=iresolved ?~(viewed with-subs u.viewed)
14162+ (program-view-context u.main-parts ds with-subs state)
14163+ =/ with-keyed-view=iresolved ?~(viewed with-subs u.viewed)
14164+ =/ plain-view=(unit iresolved)
14165+ ?^(viewed ~ (program-plain-view-context u.main-parts ds with-keyed-view state))
14166+ =/ with-view=iresolved ?~(plain-view with-keyed-view u.plain-view)
1377514167 =/ initialized=(unit iresolved)
13776− (program-init-context u.main u.main-parts defs.mod with-view state)
13777− =/ components=iresolved ?~(initialized with-view u.initialized)
13778− (program-main-context u.main defs.mod components state)
14168+ (program-init-context u.main u.main-parts ds with-view state)
14169+ =/ with-initialized=iresolved ?~(initialized with-view u.initialized)
14170+ =/ plain-init=(unit iresolved)
14171+ ?^(initialized ~ (program-plain-init-context u.main-parts ds with-initialized state))
14172+ =/ components=iresolved ?~(plain-init with-initialized u.plain-init)
14173+ (program-main-context u.main ds components state)
1377914174 =. env env.recovered
1378014175 =. artifacts.resolution artifacts.recovered
1378114176 =. env
13782− ?: (module-values-complete defs.mod env) env
14177+ ?: (module-values-complete ds env) env
1378314178 ?: |(?=([%ui %stores *] at) ?=(^ imports.mod) ?=(^ prelude) ?=(^ prelude-values) ?=(^ prelude-molds)) env
1378414179 ?: (gth (met 3 src) 65.536) env
13785− ?: (gth (lent defs.mod) 64) env
13786− ?. (dg-source-candidate defs.mod 64) env
14180+ ?: (gth (lent ds) 64) env
14181+ ?. (dg-source-candidate ds 64) env
1378714182 =/ transaction=(unit dgcommit) (dg-root-source at src)
1378814183 ?~ transaction env
1378914184 ?: (dg-interface-safe env.u.transaction) env.u.transaction
1379014185 env
13791− ?. (module-values-complete defs.mod env)
14186+ =/ required=(list def)
14187+ ?~ store-parts ds
14188+ (skim ds |=(d=def !&(?=(%value -.d) =(%main name.d))))
14189+ ?. (module-values-complete required env)
1379214190 [%| [(crip "module definitions need unsupported inference: {(spud at)}") ~]]
13793− =/ initial=irequest-graph [(silt `(list path)`~[at]) ~ modules prelude prelude-values prelude-molds externals mark-externals]
14191+ =/ initial=irequest-graph [(silt `(list path)`~[at]) ~ ~ modules prelude prelude-values prelude-molds externals mark-externals]
1379414192 =/ graph=(unit irequest-graph) (request-graph-merge resolved.p.js initial (add 1 (lent resolved.p.js)))
1379514193 ?~ graph [%| ['module request evidence needs unsupported inference' ~]]
1379614194 =/ static-main=(unit ischeme)
1379714195 ?~ main ~
1379814196 ?^ main-parts ~
1379914197 ?^ page-parts ~
14198+ ?^ store-parts ~
1380014199 (static-main-specialized env prelude)
1380114200 =? env ?=(^ static-main)
1380214201 [[%main u.static-main] (skim env |=(entry=[name=term scheme=ischeme] !=(%main name.entry)))]
14202+ =/ store-main=(unit ischeme)
14203+ ?~ store-parts ~
14204+ ?~ declared ~
14205+ (store-main-closed u.store-parts action.u.declared env p.mts prelude)
14206+ =? env ?=(^ store-main)
14207+ [[%main u.store-main] (skim env |=(entry=[name=term scheme=ischeme] !=(%main name.entry)))]
1380314208 =/ kind-ok=?
1380414209 ?~ main &
13805− ?^ main-parts (program-main-closed u.main-parts defs.mod env prelude resolved.p.js u.graph)
13806− ?^ page-parts (page-main-closed u.page-parts defs.mod env prelude resolved.p.js u.graph)
14210+ ?^ main-parts (program-main-closed u.main-parts ds env prelude resolved.p.js u.graph)
14211+ ?^ page-parts (page-main-closed u.page-parts ds env prelude resolved.p.js u.graph)
14212+ ?^ store-parts ?=(^ store-main)
1380714213 ?=(^ static-main)
1380814214 ?. kind-ok
1380914215 [%| [(crip "module kind needs unsupported inference: {(spud at)}") ~]]
14216+ =/ store-derived=(unit [values=ienv evidence=istore-request-evidence])
14217+ ?~ declared ~
14218+ ?~ prelude ~
14219+ =/ state=(unit ischeme) (find-jibb-mold %state [~ p.mts at ~ ~ ~ ~ ~])
14220+ ?~ state ~
14221+ =/ action-mold=(unit ischeme) (find-jibb-mold action.u.declared [~ p.mts at ~ ~ ~ ~ ~])
14222+ ?~ action-mold ~
14223+ =/ schemes=(unit [state=ischeme action=ischeme])
14224+ (store-derived-schemes u.prelude prelude-values prelude-molds typ.u.state typ.u.action-mold)
14225+ ?~ schemes ~
14226+ =/ evidence=istore-request-evidence
14227+ [at src typ.u.state action.u.declared typ.u.action-mold]
14228+ `[~[[%state state.u.schemes] [action.u.declared action.u.schemes]] evidence]
14229+ ?: &(?=(^ declared) ?=(~ store-derived))
14230+ [%| [(crip "store derived gates need unsupported inference: {(spud at)}") ~]]
14231+ =? env ?=(^ store-derived) (weld values.u.store-derived env)
14232+ =? graph ?=(^ store-derived)
14233+ `u.graph(stores [evidence.u.store-derived stores.u.graph])
14234+ ?. (request-graph-bounded u.graph)
14235+ [%| ['module request evidence needs unsupported inference' ~]]
1381014236 =/ iface=ifile [env p.mts at ~ artifacts.resolution ~ `src graph]
1381114237 [%& [iface [[at iface] cache.p.js]]]
1381214238::
jibb-dev/lib/jibb/prelude.jibb+5
@@ -514,3 +514,8 @@
514514
515515++ page |= [load=$-(R (ask D)) view=$-(D (element !!))]
516516 ^- (page R D) [load view]
517+
518++$ store |$ [S] [init=S update=*]
519+
520+++ store |= [init=S update=$-([A S] S)]
521+ ^- (store S) [init update]
tests/golden/types-prelude-ask/source.jibb+1−1
@@ -40,7 +40,7 @@
4040++ ordinary-path ^- path ~[~.items]
4141++ ask-from-ordinary (agent ordinary-path |=(v=[mark=@tas state=(unit *) fact=*] [state=0 message="ok"]))
4242++ ask-from-qath (agent %/items |=(v=[mark=@tas state=(unit *) fact=*] [state=0 message="ok"]))
43−++ store |= rec=$-([state=(unit *) fact=*] [state=* message=@t])
43+++ store-ask |= rec=$-([state=(unit *) fact=*] [state=* message=@t])
4444 ^- (ask @t) [%store module="/ui/store/cart" name=%state receive=rec]
4545++ wrong-store |= rec=$-([state=(unit *) fact=*] [state=* message=@p])
4646 ^- (ask @t) [%store module="/ui/store/cart" name=%state receive=rec]
tests/golden/types-prelude-ask/tokens.txt+25−25
@@ -639,31 +639,31 @@
63963942:95 tight glyph )
64064043:1 NEWLINE
64164143:1 glyph ++
642−43:4 name store
643−43:10 glyph |=
644−43:13 name rec
645−43:16 tight glyph =
646−43:17 tight glyph $-(
647−43:20 tight glyph [
648−43:21 tight name state
649−43:26 tight glyph =
650−43:27 tight glyph (
651−43:28 tight name unit
652−43:33 glyph *
653−43:34 tight glyph )
654−43:36 name fact
655−43:40 tight glyph =
656−43:41 tight glyph *
657−43:42 tight glyph ]
658−43:44 glyph [
659−43:45 tight name state
660−43:50 tight glyph =
661−43:51 tight glyph *
662−43:53 name message
663−43:60 tight glyph =
664−43:61 tight aura @t
665−43:63 tight glyph ]
666−43:64 tight glyph )
642+43:4 name store-ask
643+43:14 glyph |=
644+43:17 name rec
645+43:20 tight glyph =
646+43:21 tight glyph $-(
647+43:24 tight glyph [
648+43:25 tight name state
649+43:30 tight glyph =
650+43:31 tight glyph (
651+43:32 tight name unit
652+43:37 glyph *
653+43:38 tight glyph )
654+43:40 name fact
655+43:44 tight glyph =
656+43:45 tight glyph *
657+43:46 tight glyph ]
658+43:48 glyph [
659+43:49 tight name state
660+43:54 tight glyph =
661+43:55 tight glyph *
662+43:57 name message
663+43:64 tight glyph =
664+43:65 tight aura @t
665+43:67 tight glyph ]
666+43:68 tight glyph )
66766744:3 INDENT
66866844:3 glyph ^-
66966944:6 glyph (
tests/golden/types-prelude-ask/tree.txt+11−11
@@ -266,17 +266,17 @@
266266 (tuple 42:72
267267 (face 42:73 state (lit 42:79 0))
268268 (face 42:81 message (str 42:89 "ok")))))))
269− (value 43:1 store
270− (gate 43:10
271− (face 43:13 rec
272− (fn 43:17
273− (cell 43:20
274− (face 43:21 state
275− (apply 43:27 unit (noun 43:33)))
276− (face 43:36 fact (noun 43:41)))
277− (cell 43:44
278− (face 43:45 state (noun 43:51))
279− (face 43:53 message (aura 43:61 @t)))))
269+ (value 43:1 store-ask
270+ (gate 43:14
271+ (face 43:17 rec
272+ (fn 43:21
273+ (cell 43:24
274+ (face 43:25 state
275+ (apply 43:31 unit (noun 43:37)))
276+ (face 43:40 fact (noun 43:45)))
277+ (cell 43:48
278+ (face 43:49 state (noun 43:55))
279+ (face 43:57 message (aura 43:65 @t)))))
280280 (body 44:3
281281 (cast 44:3
282282 (apply 44:6 ask (aura 44:11 @t))
tests/golden/types-prelude-ask/types.txt+1−1
@@ -35,7 +35,7 @@ partial inference; module not checked
3535++ ordinary-path: (list @ta)
3636++ ask-from-ordinary: call constraint is not supported by partial inference
3737++ ask-from-qath: call constraint is not supported by partial inference
38−++ store: $-($-([state=(unit *) fact=*] [state=* message=@t]) (ask @t))
38+++ store-ask: $-($-([state=(unit *) fact=*] [state=* message=@t]) (ask @t))
3939++ wrong-store: cast constraint is not supported by partial inference
4040++ incomplete: missing union case [%store [module=@t [name=@tas receive=$-([state=(unit *) fact=*] [state=* message=@t])]]]
4141++ complete: $-((ask @t) @t)
tests/lib/jibb-store.hoonnew file+261
@@ -0,0 +1,261 @@
1+:: Unchanged cart store and basket, derived requests, and rejection guards.
2+/+ jibb
3+/* prelude %jibb /lib/jibb/prelude/jibb
4+/* internal %jibb /lib/jibb/internal/jibb
5+/* cart %txt /tests/type-store/cart/txt
6+/* basket %txt /tests/type-store/basket/txt
7+|%
8+++ text
9+ |= lines=wain
10+ ^- @t
11+ (rap 3 (turn lines |=(line=@t (cat 3 line '\0a'))))
12+::
13+++ store-detailed
14+ |= [at=path src=@t modules=jbundle:jibb prepared=iprelude:jibb]
15+ ^- jfile-detailed-result:jibb
16+ (infer-jibb-file-detailed:jibb at src ~ ~ modules ~[at] values.prepared molds.prepared ~ `iface.prepared)
17+::
18+++ store-legacy
19+ |= [at=path src=@t modules=jbundle:jibb prepared=iprelude:jibb]
20+ ^- jfile-result:jibb
21+ (infer-jibb-file:jibb at src ~ ~ modules ~[at] values.prepared molds.prepared ~ `iface.prepared)
22+::
23+++ store-cart-source
24+ |= [poke=@t main=@t init=@t update=@t extra=@t]
25+ ^- @t
26+ %+ rap 3
27+ :~ '+$ state [items=(list @t) open=?]\0a'
28+ '+$ cart-action\0a [%add item=@t]\0a %toggle\0a'
29+ poke main init update extra
30+ ==
31+::
32+++ store-basket-source
33+ |= [update=@t subs=@t extra=@t]
34+ ^- @t
35+ %+ rap 3
36+ :~ '/= cart /ui/stores/cart\0a'
37+ '++ main (program init update view subs)\0a'
38+ '+$ model [cart=state.cart note=@t]\0a'
39+ '+$ msg\0a [%noted text=@t]\0a %add\0a %toggle\0a [%got cart=state.cart]\0a [%acked err=(unit @t)]\0a'
40+ '++ init |= ~\0a [[~ %.n] ""]\0a'
41+ update subs
42+ '++ view |= m=model\0a column ~[gap+%s1] ~[\0a (text "{(lent items.cart.m)} items")\0a field "Item" note.m |=%noted\0a button "Add" %add\0a'
43+ extra
44+ ==
45+::
46+++ store-consumer-source
47+ ^- @t
48+ %+ rap 3
49+ :~ '/= cart /ui/stores/cart\0a'
50+ '+$ local-state state.cart\0a'
51+ '+$ local-action cart-action.cart\0a'
52+ '++ imported-main main.cart\0a'
53+ '++ imported-request |= reply=$-(local-state M) (state.cart reply)\0a'
54+ '++ imported-poke |= action=local-action (cart-action.cart action)\0a'
55+ ==
56+::
57+++ store-rejections
58+ |= [cases=(list [label=tape at=path src=@t modules=jbundle:jibb]) prepared=iprelude:jibb]
59+ ^- (list tape)
60+ %+ murn cases
61+ |= c=[label=tape at=path src=@t modules=jbundle:jibb]
62+ =/ result=jfile-detailed-result:jibb
63+ (store-detailed at.c src.c modules.c prepared)
64+ ?: ?=(%| -.result) ~
65+ `(weld label.c ": accepted")
66+::
67+++ store-evidence-failures
68+ |= [cart=ifile:jibb basket=ifile:jibb src=@t prelude=ifile:jibb]
69+ ^- (list tape)
70+ ?~ graph.cart ~["cart evidence is missing"]
71+ ?~ graph.basket ~["basket evidence is missing"]
72+ =/ parsed (parse:jibb /ui/basket/jibb src)
73+ ?: ?=(%| -.parsed) ~["basket evidence source does not parse"]
74+ =/ main=(unit def:jibb) (program-main-def:jibb defs.p.parsed)
75+ ?~ main ~["basket evidence main is missing"]
76+ =/ parts=(unit [init=term update=term view=term subs=term])
77+ (program-main-parts:jibb u.main)
78+ ?~ parts ~["basket evidence main parts are missing"]
79+ ?. ?=([* ~] stores.u.graph.cart) ~["cart store evidence is not unique"]
80+ =/ evidence=istore-request-evidence:jibb i.stores.u.graph.cart
81+ =/ imports=ijimports:jibb ~[[%cart cart]]
82+ =/ missing=irequest-graph:jibb u.graph.basket(stores ~)
83+ =/ mismatch=irequest-graph:jibb
84+ u.graph.basket(stores ~[evidence(source 'mismatched')])
85+ =/ ambiguous=irequest-graph:jibb
86+ u.graph.basket(stores ~[evidence evidence])
87+ =/ many=(list istore-request-evidence:jibb)
88+ %+ turn (gulf 0 255)
89+ |= n=@ud
90+ evidence(store-at (stab (crip "/ui/stores/{(a-co:co n)}/jibb")))
91+ =/ oversized=irequest-graph:jibb u.graph.basket(stores [evidence many])
92+ ?: (request-graph-bounded:jibb oversized) ~["oversized request graph was accepted"]
93+ =/ detached=ifile:jibb cart(graph `u.graph.cart(stores ~))
94+ =/ ordinary=ienv:jibb
95+ (skim values.cart |=(entry=[name=term scheme=ischeme:jibb] !=(%state name.entry)))
96+ =/ forged=ifile:jibb
97+ cart(values [[%state [[%fn [%atom %t] [%atom %t]] ~]] ordinary])
98+ =/ without-action=ienv:jibb
99+ (skim values.cart |=(entry=[name=term scheme=ischeme:jibb] !=(%cart-action name.entry)))
100+ =/ forged-action=ifile:jibb
101+ cart(values [[%cart-action [[%fn [%atom %t] [%atom %t]] ~]] without-action])
102+ =/ graphs=(list [label=tape graph=irequest-graph:jibb])
103+ :~ ["missing store evidence" missing]
104+ ["store source mismatch" mismatch]
105+ ["ambiguous store evidence" ambiguous]
106+ ==
107+ =/ failures=(list tape)
108+ %+ murn graphs
109+ |= c=[label=tape graph=irequest-graph:jibb]
110+ ?: (program-main-closed:jibb u.parts defs.p.parsed values.basket `prelude imports graph.c)
111+ `label.c
112+ ~
113+ =? failures (program-main-closed:jibb u.parts defs.p.parsed values.basket `prelude ~[[%cart detached]] u.graph.basket)
114+ ["evidence outside the store interface" failures]
115+ =? failures (program-main-closed:jibb u.parts defs.p.parsed values.basket `prelude ~[[%cart forged]] u.graph.basket)
116+ ["forged state member" failures]
117+ =? failures (program-main-closed:jibb u.parts defs.p.parsed values.basket `prelude ~[[%cart forged-action]] u.graph.basket)
118+ ["forged action constructor" failures]
119+ failures
120+::
121+++ store-errors
122+ |= [public=@t private=@t cart-source=@t basket-source=@t]
123+ ^- (list tape)
124+ =/ prepared=(unit iprelude:jibb)
125+ (prepare-prelude-with-internal:jibb public private)
126+ ?~ prepared ~["store prelude did not prepare"]
127+ =/ store-value=(unit ischeme:jibb) (ienv-lookup:jibb %store values.iface.u.prepared)
128+ =/ store-mold=(unit ischeme:jibb) (find-jibb-mold:jibb %store iface.u.prepared)
129+ ?~ store-value ~["store builder is missing"]
130+ ?~ store-mold ~["store mold is missing"]
131+ =/ expected-builder=itype:jibb
132+ [%fn [%cell [%face %init [%var 0]] [%face %update [%fn [%cell [%var 1] [%var 0]] [%var 0]]]] [%cell [%face %init [%var 0]] [%face %update [%noun ~]]]]
133+ ?. &(?=([@ @ ~] vars.u.store-value) =(typ.u.store-value expected-builder)) ~["store builder scheme differs"]
134+ =/ expected-mold=itype:jibb [%cell [%face %init [%var 0]] [%face %update [%noun ~]]]
135+ ?. &(?=([@ ~] vars.u.store-mold) =(typ.u.store-mold expected-mold)) ~["store mold scheme differs"]
136+ =/ cart-at=path /ui/stores/cart/jibb
137+ =/ modules=jbundle:jibb ~[[cart-at cart-source]]
138+ =/ detailed=jfile-detailed-result:jibb
139+ (store-detailed cart-at cart-source ~ u.prepared)
140+ ?: ?=(%| -.detailed) ~[(weld "cart was rejected: " (trip message.p.detailed))]
141+ =/ cart=ifile:jibb iface.p.detailed
142+ =/ legacy=jfile-result:jibb (store-legacy cart-at cart-source ~ u.prepared)
143+ ?: ?=(%| -.legacy) ~["legacy cart was rejected"]
144+ ?. =(values.cart values.iface.p.legacy) ~["detailed and legacy cart values differ"]
145+ ?. =(molds.cart molds.iface.p.legacy) ~["detailed and legacy cart molds differ"]
146+ =/ cart-main=(unit ischeme:jibb) (ienv-lookup:jibb %main values.cart)
147+ ?~ cart-main ~["cart main is missing"]
148+ =/ actual-main=@t (crip (show-itype:jibb typ.u.cart-main ~))
149+ ?. =(actual-main '[init=[items=(list @t) open=?] update=*]') ~["cart main type differs"]
150+ ?. &(?=(~ vars.u.cart-main) ?=(~ (itype-vars:jibb typ.u.cart-main))) ~["cart main is open"]
151+ =/ state=(unit ischeme:jibb) (find-jibb-mold:jibb %state cart)
152+ =/ action=(unit ischeme:jibb) (find-jibb-mold:jibb %cart-action cart)
153+ ?~ state ~["state mold is missing"]
154+ ?~ action ~["cart-action mold is missing"]
155+ ?^ (find-jibb-mold:jibb %poke cart) ~["poke declaration leaked as an exported mold"]
156+ =/ ask=(unit ischeme:jibb) (request-compatible-ask:jibb u.prepared)
157+ =/ poke=(unit ischeme:jibb) (store-compatible-poke:jibb u.prepared)
158+ ?~ ask ~["canonical ask is unavailable"]
159+ ?~ poke ~["canonical poke is unavailable"]
160+ =/ ask-result=(unit itype:jibb) (template-apply:jibb u.ask ~[[%var 0]])
161+ ?~ ask-result ~["canonical ask did not instantiate"]
162+ =/ expected-state=ischeme:jibb [[%fn [%fn typ.u.state [%var 0]] u.ask-result] ~[0]]
163+ =/ expected-action=ischeme:jibb [[%fn typ.u.action typ.u.poke] ~]
164+ =/ state-values=(list [name=term scheme=ischeme:jibb])
165+ (skim values.cart |=(entry=[name=term scheme=ischeme:jibb] =(%state name.entry)))
166+ =/ action-values=(list [name=term scheme=ischeme:jibb])
167+ (skim values.cart |=(entry=[name=term scheme=ischeme:jibb] =(%cart-action name.entry)))
168+ ?. ?=([* ~] state-values) ~["derived state member is not unique"]
169+ ?. =(scheme.i.state-values expected-state) ~["derived state scheme differs"]
170+ ?. ?=([* ~] action-values) ~["derived cart-action member is not unique"]
171+ ?. =(scheme.i.action-values expected-action) ~["derived cart-action scheme differs"]
172+ ?~ graph.cart ~["cart request graph is missing"]
173+ ?. ?=([* ~] stores.u.graph.cart) ~["cart store evidence is not unique"]
174+ =/ evidence=istore-request-evidence:jibb i.stores.u.graph.cart
175+ ?. &(=(store-at.evidence cart-at) =(source.evidence cart-source)) ~["store evidence does not retain exact path/source"]
176+ ?. &(=(state.evidence typ.u.state) =(action.evidence typ.u.action) =(%cart-action action-name.evidence)) ~["store evidence types differ"]
177+ =/ basket-result=jfile-detailed-result:jibb
178+ (store-detailed /ui/basket/jibb basket-source modules u.prepared)
179+ ?: ?=(%| -.basket-result) ~[(weld "basket was rejected: " (trip message.p.basket-result))]
180+ =/ basket=ifile:jibb iface.p.basket-result
181+ =/ basket-legacy=jfile-result:jibb
182+ (store-legacy /ui/basket/jibb basket-source modules u.prepared)
183+ ?: ?=(%| -.basket-legacy) ~["legacy basket was rejected"]
184+ ?. =(values.basket values.iface.p.basket-legacy) ~["detailed and legacy basket values differ"]
185+ =/ basket-main=(unit ischeme:jibb) (ienv-lookup:jibb %main values.basket)
186+ ?~ basket-main ~["basket main is missing"]
187+ =/ expected-basket=@t '[init=$-(~ [cart=[items=(list @t) open=?] note=@t]) [update=$-([msg [cart=[items=(list @t) open=?] note=@t]] [[cart=[items=(list @t) open=?] note=@t] (list (cmd msg))]) [view=$-([cart=[items=(list @t) open=?] note=@t] (element msg)) subs=$-([cart=[items=(list @t) open=?] note=@t] (list (sub msg)))]]]'
188+ =/ actual-basket=@t (crip (show-itype:jibb typ.u.basket-main ~))
189+ ?. =(actual-basket expected-basket) ~["basket main type differs"]
190+ ?~ graph.basket ~["basket request graph is missing"]
191+ ?. (lien stores.u.graph.basket |=(r=istore-request-evidence:jibb =(r evidence))) ~["basket did not merge exact store evidence"]
192+ =/ consumer-result=jfile-detailed-result:jibb
193+ (store-detailed /tests/store/consumer/jibb store-consumer-source modules u.prepared)
194+ ?: ?=(%| -.consumer-result) ~["downstream store import was rejected"]
195+ =/ consumer=ifile:jibb iface.p.consumer-result
196+ =/ imported-main=(unit ischeme:jibb) (ienv-lookup:jibb %imported-main values.consumer)
197+ ?~ imported-main ~["downstream main is missing"]
198+ =/ expected-import=itype:jibb (itype-in-import:jibb typ.u.cart-main cart %cart `iface.u.prepared)
199+ ?. =(typ.u.imported-main expected-import) ~["downstream main type differs"]
200+ =/ local-state=(unit ischeme:jibb) (find-jibb-mold:jibb %local-state consumer)
201+ =/ local-action=(unit ischeme:jibb) (find-jibb-mold:jibb %local-action consumer)
202+ ?~ local-state ~["downstream state mold is missing"]
203+ ?~ local-action ~["downstream action mold is missing"]
204+ =/ imported-state=itype:jibb (itype-in-import:jibb typ.u.state cart %cart `iface.u.prepared)
205+ =/ imported-action=itype:jibb (itype-in-import:jibb typ.u.action cart %cart `iface.u.prepared)
206+ ?. &(=(typ.u.local-state imported-state) =(typ.u.local-action imported-action)) ~["downstream molds differ"]
207+ ?~ (ienv-lookup:jibb %imported-request values.consumer) ~["downstream state request is missing"]
208+ ?~ (ienv-lookup:jibb %imported-poke values.consumer) ~["downstream action constructor is missing"]
209+ =/ direct=jfile-detailed-result:jibb
210+ (store-detailed /tests/direct/cart/jibb cart-source ~ u.prepared)
211+ ?: ?=(%| -.direct) ~["direct store outside /ui/stores was rejected"]
212+ =/ grouped=@t (store-cart-source '+$ poke cart-action\0a' '++ main (store (init) (update))\0a' '++ init ^- state [~ %.n]\0a' '++ update |= [a=cart-action s=state]\0a ?- a\0a [%add item] s(items=[item items.s])\0a %toggle s(open=(not open.s))\0a' '')
213+ =/ grouped-result=jfile-detailed-result:jibb
214+ (store-detailed /tests/direct/grouped/jibb grouped ~ u.prepared)
215+ ?: ?=(%| -.grouped-result) ~[(weld "grouped direct store main was rejected: " (trip message.p.grouped-result))]
216+ =/ gate-state=@t '+$ state [callback=$-(@t @t)]\0a+$ action %set\0a+$ poke action\0a++ main (store init update)\0a++ init ^- state [callback=same]\0a++ update |= [a=action s=state] s\0a'
217+ =/ gate-result=jfile-detailed-result:jibb
218+ (store-detailed /tests/direct/gate-state/jibb gate-state ~ u.prepared)
219+ ?: ?=(%| -.gate-result) ~["gate-bearing store state was rejected"]
220+ =/ evidence-failures=(list tape) (store-evidence-failures cart basket basket-source iface.u.prepared)
221+ ?^ evidence-failures evidence-failures
222+ =/ normal-poke=@t '+$ poke cart-action\0a'
223+ =/ normal-main=@t '++ main (store init update)\0a'
224+ =/ normal-init=@t '++ init ^- state [~ %.n]\0a'
225+ =/ normal-update=@t '++ update |= [a=cart-action s=state]\0a ?- a\0a [%add item] s(items=[item items.s])\0a %toggle s(open=(not open.s))\0a'
226+ =/ cart-cases=(list [label=tape at=path src=@t modules=jbundle:jibb])
227+ :~ ["wrong init" /tests/store/wrong-init/jibb (store-cart-source normal-poke normal-main '++ init ^- state [~ "bad"]\0a' normal-update '') ~]
228+ ["wrong action" /tests/store/wrong-action/jibb (store-cart-source normal-poke normal-main normal-init '++ update |= [a=@t s=state] s\0a' '') ~]
229+ ["wrong result" /tests/store/wrong-result/jibb (store-cart-source normal-poke normal-main normal-init '++ update |= [a=cart-action s=state] "bad"\0a' '') ~]
230+ ["unknown poke" /tests/store/unknown-poke/jibb (store-cart-source '+$ poke missing\0a' normal-main normal-init normal-update '') ~]
231+ ["qualified poke" /tests/store/qualified-poke/jibb (store-cart-source '+$ poke cart-action.cart\0a' normal-main normal-init normal-update '') ~]
232+ ["duplicate poke" /tests/store/duplicate-poke/jibb (store-cart-source '+$ poke cart-action\0a+$ poke cart-action\0a' normal-main normal-init normal-update '') ~]
233+ ["duplicate state" /tests/store/duplicate-state/jibb (store-cart-source normal-poke normal-main normal-init normal-update '+$ state @t\0a') ~]
234+ ["state derived collision" /tests/store/state-collision/jibb (store-cart-source normal-poke normal-main normal-init normal-update '++ state 0\0a') ~]
235+ ["action derived collision" /tests/store/action-collision/jibb (store-cart-source normal-poke normal-main normal-init normal-update '++ cart-action 0\0a') ~]
236+ ["import derived collision" /tests/store/import-collision/jibb (cat 3 '/= state /ui/stores/other\0a' (store-cart-source normal-poke normal-main normal-init normal-update '')) ~]
237+ ["alias main" /tests/store/alias-main/jibb (store-cart-source normal-poke '++ main (build init update)\0a' normal-init normal-update '++ build store\0a') ~]
238+ ["hand-built main" /tests/store/hand-main/jibb (store-cart-source normal-poke '++ main [init update]\0a' normal-init normal-update '') ~]
239+ ==
240+ =/ normal-basket-update=@t '++ update |= [=msg m=model]\0a ?- msg\0a [%noted t] [m(note=t) ~]\0a %add [m(note="") ~[[%poke (cart-action.cart [%add note.m]) |=%acked]]]\0a %toggle [m ~[[%poke (cart-action.cart %toggle) |=%acked]]]\0a [%got c] [m(cart=c) ~]\0a [%acked err] [m ~]\0a'
241+ =/ normal-subs=@t '++ subs |= m=model\0a ~[[%watch (state.cart |=%got)]]\0a'
242+ =/ wrong-payload=@t '++ update |= [=msg m=model]\0a ?- msg\0a [%noted t] [m(note=t) ~]\0a %add [m(note="") ~[[%poke (cart-action.cart [%add ~zod]) |=%acked]]]\0a %toggle [m ~[[%poke (cart-action.cart %toggle) |=%acked]]]\0a [%got c] [m(cart=c) ~]\0a [%acked err] [m ~]\0a'
243+ =/ basket-cases=(list [label=tape at=path src=@t modules=jbundle:jibb])
244+ :~ ["wrong poke payload" /ui/basket/jibb (store-basket-source wrong-payload normal-subs '') modules]
245+ ["wrong state reply" /ui/basket/jibb (store-basket-source normal-basket-update '++ subs |= m=model\0a ~[[%watch (state.cart |=%acked)]]\0a' '') modules]
246+ ["helper state request" /ui/basket/jibb (store-basket-source normal-basket-update '++ subs |= m=model\0a ~[[%watch request]]\0a' '++ request ^- (ask msg) (state.cart |=%got)\0a') modules]
247+ ["program under store path" /ui/stores/basket/jibb basket-source modules]
248+ ==
249+ =/ page=@t '/= cart /ui/stores/cart\0a++ main (page load view)\0a++ load |= ~ (state.cart same)\0a++ view |= s=state.cart ^- (element !!) (text "page")\0a'
250+ =/ page-case=[label=tape at=path src=@t modules=jbundle:jibb]
251+ ["store state as page load" /tests/store/page/jibb page modules]
252+ =/ failures=(list tape) (store-rejections (weld cart-cases (weld basket-cases ~[page-case])) u.prepared)
253+ ?^ failures failures
254+ ~
255+::
256+++ test-store
257+ ^- tang
258+ =/ failures=(list tape)
259+ (store-errors prelude internal (text cart) (text basket))
260+ (turn failures |=(reason=tape leaf+reason))
261+--
tests/type-store/basket.txtnew file+32
@@ -0,0 +1,32 @@
1+:: /ui/basket.jibb
2+/= cart /ui/stores/cart
3+
4+++ main (program init update view subs)
5+
6++$ model [cart=state.cart note=@t]
7++$ msg
8+ [%noted text=@t]
9+ %add
10+ %toggle
11+ [%got cart=state.cart]
12+ [%acked err=(unit @t)]
13+
14+++ init |= ~
15+ [[~ %.n] ""]
16+
17+++ update |= [=msg m=model]
18+ ?- msg
19+ [%noted t] [m(note=t) ~]
20+ %add [m(note="") ~[[%poke (cart-action.cart [%add note.m]) |=%acked]]]
21+ %toggle [m ~[[%poke (cart-action.cart %toggle) |=%acked]]]
22+ [%got c] [m(cart=c) ~]
23+ [%acked err] [m ~]
24+
25+++ subs |= m=model
26+ ~[[%watch (state.cart |=%got)]]
27+
28+++ view |= m=model
29+ column ~[gap+%s1] ~[
30+ (text "{(lent items.cart.m)} items")
31+ field "Item" note.m |=%noted
32+ button "Add" %add
tests/type-store/cart.txtnew file+13
@@ -0,0 +1,13 @@
1+:: /ui/stores/cart.jibb
2++$ state [items=(list @t) open=?]
3++$ cart-action
4+ [%add item=@t]
5+ %toggle
6++$ poke cart-action
7+
8+++ main (store init update)
9+++ init ^- state [~ %.n]
10+++ update |= [a=cart-action s=state]
11+ ?- a
12+ [%add item] s(items=[item items.s])
13+ %toggle s(open=(not open.s))
tests/type-todo-full/alias.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tests/type-todo-full/ambiguous-mapper.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tests/type-todo-full/open-key.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tests/type-todo-full/wrong-message.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tests/type-todo-full/wrong-model.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tests/type-todo-full/wrong-result.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tests/type-todo-full/wrong-watch.txt+2−2
@@ -19,8 +19,8 @@
1919 ?- (gth (lent (tuba (trip t))) 80)
2020 %.y [m(draft=t error=`"Too long") ~]
2121 %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") `[%poke (todo-action.todo [%add draft.m]) |=%acked]]
23− [%toggled id] [m `[%poke (todo-action.todo [%toggle id]) |=%acked]]
22+ %submit [m(draft="") ~[[%poke (todo-action.todo [%add draft.m]) |=%acked]]]
23+ [%toggled id] [m ~[[%poke (todo-action.todo [%toggle id]) |=%acked]]]
2424 [%got ts] [m(todos=ts) ~]
2525 [%acked err] [m(error=err) ~]
2626
tools/testdata/ship-selftest+4
@@ -329,6 +329,7 @@ def generator_checks(tmp):
329329 'tests/lib/jibb-program-init.hoon',
330330 'tests/lib/jibb-program-update.hoon',
331331 'tests/lib/jibb-program-watch.hoon',
332+ 'tests/lib/jibb-store.hoon',
332333 'tests/lib/jibb-todo-full.hoon',
333334 'tests/lib/jibb-theme.hoon',
334335 'tests/lib/jibb-todo-api.hoon',
@@ -426,6 +427,9 @@ def generator_checks(tmp):
426427 check('program watch shared fixture is assembled',
427428 {'tests/lib/jibb-program-watch.hoon', 'tests/type-program-watch/about.txt'}
428429 <= set(normal.files))
430+ check('unchanged cart store and basket fixtures are assembled',
431+ {'tests/lib/jibb-store.hoon', 'tests/type-store/cart.txt',
432+ 'tests/type-store/basket.txt'} <= set(normal.files))
429433 check('full todo sources and exact main report are assembled',
430434 {'tests/lib/jibb-todo-full.hoon', 'tests/type-gate-free/todo.txt',
431435 'tests/type-api-paths/api.txt', 'tests/type-todo-full/expected.txt',
tools/type-store-testnew file+41
@@ -0,0 +1,41 @@
1+#!/usr/bin/env python3
2+"""Check the unchanged cart store and basket 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+parser.add_argument('--timeout', type=float, default=300,
13+ help='seconds allowed for urbit eval (default: 300)')
14+args = parser.parse_args()
15+for fixture, actual in (('tests/type-store/cart.txt', 'my-app/ui/stores/cart.jibb'),
16+ ('tests/type-store/basket.txt', 'my-app/ui/basket.jibb')):
17+ if (root / fixture).read_bytes() != (root / actual).read_bytes():
18+ sys.exit(f'{fixture} differs from {actual}')
19+tests = (root / 'tests/lib/jibb-store.hoon').read_text()
20+tests = tests[tests.index('\n|%\n') + 1:]
21+tests = tests[:tests.index('\n++ test-store')] + '\n--\n'
22+program = ('=/ jibb .\n=/ suite\n' + tests +
23+ '\n=/ failures=(list tape) (store-errors:suite prelude internal cart basket)\n'
24+ '^- @t\n?~ failures \'unchanged cart store and basket passed\'\n'
25+ '(of-wain:format (turn failures crip))\n')
26+with tempfile.TemporaryDirectory(prefix='jibb-store-') as tmp:
27+ path = Path(tmp) / 'store.hoon'
28+ path.write_text(program)
29+ command = [str(root / 'tools/hoon'), '--lib', args.lib, '--raw', '-f', str(path),
30+ '--timeout', str(args.timeout),
31+ '--cord', 'prelude=' + str(root / 'jibb-dev/lib/jibb/prelude.jibb'),
32+ '--cord', 'internal=' + str(root / 'jibb-dev/lib/jibb/internal.jibb'),
33+ '--cord', 'cart=' + str(root / 'tests/type-store/cart.txt'),
34+ '--cord', 'basket=' + str(root / 'tests/type-store/basket.txt')]
35+ result = subprocess.run(command, stdout=subprocess.PIPE)
36+if result.returncode:
37+ sys.exit(result.returncode)
38+if result.stdout != b'unchanged cart store and basket passed\n':
39+ sys.stderr.buffer.write(result.stdout)
40+ sys.exit(1)
41+print('unchanged cart/basket detailed/legacy, schemes, imports, watch evidence and negatives passed')