feat(sync): local-first multi-machine artifact sync - #731
Conversation
|
Feedback is welcome. Still in draft mode since work and testing to this point has been completely agent driven, a combination of GPT-5.5 and Claude 4.8. Next up is manually trying various distributed machine scenarios and seeing how well any of this works in practice. Assuming the idea eventually proves out, I'm happy to split into smaller manageable PR. |
roborev: Combined Review (
|
## Summary - Keep the candidate-window and boundary-session behavior in `internal/postgres/push.go` unchanged for this PR, and batch the PostgreSQL-side comparison reads used to decide whether a candidate session can be skipped. - Implement new batched loaders in `internal/postgres/push_fingerprint.go` for message aggregates, message content hashes, role/time fingerprints, message flags, message system ordinals, token fingerprints, tool-call aggregates, tool-call fingerprints, and usage fingerprints, with chunking inside the helper when session counts exceed `ANY($1)` practicality. - Use the preloaded message and tool-call aggregates on the hot no-op path, and retry any comparison-preload SQL failure in a fresh transaction without the batched preload instead of continuing inside an already-aborted transaction. - Add targeted regression tests in `internal/postgres/push_test.go` and `internal/postgres/push_fingerprint_test.go` to cover the new batch-driven skip decision path and helper behavior with empty inputs. ## Scope - Files changed are `internal/postgres/push.go`, `internal/postgres/push_fingerprint.go`, `internal/postgres/push_test.go`, and `internal/postgres/push_fingerprint_test.go`. - No boundary/windowing semantics, no schema changes, and no changes to PR #731 or broader sync-work areas. ## Notes - A focused PG comparison query-count assertion was not added because the existing harness does not expose a stable helper-call/query metric for this exact path without adding brittle test-only instrumentation. - The review-driven follow-up keeps the existing non-batched fingerprint fallback, but now that fallback only runs from a clean transaction after preload failure instead of on the poisoned transaction that raised the preload error. Fixes #331 Co-authored-by: Rod Boev <rodboev@users.noreply.github.com>
|
Thanks for the review. Both findings were valid and are addressed in 28048707 and f252c35f. High — Windows-invalid Note this changes the canonical on-disk HLC string ( Medium — divergent origin sources. Confirmed:
Claude Opus 4.8 reasoning-medium on behalf of maphew |
roborev: Combined Review (
|
|
Thanks again. All three findings were valid and are addressed in 055f3b3c. High — local metadata events missing from the replay register ( Medium — remote HLCs not observed by the local clock ( Medium — one unavailable target aborted the rest of the origin (
Claude Opus 4.8 reasoning-medium on behalf of maphew |
roborev: Combined Review (
|
|
Thanks. Both convergence gaps were valid and are fixed in 1d8d24c1 and 8cac9fff. Medium — usage-only sessions never exported ( Medium — bulk star emitted no metadata events (
Claude Opus 4.8 reasoning-medium on behalf of maphew |
roborev: Combined Review (
|
|
Thanks. Addressed in e77db3a9, 4110dce2, acbb7899, and 6ea6fa89. Medium — Medium — unconditional S3 PUT violates write-once ( Medium — Medium — remote events applied before the HLC advances (
Claude Opus 4.8 reasoning-medium on behalf of maphew |
roborev: Combined Review (
|
6ea6fa8 to
18c0f18
Compare
roborev: Combined Review (
|
|
I will rebase this |
18c0f18 to
b228d18
Compare
roborev: Combined Review (
|
|
I'll continue to work a bit on this to see if I can get it into a state that I'm comfortable with |
b228d18 to
16e5a7b
Compare
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
efb934f to
550372b
Compare
roborev: Combined Review (
|
roborev: Combined Review (
|
eaf6694 to
f944578
Compare
roborev: Combined Review (
|
d8f0292 to
69ce721
Compare
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
5ce0710 to
c7f2d4a
Compare
roborev: Combined Review (
|
c7f2d4a to
3be2fcd
Compare
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
|
I'm still working on this, there were a bunch of performance concerns. I am going to release 0.38.0 first and then see about this |
|
I am still tracking this and will return to it in the near future |
|
Thanks for the performance work, Wes. Since the 0.38 release is out, I can take the branch-maintenance pass: bring #731 up to current main, resolve the conflicts, address the two latest correctness findings, and post reproducible large-archive benchmark results. After that, would you prefer a staged PR series or to keep this together? |
|
Following up: I kept #731 untouched and split the assist into three draft side PRs, each targeting the feature branch in my fork:
All three are mergeable and green across CI and the benchmark gate. The documented 200-session × 80-message (~6.1 MB) run on an i9-13900 measured about 0.95s export, 0.87s import, 0.58s converged no-op, and 0.67s incremental sync. Use, cherry-pick, or choose whatever is helpful. I will not push changes to #731. |
7fe9180 to
719553a
Compare
roborev: Combined Review (
|
roborev: Combined Review (
|
|
We've built a CAS system for msgvault that is in kenn-io/kit, I am working on generalizing that so that it can serve as the CAS layer for this PR, but it is going to take me some time, maybe another week. That will prevent creating an independent content-addressed storage system for this feature alone. Stay tuned |
0082cca to
cc88a44
Compare
roborev: Combined Review (
|
|
https://github.com/kenn-io/docbank is now public so I'm looking at how we could base the artifact management on docbank to reduce code ownership for CAS in agentsview |
- docs: design docbank-backed artifact storage - docs: refine docbank artifact storage design - docs: plan docbank artifact repository migration - refactor(artifact): define logical store contract - test(artifact): strengthen logical store contract - test(artifact): isolate digest mismatch coverage - refactor(artifact): isolate filesystem repository - refactor(artifact): move zstd to wire boundaries - fix(artifact): observe final wire cancellation - test(artifact): prove bounded wire allocations - feat(artifact): add Docbank repository adapter - fix(artifact): validate Docbank vaults before opening - fix(artifact): own repository initialization - fix(artifact): classify reverse repository overlap - feat(artifact): persist incremental publication state - fix(artifact): harden incremental publication state - fix(artifact): retain export generation authority - refactor(artifact): export canonical objects to store - fix(artifact): fence checkpoint publication - refactor(artifact): import through verified repository - fix(artifact): harden verified repository import - fix(artifact): bound repository import traversal - fix(artifact): make repository listing incremental - fix(artifact): recover filesystem catalog mutations - fix(artifact): recover interrupted filesystem removals - fix(artifact): make removal rollback crash-idempotent - fix(artifact): bind recovery intents to catalog identity - fix(artifact): serialize filesystem store mutations - fix(artifact): retain mutation ownership through cancellation - build(deps): pin docbank v0.10.0 - refactor(artifact): stream transport exchange - fix(artifact): bound peer exchange end to end - fix(artifact): close peer pagination gaps - fix(artifact): finish peer cursor lifecycle - feat(artifact): share Docbank vault through lifecycle - fix(artifact): bound repair and peer lifecycle - fix(artifact): retain metadata operations through shutdown - feat(artifact): bound retention and batch packing - fix(artifact): bound maintenance continuation - fix(artifact): preserve maintenance policy on resume - perf(artifact): trigger packing from write receipts - perf(artifact): recover stored loose backlog - fix(artifact): preserve exact packing backlog - feat(artifact): add explicit vault reset - fix(artifact): preserve reset metadata and shutdown safety - fix(artifact): gate reset move against shutdown - fix(artifact): bound shutdown during vault reset - fix(artifact): recover interrupted vault republish - fix(artifact): bound reset baseline recovery - test(artifact): exercise protocol paths on Docbank - refactor(artifact): construct syncs on Docbank - refactor(artifact): retire local filesystem repository - fix(artifact): preserve future metadata formats - build(deps): pin Docbank PR head - test(artifact): characterize bounded Docbank transport - docs(artifact): prepare synchronization guide for review
cc88a44 to
c3be274
Compare
Implements local-first multi-machine artifact sync from #692. Each machine retains its SQLite archive and exchanges immutable, content-addressed session artifacts plus a hybrid logical clock metadata ledger through shared folders, HTTP peers, or S3-compatible object stores.
The sync path preserves origin-aware identities through SQLite and optional PostgreSQL, treats imported artifacts as untrusted input, regenerates corrupt local objects from SQLite, and safely retries partially published metadata. Lifecycle operations serialize local trash, restore, and purge mutations with peer metadata replay, so pre-publication failures compensate safely and purge artifacts become durable before local deletion.
Transport security matches the project threat model: non-loopback HTTP requires explicit --allow-insecure consent, authenticated redirects are rejected, custom S3 endpoints require TLS outside loopback unless explicitly opted in, and insecure object-store cleanup cannot delete remote objects.
Automatic garbage collection prunes both the local store and target after folder sync. HTTP and S3 targets retain superseded history until transport-aware remote pruning is available, preventing remote-only artifacts from entering a recurring download-and-delete loop.
The branch also adds conflict and peer visibility, conservative manual garbage collection, and operational documentation. Legacy PostgreSQL identities converge without duplicating sessions or losing local curation, relationships, source state, or soft-delete state.
Closes #692.
Closes #1034.
Closes #1035.