writeonce/docs/stories/porch/00-story.md
shoney.arickathil 3a73938d2e docs(status): reconcile board, graph and story tables with the 2026-09-09..11 landings
- board: language 18 row (hold lifted 2026-09-11, split — 18 keeps
  transaction { }, cache/flags/jobs to porch 10); In-progress rows for
  databasev2 4 part B / 5 / language 18 and the Active slice; databasev2
  rows 2 (CLOSED, 6a), 4 (part B re-brainstormed), 5 (ready), 7 (CLOSED),
  13 (new); the held list drops 18
- dependency graph: new §8 databasev2 (nodes 1–13, edges, states table);
  graph 1's 23/32 nodes turn done and their edge becomes undirected (they
  compose; neither needs the other); language 18 / porch 10 nodes and
  edges across the porch and language graphs; wmux gains the databasev2 2
  edge (DB2W) the prose already named
- databasev2 00-story: sequence rows 1/2/4/5/7/8/11/12/13/14, the ASCII
  graph (2 no longer needs 1; 2 → 11, 12) and the order rationale
- 01: the budget finding redirected to 5; 06: the Needs line marked
  superseded, task 7's 2026-08-30 measurement quoted; 09: the report's
  group-by is still refused, schema-sharing is language-track work; 10: an
  in-tree signing answer exists (rv2 9), Ed25519-vs-reuse still open
- porch 00-story: row 10 (memory features over @table, refine stub) and
  the "not porch's" table updated for the split

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 423b3c187b626f69da1ddb942c3c7849a3ee5a73)
2026-09-15 01:16:24 +02:00

91 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 over a sharded actor pool — exact counting, restart-durable | ✅ **done** 2026-08-30; re-scoped to the limiter alone |
| 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 |
| 9 | [Idempotent replay](09-idempotent-replay.md) | idempotent replay of unsafe requests, the actor running the route handler | ⏸ built and reverted; blocked on [language 41](../language-runtime-database/41-actor-arena-crash.md) |
| 10 | [Memory features over `@table`](10-memory-features-over-table.md) | TTL cache, `@table` feature flags, durable job queue — the three `.wo` pieces split out of language 18 on 2026-09-11 | stub, `readiness: refine`; needs [language 18](../language-runtime-database/18-memory-db-features.md)'s `transaction { }` for the jobs demo, and 1–3 |
```
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 |
| `transaction { }` | language: [iteration 18](../language-runtime-database/18-memory-db-features.md) — the engine + language half; TTL cache, `@table` feature flags and the durable job queue **moved into this track** as [iteration 10](10-memory-features-over-table.md) on 2026-09-11 |
| 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.