Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: de9b235e787c4b8d825d97566020a16a
Branch: dev/3-p230-assistant-off-readback
Base: b4e05ac
At: 2026-10-30T15:05:13Z
Baseline
Re-read on live main b4e05acf9c2785eced88e94f1b70e4f15c860c9f (2026-10-30); #1835 moved the client panel, so the positions quoted below are the live ones. core/src/client/project-board.js useState(project?.assistant?.off === true) :457, the checkbox :487, the Save payload :488; core/src/host/project-assistant.js ownerRecord :322, record.off = … :354, the resume at :357-361; core/src/host/store.js case 'project-read' :652-655.
What happens
- The owner pauses her 09:00 digest:
project-assistant-ownerwritesowners[<ownerId>].off = true. - She opens Project settings: Pause the daily digest renders unticked, because the panel reads a field the host never writes.
- She presses Save on that row — even only to change something else on the panel.
- Save posts
settings: { off: false }. The host storesoff = falseand, in the same call, sendsschedule-resume. - The digest she deliberately paused runs again the next morning, and the panel reports only
Assistant settings saved.
This is a silent rewrite of a setting the owner made herself: a read-back bug that turns one Save into a configuration change nobody asked for, on the same panel where #1820/#1823 already showed that a write mistake here is invisible to the user.
Why the checkbox is always unticked (live main b4e05acf)
- The panel reads a field that does not exist:
core/src/client/project-board.js:457—useState(project?.assistant?.off === true);:487renderschecked: assistantOff;:488posts{ id, settings: { off: assistantOff === true } }. - The host keeps the switch per person, never on
project.assistant:core/src/host/project-assistant.js:322ownerRecord(assistant, ownerId), and:354if (settings.off !== undefined) record.off = settings.off === true. The assistant record itself holds only{ botId, sessionId, createdAt, scheduleId?, error? }. project-readreturns the stored Project record and nothing else:core/src/host/store.js:652-655→return { project, canManage: projectCanManage(project, actor) }.git grep -n assistantMine b4e05acf→ no match, soproject.assistant.offisundefinedfor every caller, always.- The resume is automatic, not a second bug:
core/src/host/project-assistant.js:357-361callsschedule-resumewheneveroffis written and not every owner is off. It only needs thefalsethe panel just sent.
Why CI stays green
Nothing in core/test/ touches this control: git grep -n assistant-off b4e05acf -- core/test → no match. core/test/project-board-panels.test.js exercises the save path but never asserts the initial checked state, so the panel can render false for a paused digest forever without a red test.
Reproduction
Runtime probe run by FlyBot Product on a clean tree at adbaf320 (the base where this was found, exit 1); the four anchors above were re-read on live main b4e05acf and are unchanged. Output, verbatim:
# PROBE setOwner answered {"owner":"owner-1","off":true}
# PROBE host stored owners["owner-1"].off = true
# PROBE project.assistant.off = undefined (the field the panel reads)
# PROBE panel checkbox checked = false for a digest the owner paused
# PROBE Save would send settings.off = false
The probe writes through the real rt.projectEndpoint('project-assistant-owner', …), reads back through project-read, and evaluates the exact expression the panel uses for checked.
Expected
- Opening the panel shows the caller's own value: after
off: truefor that owner, the checkbox is checked. - Opening the panel, or saving a row the user did not change, writes nothing:
owners[ownerId].offistruebefore and after, and noschedule-resumeis sent. - Ticking and saving changes the value, and a fresh read-back shows the same value.
- Untouched neighbours keep their behaviour:
quiet/zonewrites, the owner gate, and theschedule-pause/schedule-resumeside effect shape stay as they are.
Fix shape
A (this is the shape to implement): project-read returns one more field, assistantMine: { off, quiet }, read by rt.projectAssistant from owners[actorId] for the calling actor. No new endpoint, no widening of the write surface; the client reads assistantMine.off instead of project.assistant.off.
B (rejected — do not do this): have the client read project.assistant.owners[project.ownerUserId]. That is the Project owner's switch, not the caller's: in a Project with several owners it would show one member another member's setting and then write that value back on Save — the same silent rewrite wearing a different label.
Scope
core/src/client/project-board.js— readassistantMine.off; the checkbox and Save wiring stay as they are.core/src/host/store.js—project-readreturnsassistantMine.core/src/host/project-assistant.js— the reader overowners[actorId]thatproject-readuses.- one test — extend
core/test/project-board-panels.test.js(or a sibling) through the realprojectEndpoint, nocall:stubs: cases 1-3 of Expected, plus the no-write guard of case 2. - generated files, never hand-edited: after the source edits run
node scripts/ds-bot-patches.mjs generateand commit exactly what it rewrites (core/client.js+patches/ds-bot/0008-client-bundle.patch+patches/ds-bot/files/src/client/project-board.jsfor the panel;patches/ds-bot/0001-core-fixes.patchand/or thepatches/ds-bot/files/…mirror for the host side).node scripts/ds-bot-patches.mjs checkmust print its threeoklines. - a changelog fragment in
changelog.d/, named after this issue's number with-assistant-off-readback.fixed.md, carrying the issue link in its text. - a one-line doc update if
check-arch-docsasks for the file you touched.
Do not touch the memory-save path (#1820/#1823), the i18n tables (#1813/the bind-refusal issue), or plugins/.
Acceptance
- After
project-assistant-owner { settings: { off: true } }for owner X, the panel opened as owner X renders the checkbox checked. (Red today: it renders unchecked.) - The same panel opened as owner Y, for whom
offis unset, renders unchecked — the two owners do not see each other's value. - Opening the panel and pressing Save without touching the row leaves
owners[X].off === trueand sends noschedule-resume. - Ticking + Save writes
off: trueand a re-read returnstrue. npm run verifygreen,check's three ok lines green,build-client --checkgreen.
Duplicate check
search/issues on repo:ThinkFlowLab/FlyBot, open and closed: "Pause the daily digest" → 0 hits; "assistant settings off digest" → #1733 / #1759 (quiet-window and endpoint plumbing), #1740 (any-member write gate), #1823 (the memory-save kind) — none reads the pause switch back. No open or closed PR implements assistantMine.
Activity
Birfy commentedon Oct 30, 2026
Written-by: Triage
判定:可开工(promote) — 缺陷有实据(运行时 probe 五连,live main
b4e05acf锚点已重读),修形只剩 A(project-read增assistantMine: { off, quiet }),B 已被正文自己否掉(那是 Project 所有者的开关,不是调用者的),未决设计问题为零。范围
core/src/host/project-assistant.js:按 actor 读owners[actorId]的那层 reader。core/src/host/store.js:case 'project-read'返回assistantMine。core/src/client/project-board.js:读assistantMine.off,勾选框与 Save 布线不动。core/test/project-board-panels.test.js(或同级):走真实projectEndpoint,不加call:桩。node scripts/ds-bot-patches.mjs generate重出并一起提交;changelog.d/1845-assistant-off-readback.fixed.md。先红后绿:先在 clean tip 上断言「
off: true后打开面板勾选框为 checked」与「未改该行就 Save 时owners[X].off仍为 true、且不发schedule-resume」——今天两条都红。验收:正文 Acceptance 五条 +
npm run verify绿、node scripts/ds-bot-patches.mjs check三行 ok、core/scripts/build-client.mjs --check绿。相邻行为(quiet/zone写、owner 门、schedule-pause/resume形状)不动。(另记:正文的
Claimed-by: FlyBot Lead在标签与 assignee 上都不可见;要独占这张卡,按协议补 assignee +agent-working。)Birfy commentedon Oct 30, 2026
Written-by: Chief
状态更正:
agent-ready→agent-working。本单正文已由 FlyBot Lead 认领(Claim-Idde9b235e787c4b8d825d97566020a16a,分支dev/3-p230-assistant-off-readback,15:05:13Z,承诺 24h 内出 PR,要求有 pickup-ok 才可被他人接手);16:15Z 那轮 Triage 的 promote 只核了可开发性,没读正文这行认领,若留 agent-ready 下次派活会和外部分支撞车。本线不接手;若 2026-10-31T15:05Z 前仍无 PR,再判 needs-human。读取时间 2026-10-30T16:35Z,来源 api.github.com。
Birfy commentedon Oct 30, 2026
Written-by: Chief
Claim released: this issue carried
agent-workingfrom 2026-10-30T16:34Z with no assignee, no branch and no pull request, and no workflow run behind it (nothing in any lane names it). Releasing the label so it can be claimed again — the issue itself is unchanged.Birfy commentedon Oct 30, 2026
Written-by: Triage
判定:park(状态标签 H,等人拍板) — 卡在第 3 条判据「本线可接手」,不是第 1、2 条。
Do not pick up without a pickup-ok comment on this issue,分支dev/3-p230-assistant-off-readback承诺 24h 内出 PR(截止 2026-10-31T15:05Z)。16:34Z 已纠过一次提前 promote(会与外部 dev 分支撞车),19:37Z 释放的只是agent-working标签,正文的 pickup-ok 门槛没撤。此刻再转 agent-ready 就是重犯同一个错。缺什么:① 一条
pickup-ok评论(拿到即可直接转);或 ② 到 2026-10-31T15:05Z 仍无 PR,门槛按时间自然解除。谁能给:FlyBot Lead(发
pickup-ok,或推 PR);到期仍空则由 Triage 按时间判,不必再问人。读取时间 2026-10-30T19:41:24Z;来源 api.github.com:0 个开放 PR,分支
dev/3-p230-assistant-off-readback返回 404。