Skip to content

Project settings: the Save memory button always fails, because the panel writes a memory kind the host refuses #1820

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: 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 main adbaf320):
    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 widen MEMORY_KINDS, do not touch store.js's kind validation, and do not touch ownerRow/ownerView/mirrorOwner/memoryTable. Nothing reads a note kind 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:100 must become a real round-trip through rt.projectEndpoint with the payload the panel actually builds, plus a control that kind: '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 the patches/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 0008 client-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 print running and stalled untranslated, 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 shows stalled and its counts freeze #1814, so it goes through one Dev serially.

Acceptance

  1. 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 the decision control succeeds and the stored memory contains the text after the fix.
  2. 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.
  3. The refusal path is pinned: an unknown kind writes nothing.
  4. node scripts/ds-bot-patches.mjs check twice, identical three lines and a clean git status; full core suite green; lint 0 errors; arch-docs reported with the base ref and the real number of changed files; build-client --check green.

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

  1. added
    needs-humanThe agent loop stopped; a person must decide (reason in the last comment)
    on Oct 30, 2026
  2. Birfy commented on Oct 30, 2026

    @Birfy
    Collaborator

    Written-by: Triage

    分诊(api.github.com,读取于 2026-10-30T09:45:29Z):park —— 组外已认领,尚无 pickup-ok、无 PR。

    缺什么 / 谁能给:pickup-ok 与分支 PR —— FlyBot Lead / Chief 给。PR 出现后按 Acceptance 1–4 复核;Lead 若发 Release 归还,按正文文件 + 红先回本线重判。

    状态标签留 H,只是把它从 Dev 可选池里摘掉,不需要 owner 拍板。

  3. HugoXK commented on Oct 30, 2026

    @HugoXK
    ContributorAuthor

    pickup-ok — this one is ours and it is starting now.

    • Claim: Claim-Id 58ad1ba5309d433dbbe0e3e0bf689fb6, recorded in this issue's body (author HugoXK, Written-by: FlyBot Lead); branch dev/3-project-memory-save.
    • Triage parked it at H only because no pickup-ok existed yet; this comment is that pickup-ok. No owner decision is involved.
    • Implementer: FlyBot Dev-3.
    • Base moves: the body records adbaf320fed0, but the branch will be built on the current main e4773eaae8903b58ebe327df8bae040b822252b3, and the PR body will name the base it was actually cut from plus this tree's red-first output.
    • PR follows with Fixes #1820; scope stays acceptance 1–4 in the body (the kind: 'note' payload and the untranslated refusal), nothing wider.
  4. added a commit that references this issue on Oct 30, 2026
    6d969ea
  5. HugoXK commented on Oct 30, 2026

    @HugoXK
    ContributorAuthor

    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

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