Skip to content

fix(wallpaper): preserve rollback and recover after host restarts - #228

Merged
Lucas1479 merged 6 commits into
mainfrom
codex/fix-wallpaper-uncertain-mount
Oct 19, 2026
Merged

Lucas1479 merged 6 commits into
mainfrom
codex/fix-wallpaper-uncertain-mount

Conversation

@Desolate-Jix

@Desolate-Jix Desolate-Jix commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Mount and settings failures must roll back without losing the original error. A pending Set must remain fenced while its actual receiving process can still complete it; after that process exits, normal recovery must also work when the user manually restarted Lively.

This revision preserves the phase-aware rollback repair and fixes the remaining restart boundary:

  • Persist Preparing before settings, Pending plus the actual Set receiver's PID/start identity before dispatch, and Settled after the native RPC returns. Receiver identity is separate from process-cleanup ownership.
  • Bind identity to the same connected named pipe carrying Set. The locked GrpcDotNetNamedPipes 3.1.0 adapter uses one internal PipeCallback hook and a request marshaller; binding, identity or journal failures block dispatch explicitly, without retries or process-name guesses.
  • Close a dispatch gate on every invocation exit and wait for an entered persistence boundary. A connection arriving after timeout cannot write a journal or request; a timeout during persistence retains Pending instead of performing settings-only cleanup prematurely.
  • Recover after the original receiver is confirmed gone, including user restarts and PID reuse. Process exit only unlocks the existing restore/verification path; it is not restoration success or ownership of a manually started host. User wallpaper/layout changes remain authoritative.
  • Preserve settings-only rollback, original automatic rollback, retries, dual errors and exact cleanup ownership. Older published phase-less journals remain supported. Identity-less Pending journals from unpublished drafts are rejected as invalid without rewriting their contents or changing the desktop; the draft-only process-enumeration exit barrier has been removed.
  • Remove the unpublished MountUnconfirmed draft compatibility path after checking for existing local consumers; no recovery data was deleted. Recovery guidance now matches Electron's run entry point, which already performs Restore.

Validation

Current revision: f3b2e3b195a2b30a3cc2315957436ab09776b494.

  • 50 deterministic C# contracts passed: dotnet run --no-restore --project wallpaper/windows/Amadeus.Wallpaper.Tests.
  • Replaced the two draft-only compatibility tests with invalid-Pending contracts for both a running and an absent host. Both new contracts failed before the cleanup and passed afterward; they verify that recovery neither rewrites the journal nor touches the host.
  • Includes real randomly named local pipe servers exercising Session's actual journal: the Set handler sees Pending plus its own receiver identity before execution; identity, real journal-write and missing-hook failures execute zero Sets. Deadline regressions remain covered.
  • Covers an original receiver still alive, manual/helper restart, PID reuse, unknown liveness, published phase-less journals, recovery failures/retries, user choices and cleanup ownership.
  • 20 Electron wallpaper lifecycle tests passed: node --experimental-strip-types --test electron/tests/windowsWallpaper.test.mjs. Diff and UTF-8 checks passed.
  • Real Lively 2.2.1.0 shared-host mount/restore passed on Windows: a temporary local HTML scene used Session's actual custom Set path, its recorded receiver matched the running Lively process, and the original wallpaper/options were restored with the shared host preserved and the test journal removed. This did not cover cold host startup or an induced real-host timeout.
  • A self-contained win-x64 helper was built successfully. Its GrpcDotNetNamedPipes version and content hash matched the repository lock. All 15 hosted CI checks passed for this head across Electron Windows, Python Windows, Python Linux, Python macOS and Local model installation candidates.
  • Bilingual lifecycle and support boundaries.

Existing protocol limitation

The false-empty/unconfirmed-close counterexample in #233 predates this PR and remains unresolved. It is retained as a diagnostic, not counted as passing recovery acceptance:

dotnet run --project wallpaper/windows/Amadeus.Wallpaper.Tests -- --false-empty-counterexample

Its current output still reports journalRetained=false, stopRequested=true, strongRecoveryProven=false. Neither a successful close acknowledgement nor an empty wallpaper report proves player exit. This bounded repair does not claim to solve that host-side protocol limitation.

@Desolate-Jix
Desolate-Jix marked this pull request as ready for review October 15, 2026 13:45
@Lucas1479

Copy link
Copy Markdown
Member

复核结论:保护未确认挂载的恢复日志这一目标成立,但当前实现引入 P1 回归,请返工后再请求重新审查;当前版本不建议合并。

[P1] 真实挂载失败后,自动回滚和后续恢复会被永久挡住

核验提交:0821a9c16d00d43661886790a887ffe830ca19f6,对照基线 a9a488ae。Session.cs:42–61 对任意 Mount 异常跳过同 Session 的收尾;新 Session 又要求目标显示必须报告至少一张壁纸才能恢复。播放器真的失败、旧壁纸已关闭而新场景未加载时,空报告是正确状态,但恢复仍一直被拒绝。

我用原版/PR 版的实际 Session.cs 配合同一个合成 IWallpaperHost 探针,复现了“原来有旧壁纸”和“原来为空”两种初态。没有操作真实桌面。

真实播放器失败后的行为 原版 当前 PR
同次 try/finally 收尾 恢复原壁纸/设置,删除日志,释放自有宿主 桌面为空,设置未恢复,日志和自有宿主保留
新 Session 连续 recover 三次 均成功 均报 mount outcome is unconfirmed
下一次 Mount 成功 Recover the previous wallpaper session first

PR 的 Program.cs:69–77 将原来的自动回滚测试改写了:第 75 行先手动把旧壁纸加入 ActualItems,再调用 Restore。这个断言不能证明原有自动恢复契约仍然成立。当前 16 项测试通过不足以排除此回归。

此外,SetSessionOptions 阶段的异常也会设置 mountFailed;这时尚未调用 SetWallpaper,却同样跳过当前 Session 的设置恢复。设置写入自身仍可能部分生效,需要按实际操作阶段处理收尾。

请保留原有自动回滚能力,同时保护确实无法确认的事务。可考虑在未确认挂载时,按项目路径显式关闭 Amadeus 自己的场景,再执行恢复;这个方向需要先在 Lively 2.2.1.0 验证:关闭未上报/不存在的项目是否安全、如何确认关闭已生效,以及关闭或恢复失败时如何保留日志和原始错误。不能仅把命令发送成功视为恢复完成。

重新提交时请恢复未经手动补回壁纸的旧回滚测试,并覆盖:真实失败且报告为空、场景实际存在但未上报、原桌面为空、设置阶段失败、关闭/恢复失败后的重试,以及用户新选择仍优先。

@Desolate-Jix
Desolate-Jix marked this pull request as draft October 16, 2026 06:14
@Desolate-Jix Desolate-Jix changed the title fix(wallpaper): retain recovery after an unconfirmed mount fix(wallpaper): restore phase-aware rollback and preserve cleanup errors Oct 16, 2026
@Lucas1479
Lucas1479 marked this pull request as ready for review October 17, 2026 00:55

@Lucas1479 Lucas1479 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed revision: 4e8b0caa67e1ac48903b34ba5976f29b032b454f. This revision incorporates main; its wallpaper implementation and tests are unchanged from 6dfb187c, which was independently tested.

The previous P1 against 0821a9c1 is fixed: actual mount failures and settings-stage failures now roll back according to their phase, and the original automatic rollback test has been restored. All 35 deterministic contracts passed in an independent rerun. Preserving primary and cleanup errors, avoiding duplicate cleanup, and respecting the user's newer wallpaper selection are sound improvements.

The remaining reason for requesting changes is described inline: Pending recovery currently depends on whether this helper invocation just started the host, rather than whether the process that received the original request is still alive. Recovery therefore remains blocked even after the user has restarted Lively. Please also align the recovery guidance with Electron's actual entry point: Electron invokes run, which already performs Restore first; it does not expose a separate recover button. Do not address this by unconditionally restarting a host that the helper originally launched but that now displays a wallpaper newly selected by the user.

Please also verify the need for, and otherwise remove, the unpublished draft's MountUnconfirmed compatibility path, as described in the non-blocking inline suggestion.

Scope: the false-empty/unconfirmed-close counterexample in #233 already exists in the baseline. It should not be presented as a regression introduced by this PR, and this bounded repair does not need to solve the entire Lively protocol. The independent counterexample still reports journalRetained=false, stopRequested=true, and strongRecoveryProven=false. Retain that diagnostic and the documented support boundaries; successful execution of the diagnostic is not recovery acceptance.

At the latest check recorded in this review, the new head had 14 successful checks and one failure. The macOS voice-tier job passed 244 Python tests, then failed while downloading Electron in install-electron with TypeError: fetch failed. That log does not establish a wallpaper-code regression, but complete check results for the current head are still needed before merging. The PR description should also reflect its actual non-draft status.


复核提交:4e8b0caa67e1ac48903b34ba5976f29b032b454f。该提交已合入当前 main;壁纸实现及测试与已复跑的 6dfb187c 相同。

上轮针对 0821a9c1 的 P1 已修复:真实挂载失败和设置阶段失败能够按阶段回滚,原自动回滚测试已恢复;35 项确定性契约独立复跑通过。主错误/清理错误保留、避免重复清理以及用户新选择优先的方向成立。

本轮仍请求修改的具体问题见行内评论:Pending 恢复目前依据“这次 helper 是否刚启动宿主”,而非“原请求的接收进程是否仍存活”,所以用户已经完成重启后仍会被拒绝。请同时让恢复提示与 Electron 的真实入口一致:Electron 调用的是 run,该入口本身就先执行 Restore,并不提供单独的 recover 按钮。不要为了修复此问题而无条件重启最初由 helper 启动、后来已承载用户新壁纸的宿主。

另请核实并清理未发布草稿的 MountUnconfirmed 兼容路径,见非阻断行内建议。

范围说明:#233 的假空/关闭不确认反例在基线已存在,不应表述为本 PR 新引入的回归,也不要求这个有限修复顺带解决整个 Lively 协议。独立反例仍得到 journalRetained=false、stopRequested=true、strongRecoveryProven=false;请保留它及支持边界,不将其执行成功计为恢复验收。

最近核查的新 head CI 为 14 项成功、1 项失败;macOS voice-tier 在 244 项 Python 测试通过后,于 install-electron 下载阶段报 TypeError: fetch failed。这份日志没有证明壁纸代码回归,但合并前仍需取得当前 head 的完整检查结果。PR 正文也需要同步已转为非草稿的实际状态。

@Desolate-Jix Desolate-Jix changed the title fix(wallpaper): restore phase-aware rollback and preserve cleanup errors fix(wallpaper): preserve rollback and recover after host restarts Oct 17, 2026

@Lucas1479 Lucas1479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed revision: f3b2e3b195a2b30a3cc2315957436ab09776b494.

The previous P2 is resolved: Pending stores the PID and start time of the server on the actual Set pipe before dispatch; recovery checks that receiver independently from cleanup ownership. Manual restarts, PID reuse and unknown liveness are covered. The dispatch gate prevents late connections from recreating journals or sending Set after the invocation ends.

The non-blocking P3 cleanup is also complete. Main and v0.17.0-alpha.0 never wrote Phase, so the unpublished identity-less Pending exit-barrier compatibility path and its process-enumeration API have been removed. Such journals now raise InvalidDataException without being rewritten or touching the host. Published phase-less journals retain their prior recovery semantics.

Validation on this revision:

  • 50 C# contracts passed. Both replacement invalid-journal contracts failed before the cleanup and passed afterward.
  • 20 Electron wallpaper lifecycle tests passed.
  • Real Lively 2.2.1.0 shared-host mount/restore passed: the recorded receiver matched the real host; original wallpaper/options were restored; the shared process survived; the test journal was removed. This does not cover cold host startup or an induced real-host timeout.
  • Self-contained win-x64 build, dependency-version/content-hash comparison, diff and UTF-8 checks passed.

No remaining blocking code finding from this review. #233 remains a documented baseline protocol limitation, not a regression fixed by this PR. Merge remains subject to current-head CI and repository protection rules.

中文:原 P2 已修复;P3 草稿兼容分支已删除,缺少接收者身份的 Pending 日志直接报无效并保留原文件。50 项 C#、20 项 Electron 契约及真实 Lively 共享宿主挂载/恢复验证通过。本轮代码复核通过;合并仍须满足当前提交的 CI 与仓库门禁。

@Lucas1479
Lucas1479 merged commit 559e9da into main Oct 19, 2026
15 checks passed
@Lucas1479
Lucas1479 deleted the codex/fix-wallpaper-uncertain-mount branch October 19, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants