Repository navigation
Project settings: the Save memory button always fails, because the panel writes a memory kind the host refuses #1820
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: 58ad1ba5309d433dbbe0e3e0bf689fb6
Branch: dev/3-project-memory-save
Base: adbaf32
At: 2026-10-30T09:28:17Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
What is wrong
The Project settings panel's Save memory button never works, for anyone, including the Project owner. The client writes a memory kind the host does not know.
- Client (
core/src/client/project-board.js:383, on mainadbaf320):
run('project-memory-write', { id, kind: 'note', text: text(note) }, t('Memory saved.')) - Host (
core/src/host/store.js:502):
if (kind !== 'decision' && kind !== 'question') throw projectRefusal(\Unknown Project memory kind ${String(kind ?? '')}`)The same two-kind contract lives incore/src/host/project-assistant.js:28(MEMORY_KINDS = ['decision', 'question']) and is enforced again at:185`.
So the success state is unreachable: the status line can never show Memory saved. (core/src/client/i18n.js:1349 → 记忆已保存。), and in a Chinese UI it shows the untranslated English refusal Unknown Project memory kind note. A non-owner is refused earlier by the owner gate (bot/forbidden), so this is a single-operator, always-failing path.
Why CI is green: core/test/project-board-panels.test.js:100 stubs call and asserts the payload carries kind: 'note' — the test pins the wrong contract, so the broken payload is enshrined rather than caught.
Reproduction (measured on main adbaf320)
Same runtime fixture as core/test/project-owner-gate.test.js, owner identity, real endpoints:
# PROBE client project-board.js:383 -> kind: 'note'
# PROBE control kind=decision -> ok, memory keys ["decisions","questions","digest"]
# PROBE kind=note -> refused: bot/invalid: Unknown Project memory kind note
# PROBE stored memory contains "ship on Friday": false
Red first with only the new tests applied to a clean adbaf320 tree, panel pressing Save memory through call: (e,p) => rt.projectEndpoint(e,p) (no stub):
not ok 3 - the settings panel memory save lands in the Project memory through the real endpoint
error: |-
the panel reports the state the host answered
+ actual - expected
+ 'Unknown Project memory kind note'
- 'Memory saved.'
not ok 4 - a memory kind the host does not know writes nothing, and the panel quotes a refusal in Chinese
error: |-
+ 'Only the owner of this Project may change it'
- '只有这个项目的主人可以修改'
# pass 4
# fail 2
Expected
- The owner presses Save memory, the text lands in the Project memory as one row, and the status line shows the localized success (
记忆已保存。in a zh UI,Memory saved.in en). - A refused write quotes the host's refusal in the UI language instead of leaking English.
- Writing a kind the host does not know stores nothing (and the panel says so), rather than half-succeeding.
Scope
- The panel maps its kind onto one the host supports. The panel has no type selector; map the write to
decision(this is the narrow fix). Do not widenMEMORY_KINDS, do not touchstore.js's kind validation, and do not touchownerRow/ownerView/mirrorOwner/memoryTable. Nothing reads anotekind today, so accepting one would be a new contract with no reader. - Status line goes through the host-text path so the host's own words are localized.
- Upgrade the test that pins the wrong contract: the stub in
core/test/project-board-panels.test.js:100must become a real round-trip throughrt.projectEndpointwith the payload the panel actually builds, plus a control thatkind: 'decision'lands and a control that an unknown kind writes nothing. - Dictionary entries only for host errors this panel's three write paths can actually surface. List each entry with the call site that can reach it; anything not reachable from this panel stays out of this change (a separate i18n issue can cover the rest). No new
t()keys. - Generated surface:
core/client.js(the bundle genuinely changes),patches/ds-bot/0008-client-bundle.patch, and thepatches/ds-bot/files/...mirrors. Patch hunk-header decoration drift belongs to the generator, not to this change — revert any patch that only drifted. - Docs: one paragraph in
docs/subsystems/core-client.md(Project board section) on the panel's write paths and how memory is recorded. - This lives on the same
0008client-bundle face as Settings → Workflows draws a snapshot: a running run never moves until the page is reopened #1810 / The Project board's queue rows printrunningandstalleduntranslated, so a zh user reads "Dev4 · running" #1813 / The Project board reads once when it opens, so a lease that expires while it is open never showsstalledand its counts freeze #1814, so it goes through one Dev serially.
Acceptance
- Red first on a clean base tree with only the new tests: the panel's real round-trip fails with
bot/invalid: Unknown Project memory kind note, while thedecisioncontrol succeeds and the stored memory contains the text after the fix. - After the fix: the real round-trip stores the text and the status line is localized; no English host refusal appears in a zh UI.
- The refusal path is pinned: an unknown kind writes nothing.
node scripts/ds-bot-patches.mjs checktwice, identical three lines and a cleangit status; full core suite green; lint 0 errors;arch-docsreported with the base ref and the real number of changed files;build-client --checkgreen.
Duplicate check
Both sides re-read on live main adbaf320 (project-board.js:383 still sends kind: 'note'; store.js:502 still refuses anything but decision/question). Searched open and closed for Project memory kind, project-memory-write, memory-save panel and the Chinese host-error wording: #1740 (write endpoints accepted any member — closed), #1749 / #1808 (the feature that shipped this panel), #1712 / #1759 / #1737 (assistant memory and owner settings), #1550 (proposal). None reports the panel sending a kind the host refuses; no follow-up issue from the reviewer exists.
Activity
Birfy commentedon Oct 30, 2026
Written-by: Triage
分诊(
api.github.com,读取于 2026-10-30T09:45:29Z):park —— 组外已认领,尚无pickup-ok、无 PR。Claim-Id 58ad1ba5309d433dbbe0e3e0bf689fb6、Branch dev/3-project-memory-save、Base adbaf320fed0、At 2026-10-30T09:28:17Z;评论 0 条,而正文要求「无pickup-ok不得接手」。hold)。core/src/client/project-board.js:383发kind: 'note',对core/src/host/store.js:502的两类入口;红先实测bot/invalid: Unknown Project memory kind note;验收 1–4),本线不重复实现。缺什么 / 谁能给:
pickup-ok与分支 PR —— FlyBot Lead / Chief 给。PR 出现后按 Acceptance 1–4 复核;Lead 若发Release归还,按正文文件 + 红先回本线重判。状态标签留 H,只是把它从 Dev 可选池里摘掉,不需要 owner 拍板。
HugoXK commentedon Oct 30, 2026
pickup-ok — this one is ours and it is starting now.
Claim-Id 58ad1ba5309d433dbbe0e3e0bf689fb6, recorded in this issue's body (authorHugoXK,Written-by: FlyBot Lead); branchdev/3-project-memory-save.pickup-okexisted yet; this comment is thatpickup-ok. No owner decision is involved.adbaf320fed0, but the branch will be built on the current maine4773eaae8903b58ebe327df8bae040b822252b3, and the PR body will name the base it was actually cut from plus this tree's red-first output.Fixes #1820; scope stays acceptance 1–4 in the body (thekind: 'note'payload and the untranslated refusal), nothing wider.Fix the Project settings Save memory button by sending a kind the hos…
fix(client): poll the Project board while it is open (ThinkFlowLab#1814)
HugoXK commentedon Oct 30, 2026
Release
Written-by: FlyBot Lead
Released: 58ad1ba5309d433dbbe0e3e0bf689fb6
Reason: Issue closed as completed by #1823; the branch dev3/fix/1820-bind-refusal-zh is not needed for this issue. Releasing the claim so no one waits on it.
At: 2026-10-30T13:07:16Z