Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions docs/evidence/issue233-lively-recovery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Windows managed wallpaper: #233

The offline counterexample reproduced on unmodified Amadeus main
`53f8f4f2b130edcc6e30cf22826b657bbac344ec`. A settled Set was followed by
a mount-confirmation timeout; Lively's simulated list returned no entries, and
its project Close succeeded without removing the managed scene.

| Same synthetic case | Recovery journal | Owned-host shutdown |
| --- | --- | --- |
| Unmodified main, failed Close | Deleted | Requested |
| With the player check, failed Close | Retained; both errors reported | Not requested |
| Retry after Close actually removes the scene | Deleted | Requested |

Run `python tools/probes/windows_wallpaper_counterexample.py` and
`python -m pytest tests/test_windows_wallpaper_helper.py`. The latter includes
a real Windows child process with synthetic player arguments, left running
after the fake registry has removed its row. It exercises native process
inspection; it is not a stock-Lively desktop reproduction. The host's
enumeration and close semantics still need independent correction upstream.

## Span and process-exit regressions

On PR head `5658a379`, the span repro refused both restoration attempts: the
synthetic registry moved the project from the old primary to the new one while
the real hidden test wrapper kept its original launch arguments. No Close was
sent. With the project-count check, the same repro closed the project once,
restored the original scene and cleared the journal. A separate two-wrapper
case still vetoes a partial report even when an unrelated project is listed.
These are Windows process and lifecycle tests with a simulated registry, not
a physical multi-monitor Lively run.

The command-line query now translates NTSTATUS using Windows' own mapping.
`STATUS_PROCESS_IS_TERMINATING` reaches the same access-denied handling as
the image query, while an unrelated invalid-parameter error remains distinct.
The two-second post-Close window was introduced by this PR. The nine earlier
stock desktop runs belong to `5658a379`; they do not qualify this revision.

## Upstream report drafts (not submitted)

Destination: [lively-community/lively issues](https://github.com/lively-community/lively/issues).
The two reports concern different RPC contracts. Both were checked on the
official 2.2.1.0 release tag (`6860a4093fc50058c4815908658a4391c4449935`)
and default branch (`25a0a5f4ed1988ff42117d3a17feb321062237fe`). The
source findings below do not rely on a modified installed DLL.

### GetWallpapers can complete successfully with an incomplete inventory

**Problem.** Clients cannot distinguish an empty desktop from an error
enumerating its wallpapers. An exception after the first row can also yield a
successful partial inventory.

**Upstream check and evidence.** In
[GetWallpapers](https://github.com/lively-community/lively/blob/25a0a5f4ed1988ff42117d3a17feb321062237fe/src/Lively/Lively/RPC/WinDesktopCoreServer.cs#L197-L241),
the server assigns the possibly null display name to a protobuf string inside
the enumeration loop. Its catch logs the exception and returns normally.
Suggested regression: supply a registry with a null display name, both as the
first and second entry. Return the complete valid records or a failed RPC;
never return success with just the prefix. This is source evidence, not a
new live reproduction of the fault. No matching report was found by method name.

### CloseWallpaperLibrary success does not establish project/player cleanup

**Problem.** A project-scoped Close can report success on a metadata error;
even when the registry removes a matching WebView2 wallpaper, the reply does
not establish that its player exited.

**Upstream check and evidence.** [CloseWallpaperLibrary](https://github.com/lively-community/lively/blob/25a0a5f4ed1988ff42117d3a17feb321062237fe/src/Lively/Lively/RPC/WinDesktopCoreServer.cs#L285-L298)
catches exceptions constructing/closing the library item, then returns an empty
success response. [The core](https://github.com/lively-community/lively/blob/25a0a5f4ed1988ff42117d3a17feb321062237fe/src/Lively/Lively/Core/WinDesktopCore.cs#L981-L1005)
closes/disposes matching players and removes their records; the RPC does not
wait for a verified exit of the specific player. Check bad metadata and an
induced player-close failure separately from a valid project already absent.
The downstream [#233](https://github.com/Code-Amadeus/Amadeus/issues/233)
records both a real IPC close control and a separately labelled simulated
counterexample. [Lively #2939](https://github.com/lively-community/lively/issues/2939)
concerns browser subprocesses after switching wallpapers, not this RPC's
completion contract.
55 changes: 34 additions & 21 deletions docs/windows_wallpaper_lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,22 +205,34 @@ Lively 不会继续迟到挂载。
回退旧 helper 前,须先用本 helper 处理未完成日志。旧程序不理解 `Phase`;日志尚存
时不支持降级,不会为允许降级而重置或删除恢复记录。

#264 replaces the helper runtime while preserving phase-aware rollback and error
preservation. It does
**not** repair stock Lively 2.2.1.0's reporting/close protocol: `GetWallpapers`
can return a falsely empty stream, and project close can swallow errors and
return success without removing a player. A close response plus an empty stream
cannot prove strong recovery or player exit. For an originally empty desktop,
the retained baseline empty-report behavior can still delete the journal and
request owned-host shutdown while an unreported scene remains. This is a known
unresolved limitation, not an accepted strong-recovery guarantee. Scene removal
is not inferred from a PID, a layout file or a timing heuristic to hide it.

本次替换 helper 运行时,保留按阶段回滚及异常合同,**未修复**原版 Lively 2.2.1.0 的报告及关闭
协议:`GetWallpapers` 可能假空,项目关闭也可能吞错后返回成功却没有移除播放器。
关闭回执加空流不能证明强恢复或播放器退出。对于原来为空的桌面,保留的 baseline
空报告行为仍可能在未报告场景存在时删除日志并请求停止自有宿主。这是明确未解决的
限制,不能视为强恢复已验收;本轮不以 PID、磁盘 layout 或延时推断场景移除来掩盖它。
**#233 — missing scene / surviving player.** Stock Lively 2.2.1.0 can return an
empty or partial list on enumeration error and acknowledge a close without
waiting for its player to exit. Amadeus mounts its loopback wallpaper using
Lively's WebView2 player. Before saving a before-image or committing recovery,
the helper counts live wrappers for the Amadeus loopback URL in the current
Windows session. If that count exceeds the number of entries for the managed
project, the list cannot confirm cleanup. It does not match the player's launch display
to a registry row: in span mode [Lively can update the primary display without
relaunching the player](https://github.com/lively-community/lively/blob/6860a4093fc50058c4815908658a4391c4449935/src/Lively/Lively/Core/WinDesktopCore.cs#L742-L750).
Counts can veto cleanup; the existing project and monitor checks still decide
which scenes can be restored. After a scoped Close, the helper allows up to two
seconds for fresh observations without issuing Close again. If the discrepancy
or an access denial persists, the recovery journal is retained and host shutdown
is blocked. Retry `recover` once the conflict is resolved; do not delete the journal.

This check covers the managed WebView2 wrapper, not the complete registry of
all Lively plugins. A preview or another project using the same Amadeus endpoint
can also make the observation ambiguous; close that preview before retrying.
Absence of a wrapper does not certify an arbitrary empty/partial host registry,
or exit of every descendant. Those guarantees need truthful results from
[Lively's list and close RPCs](https://github.com/lively-community/lively/blob/6860a4093fc50058c4815908658a4391c4449935/src/Lively/Lively/RPC/WinDesktopCoreServer.cs#L197-L298).

**#233:场景漏报,但播放器仍在运行。** helper 在保存桌面原状和确认恢复前,对比当前
Windows 会话内使用 Amadeus 回环地址的 WebView2 播放器数量与托管项目的登记条目数。
播放器多于条目才构成漏报。跨屏模式更换主屏时,Lively 会更新登记的显示器,不会重启
播放器,因此不比较启动参数里的旧屏号。数量只用于否决清理;原有项目和显示器检查
仍决定恢复哪张壁纸。对指定项目发出 Close 后,最多等两秒重新核验;持续漏报或拒绝
访问时,保留恢复日志,不关闭宿主。排除冲突后可重试 `recover`,不要删除日志。

Deterministic contracts separate fake actual state from reported state and cover
rollback, retries, late requests, user choices, journal compatibility and both
Expand All @@ -229,16 +241,17 @@ execute before Session persists the actual pipe receiver, and executes zero time
when identity, persistence or transport binding fails. These pipes never connect
to Lively or change the desktop. They also cover a connection arriving after its
response deadline and a persistence boundary blocked across that deadline. The
separate `--false-empty-counterexample` diagnostic records the
unresolved false-empty/no-op-close case without adding it to the passing contract
count. These checks do not establish real Lively mounting or close completion.
separate counterexample probe records the failed close and subsequent retry.
A native contract keeps an actual hidden test process alive after its registry
row is removed. It exercises the production Windows observer without replacing
the user's wallpaper. These checks do not certify stock Lively's whole lifecycle.

离线契约分离 fake 真实状态与报告状态,覆盖回滚、重试、迟到请求、用户选择、日志
兼容与双重异常。随机命名的本地管道契约还核验:Session 持久保存实际接收进程前
Set 不得执行,身份、持久化或传输绑定失败时执行次数为零;这些管道不连接 Lively,
也不改变桌面;还覆盖响应超时后连接迟到、持久化边界阻塞跨越响应超时的竞态。
独立 `--false-empty-counterexample` 诊断记录未解决的假空及关闭
no-op 反例,不计入契约通过数;这些检查不证明真实 Lively 挂载或关闭完成。
独立反例探针记录假空、关闭未生效以及重试的结果;原生契约用真正的测试子进程验证
漏报检测,不操作用户桌面,不等于原版 Lively 全链路实机验收。

If Lively must be started with its screenshot-to-wallpaper options temporarily
disabled, `Lively Wallpaper\Amadeus.launch-settings.json` backs up just those
Expand Down
Loading
Loading