docs: iteration 15 closeout (Task 5)

- error catalog: WO-E106 (dependency fetch/shape failures, one code, message
  names dep + step) and WO-E107 (dep/local module-name collision) rows.
- README: a Dependencies subsection under the manifest docs — [deps] syntax,
  .wo-deps/wo.lock behavior, offline-when-locked, --update-deps, flat-only.
- board: iteration 15 row -> landed (deps-accept 8/0), pending row removed;
  story 15 header records the landing; 08-project-structure notes
  .wo-deps (gitignored) + wo.lock (committed); plan checkboxes all ticked.

(One self-inflicted casualty during this task, restored from git before
commit: a buggy doc-edit script truncated 08-project-structure.md; the file
was recovered intact and the intended one-liner applied by hand.)

Gates at closeout: deps-accept 8/0, woc-test 540/0, oop-e2e 87/0,
log-watcher 7/0, employee 8/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
shoney.arickathil 2026-08-19 19:23:18 +02:00
parent 5d5d7f61ab
commit e48b175472
6 changed files with 49 additions and 22 deletions

View file

@ -262,6 +262,24 @@ runtime = "../../../runtime/wovm" # path to the wovm the binary is built from
`woc myproject/` compiles every `.wo` file under the directory as one program. `woc myproject/` compiles every `.wo` file under the directory as one program.
### Dependencies
A project can depend on other writeonce repositories — exact-rev git
dependencies, declared in the manifest:
```toml
[deps]
niceframework = { git = "https://github.com/shoneyj/niceframework", rev = "v0.1.0" }
```
`woc` fetches each dep (via the `git` binary) into `.wo-deps/<name>/`, pins
the resolved commit in `wo.lock`, and `use niceframework` (or
`use niceframework/sub`) imports its public names like any module. Builds
never touch the network once the lock is satisfied; a moved tag is reported,
and `woc --update-deps myproject/` refreshes the lock deliberately. Flat
dependencies only (a dep may not have its own `[deps]`) — honest and small,
by design.
Programs that create tables read their data directory from the `WO_DATA` Programs that create tables read their data directory from the `WO_DATA`
environment variable at run time: environment variable at run time:

View file

@ -130,7 +130,7 @@ that sequences its tasks. Read one, approve, then the next starts.
| 12 | [Blue-green deploy](stories/language-runtime-database/12-blue-green-deploy.md) | ⬜ | Hold | | 12 | [Blue-green deploy](stories/language-runtime-database/12-blue-green-deploy.md) | ⬜ | Hold |
| 13 | [Compile-time metaprogramming](stories/language-runtime-database/13-compile-time-metaprogramming.md) | ⬜ needs a spec first | | 13 | [Compile-time metaprogramming](stories/language-runtime-database/13-compile-time-metaprogramming.md) | ⬜ needs a spec first |
| 14 | [skillhost host workload](stories/language-runtime-database/14-skillhost-host-workload.md) | ⬜ gaps recorded (branch query-grammar found skillhost needs no new query grammar); each gap a candidate iteration | | 14 | [skillhost host workload](stories/language-runtime-database/14-skillhost-host-workload.md) | ⬜ gaps recorded (branch query-grammar found skillhost needs no new query grammar); each gap a candidate iteration |
| 15 | [deps: `wo.toml [deps]`](stories/language-runtime-database/15-deps-package-manager.md) | ⬜ spec'd 2026-08-18 (web-framework spec §A); the enabler for 16 | | 15 | [deps: `wo.toml [deps]`](stories/language-runtime-database/15-deps-package-manager.md) | ✅ **landed 2026-08-18** (branch web-framework): [deps] inline tables, git-binary fetch, wo.lock pinning, offline-when-locked, --update-deps, WO-E106/E107; `just deps-accept` 8/0 |
| 16 | [web framework](stories/language-runtime-database/16-web-framework.md) | ⬜ spec'd 2026-08-18 (§B; h2c parked §C behind 8/9f/11); TLS proxy-terminated by decision | | 16 | [web framework](stories/language-runtime-database/16-web-framework.md) | ⬜ spec'd 2026-08-18 (§B; h2c parked §C behind 8/9f/11); TLS proxy-terminated by decision |
--- ---
@ -320,7 +320,6 @@ The C proving-ground work (`exploration/c-runtime/`, phases A–F: 859k reads/s,
| 9f | io_uring group-commit write path — batched durability overlapped on shard threads, fsync fallback | **no spec yet** — brainstorm after iterations 8 + 9e | | 9f | io_uring group-commit write path — batched durability overlapped on shard threads, fsync fallback | **no spec yet** — brainstorm after iterations 8 + 9e |
| 9g | Query grammar from real embedded-DB corpora — whole-query count + correlated exists, driven by the skillhost SQL catalogue; add only what a corpus uses | **no spec yet** — three forks; may collapse to "confirm len(query) + add exists" | | 9g | Query grammar from real embedded-DB corpora — whole-query count + correlated exists, driven by the skillhost SQL catalogue; add only what a corpus uses | **no spec yet** — three forks; may collapse to "confirm len(query) + add exists" |
| 14 | skillhost host workload — port skillhost (MCP host + confined script runner) to writeonce; drives the missing host capabilities into the open (bounded subprocess, stdin/stdout transport, fs metadata, FFI-vs-out-of-process) | **no spec yet** — gaps recorded in the iteration; each gap brainstormed on demand, bounded-subprocess first | | 14 | skillhost host workload — port skillhost (MCP host + confined script runner) to writeonce; drives the missing host capabilities into the open (bounded subprocess, stdin/stdout transport, fs metadata, FFI-vs-out-of-process) | **no spec yet** — gaps recorded in the iteration; each gap brainstormed on demand, bounded-subprocess first |
| 15 | deps — `wo.toml [deps]` exact-rev git fetch, `wo.lock`, `.wo-deps` cache, `use <dep>` resolution; flat-only v1 | [spec §A](superpowers/specs/2026-08-18-web-framework-design.md) · [plan](superpowers/plans/2026-08-18-deps-package-manager.md) |
| 16 | web framework — `.wo` library (HTTP/1.1 keep-alive behind a TLS-terminating proxy), Handler/Middleware interfaces, @table data layer; web-app sample consumes via [deps] | [spec §B](superpowers/specs/2026-08-18-web-framework-design.md) — depends on 15; h2c parked (§C) behind 8/9f/11 | | 16 | web framework — `.wo` library (HTTP/1.1 keep-alive behind a TLS-terminating proxy), Handler/Middleware interfaces, @table data layer; web-app sample consumes via [deps] | [spec §B](superpowers/specs/2026-08-18-web-framework-design.md) — depends on 15; h2c parked (§C) behind 8/9f/11 |
| 10 | HTTP service layer | [plan 6](superpowers/plans/2026-08-01-http-service-layer.md) | | 10 | HTTP service layer | [plan 6](superpowers/plans/2026-08-01-http-service-layer.md) |
| 11 | Fibers | vision §3, [blue-green exploration](plan/exploration/blue-green-vm/00-vision.md) | | 11 | Fibers | vision §3, [blue-green exploration](plan/exploration/blue-green-vm/00-vision.md) |

View file

@ -118,5 +118,8 @@ ASan, single-binary smoke, both unit gates). Sample acceptance:
- Plan/spec files: `YYYY-MM-DD-<topic>.md` under `docs/superpowers/{specs,plans}/`; - Plan/spec files: `YYYY-MM-DD-<topic>.md` under `docs/superpowers/{specs,plans}/`;
compiler plans under `docs/plan/compiler/`; normative contracts under compiler plans under `docs/plan/compiler/`; normative contracts under
`docs/plan/oop-vm/`. `docs/plan/oop-vm/`.
- A project's dependencies (iteration 15): `wo.toml [deps]` declares
exact-rev git deps; they fetch to `.wo-deps/<name>/` (gitignored) and pin
in `wo.lock` (committed).
- Sample projects live under `docs/examples/<name>/` with their own `wo.toml` - Sample projects live under `docs/examples/<name>/` with their own `wo.toml`
and module `justfile`. and module `justfile`.

View file

@ -34,6 +34,8 @@ half of the story ("moved here" / "borrowed here" / etc.).
| WO-E101 | generic syntax error: an unexpected token where the grammar expected something else, including running off the end of the file inside an unclosed block/type/interface body. Declaration-level recovery syncs to the next top-level keyword so one bad declaration yields one diagnostic, not a cascade. | `expected ')' or ',', got NEWLINE` | | WO-E101 | generic syntax error: an unexpected token where the grammar expected something else, including running off the end of the file inside an unclosed block/type/interface body. Declaration-level recovery syncs to the next top-level keyword so one bad declaration yields one diagnostic, not a cascade. | `expected ')' or ',', got NEWLINE` |
| WO-E102 | an invalid `@table(...)` configuration: `name` given twice, an `index` with no columns, or an argument key other than `name`/`index`. | `@table(name: ...) given twice` | | WO-E102 | an invalid `@table(...)` configuration: `name` given twice, an `index` with no columns, or an argument key other than `name`/`index`. | `@table(name: ...) given twice` |
| WO-E103 | haxe-parity Task 2. `inline fn ...` — the haxe keyword verdict table's own reject half of the `inline` row (`const` values are the adopted half). The whole declaration is discarded by the usual top-level recovery, same as any other bad declaration. | `` `inline fn` is rejected — optimization is the compiler's job `` | | WO-E103 | haxe-parity Task 2. `inline fn ...` — the haxe keyword verdict table's own reject half of the `inline` row (`const` values are the adopted half). The whole declaration is discarded by the usual top-level recovery, same as any other bad declaration. | `` `inline fn` is rejected — optimization is the compiler's job `` |
| WO-E106 | iteration 15 (deps, 2026-08-18). A dependency fetch/shape failure, driver-level: missing `git` binary, clone/checkout failure, a locked commit missing from the remote, cache/lock drift (a moved `rev` — the message names both SHAs and points at `woc --update-deps`), a fetched dep that is not a writeonce project, or a dep declaring its own `[deps]` (transitive — refused flat-only). One code; the message names the dependency and the failing step. | `` dependency `niceframework`: lock drift — wo.lock pins <sha> but .wo-deps has <sha> (a moved `rev`?); run `woc --update-deps` or remove .wo-deps/niceframework `` |
| WO-E107 | iteration 15 (deps). A `[deps]` name collides with a local top-level module directory of the same name — `use <name>` would be ambiguous, so the build refuses instead of silently picking one. | `` dependency `niceframework` collides with the local module directory `niceframework/` `` |
| WO-E105 | iteration 5 strictness (2026-08-18). A rejected Haxe keyword used where it would otherwise misparse — or, worst, compile clean (`return super.f()` used to): `extends`/`implements` after a class name, and `extends`/`implements`/`super`/`override`/`cast`/`Dynamic`/`untyped`/`macro`/`extern`/`operator` as an expression head or a top-level declaration head. Each cites the systems-track verdict table's doctrine reason. (`Dynamic`/`untyped` as a *type name* fire WO-E225 with the same doctrine message.) | `` `extends` is rejected: no inheritance, ever — is-a is a tagged union, has-a is composition, polymorphism is structural interfaces (principle 4) `` | | WO-E105 | iteration 5 strictness (2026-08-18). A rejected Haxe keyword used where it would otherwise misparse — or, worst, compile clean (`return super.f()` used to): `extends`/`implements` after a class name, and `extends`/`implements`/`super`/`override`/`cast`/`Dynamic`/`untyped`/`macro`/`extern`/`operator` as an expression head or a top-level declaration head. Each cites the systems-track verdict table's doctrine reason. (`Dynamic`/`untyped` as a *type name* fire WO-E225 with the same doctrine message.) | `` `extends` is rejected: no inheritance, ever — is-a is a tagged union, has-a is composition, polymorphism is structural interfaces (principle 4) `` |
| WO-E104 | iteration 7b. `@gc` on a class — the annotation is gone: GC-ness is inferred (structural cycles + demand promotion; `woc --dump-gc`). The annotation is skipped for recovery and the class classifies by inference. | `` `@gc` is not a valid annotation: GC-ness is inferred by the compiler (run `woc --dump-gc`). Remove it. `` | | WO-E104 | iteration 7b. `@gc` on a class — the annotation is gone: GC-ness is inferred (structural cycles + demand promotion; `woc --dump-gc`). The annotation is skipped for recovery and the class classifies by inference. | `` `@gc` is not a valid annotation: GC-ness is inferred by the compiler (run `woc --dump-gc`). Remove it. `` |

View file

@ -3,8 +3,13 @@
> Format: fiberloom `product/story-iteration-template`. Part of > Format: fiberloom `product/story-iteration-template`. Part of
> [Story — one language, one runtime, one database, one binary](00-story.md). > [Story — one language, one runtime, one database, one binary](00-story.md).
> >
> **Inserted 2026-08-18.** The enabler for code shared between writeonce > **Inserted 2026-08-18. LANDED the same day** (branch `web-framework`): all
> repositories — the web framework (iteration 16) is the driving consumer. > acceptance criteria met — `just deps-accept` 8/0 (cold fetch + lock, use
> <dep> and <dep>/sub, offline-when-locked with the remote deleted,
> lock-beats-moved-tag, --update-deps, drift/transitive/collision
> diagnostics WO-E106/E107, dep `fn main` never the entry, manifest shape).
> The enabler for code shared between writeonce repositories — the web
> framework (iteration 16) is the driving consumer.
> >
> **Spec exists:** [`2026-08-18-web-framework-design.md`](../../superpowers/specs/2026-08-18-web-framework-design.md) > **Spec exists:** [`2026-08-18-web-framework-design.md`](../../superpowers/specs/2026-08-18-web-framework-design.md)
> section A is normative for this iteration. **Plan:** > section A is normative for this iteration. **Plan:**

View file

@ -51,43 +51,43 @@ section A (normative). Story: [`15-deps-package-manager.md`](../../stories/langu
**Files:** modify `compiler/bin/main.ml` (manifest_parse + its doc comment). **Files:** modify `compiler/bin/main.ml` (manifest_parse + its doc comment).
- [ ] Extend the value grammar with the one-line inline table — a braced, - [x] Extend the value grammar with the one-line inline table — a braced,
comma-separated list of `key = "string"` pairs — accepted ONLY under comma-separated list of `key = "string"` pairs — accepted ONLY under
`[deps]`; anywhere else it stays "only quoted string values are supported". `[deps]`; anywhere else it stays "only quoted string values are supported".
Inside it, `git` and `rev` are required, both non-empty; any other key is Inside it, `git` and `rev` are required, both non-empty; any other key is
the existing unknown-key error. Section whitelist gains `deps`. the existing unknown-key error. Section whitelist gains `deps`.
- [ ] Represent each entry as (name, git URL, rev) in the parsed manifest; - [x] Represent each entry as (name, git URL, rev) in the parsed manifest;
a duplicate dep name is the duplicate-key error family. a duplicate dep name is the duplicate-key error family.
- [ ] Verify: a manifest with a well-formed `[deps]` parses (no behavior - [x] Verify: a manifest with a well-formed `[deps]` parses (no behavior
yet); a missing `rev`, a bare unquoted value, and an inline table outside yet); a missing `rev`, a bare unquoted value, and an inline table outside
`[deps]` each produce their named diagnostic. Run `just woc-test` — all `[deps]` each produce their named diagnostic. Run `just woc-test` — all
existing golden/manifest behavior unchanged. existing golden/manifest behavior unchanged.
- [ ] Commit. - [x] Commit.
## Task 2 — resolver: fetch, cache, lock ## Task 2 — resolver: fetch, cache, lock
**Files:** modify `compiler/bin/main.ml` (a `resolve_deps` step inside **Files:** modify `compiler/bin/main.ml` (a `resolve_deps` step inside
manifest_build, before discovery); `.gitignore` (`.wo-deps/`). manifest_build, before discovery); `.gitignore` (`.wo-deps/`).
- [ ] Layout: `.wo-deps/<name>/` beside `wo.toml`; `wo.lock` beside it too — - [x] Layout: `.wo-deps/<name>/` beside `wo.toml`; `wo.lock` beside it too —
one line per dep, name and resolved commit SHA, sorted, with a one-line one line per dep, name and resolved commit SHA, sorted, with a one-line
header comment naming the generator. header comment naming the generator.
- [ ] Cold path (no lock entry or no cache dir): run `git clone` into the - [x] Cold path (no lock entry or no cache dir): run `git clone` into the
cache dir and `git -C <dir> checkout <rev>`, then read the resolved SHA via cache dir and `git -C <dir> checkout <rev>`, then read the resolved SHA via
`git -C <dir> rev-parse HEAD`; write/refresh the lock entry. Every git `git -C <dir> rev-parse HEAD`; write/refresh the lock entry. Every git
invocation's failure is WO-E106 naming the dep, the URL/rev, and which step invocation's failure is WO-E106 naming the dep, the URL/rev, and which step
failed. A missing `git` binary is its own WO-E106 message. failed. A missing `git` binary is its own WO-E106 message.
- [ ] Warm path (lock entry present, cache dir present): compare the cache's - [x] Warm path (lock entry present, cache dir present): compare the cache's
HEAD SHA to the lock; equal means proceed with zero network. A cache HEAD SHA to the lock; equal means proceed with zero network. A cache
matching the manifest `rev` label but not the lock (a moved tag) is matching the manifest `rev` label but not the lock (a moved tag) is
WO-E106 "lock drift" naming both SHAs and pointing at `--update-deps`. WO-E106 "lock drift" naming both SHAs and pointing at `--update-deps`.
- [ ] `woc --update-deps <dir>`: re-fetches every dep at its manifest rev and - [x] `woc --update-deps <dir>`: re-fetches every dep at its manifest rev and
rewrites the lock; document in the usage text. rewrites the lock; document in the usage text.
- [ ] Guard rails, each its own diagnostic: the fetched dep has no `wo.toml` - [x] Guard rails, each its own diagnostic: the fetched dep has no `wo.toml`
or no `name` (not a writeonce project); the dep's `wo.toml` contains or no `name` (not a writeonce project); the dep's `wo.toml` contains
`[deps]` (transitive — refused flat-only, per spec); the dep name collides `[deps]` (transitive — refused flat-only, per spec); the dep name collides
with a local top-level module directory in the app (WO-E107). with a local top-level module directory in the app (WO-E107).
- [ ] Verify manually against a local `file://` remote: cold build fetches - [x] Verify manually against a local `file://` remote: cold build fetches
and writes the lock; second build is offline (prove by running with and writes the lock; second build is offline (prove by running with
`GIT_TRACE` absent and the remote renamed away); tag-move produces the `GIT_TRACE` absent and the remote renamed away); tag-move produces the
drift diagnostic; `--update-deps` clears it. Commit. drift diagnostic; `--update-deps` clears it. Commit.
@ -97,22 +97,22 @@ manifest_build, before discovery); `.gitignore` (`.wo-deps/`).
**Files:** modify `compiler/bin/main.ml` (discovery + `module_of` + entry **Files:** modify `compiler/bin/main.ml` (discovery + `module_of` + entry
candidate filtering in manifest_build's pipeline call). candidate filtering in manifest_build's pipeline call).
- [ ] Discovery: after resolve_deps, discover each dep root exactly as the - [x] Discovery: after resolve_deps, discover each dep root exactly as the
app root is discovered (same skip rules — dot-dirs, `target/`, and now app root is discovered (same skip rules — dot-dirs, `target/`, and now
`.wo-deps/` itself under the app root so dep trees are never discovered `.wo-deps/` itself under the app root so dep trees are never discovered
twice) and append its files to the compilation unit list. Deterministic twice) and append its files to the compilation unit list. Deterministic
order: app files first (sorted, as today), then deps sorted by name. order: app files first (sorted, as today), then deps sorted by name.
- [ ] Module mapping: `module_of` for a dep file prefixes the dep name — the - [x] Module mapping: `module_of` for a dep file prefixes the dep name — the
dep's root maps to module `<name>`, its subdirectory `sub/` to dep's root maps to module `<name>`, its subdirectory `sub/` to
`<name>/sub` — so the existing `use` resolution, collision diagnostics, `<name>/sub` — so the existing `use` resolution, collision diagnostics,
and `pub` visibility work across the boundary with no changes in and `pub` visibility work across the boundary with no changes in
`types.ml`. `types.ml`.
- [ ] Entry restriction: the `main` the emitter selects (and WO-E405 checks) - [x] Entry restriction: the `main` the emitter selects (and WO-E405 checks)
must come from the app root's own files; a dep's `fn main` is never an must come from the app root's own files; a dep's `fn main` is never an
entry candidate. The spec's rule "a dep's main is ignored" means exactly entry candidate. The spec's rule "a dep's main is ignored" means exactly
the selection filter — the fn itself still compiles as an ordinary the selection filter — the fn itself still compiles as an ordinary
module-scoped fn. module-scoped fn.
- [ ] Verify: an app importing one dep via `use <name>` and `use <name>/sub` - [x] Verify: an app importing one dep via `use <name>` and `use <name>/sub`
builds and runs; the dep having its own `fn main` changes nothing; builds and runs; the dep having its own `fn main` changes nothing;
`woc --dump-owner`/`--dump-bc` on the app still work (multi-file dump `woc --dump-owner`/`--dump-bc` on the app still work (multi-file dump
conventions apply to dep files like any other unit). Commit. conventions apply to dep files like any other unit). Commit.
@ -124,15 +124,15 @@ candidate filtering in manifest_build's pipeline call).
script builds its `file://` remotes in a temp dir at run time, so nothing script builds its `file://` remotes in a temp dir at run time, so nothing
network-shaped or `.git`-shaped is committed). network-shaped or `.git`-shaped is committed).
- [ ] The gate script, one check per behavior, log-watcher-accept style: - [x] The gate script, one check per behavior, log-watcher-accept style:
(1) cold fetch + lock written + app runs; (2) offline rebuild with the (1) cold fetch + lock written + app runs; (2) offline rebuild with the
remote removed; (3) moved-tag drift diagnostic; (4) `--update-deps` remote removed; (3) moved-tag drift diagnostic; (4) `--update-deps`
refresh; (5) transitive-dep refusal; (6) dep-name/local-module collision; refresh; (5) transitive-dep refusal; (6) dep-name/local-module collision;
(7) dep `fn main` ignored — app's entry wins; (8) missing-`rev` manifest (7) dep `fn main` ignored — app's entry wins; (8) missing-`rev` manifest
diagnostic. Exit nonzero on the first failure, count summary at the end. diagnostic. Exit nonzero on the first failure, count summary at the end.
- [ ] `just deps-accept` wired; run it plus `just woc-test` and - [x] `just deps-accept` wired; run it plus `just woc-test` and
`just oop-e2e` — all green, nothing pre-existing re-blessed. `just oop-e2e` — all green, nothing pre-existing re-blessed.
- [ ] Commit. - [x] Commit.
## Task 5 — docs closeout ## Task 5 — docs closeout
@ -142,7 +142,7 @@ network-shaped or `.git`-shaped is committed).
story `15-deps-package-manager.md` (status note), `docs/08-project-structure.md` story `15-deps-package-manager.md` (status note), `docs/08-project-structure.md`
(`.wo-deps/` + `wo.lock` in the project-layout listing). (`.wo-deps/` + `wo.lock` in the project-layout listing).
- [ ] Apply; `just deps-accept` still green; commit. - [x] Apply; `just deps-accept` still green; commit.
## Success criteria (from the story, restated as the gate) ## Success criteria (from the story, restated as the gate)