docs: framework v1/v2 split + per-feature status ledger

- framework README core checklist expanded into the v1 STATUS LEDGER:
  seven categories (transport, routing, request/response, context &
  middleware, storage integration, security, crypto), every item
  marked done / partial-with-named-gap / candidate / parked-behind-8-11
  / needs-runtime-seam
- verified before labeling: BODY_MAX caps headers AND body (size limits
  done); net has no timeout or unix-socket or peer-address surface
  (runtime seams); language has NO bitwise operators, so SHA/HMAC/CRC32
  must be C runtime builtins or bit ops land first (fork to brainstorm);
  radix routing waits for 9e to measure the linear scan first
- crypto hard stop recorded: HS256 unlocks and nothing past it
- memory-rich features relabeled FRAMEWORK V2 = iteration 18 (story +
  spec banners + board rows); v1 gaps land as slices per the ledger

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
shoney.arickathil 2026-08-20 04:07:39 +02:00
parent 24ff960950
commit 234bd43466
5 changed files with 101 additions and 23 deletions

View file

@ -52,11 +52,16 @@ takes multipart/form/JSON; `just web-app` **21/0**. Surfaced + fixed the
RETURN flavor of the interp-of-borrowed-place emitter bug (emit_return now
sees through Interp; same corpus pin). Body-parsing hooks: all three ✅.
Next: **iteration 18** (memory-rich framework features — TTL cache,
@table flags, durable job queue with drain-on-request, `transaction { }`
over the WAL's staged batch; forks settled 2026-08-20, brainstormed the
same day) — spec, then plan, then implementation on approval. After 18,
the order resumes at 9c/9d.
Scope split (2026-08-20): the surface above plus the remaining transport/
routing/security gaps is **framework v1**, tracked item-by-item in the
[framework README's status ledger](examples/writeonce-framework/README.md)
(✅/🔶/⬜/⏸/🔧 per feature — timeouts and Unix sockets need `net` runtime
seams, crypto hashes need C builtins since the language has no bitwise
operators, streaming/cancellation park behind 8/11). The memory-rich
features are **framework v2** = iteration 18 (spec written, awaiting
review): TTL cache, @table flags, durable job queue with drain-on-request,
`transaction { }` over the WAL's staged batch. After 18, the order resumes
at 9c/9d.
---
@ -172,7 +177,7 @@ that sequences its tasks. Read one, approve, then the next starts.
| 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) | ✅ **landed 2026-08-19** — writeonce-framework (HTTP/1.1 + router + Handler/Middleware) consumed by web-app through [deps]; h2c parked (§C) behind 8/9f/11. **v1 polish landed 2026-08-20** (branch framework-v1): get/post/put/delete_ helpers, 405+Allow, HEAD, Logging middleware, set_header; `just web-app` 16/0; fixed the interp-borrowed-field emitter crash en route. **Auth-in-core landed 2026-08-20**: http/auth.wo (Bearer/Basic, ct_eq, req.principal), web-app dogfoods BearerAuth, gate 17/0 |
| 17 | [library projects + `internal/`](stories/language-runtime-database/17-library-projects-internal.md) | ⏸ **PARKED 2026-08-20** (developer directive; framework v1 first) — forks settled, spec + plan approved and ready on branch `library-internal`: kind = "library" key; Go internal/ rule, dep-boundary-only; lib+bin dual; VM/GC untouched by design |
| 18 | [memory-rich framework features](stories/language-runtime-database/18-memory-db-features.md) | 🔄 **spec written 2026-08-20, awaiting review** ([spec](superpowers/specs/2026-08-20-memory-db-features-design.md)): TTL cache + @table flags + durable job queue (drain-on-request) + `transaction { }` over the WAL's staged batch; pub/sub REJECTED until 8/11 |
| 18 | [framework v2: memory-rich features](stories/language-runtime-database/18-memory-db-features.md) | 🔄 **spec written 2026-08-20, awaiting review** ([spec](superpowers/specs/2026-08-20-memory-db-features-design.md)): TTL cache + @table flags + durable job queue (drain-on-request) + `transaction { }` over the WAL's staged batch; pub/sub REJECTED until 8/11 |
---

View file

@ -63,22 +63,85 @@ writeonce-framework = { git = "https://github.com/shoneyj/writeonce-framework",
fibers/shards) with `part_named` for fields; `media_type(req)` names
the body's media type for content negotiation.
## The core checklist (what a framework core owes, and where this one is)
## The v1 surface — status ledger (2026-08-20)
| Core concern | State |
The target surface of **framework v1**, tracked per item. The memory-rich
features (TTL cache, feature flags, durable job queue, `transaction { }`)
are **framework v2** — iteration 18, spec written, NOT part of v1.
Legend: ✅ shipped · 🔶 partial (gap named) · ⬜ candidate slice ·
⏸ parked behind a runtime iteration · 🔧 needs a runtime/compiler seam
first (pure `.wo` cannot express it yet).
### Transport
| Item | State |
| --- | --- |
| HTTP parsing + connection lifecycle | ✅ `http/parse.wo`, `http/serve.wo` (keep-alive, 400-and-survive, fd-clean, SIGTERM) |
| Routing: path params, method dispatch, precedence | ✅ `:param` captures, first-match-wins, wrong-method = 405 + `Allow` |
| Middleware chain, ordering guarantee | ✅ registration order, `?Resp` short-circuits |
| Request/response types | ✅ `Req`/`Resp` + builders + `set_header` |
| Bearer/Basic auth mechanism + principal | ✅ `http/auth.wo`, `req.principal` |
| Body parsing hooks: JSON | ✅ the language's checked `json.decode` |
| Body parsing hooks: form-encoded | ✅ `form_values(req)` — nil unless the content-type says form; `media_type(req)` exposed for content negotiation |
| Body parsing hooks: multipart | ✅ `multipart_parts(req)` (RFC 7578: fields + file parts, filename/mime kept) + `part_named` |
| Error handling → status mapping | 🔶 trap = 500, builders per status; a per-error mapping hook is a candidate slice |
| Body streaming, backpressure | ⏸ needs fibers/shards (iterations 8/11) — whole bodies until then, by design |
| Cancellation propagation | ⏸ process-level only (`env.stopping()`); per-request cancel needs fibers (11) |
| Configuration + graceful shutdown | 🔶 SIGTERM drains and closes clean; config is ctor fields — a config record is a candidate slice |
| HTTP/1.1 parsing | 🔶 parses + 400-and-survive; STRICT ambiguity rejection (duplicate/conflicting `Content-Length`, oversize checks beyond BODY_MAX) not audited — hardening slice |
| Keep-alive | ✅ pipelined-serve / close-when-idle (starvation-honest until 8/11) |
| Read/write/idle timeouts | 🔧 `net` has no timeout surface — runtime seam, then a framework knob |
| Request size limits | ✅ BODY_MAX bounds headers AND body |
| Unix socket binding | 🔧 `net.listen` is TCP-only — runtime seam |
| Graceful SIGTERM | ✅ in-flight request completes (blocking model), listener + fds closed, storage is per-commit durable (WAL fdatasync — nothing to checkpoint) |
### Routing
| Item | State |
| --- | --- |
| Path matching | 🔶 linear scan, first-match-wins; a radix tree is a performance slice that waits for iteration 9e to MEASURE it first |
| Method dispatch · path params · 404 · 405+`Allow` | ✅ |
| Wildcards | ⬜ only `:param` today; `*rest` capture is a candidate slice |
| Precedence rules | 🔶 registration order IS the rule (documented); specificity-based precedence unneeded until wildcards exist |
| Route groups | ⬜ candidate slice (prefix + per-group middleware) |
### Request/response
| Item | State |
| --- | --- |
| Case-insensitive headers · query parsing | ✅ (names lowercased on read) |
| JSON · form-urlencoded · multipart | ✅ all three hooks (`json.decode`, `form_values`, `multipart_parts`) |
| Content negotiation | 🔶 `media_type(req)` covers the request side; `Accept`-driven response negotiation ⬜ |
| Trusted-proxy client IP | 🔶 `X-Forwarded-For/-Proto` parsing is expressible (candidate slice); VERIFYING the peer is the trusted proxy needs a peer-address runtime seam 🔧 |
| Status/header setting · redirects | ✅ builders + `set_header` |
| Lazy body streaming + backpressure · streaming responses · explicit commit point | ⏸ 8/11 — whole bodies, one write, by design |
| ETag + conditional requests | ⬜ candidate; wants the crypto slice's hashing |
### Context & middleware
| Item | State |
| --- | --- |
| Ordered middleware chain | ✅ registration order, `?Resp` short-circuits |
| Request-scoped context | 🔶 `req.params` + `req.principal` are the context today; a general `req.ctx` bag is a candidate slice |
| Guaranteed teardown | 🔶 every fd closes on every path (gate-proven); no user teardown hooks yet |
| Cancellation into pending storage ops | ⏸ fibers (11) |
| Panic recovery | 🔶 trap = 500 and the server survives ✅; "rolls back the transaction" is framework v2 (needs `transaction { }`, iteration 18) |
### Storage integration (the differentiator — framework v2 territory)
| Item | State |
| --- | --- |
| Transaction-per-request middleware (commit on 2xx, roll back otherwise) | ⏸ **v2** — needs iteration 18's `transaction { }` |
| Cancellation → rollback | ⏸ fibers (11) + v2 |
| Migration generation + review workflow | ⬜ recorded future story (script-based destructive migrations) |
| Eager-loading API (N+1) | ⬜ query-surface work (9-series), not framework code |
| Tenant-scoped query roots | ⬜ future; wants the query surface to grow scoped roots first |
### Security
| Item | State |
| --- | --- |
| Constant-time comparison · Authorization parsing · Basic auth · principal | ✅ `http/auth.wo`, `req.principal` |
| CORS | ⬜ candidate slice (middleware + preflight answers) |
| Security headers | ⬜ candidate slice (one middleware, a header set) |
| Host validation | ⬜ candidate slice (middleware against a host allowlist) |
| Strict parsing | 🔶 same item as Transport's hardening slice |
### Crypto (self-written, hard-stop after JWT HS256)
| Item | State |
| --- | --- |
| base64 | ✅ pure `.wo` (`http/auth.wo`) |
| SHA-256 · SHA-512 · HMAC · CRC32 | 🔧 the language has NO bitwise operators — these are C runtime builtins (libc-only doctrine permits hand-rolled crypto in the runtime) or the language grows bit ops first; the fork goes to a brainstorm before the slice |
| Unlocks (signed cookies, CSRF, session integrity, webhook verification, JWT HS256) | ⬜ framework slices AFTER the hash primitives exist; **hard stop there** — no RS256, no JOSE zoo |
## The consuming sample

View file

@ -66,7 +66,7 @@ iterations); no commits by agents — drafts go to `.dev/commit.md`.
| 15 | [deps: `wo.toml [deps]`](15-deps-package-manager.md) | exact-rev git dependencies + `wo.lock` + `.wo-deps` cache; `use <dep>` resolves a fetched project as a module root; flat-only, network-free when locked |
| 16 | [web framework](16-web-framework.md) | a `.wo`-library framework (HTTP/1.1 keep-alive behind a TLS-terminating proxy): router, `Handler`/`Middleware` structural interfaces, `@table` data layer; `docs/examples/web-app` consumes it via `[deps]`; h2c parked behind 8/9f/11 |
| 17 | [library projects + `internal/`](17-library-projects-internal.md) | first-class library projects (`wo.toml` kind = "library", checkable without an entry, dual lib+bin) and dependency privacy (Go's `internal/` rule at the [deps] boundary) — forks settled 2026-08-20, spec/plan next |
| 18 | [memory-rich framework features](18-memory-db-features.md) | what the embedded store + one process buy for free: TTL cache class, @table feature flags with cached reads, a durable @table job queue with drain-on-request, and `transaction { }` exposing the WAL's staged batch (enqueue + write, one commit — no outbox) — forks settled 2026-08-20, spec/plan next |
| 18 | [framework v2: memory-rich features](18-memory-db-features.md) | what the embedded store + one process buy for free: TTL cache class, @table feature flags with cached reads, a durable @table job queue with drain-on-request, and `transaction { }` exposing the WAL's staged batch (enqueue + write, one commit — no outbox) — forks settled 2026-08-20, spec/plan next |
Review protocol: the developer reads one iteration, approves or amends;
the next starts only after approval. Each iteration is an unsplittable

View file

@ -1,4 +1,10 @@
# Iteration 18 — memory-rich framework features over the embedded database
# Iteration 18 — framework v2: memory-rich features over the embedded database
> **Scope label (2026-08-20): this iteration is FRAMEWORK V2.** Framework
> v1 is the transport/routing/body/security surface tracked in the
> [framework README's status ledger](../../examples/writeonce-framework/README.md);
> v2 is what the embedded store adds on top. v1 gaps land before or
> alongside v2 as slices, per the ledger.
> Format: `product/story-iteration-template`. Part of
> [Story — one language, one runtime, one database, one binary](00-story.md).

View file

@ -1,5 +1,9 @@
# Iteration 18 — memory-rich features over the embedded database: design
# Iteration 18 — framework v2: memory-rich features over the embedded database (design)
> **Scope label: FRAMEWORK V2** — framework v1 is the surface tracked in
> the framework README's status ledger; this spec is what the embedded
> store adds on top of it.
>
> **Status: spec, awaiting review (2026-08-20).** Decisions were settled in
> [the iteration](../../stories/language-runtime-database/18-memory-db-features.md);
> this spec makes them buildable. The plan follows after review.