feat(library): 暂存未入库原件并在确认归档后释放 - #4730
Merged
MagicLizi merged 27 commits intoSep 24, 2026
Merged
Conversation
Re-resolve the live binding on each request so a missing custom root stays unavailable instead of recreating an empty library. Same-disk restore continues through existing open/status; a rebuilt path remains binding-moved. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Unavailable cached custom sessions are not required to keep the live identity. Restore still uses the original disk object; a replaced directory stays binding-moved. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Host H1 is a thin LibraryVault adapter for plugin upload staging. It keeps owner×ghost isolation, hard quota, tombstones, and ACK-gated release without a second media library, new UI, or TCC path. Quota counts durable, orphan blobs, closed tmp, and in-memory uploads without overlap. abort of a commitPending blob is STREAM_INVALID so the landed original stays reserved until ACK. disposeAll/bind/unbind/relocate/delete drain in-flight release behind relocating. First-minted staging roots also fsync parent directory entries; Windows still reports fsynced:false. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Same-instance retry after a durable manifest write plus failed journal fsync no longer dies on ifNotExists ALREADY_EXISTS. Matching identity is adopted; conflicting identity is rejected without overwrite. New originals write intent.json before blob rename. A new Store recovers only from that trusted identity after hash/bytes checks, then installs manifest+dirsync. Incomplete or conflicting intent fails closed and keeps the source. Historical orphans without intent stay billed in isolation and are not TTL-deleted. Signed-off-by: PraiseZhu <zhuzan@xd.com>
A stale custom resolveLibraryRoot could still reach vault.open, which recursively created the missing user parent and reported ready empty. Custom open now refuses to recreate a vanished parent (disk-missing); default first-time create still mkdir. keep files remain in the renamed directory and are not treated as deleted. Signed-off-by: PraiseZhu <zhuzan@xd.com>
…rift Stale resolve plus a same-path new inode is binding-moved at the mkdir boundary. disk-missing after a granted extraDir actually revokes the slot. Auto-open failures latch drift so status-only restore works. Keep files stay in the renamed-away directory. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Custom skeleton mkdir is non-recursive so a vanished user parent cannot be rebuilt as an empty library. Default roots still create recursively. Keep files stay in the renamed-away directory. Signed-off-by: PraiseZhu <zhuzan@xd.com>
After the last successful inspect, hold the parent directory and compare path identity after mkdir(root). A same-path new inode fails closed as binding-moved; an empty root created on the replacement is rolled back and keep files stay parked. Node has no mkdirat; this is not atomic. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Darwin mkdirat/openat (SYS_mkdirat=475) and Linux /proc/self/fd keep ghostId/meta on the granted parent object. Missing helper fail-closed before mutation; no path mkdir fallback. Windows custom init unsupported. Default roots still mkdir recursively. Keep files stay parked. Signed-off-by: PraiseZhu <zhuzan@xd.com>
After the held parent fd is closed, custom open does not write, rename, or unlink under this.root. Sweep unlink and persistUsage are skipped; read-only usage scan remains. Default roots unchanged. Later library writes still persist. Isolated D: no replacement usage.json. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Open an already-initialized custom library from the held parent fd without mkdir. Missing structure on platforms without create stays fail-closed. Teardown only the captured session. Reuse a valid usage ledger; scan only when it is missing or corrupt. Custom tmp is not path-unlinked. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Existing libraries open from the inherited parent handle with NtCreateFile FILE_OPEN+ReadFile. FileIndex 0 and missing helpers fail closed. Create stays unsupported on Windows. Linux may unlink only uuid.tmp/.stream staging leftovers via /proc/self/fd. No path mkdir fallback. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Pretty-printed and compact meta/usage payloads both parse. Malformed JSON or failed field checks stay CORRUPT. Do not split on the first newline of the helper stdout. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Age and an empty streams map cannot prove a fsynced .tmp/.stream is garbage after a crash before rename. Open no longer unlinks them. P2_tmp stays unresolved. Unknown names are kept. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Create dirs with FILE_OPEN_IF and meta.json with FILE_CREATE from the inherited parent handle. No path mkdir, no rollback rmdir, no new native dependency. Existing FILE_OPEN stays read-only. Missing helper still fails closed before mutation. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Record list/resolver/control monotonic marks and dump them on waitFor failure so Linux CI can discriminate missed 500ms poll vs unpublished system-deny. Keep the original assertion and timeout. Mac is syntax sanity only. Signed-off-by: PraiseZhu <zhuzan@xd.com>
FILE_CREATE collision is exists only after FILE_OPEN of a regular file. Reparse and unknown collisions fail closed. CreateRelative always releases handles it still owns, including the catch path. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Keep 94f36c0 as an ancestor. Resolve the only content conflict in pi-startsession-cleanup onto main mockRunDiscovery (list+scan) while keeping the 132dc waitFor diagnostics and original system-deny assertion. Library files are the automatic merge result only. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Consume ed4bef8. Keep 94f as ancestor. Re-resolve pi-startsession-cleanup onto mockRunDiscovery (list+scan) plus 132dc diagnostics, taking main 3s durable-approval waitFor timeout. No extra Library hand edits. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Keep 5c2 as first parent and 4728 d7c as ancestor. Resolve slot/vault by retaining staging dispatch/fsync/quota and custom dirfd fail-closed open. Tests auto-merged. Signed-off-by: PraiseZhu <zhuzan@xd.com>
…serve Idle incomplete uploads now yield BUSY/QUOTA slots after timeout. Concurrent begin reservations are checked against reserveBytes. Durables and commitPending originals are never TTL-deleted. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Refresh closed tmp bytes after idle abort before quota admission. Disk reserve subtracts only unwritten stream remainder; commitPending does not double-count landed blobs. Durables stay off TTL. Signed-off-by: PraiseZhu <zhuzan@xd.com>
20 tasks
Restart resets app-session generation so live ownerScopeKey (local:id:2 vs local:id:0) no longer matches the on-disk manifest. Treat generation as a process lease, not durable owner identity. Signed-off-by: PraiseZhu <zhuzan@xd.com>
PraiseZhu
marked this pull request as ready for review
September 20, 2026 23:31
|
Greptile P1: vanished custom ghost dirs must not rebuild an empty library on a live vault; staging.release re-hashes the unique original and blocks concurrent library mutates until the staging original is gone. P2: disposeAll now invalidates staging stores, uploads, and vaults. Signed-off-by: PraiseZhu <zhuzan@xd.com>
… fail-closed Binding records first-create vs already-built trees without bumping generation. Restart after `<parent>/<ghostId>` disappears now returns disk-missing instead of initializing an empty replacement library. Signed-off-by: PraiseZhu <zhuzan@xd.com>
Greptile P1 r4058467558 needs a real per-ghost mutex, not only a second hash. Mutating Library ops and staging.release now share one chain so hash-then-delete cannot overlap write/delete/rename. Relocating releases still fail closed without taking the lock. Signed-off-by: PraiseZhu <zhuzan@xd.com>
# Conflicts: # apps/desktop/src/main/cindy-brain/__tests__/librarySlot.test.ts # apps/desktop/src/main/cindy-brain/__tests__/libraryVault.test.ts # apps/desktop/src/main/cindy-brain/librarySlot.ts # apps/desktop/src/main/cindy-brain/libraryVault.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
这次改了什么
摘要
Mivo 导入的原件在写入 Library 前若只保存在插件的非持久 Electron 分区,整应用重启后可能无法恢复。本次在 Host 增加按账号与插件隔离的上传暂存,复用 LibraryVault 的文件操作;原件就位前先耐久记录完整任务身份,完整数据与恢复记录持久化后才返回耐久回执,归档完成后核验 Library 正本再释放。清单已存在时逐字段校验后幂等恢复,重建宿主实例时按可信任务记录校验原件并补完归档记录。同 epoch 进程重启后,磁盘
ownerScopeKey的 generation 与 live key 对齐为 durable owner,避免误报 manifest 字段非法。变更类型
feat新功能fix缺陷修复refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
d7c68cd96、cherry-pick 配额 P1,并在 6445 之上修重启 recovery。不是无重叠的独立 diff。UI 变化
不涉及。
怎么验证的
自动验证
当前 head:
7faa6c91aca9fc983bc65a082ada2d78a27b1bb1(祖先6445e75671eed381ed5ec655c50eb054d21c67ef)。旧 SHA 绿不能复用到本 head。独立差额审 APPROVE @ 7faa,24/24 独立复跑。不是 GitHub Approve。
6445 真实 Host 重启 E2E:FAIL(
staging.listmanifest 字段非法);失败材料保留,不用 6445/单测替代 7faa。7faa 独立实机(2026-09-21-ai-ui-4730-e2e.md):首次 begin/chunk/commit/list/read PASS;同 epoch 重启 list/read 同一 durable PASS;0a386×7faa lostACK PASS;Library.write ACK SHA7adec1fb81fa4fd1f57f6be013191b402254627a7ecf3b1c4a663d978b6e2d97、generation 0、identity 绑定 PASS;release 首次 true / 重复 false → list 移除 → canonical read 同 hash PASS。容量/idle 压力 未实机触发,仅单测。云端 client-ci https://github.com/makecindy/cindy/actions/runs/35528298590 @ 7faa completed success。
手工验证
6445 真实 Host 重启 recovery FAIL 已取证保留。7faa 真实 Host:重启 recovery + ACK/release 后半链已过(见
2026-09-21-ai-ui-4730-e2e.md)。容量/idle 未实机。未执行的验证
风险
风险分类
影响与回滚
requireOwner仍用完整 generation key。路径命中插件基座白名单;fix(library): 自定义媒体库暂时不可用时不重建空库 #4728 批准不得复用。touches:plugin-base仍缺(fork 无 AddLabels 权限)。提交前检查
git commit -s,见 DCO)