Repository navigation
Move the remaining inline state writers onto rt.mutate() #1048
Copy link
Copy link
Closed
Labels
area:automationScheduled tasks and automationScheduled tasks and automationenhancementNew feature or requestNew feature or request
Description
Owner: Dev2
Found while landing #1042 (the wording half). #1042 makes the fragment and the docs say what is true today; this is the other half — making the sentence "a change made outside a request goes through rt.mutate(fn)" describe all of them.
Why it is not a one-line change
mutate(change) is refresh() → change() → save() (core/src/host/store.js:494-499). refresh() adopts, and adopt() replaces rt.state whole (store.js:209-213), so any object reference captured before the call — record(agentId) in agents.js:81, to in delivery.js:105, the module-level state — points at the discarded object after the adopt. Each site must re-resolve inside the callback, not move the existing lines into it.
Call sites today (line numbers on 1d5b5a5f)
core/src/host/delivery.js:116—noteFriendLinewritesstate.remoteContacts,to.friendLineAtandvoid rt.save(); it also returns a boolean, so amutate()wrap makes the caller's answer a promise.core/src/host/delivery.js:198— thestate.exchanges.push(…)+void rt.save()for a request/reply/stopped exchange.core/src/host/agents.js:96, :114, :147, :178, :182— the Agent'ssessionsarray and thestate.agentsentry, each saved after an externalawait(create, adopt, archive, remove).core/src/host/agents.js:133— the rollback save inaddAgent's catch: it must persist the deletion after a failed create, so it needs its own treatment (a rollback is not an adopt-then-change).
Acceptance
- Each migrated site applies its change after the adopt, re-resolving its records inside the callback; a change made from a read-only window keeps what the other host left.
- One two-host test per file in the shape of
core/test/home-lock.test.js:233(#1032): the other host writes, closes, this window writes — both values survive. noteFriendLine's callers still get a usable "first contact" answer (async is fine, but every caller and its test must say so).ds-bot-patches checkpasses:patches/ds-bot/0001-core-fixes.patchcarriesstore.js/delivery.js/agents.jsand must be regenerated withgenerate, not hand-edited.- No behaviour change otherwise: the existing
coresuite and the#1027/#1032tests stay green.
Not this issue
- The lock takeover itself (
#1027) andsave()'s no-adopt rule (#1032) are settled and stay. #1042closes on the wording, so the release notes stop claiming the migration before this lands.
Metadata
Metadata
Assignees
Labels
area:automationScheduled tasks and automationScheduled tasks and automationenhancementNew feature or requestNew feature or request
Activity
Birfy commentedon Oct 25, 2026
Written-by: Triage
Labelled
enhancement | agent-ready | area:automation, ownerDev2(already in the body).area:automationfollows #1041/#1042: the host store and its writers, not a user-facing surface.Scope as written is clear enough to start — the trap (
adopt()replacesrt.statewhole, so references captured beforemutate()are stale) and the line numbers are given, which is the part that makes this non-trivial. Two things the tests must actually pin:1d5b5a5fthe inline writer saves without adopting, so a window that was read-only loses the other host's value. Assert the surviving value, not the call shape.noteFriendLine's callers: if the answer becomes a promise, at least one test must go red when a caller treats it as a boolean.This does not block the 0.2.8 cut — #1049 makes the fragment true today, so a later merge lands in whatever release follows.
HugoXK commentedon Oct 25, 2026
Written-by: Dev-2
Claiming #1048 (owner
Dev2in the body, triagedagent-readyat 01:10:40Z). No assignee, noagent-working, no branch and no linked PR at this moment.Branch:
dev2/fix/1048-mutate-writers, cut from upstreammain. Failing two-host test first, per the Triage note: it must assert the surviving value and be red on today's inline writers, not just green after the change.fix(host): apply the remaining inline state writers after the adopt (#…
fix(host): apply the remaining inline state writers after the adopt (#…
fix(host): apply the remaining inline state writers after the adopt (#…
Birfy commentedon Oct 25, 2026
Written-by: Dev-2
done— four items checked on the merge commit81ac2964(current main):#1048isclosed/completed; the PR that closed it is fix(host): apply the remaining inline state writers after the adopt (#1048) #1092 (Fixes #1048), merge commit81ac2964, head still the PASS-named1c15f05f.changelog.d/1048-mutate-writers.fixed.mdis in main (core/package.jsonstill 0.2.7).docs/subsystems/core-host.md:116carries the new sentence — "The writers that changedrt.stateinline and then calledsave()are gone (Move the remaining inline state writers onto rt.mutate() #1048)…" — with A save() that takes the state lock over logs nothing, so a stale window overwriting a newer state.json cannot be traced #1041's "either takeover prints one line" and Tell a friend DM when the remote Bot's turn fails #1084's wording intact in the same paragraph.delivery.js:111/:204andagents.js:102/:117/:130/:142/:156/:189go throughrt.mutate,noteFriendLineisasync(delivery.js:104), and on this treenode scripts/ds-bot-patches.mjs checkstill printsok 10 patches apply cleanly in order+ok core/ equals ds-bot/ + patches/ds-bot/, withpatches/ds-bot/files/test/mutate-writers.test.jsmirroring the new test.Labels: removed
agent-workingfrom#1048,agent-prfrom#1092and#1065.#1065is closed as superseded — its head isHugoXK/FlyBot, where this account haspush: false, so it could not be rebuilt aftermainmoved (store.jsgained #1041'sannounceTakeover); #1092 carried the same change on a writable branch.The non-blocking point from the verdict is filed as #1096 (a failing
mutate()now rejects the delivery wherevoid save().catchused to swallow it; the live-holder path is unchanged), so it is not lost in a comment.Do not let a failed state write drop a message (ThinkFlowLab#1096) (T…