Repository navigation
feat(workspace): show a first-Goal home instead of a fresh-install health alert - #6527
huangruiteng merged 4 commits into
Conversation
…alth alert
A fresh install opens the manager home with no registry yet. The home
rendered that as a red system-health alert with protocol text
("payload.ok === false", hard-coded Chinese) above an empty "All Goals"
heading, and the workspace-directory read answered 500.
Chat status now passes the existing `allow_missing_registry` rule, so an
absent default registry is the warning the CLI already reports for it, and
the discovery view returns an empty directory instead of failing. The home
read model carries a typed `no_goals` classification that holds only when
the source is healthy with zero Goals and no history; the page then shows
what a Goal is, one Create action reusing the existing form, and three
example requests that only fill the composer. Health issues are localized
owner-language sentences; the source's raw contract lines stay in a
collapsed disclosure. A corrupt registry keeps its banner and gets no
first-Goal invitation.
Validation: new browser scenario `first-goal-home` (desktop, phone, en,
create form, unhealthy negative), workspace contract test, dashboard tsc,
CSS token check, and Python tests for the status and directory paths.
The packaged bundle was served on an empty HOME and read back.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: song <liusongstep@gmail.com>
Add the synthetic-fixture screenshot the first-goal-home browser scenario produces, so the user guide's first-open section shows the composition. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: song <liusongstep@gmail.com>
…oal home CI shard 3 saw one POST to the sessions route after the example click and read it as a send. Session admission on composer focus is not a send; the assertion now counts only Turn creation and steering, and names any request it did see. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: song <liusongstep@gmail.com>
11a5ba0 to
f22b3f4
Compare
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · xhigh
[P2] 热刷新失败后,需要撤销首次 Goal 引导,而不能继续把来源显示为空且已更新。详见下方风险与回归步骤。
动机
第一次打开个人工作区、还没有 Goal 的用户,需要知道接下来如何描述目标,同时分清空工作区与读取失败。
原来缺少 registry 文件就显示系统错误;本次把它作为空工作区并提供创建入口。但先成功加载后若 registry 损坏,热刷新仍显示空工作区,甚至短暂提示刚刚更新。
已验证缺失文件时目录与状态都返回 200、示例只填入输入框、创建按钮打开原表单;尚未达到读取失败时撤销首次引导并显示错误的结果。
不把这个首页切片当成真实模型执行、首个成果、全局 App 安装采用或长期多轮推进的完整验收。
所以这次评审认可“新安装缺失 registry 不应当作损坏”的问题定义,但不能仅凭首次截图或冷启动负例判断错误恢复已完成。这里的 registry 是登记已有 Goal 的目录;读不到当前目录,不等于已证明没有 Goal。用户应该能在首页看到有效下一步,也应该在来源读取失败时知道先修复或重试。
改动思路
复用既有 Chat 缺失文件规则、状态收集和创建表单;首次引导是本地 TypeScript 读模型,不应另建配置、持久化状态或 Python 决策源。
本 PR 只交付空工作区首页、来源诊断和既有创建入口;完整首个成果仍在原 S1/S5 工作内。当前切片自身的热刷新失败恢复必须在本 PR 补齐。
具体链路是 Chat 目录/状态读取 → 既有缺失文件规则 → 首页读模型 → 首次引导 → 原创建表单或输入框。读取只负责观察;点示例只是填入文本;真正创建仍走既有配置检查和确认,没有新增自动执行权、Agent 注册或调度策略。不要通过吞掉所有异常来得到空目录:本次 helper 只捕获 FileNotFoundError,损坏 JSON 仍返回 500,这个后端边界是正确的。
以本次 head 为准,三种情况应当区分:
| 状态 | 当前实际结果 | 判断 |
|---|---|---|
| 新安装,文件确实不存在 | 两个实际 HTTP 入口均 200,显示首次引导 | 正常空工作区 |
| 页面首次打开时文件已损坏 | 两个入口 500,冷页面显示加载失败 | 正确拒绝 |
| 先成功读取空工作区,再损坏并热刷新 | 两个入口 500,仍显示 No Goals yet / Create a Goal,短暂显示 Updated just now | 本次阻塞项:旧快照被当成当前事实 |
该表是实际安装后端和页面的观察,不能用一个伪造 ok:false 状态对象替代第三行。现有请求失败状态就是合适的 owner,修复应把它传入派生首页并修正刷新结果,不必另建持久化健康标记。
具体改动
审查 head:f22b3f4370a5cdfd6c7dc8e6d14fea57d483c6e8;真正共同基线为 0e0a3e06e6b6e52702d207ac1f729b70c1840bfb。完整 PR 为 15 个文件、+390/-13。发布前发现旧 head 已变,已丢弃旧结论并按当前完整方案重新核对:14 个 base/head 内容对逐字相同;剩下的浏览器场景只把“没有发送”计数从所有 sessions POST 改为 /sessions/:id/turns。会话接纳与提交 Turn 的确不同,但该测试修正没有覆盖热刷新 500。
独立规范是 docs/architecture/rfcs/loopx-overall-roadmap-v0.md,判断版本固定为 e0cfa33aed564dbc917cb1186568621bfd41cdb9,并结合相同变更前版本的 docs/development/design.md。没有拿作者改动后的描述反向定义验收:
- S1:deferred。此次是首个 Goal 的入口切片;真实模型给出首个有用结果、后续持续推进与依赖回返,仍由原产品验收承担,不能从这个首页推断已完成。
- S5:not_met。正常入口更清楚,但“可操作错误、离线退化”的当前切片条件没有闭环:热刷新失败仍邀请创建并报告已更新。最小修复为传递当前来源读取失败、撤销首次引导并正确显示重试,再证明恢复后的正常路径。
设计中的 Owner language first 和 States that are designed, not defaulted 支持本次本地化、原始诊断折叠和专门空状态;同时要求真实错误与空状态可分辨。这不是额外要求付费模型测试或完成整个 S1。
关键实现逐项核对如下:
_discovery_registry,77 行 仅将 FileNotFoundError 转为空元数据;目录入口改走它,访问检查、未知 Goal 与其他读取失败仍保留。Chat 的 collect_status 显式传allow_missing_registry=True,另外两个 Python 文件仅透传到既有 check_contract;CLI 默认仍 False,不做静默全局默认切换。buildPersonalHomeModel,1149 行 用 healthy、零 Goal、零历史派生本地no_goals类型;personal-workspace-model.ts的可选字段、规范化及 progressive incomplete 分支一起适配。这个类型不持久化,也不是公共协议词表。问题是 healthy 只来自上次 payload,当前请求失败没有使其失效。ManagerHomeBoard,119 行 增加首次引导、三个示例及原创建回调,移除该状态下空的 All Goals 标题;只读时不提供写操作。健康横幅仍保留、原始诊断通过 details 折叠。CSS 使用现有 token 并补 brutal 覆盖,i18n 提供中英文,不把协议断言当主文案。- 文档增加 First open / 首次打开及合成截图。Python 测试分别覆盖缺失、损坏和访问边界;浏览器场景覆盖桌面、390px、英文、示例和表单,但负例直接提供失败 payload,未执行“已有成功快照后返回 HTTP 500”。源码正则测试只能约束形状,不能证明运行时错误会传播。
对主干的风险
[P2] 当前请求失败后仍保留首次邀请及更新成功提示。 位置是上述新 onboarding 条件 1149–1153 行及其既有请求生命周期。复现不依赖模拟状态返回:正常 wheel 安装到隔离 Python 3.11 环境,用真实 Chat 服务和独立空目录启动;页面成功得到空工作区后,把该私有 registry 写成损坏 JSON,再点 Refresh。status.json?view=workspace-directory 和 status.json?goal_activation=active 都返回 500,页面仍显示 No Goals yet、Create a Goal,并短暂显示 Updated just now。冷 reload 才显示 HTTP 500;移除损坏文件再重试可恢复。
因果上,旧 loadFromUrl 的 catch 保留已加载 payload/progress,且没有向调用者抛出;refreshWorkspace await 后进入 done。这个 catch 本身早于 PR,但新增的“仅健康空来源才展示”的邀请直接复用了旧快照,缺少当前错误失效条件。因此我没有把旧加载器所有问题都归为本次新增,而是要求本次新增状态遵守它自己的有效性边界。新建空状态会误导用户继续创建;这属于当前入口的可见正确性,不需要等父级完整产品改造。
最小修复:把当前来源的 loading/error/freshness 状态接入首页派生结果;热刷新失败时撤销首次引导,显示可重试的错误且不报告更新成功。补充先成功加载、再返回真实 HTTP 500、修复后重试的浏览器回归。
回归必须包含成功读取 → 真正 HTTP 500 → 错误可见且首次邀请消失、不显示更新成功 → 修复来源并重试后恢复。首次挂载 ok:false 的截图不能区分这条路径;也不要删除断言或通过把所有读取失败变成空目录解决。
已执行和复用的证据边界如下。旧 11a5 的相关 Python 家族共 130 passed、零 skip;其全部相关生产/测试 base/head 内容对与当前相同,状态消费者和依赖没有在该路径漂移,所以明确按失效矩阵复用。当前 head 重新完成正常 frontend type/build、wheel 和独立安装;真实 HTTP 的 absent / corrupt / restored 三状态共六次请求分别为 200/200、500/500、200/200;独立 CLI 默认缺失 registry 仍是 contract false。
页面证据来自 Ego Lite 的真实安装服务:中文桌面、英文 390px 无横向溢出,示例原文填入且没有提交,原表单打开及 Escape 取消。未配置真实 Agent endpoint 时,检查配置明确显示未注册,未创建 Goal或执行模型;这不是首个成果验收。新旧普通 wheel 的全部 15 项前端资源逐字相同,相关 14 个内容对一致,因此复用这些视图及错误观察;没有宣称又运行了一次新 head 的浏览器或全局 App。
当前风险 premerge 的 5 项 direct 均通过,19 项 selected 中 18 项通过,1 项为下述旧交接状态失败;没有放宽它。
另有单独红灯需要保留:风险 canary 中运行交接状态 smoke 在共同基线和本次 head 都断言失败,期望 runtime_handoff_post_progress,实际 active_state_agent_todo,落在同一 fixture 的同一状态优先级断言。完整断言只规范化临时路径及路径派生哈希,不隐藏实际分类或下一步。PR 没改交接分类器、原 fixture、历史或 CLI 默认路径,这项旧失败与本次首页错误分开,不以重跑绿色、调阈值或删断言抹去。其余检查、Ruff、DCO、diff 和公开边界逐项记录;遵循 wait_for_ci=false,没有获取、轮询或等待 hosted CI。
我的整体评价
在当前 exact head 上 REQUEST_CHANGES。问题定义、既有 owner 复用和差分规模合理;首次缺失文件、正常引导、后端损坏拒绝已经有实证。阻塞的是热刷新失败被当作健康空工作区,这个切片自身的错误恢复尚未成立。修好上面的单个状态失效边界,并用真实失败后的恢复回归证明,即可重新判断,无需新增配置、协议或扩大到完整长期路线图。
长期推进判断为 preserved:本次没有改调度、预算、Todo 或后续执行权,也没有证明真实长期收益。用户体验判断为 regression:新增邀请和更新提示会在当前来源失败时继续出现。相关前瞻整理应在现有请求 owner 内补齐错误失效;把大型首页 builder 整体抽到新模块可后续评估,不能替代当前修复。模块类型、可用来源、已安装模型或示例按钮都不是执行授权;单次截图、构建成功和案例数量也不证明实际采用。维护者首屏审阅、合并与发布继续是独立边界,本评审未执行合并、升级或消除其他审查意见。
English verdict: REQUEST_CHANGES — At f22b3f4, real warm refreshes return HTTP 500 for both status reads yet retain the new first-Goal invitation and briefly report an update success. Invalidate onboarding on the current source error and test recovery after a successful initial read. Normal-wheel HTTP checks distinguish absence from corruption; unchanged production/blob and built-asset comparisons bound reused Python/visual evidence. The separately reproduced baseline handoff canary failure remains failed; no CI, model adoption, merge or release is claimed.
…t read fails
Review on the first-Goal home found that a warm refresh returning HTTP 500
for both status reads kept the retained empty payload on screen: the page
still invited the owner to create a Goal and the header briefly reported
"Updated just now". A payload from the last successful read is not a
current fact once the source cannot be read.
The refresh callback now reports its outcome instead of swallowing the
error: the dashboard reads with `rejectOnError` and returns
`{ ok, error }`, the page shows "Refresh failed" on a failed result and
never advances to "Updated", and the retained load error reaches the home
read model as `sourceError`. With it set, the home withdraws the first-Goal
state and shows a retryable failure in owner language ("the status source
could not be read; what is shown is the last successful read") with the
raw diagnostics still collapsed and a Retry that re-reads the source.
The browser scenario now covers the path the review asked for: a
successful empty read, then both status routes answering HTTP 500 on
refresh (invitation withdrawn, failure and retry visible, header reports
the failure and no update), then the source restored and Retry bringing
the first-Goal state back with "Updated just now".
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: song <liusongstep@gmail.com>
|
Thanks for the precise reproduction. Fixed in the new head; the blocking row of your table now reads: successful read → both status routes answer HTTP 500 on refresh → the first-Goal invitation is withdrawn, a retryable failure is shown in owner language, and the header reports "Refresh failed" and never "Updated just now" → source restored and Retry brings the first-Goal state back. What changed
Not changed, on purpose. The backend boundary stays as you described: only Validation on the new head: |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · xhigh
动机
未发现当前 head 的阻塞项,结论为 APPROVE。完整复审 df7a8876e33a7894e51c784ebcb21e50290737da,比较基线 0e0a3e06e6b6e52702d207ac1f729b70c1840bfb,包括最初的首页改动和本次修复,未继承上一版结论。
首次打开个人工作区、尚无 Goal,并需要辨别空工作区与读取失败的用户。
首次安装还没有注册文件的用户原来只看到系统错误;本次提供首个 Goal 入口,并在后续读取失败时撤下空状态邀请、显示错误和重试。
当前正常安装包已验证:缺失注册文件可进入引导,真实 HTTP 500 显示失败且不报更新成功,修复后重试恢复。
本次不证明真实模型产出的首个有用结果、长期持续工作、桌面宿主升级或完整路线图验收。
S1 的真实模型首次成果与后续持续推进仍待原路线图验收;本次关闭的是首次入口及其读取失败恢复切片。
独立规范是 docs/architecture/rfcs/loopx-overall-roadmap-v0.md,spec_revision 0e0a3e06e6b6e52702d207ac1f729b70c1840bfb,并结合该版本 docs/development/design.md 的空、错、取消与可理解下一步要求。S1:保留原有真实首次成果与持续工作验收,本 PR 不关闭它。S5:当前切片的可操作错误、恢复和直接创建入口已验证,不能把一张首页截图解释成整个 S5 完成。
改动思路
缺失文件判定复用现有后端契约;读取失败复用现有请求错误和页面刷新回调,不新增持久状态或调度器。
当前 PR 交付首次 Goal 入口与真实读取失败恢复,真实模型首次成果及长期持续工作继续由原 S1 验收。
入口仍是打包的 /chat/ 与既有状态 API:后端只把缺少默认注册文件视为合法空来源;损坏、不可读及访问校验继续失败。前端从健康状态与完整 Goal/历史数量派生首次引导;当前请求失败时,已保留的空结果只能作为上一次读取内容,不能继续证明现在没有 Goal。loadError → sourceError → PersonalGoalHome 覆盖引导和健康提示,WorkspaceRefreshResult 把成功与失败交回 refreshWorkspace,失败不会增加历史刷新版本或短报更新成功。
创建按钮直接打开侧栏已使用的类型化表单,不增加一轮选择或确认;示例只预填既有输入框,发送仍由用户决定。保留现有表单确认,提供实际创建所需信息和操作授权。恢复按钮沿用原刷新通路,不建立新的重试调度器。用文字描述这个两分支流程已经足够,未声称验证新的图形渲染。
具体改动
完整范围为 16 个路径,+485/-22。chat_status_api.py::_discovery_registry、collection.py、status.py 复用 allow_missing_registry,Chat 明确允许缺失、CLI 默认仍严格;目录与完整状态两个入口均保持损坏文件为 HTTP 500。两个 Python 测试文件覆盖缺失默认文件、目录路径和损坏输入,不通过放松所有错误来制造空状态。
前端 buildPersonalHomeModel、PersonalGoalHome 和 ManagerHomeBoard 负责零 Goal/历史计数、渐进加载、来源健康与渲染;personal-workspace-model.ts 使用本地 no_goals 与刷新结果联合类型,不新增持久协议。personal-workspace-page.tsx::refreshWorkspace 检查返回值,来源重试复用它;原来允许 void 的回调仍兼容,Dashboard 对其他调用者继续返回结果而非突然拒绝 Promise。CSS、英文/中文 i18n 和指南/截图配套,原始来源检查仍在折叠诊断中。浏览器入口、first-goal-home.mjs、共享 fixture 与 contract smoke 覆盖了本次真实 500 窗口及修复后重试;fixture 默认不开启故障,其他场景不受影响。
当前验证:130 项 Python 通过、0 skip;前端类型检查与正常构建、正常 wheel 打包通过。独立 Python 3.11 安装在检出目录外,真实状态目录/完整入口分别得到缺失 200/200、损坏 500/500、修复 200/200,未拦截后端响应。实际浏览器从成功空状态开始再写入损坏注册文件,两次请求均 500,此时不再有首次引导、不出现“刚刚更新”,而是错误提示和重试。键盘 Enter 重试恢复;冷启动 500 与重试也通过。示例原文进入输入框且 0 POST,创建表单打开/Escape 取消;中文桌面、英文 390px 与 reduced-motion 均实际查看,无横向溢出。原生打包 first-goal、已有 Goal 的 M2、Chat recovery 都通过,后两项以正常安装包提供前端资源、API 场景仍是测试 fixture,不能称完整生产模型采用。Contract/theme、Ruff、DCO、diff/public boundary 通过。
对主干的风险
风险集中在共用请求与页面刷新边界:失败不能被旧快照掩盖,也不能把其他调用者改成未处理的 Promise 拒绝。本次复用现有错误、请求 fence 和确认表单,并执行了正常/失败/恢复以及有 Goal 的原路径,没有加入新注册状态、权限或定时任务。新引导只由完整计数和健康事实派生,不用有限列表为空推断全局为空;渐进加载未完成仍不会当成首次工作区。CLI 默认拒绝缺失注册文件的契约与 Chat 首次发现的例外分别验证。
风险 canary 的 5 个直接检查通过;19 个选中检查为 18 通过、1 失败,不能称全绿。失败仍是 runtime-handoff-status-read-path-smoke.py:209,期望 runtime_handoff_post_progress 却得到 active_state_agent_todo。对照不可变基线 0e0a3e06e6b6e52702d207ac1f729b70c1840bfb 的既有执行和本次完整断言,除临时路径、生成时间及其派生指纹外全部语义相同;从 f22 到当前 head 只有 UI/浏览器测试变化,交接判定、夹具、依赖和 CLI 默认路径未变。本次 UI/API 不变量有独立通过证据,因此该失败不归入本 PR 回归,但仍保留其修复责任与合并验证限制;没有调低门槛、删断言或称它已修复。未查询、等待或触发 GitHub CI。
可选改进:重试按钮实测高度 36px;设计文档对 44px 的表述是“should / where practical”,键盘恢复和当前布局已通过,可在同一按钮样式边界扩大触控面积,不作为本次硬阻塞。窄屏顶部已有控件仍较紧,本次不扩展成全局导航重排。首屏发布批准、未消解 review、分支 readiness 与合并授权仍分别判断。
我的整体评价
当前原先的热刷新阻塞已用同一真实故障场景消除:来源失败时不再继续邀请创建,也不再声称更新成功;修复后能直接恢复。全 PR 提供的是可用且可撤回的首次入口切片,而非只补一个类型或一张截图。缺失文件判定复用现有后端契约;读取失败复用现有请求错误和页面刷新回调,不新增持久状态或调度器。当前 PR 交付首次 Goal 入口与真实读取失败恢复,真实模型首次成果及长期持续工作继续由原 S1 验收。
未来变更准备方面,本次已采用现有状态校验、错误生命周期、表单和刷新 owner,没有必要再抽象一层通用框架。与创建、刷新相关的前端和 CLI 边界已经检查,Lark 没有新增入口或承诺。保留真实模型首次结果、长期推进、安装宿主和交接 canary 的证据缺口;本评审不合并、不升级、不撤销其他人的评审。
English verdict: APPROVE - df7a8876e33a7894e51c784ebcb21e50290737da. The full first-Goal slice now handles real warm HTTP 500 truthfully and recovers by retry. 130 Python tests, current normal-wheel real-backend/browser checks and packaged shared journeys passed; the unchanged baseline handoff canary failure remains recorded separately. No CI or full-model adoption claim.
Summary
A fresh install opens the LoopX Manager home before any Goal exists. Today that first screen is a red "系统健康" alert whose body is protocol text (
状态载荷未标记为正常 (payload.ok === false),契约检查未通过: 1 项错误 / 1 项警告, hard-coded Chinese regardless of locale) above an empty "All Goals" heading, and the?view=workspace-directorydiscovery read answers 500. The only underlying fact is that the registry file does not exist yet.This PR makes that first screen a designed first-Goal state and keeps real health problems visible in owner language.
Goal / source. Roadmap S1/S5 first-use journey (
loopx dashboardmust reach a first useful result without shell intervention) anddocs/development/design.md"Owner language first" / "States that are designed, not defaulted".Before → after (packaged Chat on an empty HOME).
payload.ok === false, empty lanes, no next action; directory read 500.+and conversational Goal drafting are unchanged.Changes
loopx/chat_status_api.py: the Chat status read passes the existingallow_missing_registryrule (the same toleranceserve_chatalready applies when it starts on an absent registry), so a missing default registry is the warning the CLI reports for it rather than a contract error. The workspace-directory view reads the registry through a helper that treatsFileNotFoundErroras an empty directory; unreadable or incompatible registries still fail.loopx/status.pyandcontrol_plane/status/collection.pyonly thread the flag through.dashboard-page.tsx): health issues become localized sentences; the source's raw contract lines go tosystemHealth.diagnostics. A typedWorkspaceHomeOnboarding(kind: "no_goals") is derived only when the source is healthy with zero Goals and no history. It is local to the home read model, not a persisted or protocol literal.personal-workspace-page.tsx/ CSS / i18n: the first-Goal section, the collapsed diagnostics on the health banner, token-only styles with brutal-theme overrides, bilingual copy.Validation
first-goal-home(dev build): first-Goal state on desktop 1440 and phone 390 (no horizontal overflow), English locale, example fills the composer and sends no turn, Create opens the Goal form and Escape closes it, and the negative case: a corrupt registry with zero Goals keeps the banner in owner language with raw lines collapsed and shows no first-Goal invitation.personal-workspace-contract.test.mjspins the typed classification, the absence of protocol fragments in health copy, and both locales for the new keys.tests/test_chat_server_cors.py: missing registry → 200 empty directory; corrupt registry → 500; the access-code test now also fails the project-registry read.tests/test_status_missing_registry.py: default remains an error, the flag turns it into a warning. 103 Python tests across the status/Chat server modules pass locally.tsc --noEmit, workspace-theme test,check:css-custom-properties,scripts/generate_semantic_inventory.py --changed-from HEAD(no new vocabulary carriers).chat_bundle.py build --install) served withloopx chat --no-openon an empty HOME and read back:/status.jsonok: true, directory 200, first-Goal state rendered.Not covered. Installed App and real-model acceptance;
examples/dashboard-home-browser-smoke.mjsfails identically on main in my environment (missing Chinese home text within 4 s) and is not attributed to this change.Known limit. CLI
loopx statusstill reports a missing default registry as a contract error; only the Chat status read tolerates it. Aligning the CLI default is a separate decision.First-screen gate. This alters the product home's first viewport. Before/after previews (desktop, phone, English, negative case) were shown to the author before commit; the screenshot above is from the committed synthetic scenario for maintainer review.
Future-facing refactor. Considered and deferred:
buildPersonalHomeModellives in the 3.5k-linedashboard-page.tsx, which is why a home-state change touches six frontend files. Extracting it into the personal-workspace feature with its own tests is a bounded follow-up, not bundled here.🤖 Generated with Claude Code
Current source-read recovery
At
df7a8876e33a7894e51c784ebcb21e50290737da, a failed current read withdraws the first-Goal invitation, reports the retained snapshot as stale with a retry, and returns an explicit refresh failure so the header does not report an update success.Independent local qualification on that exact source passes in development and the compiled packaged frontend: the existing complete first-Goal scenario, plus a real disposable Chat status backend whose registry changes from absent (200) to corrupt (both directory and active reads return HTTP 500), then back to absent with a successful retry. Chinese desktop, English390px, visible error/withdrawal, keyboard retry and recovery were exercised. Typecheck, workspace contracts and source-bundle integrity pass. The previous source fails the same new warm-refresh regression.
These checks qualify the source-error recovery path. The earlier CHANGES_REQUESTED review still needs disposition on this head; complete hosted CI, installed App and real-model acceptance remain separate and pending. No review, merge, deployment or hosted rerun is performed by this qualification.