test_a_restart_keeps_every_held_scope_and_cursor_valid registered the
second PromptManagerAPI's close with addAsyncCleanup, which unittest runs
after tearDownAsync. The base teardown then unlinked the temp database
while that API's SQLite connections were still open: Windows refuses
(WinError 32). The restart test class now closes its extra APIs in
tearDownAsync before the base teardown.
ImageAPITestCase's teardown now counts connections any live model still
holds on the test database, closes them and fails, so a handle left open
past teardown fails on Linux too instead of only on Windows.
Closes#475
The gallery root scope and the Images listing cursor were keyed with a
per-process random key, so every ComfyUI restart made an open tab's
scopes answer 409 source-changed (blank Tag image preview, a Generate
that did nothing) and its cursors fail Load more.
- utils/workspace_keys.py: one random secret in workspace-scope.key
beside the database (owner-only, never config.json or the database),
two derived keys; per-process fallback with a warning. Move library
copies it.
- Cursor v2 binds the listing scope in its MAC instead of sending an
unkeyed hash of the root paths; an unverifiable cursor answers 400
cursor-stale and Images offers Refresh instead of a dead Retry.
- POST /prompt_manager/images/rescope maps a stale target to its
current root only when the held scope was issued for it.
- Images finds a renumbered file again from the inspector, the viewer
and the Tag image dialog (the dialog stays open, draft kept); nothing
else is kept by an old root_index:path key.
- Tag image dialog: a state that blocks Save shows its reason above the
actions with Refresh, disabled actions look disabled, and an empty
preview says "Preview unavailable" (D147).