- 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>
59 lines
2.8 KiB
Markdown
59 lines
2.8 KiB
Markdown
---
|
||
track: porch
|
||
iteration: "10"
|
||
status: pending
|
||
readiness: refine
|
||
---
|
||
|
||
# porch 10 — memory features over `@table`: TTL cache, feature flags, durable jobs
|
||
|
||
> Part of [Story — `porch`, the writeonce web framework](00-story.md).
|
||
> **Stub, created 2026-09-11** by the language-18 re-brainstorm (fork 1): the
|
||
> three `.wo` pieces of
|
||
> [language 18](../language-runtime-database/18-memory-db-features.md) moved
|
||
> here; 18 keeps the language + engine half, `transaction { }`. Their spec
|
||
> text is Part B of
|
||
> [`2026-08-20-memory-db-features-design.md`](../../superpowers/specs/2026-08-20-memory-db-features-design.md);
|
||
> its jobs section is superseded (below).
|
||
|
||
## Carried over from 18, already settled — do not re-brainstorm
|
||
|
||
1. **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.
|
||
2. **Flags**: `@table(name: "wf_flags")` with `name @unique` and an Int 0/1
|
||
`on`; a read-through map filled on first read, updated in the same call as
|
||
the write. Framework tables carry the `wf_` prefix.
|
||
3. **Job row**: `wf_jobs` — `kind`, `payload` (Text, json), `attempts`,
|
||
`not_before` (wall ms, 0 = due). `enqueue` is an ordinary `insert` and is
|
||
what goes inside the business write's `transaction { }`.
|
||
|
||
## 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 `send`s 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`/`Mw` wrapper pattern).
|
||
- The web-app demo and gate legs (order + `confirm` job in one block,
|
||
`kill -9` after 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.
|