Skip to content

host/client: saving the team state replaces a link at state.json and never says so once #2471

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: 05a3f1a33a584e3db825260702c61413
Branch: dev/2-linked-state-save-notice
Base: cf4e4b5
At: 2026-11-05T00:21:29Z

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.

Written-by: FlyBot Lead

查重

live cf4e4b5a 上读 core/src/host/store.js:保存是临时名 + rename(temp, statePath),另有 tempWritable 保护临时名;stateLink 全仓 0 命中。open + closed 搜 state.json symlink / "linked" "state",只落 #2416、#2404、#2079、#2394、#2428——全是 closed,讲的是「读穿链接怎么报告」或「journal/workflow 写入穿链接」,没有一张讲「保存替换掉链接之后不告诉用户」。不重复。

现状

core/src/host/store.js 保存团队状态时写临时名再 rename(temp, statePath)。因此 state.json 本身是符号链接时,保存不写穿:链接被换成常规文件,链接目标的字节与 mtime 不变(既有用例 a link at the state file itself is replaced, not written through 已钉住)。

但保存方从不说这件事:

  • store.js 的保存结果与 ext.rt 上没有「本次保存替换了一个链接」这一位;
  • core/src/host/channel.js 的 unchanged 状态回答不携带该事实,第二个窗口因此永远不知道;
  • 客户端拿到新状态后没有任何提示。

用户视角:他把 state.json 链接到别处(备份目录、同步目录),保存后链接悄悄变成常规文件、原目标从此不再更新,而 UI 一个字都没说。

复现(live main cf4e4b5a)

  1. 让团队状态文件是链接:ln -s /tmp/target.json <home>/state.json,目标先写一份可读内容。
  2. 在 UI 里改一处设置并保存(或直接调 store 的保存路径)。
  3. 结果:state.json 已是常规文件、/tmp/target.json 的字节与 mtime 未变——预期的「不写穿」成立;但 UI 没有任何提示,另一个窗口也收不到该事实。

期望

  1. 保存替换链接后,UI 明确告知一次:i18n en/zh 都有该句,且只提示一次,不是每次保存都刷。
  2. unchanged 的状态回答携带该事实,另一个窗口也能说出同一句。
  3. 「不写穿」与「目标字节 / mtime 不变」保持,并新增回归锁。

Scope

  • core/src/host/store.js:保存记录本次是否替换了链接(计数或位),随结果返回;
  • core/src/host/channel.js:unchanged 回答携带该字段;
  • core/src/client/state-link-notice.js(新):一次性提示状态;
  • core/src/client/index.js 与 core/src/client/i18n.js(en/zh 各一句);
  • 测试:store.test.js 补一条、state-link-answer.test.js、state-link-notice.test.js(新);
  • docs/subsystems/core-host.md、docs/subsystems/core-client.md 各一句;changelog.d/ 一个 fragment;
  • 生成物随 generate 重出:core/client.js 与 patches/ds-bot/*(0008 属单一车道,本单在飞期间不并行第二张)。

验收(红先,干净 base cf4e4b5a)

  1. 「目标内容与 mtime 不变」:base 已绿,作回归锁保留;
  2. 「保存后该路径不再是链接」:base 已绿,作回归锁保留;
  3. 保存替换链接后该位为真:base 上红(stateLinkReplaced is not a function);
  4. unchanged 回答携带该事实:base 上红(undefined !== 2 / undefined !== 0);
  5. 一次性提示:base 上红(模块未导出 announceStateLink);
  6. 未替换链接的普通保存不产生提示(对照,防误报)。

撤掉实现后第 3–5 条必须重新变红。

不做什么

  • 不改「临时名 + rename」的落盘方式(它已安全,且有 tempWritable 保护);
  • 不在 host 侧跟随链接写目标(与 #2416 / #2428 的读面裁定相反);
  • 不重复 #2428(读穿链接的报告)。

Activity

  1. added
    agent-prPull request opened by an agent
    bugSomething isn't working
    on Nov 5, 2026
  2. HugoXK commented on Nov 6, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: 05a3f1a33a584e3db825260702c61413
    Reason: issue closed (merged)
    At: 2026-11-06T02:14:07Z

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions