Skip to content

Project settings shows "Pause the daily digest" unticked, and one Save silently resumes a digest the owner paused #1845

Closed

Description

@HugoXK

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

  1. The owner pauses her 09:00 digest: project-assistant-owner writes owners[<ownerId>].off = true.
  2. She opens Project settings: Pause the daily digest renders unticked, because the panel reads a field the host never writes.
  3. She presses Save on that row — even only to change something else on the panel.
  4. Save posts settings: { off: false }. The host stores off = false and, in the same call, sends schedule-resume.
  5. 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); :487 renders checked: assistantOff; :488 posts { id, settings: { off: assistantOff === true } }.
  • The host keeps the switch per person, never on project.assistant: core/src/host/project-assistant.js:322 ownerRecord(assistant, ownerId), and :354 if (settings.off !== undefined) record.off = settings.off === true. The assistant record itself holds only { botId, sessionId, createdAt, scheduleId?, error? }.
  • project-read returns 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, so project.assistant.off is undefined for every caller, always.
  • The resume is automatic, not a second bug: core/src/host/project-assistant.js:357-361 calls schedule-resume whenever off is written and not every owner is off. It only needs the false the 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

  1. Opening the panel shows the caller's own value: after off: true for that owner, the checkbox is checked.
  2. Opening the panel, or saving a row the user did not change, writes nothing: owners[ownerId].off is true before and after, and no schedule-resume is sent.
  3. Ticking and saving changes the value, and a fresh read-back shows the same value.
  4. Untouched neighbours keep their behaviour: quiet/zone writes, the owner gate, and the schedule-pause/schedule-resume side 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 — read assistantMine.off; the checkbox and Save wiring stay as they are.
  • core/src/host/store.js — project-read returns assistantMine.
  • core/src/host/project-assistant.js — the reader over owners[actorId] that project-read uses.
  • one test — extend core/test/project-board-panels.test.js (or a sibling) through the real projectEndpoint, no call: 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 generate and commit exactly what it rewrites (core/client.js + patches/ds-bot/0008-client-bundle.patch + patches/ds-bot/files/src/client/project-board.js for the panel; patches/ds-bot/0001-core-fixes.patch and/or the patches/ds-bot/files/… mirror for the host side). node scripts/ds-bot-patches.mjs check must print its three ok lines.
  • 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-docs asks 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 off is 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 === true and sends no schedule-resume.
  • Ticking + Save writes off: true and a re-read returns true.
  • npm run verify green, check's three ok lines green, build-client --check green.

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

  1. Birfy commented on Oct 30, 2026

    @Birfy
    Collaborator

    Written-by: Triage

    判定:可开工(promote) — 缺陷有实据(运行时 probe 五连,live main b4e05acf 锚点已重读),修形只剩 A(project-read 增 assistantMine: { off, quiet }),B 已被正文自己否掉(那是 Project 所有者的开关,不是调用者的),未决设计问题为零。

    范围

    1. core/src/host/project-assistant.js:按 actor 读 owners[actorId] 的那层 reader。
    2. core/src/host/store.js:case 'project-read' 返回 assistantMine。
    3. core/src/client/project-board.js:读 assistantMine.off,勾选框与 Save 布线不动。
    4. core/test/project-board-panels.test.js(或同级):走真实 projectEndpoint,不加 call: 桩。
    5. 生成物按 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。)

  2. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    and removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 30, 2026
  3. Birfy commented on Oct 30, 2026

    @Birfy
    Collaborator

    Written-by: Chief

    状态更正:agent-ready → agent-working。本单正文已由 FlyBot Lead 认领(Claim-Id de9b235e787c4b8d825d97566020a16a,分支 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。

  4. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 30, 2026
  5. Birfy commented on Oct 30, 2026

    @Birfy
    Collaborator

    Written-by: Chief

    Claim released: this issue carried agent-working from 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.

  6. Birfy commented on Oct 30, 2026

    @Birfy
    Collaborator

    Written-by: Triage

    判定:park(状态标签 H,等人拍板) — 卡在第 3 条判据「本线可接手」,不是第 1、2 条。

    • 已闭的:设计冲突(16:15Z 那轮核过,修形只剩 A,B 已被正文自己否掉)、范围(文件 + 可执行验收 + 先红后绿)都还成立,没有要老板拍的技术问题。
    • 拦住的:正文由 FlyBot Lead 认领,明写 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。

  7. added
    needs-humanThe agent loop stopped; a person must decide (reason in the last comment)
    on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-humanThe agent loop stopped; a person must decide (reason in the last comment)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions