|
3 | 3 | _Short by design, and printed at every session start — so findings live in |
4 | 4 | `doc/design/`, plans in `doc/roadmap.md`, and only the present tense here._ |
5 | 5 |
|
6 | | -**Updated:** 2026-07-30 · **Phase:** S0 closed, entering S1 (pre-alpha, no compiler) |
| 6 | +**Updated:** 2026-07-30 · **Phase:** S1 delivered, closing (pre-alpha, no compiler) |
7 | 7 |
|
8 | 8 | ## Next |
9 | 9 |
|
10 | | -1. **Implement `0016` — `own<T>` handles.** `flags` and `tuple` now marshal, |
11 | | - so **4 of `dev/resources/zoo.wit`'s 8 exports are callable**; the other four |
12 | | - are resource methods. `0016` decides the shape (opaque `AutoCloseable`, |
13 | | - `close` as `try { drop } finally { delete }`, lowering an `own` transfers, |
14 | | - the instance closes outstanding handles before deleting its store) and |
15 | | - `borrow` is out of scope because it **cannot appear in a return position**. |
16 | | - **Done.** `cljwit.host` marshals every `0012` row that a component can |
17 | | - express today. What is left of `0012` is `map`, `list<T,N>`, |
18 | | - `stream`/`future` and `error-context`, none of which are in a shipped |
19 | | - release. |
20 | | -3. **Host imports (`0017`).** The mechanism works — an FFM upcall stub reaches |
21 | | - Clojure from inside a component call (`bb spike-import`), pure Clojure, no C |
22 | | - shim. The API is designed and argued, and an adversarial review changed four |
23 | | - of its five decisions. Three findings that outlive the note: `add_wasip2` |
24 | | - without `wasmtime_context_set_wasi` **aborts the process** at the first WASI |
25 | | - call; an import that throws poisons the whole store, not just the call; and |
26 | | - wasmtime **frees** what the callback writes, so `lower-fn`'s Arena |
27 | | - allocation cannot be reused in that direction. Resource imports are inside |
28 | | - this unit, not after it — every `wasi:io` interface needs one. |
29 | | -4. **`0012`'s `ex-data` contract.** It promises a WIT type name that reflection |
30 | | - cannot supply; `0015` declined to be the codegen layer that would, so the |
31 | | - contract has to shrink instead. |
32 | | -5. **`require`-a-component is deferred, not pending** (`0015`). When it is |
33 | | - picked up it should be a generated `.clj`, not a macro, and the instance |
34 | | - should not be ambient. |
| 10 | +1. **Close S1 against its stop condition.** What remains of "a component this |
| 11 | + project did not author, calling and being called, with every WIT type a |
| 12 | + shipped release can express": the un-authored component (`zoo.wit`) is |
| 13 | + *called*; the *calling* side is exercised only by guests this repo wrote. |
| 14 | + One named capability gap: **a resource nested in a container in an |
| 15 | + import's signature is refused at instantiate** (`:nested-resource`) rather |
| 16 | + than marshalled — `import-stub` routes only whole parameters/results |
| 17 | + through the rep table. Accepted until a real component needs the shape; |
| 18 | + the first one that does reopens it. |
| 19 | +2. **The ergonomics layer (`0015` revisited).** Its blockers are gone — |
| 20 | + marshalling and host imports both exist — so the generated-`.clj` shape |
| 21 | + ("not a macro, and the instance not ambient") is buildable now. Decide |
| 22 | + whether S1 ships with it or it opens S2. |
| 23 | +3. **S2 — developer experience skeleton** (`doc/roadmap.md`): `cljwit.edn`, |
| 24 | + an nREPL entry point, the shadow-cljs shape. |
| 25 | + |
| 26 | +Done since the last update: `0016` `own<T>` handles, `0017` host imports |
| 27 | +(A–F), `0018` host-defined resources, `0012`'s `ex-data` contract shrunk to |
| 28 | +what reflection can supply, `0019` libwasmtime resolution for library users. |
| 29 | +What is left of `0012` is `map`, `list<T,N>`, `stream`/`future` and |
| 30 | +`error-context`, none of which a shipped release can express. |
35 | 31 |
|
36 | 32 | ## Where we are |
37 | 33 |
|
@@ -69,14 +65,19 @@ is unmeasured.** That is S0's residue and it belongs to S3. |
69 | 65 |
|
70 | 66 | ### S1 — reaching a component |
71 | 67 |
|
72 | | -**`cljwit.host` exists** (`src/cljwit/host.clj`, `0014`). Three lifetimes — |
73 | | -engine, compiled artifact, instance — with exports discovered from the |
74 | | -component itself: no WIT file and no code generation at run time. Names are the |
75 | | -exact WIT strings, including `pkg:name/iface@ver#func` for functions inside an |
76 | | -interface, with keyword aliases only where the name reads back equal to itself. |
77 | | -Every entry into a store takes a non-concurrency check, and results are lifted |
78 | | -eagerly. It marshals every `0012` row except `own`/`borrow`, `map`, |
79 | | -`list<T,N>`, `stream`/`future` and `error-context`. |
| 68 | +**`cljwit.host` is delivered** (`src/cljwit/host.clj`, `0014`). Three |
| 69 | +lifetimes — engine, compiled artifact, instance — with exports discovered from |
| 70 | +the component itself: no WIT file and no code generation at run time. Names |
| 71 | +are the exact WIT strings, including `pkg:name/iface@ver#func` for functions |
| 72 | +inside an interface, with keyword aliases only where the name reads back equal |
| 73 | +to itself. Every entry into a store takes a non-concurrency check, and results |
| 74 | +are lifted eagerly. It marshals **every `0012` row a shipped release can |
| 75 | +express, in both directions**: exports and host imports (`0017`), resources in |
| 76 | +both ownerships — guest-defined handles as `AutoCloseable` (`0016`), |
| 77 | +host-defined resources with destructors (`0018`) — and WASI, deny-by-default |
| 78 | +(`0017` E). The one named gap is a resource nested in a container in an |
| 79 | +import's signature, refused at instantiate. `0019` gives library users a |
| 80 | +libwasmtime resolution order that does not require this repo's flake. |
80 | 81 |
|
81 | 82 | **The calling convention is decided and the cost structure is measured** |
82 | 83 | (`0011`, corrected by `0013`): `MethodHandleProxies/asInterfaceInstance` behind |
|
0 commit comments