Code is the source of truth; these claims no longer matched runtime/src: - "net.connect does not exist" — landed 2026-09-07 (id 110); net.connect_tls / read_tls / write_tls (115-117) + net.accept_tls (118), WO_B_MAX 118. Fixed in jarvis 00-story (problem statement + architecture + out-of-scope), porch 00-story (proxy middleware row), rv2 7 (push-collector fork), 00-code-review - "TLS: none / proxy-mandated forever" — retired by rv2 9 (in-process TLS both directions). Fixed in porch + web-app + site example READMEs (proxy is now a deployment choice; HSTS row), 00-code-review - "no RNG anywhere in the runtime" — imprecise: the runtime has a getrandom(2) source since rv2 9 (TLS ephemerals), but nothing exposes it to .wo yet. Fixed in CODE-LOGIC (digests), lang 34, porch 2, status lang-39 row - "porch 9 blocked on language 41" — lang 41 fixed 63065ff. Fixed in porch 1, jarvis 00-story, status NEXT PLAN, dependency graph (L41 done, P9 ready) - dependency graph §7 rewritten: the runtime side is done; jarvis 1 waits only on porch (developer's porch-first order). Adds jarvis 1's dependency table + the build order that satisfies it - 00-code-review: a dated 2026-09-09 re-verification appended (record kept) - site README lives in the writeonce-site submodule: committed there, pointer bumped here Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit f1049dd9b7c7770da28bcabfc1cb1324621e7ee6)
89 lines
5.4 KiB
Markdown
89 lines
5.4 KiB
Markdown
# Story — `porch`, the writeonce web framework
|
||
|
||
The second track. Where
|
||
[`language-runtime-database/`](../language-runtime-database/00-story.md) grows
|
||
the *language*, this track grows the one library written **in** it:
|
||
[`porch`](../../examples/porch/README.md), consumed by every serving sample
|
||
through `wo.toml [deps]`.
|
||
|
||
Numbering restarts at 1 and is local to this track. Frontmatter carries
|
||
`track: porch` so a query over `docs/stories/` can tell a porch iteration 3 from
|
||
a language iteration 3. Status rules are the repo's, unchanged: `status:` in
|
||
frontmatter is the only place state lives, no directory encodes it.
|
||
|
||
## Why a separate track
|
||
|
||
Three reasons, all practical:
|
||
|
||
1. **Different substrate, different gates.** porch is `.wo` source. Its
|
||
iterations are proven by `just web-app` and `just site`, never by the
|
||
conformance corpus or `oop-accept`. Mixing them into the language track's
|
||
sequence made both harder to read.
|
||
2. **Different cadence.** A porch slice is days; a language slice that touches
|
||
`wob.h` and the VM is longer and riskier. Interleaving them in one numbering
|
||
forced false ordering decisions.
|
||
3. **The framework is now the product surface.** `writeonce.de` is served by
|
||
porch. Its gaps are what a visitor hits first, so they deserve a roadmap that
|
||
is not buried behind runtime work.
|
||
|
||
The language track stays upstream: when a porch iteration needs a new builtin,
|
||
that half is called out explicitly and the language track owns it.
|
||
|
||
## Where the sequence came from
|
||
|
||
The [Fiber v3.5.0 parity study](../../plan/exploration/fiber/00-fiber-parity.md)
|
||
— gofiber/fiber read end to end against porch's actual `.wo` source: its routing
|
||
surface, `Req`/`Res` API, binder, lifecycle hooks and the `Config` of all 32 of
|
||
its `middleware/` packages. Nine of those 32 already have a working porch
|
||
counterpart, so this is a breadth roadmap, not a rescue.
|
||
|
||
That study replaced language-track
|
||
[iteration 39](../language-runtime-database/39-web-framework-parity.md), which is
|
||
now a pointer here.
|
||
|
||
## The sequence
|
||
|
||
Ordered by dependency, not by importance — and the first slice is deliberately
|
||
the *cheapest*, so the store pattern and the gate shape are proven before the
|
||
risky work starts.
|
||
|
||
| # | Iteration | Delivers | Needs |
|
||
| --- | --- | --- | --- |
|
||
| 1 | [Store-backed middleware](01-store-backed-middleware.md) | rate limiting + idempotency over a `@table` store, serialized through a sharded actor pool | 🔄 in progress; needs no new primitive (`call`/`send`/`monitor`/`time.after` all landed) |
|
||
| 2 | [Randomness and cookies](02-randomness-and-cookies.md) | a `random_bytes` runtime builtin, repeated response headers, `Cookie:` parsing, signed cookies | a language-track builtin (phase A) |
|
||
| 3 | [Sessions](03-sessions.md) | server-side sessions, idle + absolute timeout, revocation | 2 |
|
||
| 4 | [CSRF](04-csrf.md) | token mint/verify, trusted origins, single-use tokens | 2, 3 |
|
||
| 5 | [Routing and response ergonomics](05-routing-response-ergonomics.md) | the remaining method helpers, named routes, per-route body limit, request ids, the missing response helpers | nothing — parallel to 2–4 |
|
||
| 6 | [Streaming core](06-streaming-core.md) | incremental response writes and chunked framing — the seam three iterations wait on | nothing new, but it changes `Resp` |
|
||
| 7 | [SSE and compression](07-sse-and-compression.md) | server-sent events, gzip/deflate | 6 |
|
||
| 8 | [Static files and lifecycle](08-static-and-lifecycle.md) | byte ranges, cache headers, directory listing, lifecycle hooks, the small middleware everyone ships | 6 |
|
||
|
||
```
|
||
1 ─ independent, start here
|
||
5 ─ independent, any time
|
||
2 ──▶ 3 ──▶ 4
|
||
6 ──▶ 7
|
||
└──▶ 8
|
||
```
|
||
|
||
## What this track does NOT own
|
||
|
||
| Not porch's | Owner |
|
||
| --- | --- |
|
||
| typed binding of query/params/form into a class | language: [`@derive`](../language-runtime-database/29-compile-time-metaprogramming.md) — reflection is forbidden by principle 13 |
|
||
| TTL cache, `transaction { }`, durable job queue | language: [iteration 18](../language-runtime-database/18-memory-db-features.md) |
|
||
| a `proxy` middleware | language: [iteration 38](../language-runtime-database/38-content-platform-capabilities.md) — needs `net.connect`, ✅ landed 2026-09-07 (id 110; plus `net.connect_tls` for an HTTPS upstream, runtime-v2 9). Buildable now |
|
||
| metrics, profiling, per-change CI, fuzzing | [runtime-v2 7](../runtime-v2/07-observability.md) — observability (was language iteration 30; metrics/profiling/trace-on-trap; CI + fuzz are tooling, split out) |
|
||
| TLS | ✅ [runtime-v2 9](../runtime-v2/09-in-process-tls.md) — in-process TLS 1.3 both directions (2026-09-09); porch can terminate inbound TLS with `net.accept_tls`, no front proxy required. The proxy-termination doctrine is retired |
|
||
| HTTP/2 | nobody yet — a separate protocol slice; TLS is its prerequisite, now met |
|
||
| a runtime template engine | nobody — rejected; markup is a compile-time literal (`writeonce-view`) |
|
||
| a radix-tree router | nobody yet — waiting on a *measurement*, not a decision |
|
||
|
||
## Review protocol
|
||
|
||
Same as the language track: the developer reads one iteration, approves or
|
||
amends; the next starts only after approval. Each iteration is an unsplittable
|
||
value slice with phases, per-phase tasks, Given/When/Then acceptance criteria,
|
||
and an out-of-scope list. Every phase ends with both serving gates green —
|
||
`just web-app` and `just site` — because porch has two consumers and a change
|
||
that only satisfies one is not done.
|