You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
RFC: durable Bot state journal and time-travel replay (reliability) #511
Multi-Bot bugs (a race, a lost hold, a wrong reparent) reproduce only sometimes. state.json keeps the latest snapshot; nothing gives an ordered, replayable record of state mutations.
Proposal (local, no egress, no behavior change)
core/src/host/journal.js: an append-only JSONL of state mutations ({ seq, t, op, botId, key, prev, next, actor }), capped by retention/size; mode 0600, never leaves the host.
core/scripts/replay.mjs: rebuild a read-only host up to a seq; a test helper replayTo(seq).
changed the title [-]RFC: durable Bot event journal and time-travel replay[/-][+]RFC: durable Bot state journal and time-travel replay (reliability)[/+]on Oct 20, 2026
Triage (Birfy, 2026-10-20 16:55 Asia/Shanghai). RFC, no conflict with the owner rules as written (local only, mode 0600, no egress, fail closed).
Proposed scope so it can become agent-ready: state mutations only (decisions stay in #396), opt-in behind a host flag (off by default, so every existing test is unchanged), retention 7 days or 20 MB, whichever comes first, oldest lines dropped. Replay script dev-only.
Waiting for the owner to confirm this scope (needs-human).
Claimed by Birfy (2026-10-20 17:58 Asia/Shanghai) for the hourly maintenance run, branch feat/511-state-journal on Birfy/FlyBot. Scope per the Owner decision above: state mutations only, opt-in host flag (off by default), 7 days / 20 MB retention, dev-only replay script, local only.
Minor details decided while implementing (Birfy, 2026-10-20 18:07 Asia/Shanghai), within the Owner decision (option a); PR #527:
Flag:stateJournal: true in the bot config (cordis.patch.yml); anything else is off, and off opens/writes nothing.
Where:<home>/journal/state.jsonl (file 0600, folder 0700). Only the host holding the state lock records; a read-only window records nothing.
Granularity: recorded after each successful state.json write, as the difference from the last recorded snapshot. Ops: base (whole team: first line, or a change only a key reorder explains), set, delete, append (prevLength, drop, new items — group logs and other capped lists). Paths are at most 3 keys deep (bots.<id>.<field>); botId is set on bots.<id> paths. key is an array of strings.
actor:host for saves, retention for a folded base. Per-call attribution (which tool/endpoint caused a save) would touch ~88 call sites, so it is left out.
Retention: checked at write time; when a write would pass 20 MB or the oldest change is older than 7 days, drop the oldest lines down to 90% of each cap (so the file is not rewritten on every save) and fold them into the base line so the rest still replays. If the team alone exceeds 20 MB, recording stops with a warning.
Fail closed: replay refuses the whole journal on a corrupt/incomplete line, unknown op, seq gap, missing base, or a prev mismatch; a seq outside the file is refused. On start the writer replays the file the same way; if it does not replay (or the path is not a plain file, or a write fails) it stops recording for that run with a warning and leaves the file untouched. The team's own save never depends on the journal.
Replay script:core/scripts/replay.mjs <journal> [--to <seq>] [--out <file>] prints the rebuilt state.json, or writes a new 0600 file (never overwrites). Network and process calls are stubbed to throw. Not packed. "Read-only host" = open the output as state.json in a test-bench home (documented), not in the journal's own home.
Activity
[-]RFC: durable Bot event journal and time-travel replay[/-][+]RFC: durable Bot state journal and time-travel replay (reliability)[/+]Birfy commentedon Oct 20, 2026
Triage (Birfy, 2026-10-20 16:55 Asia/Shanghai). RFC, no conflict with the owner rules as written (local only, mode 0600, no egress, fail closed).
Proposed scope so it can become
agent-ready: state mutations only (decisions stay in #396), opt-in behind a host flag (off by default, so every existing test is unchanged), retention 7 days or 20 MB, whichever comes first, oldest lines dropped. Replay script dev-only.Waiting for the owner to confirm this scope (
needs-human).Birfy commentedon Oct 20, 2026
Owner decision (Danyang Chen, 2026-10-20 17:31 Asia/Shanghai): option (a).
Birfy commentedon Oct 20, 2026
Claimed by Birfy (2026-10-20 17:58 Asia/Shanghai) for the hourly maintenance run, branch
feat/511-state-journalon Birfy/FlyBot. Scope per the Owner decision above: state mutations only, opt-in host flag (off by default), 7 days / 20 MB retention, dev-only replay script, local only.Birfy commentedon Oct 20, 2026
Minor details decided while implementing (Birfy, 2026-10-20 18:07 Asia/Shanghai), within the Owner decision (option a); PR #527:
stateJournal: truein thebotconfig (cordis.patch.yml); anything else is off, and off opens/writes nothing.<home>/journal/state.jsonl(file 0600, folder 0700). Only the host holding the state lock records; a read-only window records nothing.state.jsonwrite, as the difference from the last recorded snapshot. Ops:base(whole team: first line, or a change only a key reorder explains),set,delete,append(prevLength,drop, new items — group logs and other capped lists). Paths are at most 3 keys deep (bots.<id>.<field>);botIdis set onbots.<id>paths.keyis an array of strings.hostfor saves,retentionfor a folded base. Per-call attribution (which tool/endpoint caused a save) would touch ~88 call sites, so it is left out.prevmismatch; aseqoutside the file is refused. On start the writer replays the file the same way; if it does not replay (or the path is not a plain file, or a write fails) it stops recording for that run with a warning and leaves the file untouched. The team's own save never depends on the journal.core/scripts/replay.mjs <journal> [--to <seq>] [--out <file>]prints the rebuiltstate.json, or writes a new 0600 file (never overwrites). Network and process calls are stubbed to throw. Not packed. "Read-only host" = open the output asstate.jsonin a test-bench home (documented), not in the journal's own home.Add an opt-in state journal and a dev replay script (#527)