- the agent rename database-developer → codd (and its guide) happened inside lang-18's `aab4878` on dev, which stays there; the `docs(agents)` pick brought codd.md in beside the old file — remove the old name and its guide - docs/stories/porch/09-idempotent-replay.md: added on dev by `79e6da4`, whose earlier pick onto master (`refactor(porch-store)`) landed without it — the board, porch 1 and porch 4 link to it - docs/stories/porch/10-memory-features-over-table.md: the refine stub language 18's docs commit created on dev; the board and porch 00-story link to it, the code it waits on is not on master - docs/examples/skill-catalog/README.md: the story link fix from `b3d8c40` that its earlier pick (`8311330`) dropped in conflict resolution — dev's version taken - `just linkcheck` on master: every remaining broken link is a wmux story or spec (track not picked) or a developer-local `.dev/reference` symlink Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2.8 KiB
| track | iteration | status | readiness |
|---|---|---|---|
| porch | 10 | pending | refine |
porch 10 — memory features over @table: TTL cache, feature flags, durable jobs
Part of Story —
porch, the writeonce web framework. Stub, created 2026-09-11 by the language-18 re-brainstorm (fork 1): the three.wopieces of language 18 moved here; 18 keeps the language + engine half,transaction { }. Their spec text is Part B of2026-08-20-memory-db-features-design.md; its jobs section is superseded (below).
Carried over from 18, already settled — do not re-brainstorm
- Cache: pure
.wo, TTL + capacity, lazy expiry on read, FIFO eviction over LRU (stated tradeoff), Text values (no generics), a time-injected seam (get_at/put_at) so the fixture injects stamps instead of sleeping. - Flags:
@table(name: "wf_flags")withname @uniqueand an Int 0/1on; a read-through map filled on first read, updated in the same call as the write. Framework tables carry thewf_prefix. - Job row:
wf_jobs—kind,payload(Text, json),attempts,not_before(wall ms, 0 = due).enqueueis an ordinaryinsertand is what goes inside the business write'stransaction { }.
Re-settled by 18 on 2026-09-11 (fork 2) — the execution model
Drain-on-request and the Dispatcher.idle() seam are retired: they assumed
"no timers", which has been false since iteration 24. A job runner is an
actor the app spawns; the app sends it a poke after the block's
closing brace (a send inside the block is WO-E111 by design — the row must
be durable before anyone acts on it); the runner queries due jobs
(not_before <= time.now, take budget), deletes on success, bumps
attempts on failure, and re-arms itself with time.after for the earliest
not_before (one-shot, generation-counter idiom). The table is the durable
outbox; the poke is a hint — at boot the app pokes once and every survivor
runs without a request. The engine provides nothing new.
To refine here (what makes this ready)
- Budget per drain and the backoff shape (app-side in v1 per the spec — keep or move into the runner?).
- Where the runner lives (porch-owned actor class vs app-owned satisfying an
interface — the
Jr/Mwwrapper pattern). - The web-app demo and gate legs (order +
confirmjob in one block,kill -9after the POST, restart, the job runs; flags across restart) — these need 18's T1–T6 landed first. - Whether porch 1's pool actor is the runner's home (serialize through the same actor that owns store writes) or a second actor.
Needs
Language 18 (transaction { }) for the demo's headline; nothing else beyond
what spawn/send/time.after and @table already provide.