feat: a joined node keeps its chats' attachments in the pool #505
Dismiss Review
Are you sure you want to dismiss this review?
Labels
Clear labels
accessibility
all-platforms
area:agents
area:ai
area:chain
area:ci
area:client
area:daemon
area:p2p
area:project
area:protocol
area:runtime
area:storage
bug
chore
community
dependencies
discussion
discussion/Announcements
discussion/General
discussion/Ideas
discussion/Q&A
discussion/Show and tell
discussion/answered
documentation
duplicate
enhancement
good first issue
help wanted
i18n
infra
invalid
needs:decision
needs:hardware
paired
question
research
security
status:in-review
test
testing
tracking
wontfix
Barrier affecting people with disabilities
Run every platform's packaging and checks on this pull request, not only the three main ones
MCP server, skill, and thinking on the pool
Planner and model providers
Blockchain, SISY, verification
Continuous integration and build workflows
Desktop and web clients
sisyphusd coordinator, worker, scheduler
libp2p hosts, relays, discovery, connections between nodes
Project planning, roadmap, and governance
Protobuf schemas and RPC contracts
Workload execution and environments
Content-addressed storage, IPFS, Kubo, Cluster, S3, names, pinning
Something isn't working
Repository health, templates, Discussions, contributor experience
Updates to actions, Go modules or npm packages
Migrated from GitHub Discussions
GitHub Discussions category: Announcements
GitHub Discussions category: General
GitHub Discussions category: Ideas
GitHub Discussions category: Q&A
GitHub Discussions category: Show and tell
Q&A discussion with an accepted answer
Improvements or additions to documentation
This issue or pull request already exists
New feature or request
Good for newcomers
Extra attention is needed
Translations and right-to-left layouts
Build, CI, releases
This doesn't seem right
Waits on a decision from both owners
Waits on a machine we do not have yet
Built together by both maintainers, with co-authored commits
Further information is requested
Needs investigation or a design decision
Sealing, keys, access control, tokens, the security model
Built and in an open pull request; closes when it merges
Tests, test harnesses and the rehearsal
Roadmap and meta issues
This will not be worked on
type
Feature
A request, idea, or new functionality (GitHub issue type)
type
Task
A specific piece of work (GitHub issue type)
Milestone
No items
No Milestone
First release
Projects
Clear projects
No projects
Sisyphus roadmap
Done
No Assignees
rvnminers-A-and-N
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Sisyphus/Sisyphus#505
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #500. Stacked on #503 (slice 1). Once that merges, this rebases onto
dev, and its diff is just the commit on top.A node that has joined another's pool as a client now keeps its chat attachments there too, so a chat on a worker+client node can attach files the way it does on a coordinator.
How
The coordinator keeps one client pin per file for this node. Several owners on the node can want the same file, though: the user, each chat that has it, and the draft of an attachment not yet sent (kept for a day). The node now remembers those itself, and turns them into that one pin:
Each change is made on the coordinator first and noted locally after. A failure between the two keeps a file longer, never shorter. When the coordinator doesn't have the file, the error is
storage.ErrNotFound, so the existing attachment-pin queue drops that change instead of retrying it forever. While the node is away, a change fails withUNAVAILABLE, and the queue retries it once the node is back.packages/nodedb: migration0032_pool_file_holdsandPoolFileHolds/HoldPoolFile/ReleasePoolFile. Holds are keyed by coordinator ID, likepool_jobs, and expired ones are pruned.apps/sisyphusd/pool_files.go:*poolFilesmaps owner holds onto the coordinator pin. The daemon also uses it as the assistant's attachment pin store.Tests
TestAJoinedClientNodeKeepsItsFilesInThePoolnow drives a real chat on the joined node:Askwith it runs a privatewordcountin the pool, and the pin becomes permanent.DeleteChat, the pin falls back to the draft's expiry.TestAJoinedNodesFilesAreKeptAsLongAsTheLongestHoldcovers the hold-to-pin mapping and each failure path.TestTheHoldsOnFilesKeptInAPoolAreKeptAcrossReopeningcovers the nodedb part.make cover: every statement is covered. gofmt and vet are clean.Docs
docs/desktop-backend.md: attachments on a joined node.This persists the owner hold only after the remote pin update, which is good for avoiding premature release. There is still a lost-retry case for RemoveFile: the local API deletes the file catalogue row before calling Unpin; if the coordinator RPC fails, this row remains in pool_file_holds, but the file is no longer listed and there is no reconnect/startup path here that retries the pending release. The coordinator keeps the permanent client pin and quota indefinitely. Could we preserve the file entry until the remote change succeeds, or add a durable event-driven retry for pending hold changes, with a test for failed Unpin followed by reconnect? /cc @rvnminers-A-and-N
One recoverability gap remains around RemoveFile when the coordinator rejects or cannot receive Unpin: the durable user hold is left behind after the local catalogue entry is removed, with no reconnect/startup retry. I left an inline comment with the failure sequence and test request. /cc @rvnminers-A-and-N
Good catch, thank you. That was a real hole. I went with your first option, keeping the file entry until the remote change succeeds, in
13e1b41.RemoveFilestill takes the file off the list first, so a file is never listed after its release has gone through. If the store then fails to let it go, the entry is put back exactly as it was. The error carries the store's own code, so a joined node that is away getsUNAVAILABLErather thanINTERNAL.pool_file_holdsis written or deleted only after the coordinator call succeeds. A failedUnpintherefore leaves both the hold and the listing in place. Nothing is kept without the node showing it, and the nextRemoveFileafter reconnecting releases it.file_pin_operationsqueue, which retries on reconnect.The test is
TestAFileThatCannotBeLetGoStaysListedinapi/local_files_test.go. It covers four cases:UNAVAILABLEmakes the removal fail, and the file stays listed next to an unrelated one.The docs in
desktop-backend.mddescribe the behaviour. Could you take another look?Reviewed the updated
13e1b41change. It restores the exact catalogue entry when remote Unpin fails, preserves the store status code, and covers retry after reconnect plus list/restore failures. The failure path I raised is addressed; CI is still running, so this is code approval only. /cc @rvnminers-A-and-N