docs(chord): slice 6b D5; Harness.open in the examples

This commit is contained in:
Mario Zechner 2026-10-28 11:41:48 +00:00
parent 4ba356228c
commit 66330961bd
3 changed files with 24 additions and 12 deletions

View file

@ -1659,6 +1659,16 @@ validation and copies the v2 kernel added around Delta.
step refused fails live (`object_failed`, `broken`: memory and disk disagree); an `int` `CHECK` failure (a plugin's
value out of range) fails only that transaction (`invalid/args`). `StoreStorage` runs Durable's commit checks in the
step, where `SqliteStorage` runs them: no special case. Built in 6b (the store's step and object failure).
- **Slice 6b D5: persisted run records are documents of their object; one harness per store (owner, 2026-10-27:
"sure"):** each unsettled run's record is a keyed persisted document of its object in the engine's namespace
`chord.jobs` (owner the object's owner string, kind the job name, key the run id); Chord sets that namespace, a plugin
never does, so nothing collides; the state document stays an ordinary document of the run; `finish` deletes the
record and retires the state (Q9), so only unsettled runs are stored and in memory; activation loads them through the
engine's key listing and a load per run (no new engine read). Durable's tables are named under the type name
`pi.durable` (`"session:pi.durable:entries"`; type names are unique per app). One `StoreStorage` per store: a second
one on the same store is refused (`invalid/args`), as one host per store (rule 7). Rejected on the way: a table per
job, a store-wide runs table, `$`-marked internal names (owner: "if our abstractions can't cleanly support this
without $ magic, it's a bad abstraction").
- **The performance and memory bar, and converging reviews (owner, 2026-10-27: "yes"):** supersedes "as good as
HEAD in everything" for Chord v2 slices and pi changes. CPU: each hot path (calls, changes, watches, links) within
about 5% of HEAD, measured in bursts with alternating processes pinned to one CPU; worse is fixed or goes to the

View file

@ -1923,12 +1923,12 @@ loop. Chord has no stream type (it would need its own rules for drops, cancellat
access and execution environments from registry entries, looked up at each use:
```ts
const harness = self.open(async () => Durable.open(storage, {
const harness = self.open(async (context) => Harness.open(new StoreStorage(store), { // the host's store (slice 6b)
models: () => host.registry(HarnessModels).value,
env: (target) => host.registry(HarnessEnvironments).value(target.cwd),
settings: () => currentSettings(),
registry: durableRegistry(host.registry(HarnessExtensions)), // a RegistryReader over the composed NativeWatchable
}), (h) => h.close());
}, context), (h, _reason, context) => h.close(context));
```
Durable's `models` and `settings` accept functions (pi `7ec1f648e`). Durable opens with scheduling paused; base code

View file

@ -25,8 +25,8 @@ const worker = createHost<P>({ address: Session({ id }), principal, store, onErr
// the core facet: the harness object opens Durable on the same store
host.serve(Harness, (_, self) => {
const durable = self.open(async (context) =>
Durable.open(storeStorage(store, { owner: "session:harness" }), { …, paused: true }, context),
const harness = self.open(async (context) =>
Harness.open(new StoreStorage(store), { models, registry, … }, context), // one StoreStorage per store
(h, _reason, context) => h.close(context));
const view = self.follow(...) // Decision needed (D9): name and shape
return { … };
@ -57,8 +57,9 @@ Chord imports nothing of Durable (S13); Durable's conformance suite runs in Dura
Durable's four record tables (conversations, entries, tasks, submissions) and its ID namespace.
**Layout (D2, owner, 2026-10-27: "the whole purpose of this slice"):** declared tables of the store, written as
ordinary `put` writes: `defineTable`s that `StoreStorage` declares for itself (SQL names `"<owner>:<table>"`, e.g.
`"session:harness:entries"`), each row the record's indexed columns (`id`, `conversation_id`, `kind`, `status`, …) plus
ordinary `put` writes: `defineTable`s that `StoreStorage` declares for itself under the type name `pi.durable` (SQL names
`"<host kind>:pi.durable:<table>"`, e.g. `"session:pi.durable:entries"`; type names are unique per app, so no plugin
table can meet them), each row the record's indexed columns (`id`, `conversation_id`, `kind`, `status`, …) plus
the whole record in a `json(...)` column. The outbox, export, import and the applier handle them as every table;
Durable's layout changes later through `evolveTable`. The partial head index becomes an index on `(conversation_id,
has_head, id)` (index columns are non-`opt`); indexed strings that must stay lossless (`kind`, `requestId`, document
@ -154,12 +155,13 @@ abort request is persisted; a restart limit; the job fingerprint stored with eve
- **Where records live:**
> **Decision needed (D5).** (a) **Documents of the object:** each run's record is a keyed persisted document of the
> object (an internal definition per job, key the run id: `{ version, fingerprint, args, key?, phase, outcome?,
> abort?, restarts, trace? }`), its state document a second keyed document; both written in the transactions that
> already change them (start, state change, outcome, finish, block, drop), loaded at the object's first activation
> (all unsettled runs: `running` needs every one). (b) A table per job. Proposal: (a): the records are few, change
> in the same transactions as today, and reuse persisted documents (versions, checkpoints, export).
**Where records live (D5, owner, 2026-10-27):** each unsettled run's record is a keyed persisted document of its
object in the engine's namespace `chord.jobs` (owner the object's owner string, kind the job name, key the run id:
`{ version, fingerprint, args, key?, phase, outcome?, abort?, restarts, trace? }`); Chord sets that namespace, a plugin
never does (its documents are always `chord`), so nothing can collide. Its state document stays an ordinary document
of the run. Both change in the transactions that change them today (start, state change, outcome, finish, block,
drop); `finish` deletes the record and retires the state in its commit (Q9), so only unsettled runs are stored. At the
object's first activation the records are loaded through the engine's key listing and a load per run (no new read).
- **Resume at activation:** a run recorded `finishing` resumes `finish` only; a run recorded `running` was cut off by
a crash: `rerun` invokes `run` again with the stored args and state, `abandon` records `failed { aborted, reason: