Skip to content

Materialize members' shared notes as vault files, kept fresh automatically - #73

Open
jakepel03 wants to merge 1 commit into
mainfrom
materialize-shared-notes-69
Open

Materialize members' shared notes as vault files, kept fresh automatically#73
jakepel03 wants to merge 1 commit into
mainfrom
materialize-shared-notes-69

Conversation

@jakepel03

Copy link
Copy Markdown
Owner

Closes #69 — the read side of "a project is a folder in your vault": other members' shared notes appear as real files under Shared Projects/<project>/ and stay current automatically, so they work with native search, graph view, and backlinks instead of living behind the Discover modal.

How it works

Two-tier refresh (SharedNotesController, every 60s + on startup + a manual command):

  1. List (cheap, local): one SPARQL query per project against the local node — subscribed projects' Shared Memory replicates here in the background, so this costs milliseconds and zero network. The query returns each note's root entity with its title, dkg:sourceFileHash (upstream content fingerprint) and dkg:sourceFileName (the author's real filename). Both verified to replicate to member nodes on a live two-node 10.0.2 setup.
  2. Fetch (rare, P2P): only notes that are new or whose hash changed get their prose pulled via the existing import-artifact/read path, pinned at the curator's peer. Unreachable notes back off for 10 minutes instead of hammering the network every tick.

Planner/IO split: sharedNotes.ts is pure (listing parse + per-project plan, 15 unit tests); sharedNotesController.ts does the vault IO.

Safety rules

  • A user-edited copy is never overwritten or trashed. Every write is fingerprinted (SHA-256 in materializedNotes state); a mismatch means the user edited the file → updates for it stop with a one-time notice, and their version survives even if the note is retracted upstream.
  • Retraction → Obsidian trash (reversible), and only when the listing is non-empty — an empty listing usually means catch-up lag, and must not be read as "everything was retracted".
  • No echo loops: the shared folder is excluded from import (shouldSkipPath gained the root as a parameter — all call sites updated), and the author's shared_to/shared frontmatter is stripped from materialized copies. Without that, moving a copy out of the folder would re-share the note into the project under the receiving user's identity. Provenance is recorded instead (dkg_origin, dkg_author, dkg_hash) — which is also what Shared project folders, write side: adding a note to a project folder shares it #70's authorship-based skip will key on.
  • Own notes are never materialized (filtered by the agent-address segment of the entity URI); filename collisions between authors get a (2) suffix; leaving a project keeps the files and just drops their sync state.

UX surface

  • Command: Refresh shared notes from projects (also retries backed-off fetches and reports "up to date").
  • Settings: master toggle (default on), folder name (default Shared Projects), arrival-notice toggle. Batched notices only ("2 new, 1 updated"), never one per note.
  • Per-project opt-out field (materialize?: boolean) exists in settings data; its dashboard toggle ships with the dashboard follow-up below.

Deliberately not in this PR

Backward compatibility

Fully backward compatible: four new optional settings keys (defaults fill in on load, no migration), one optional field on SubscribedContextGraph, a new command id. shouldSkipPath's new parameter is optional; existing behavior is unchanged when it's absent. No node-floor change (the hash/filename triples are simply absent on notes shared by very old nodes — those notes still materialize, they just only re-fetch on manual refresh).

Testing

  • 40/40 tests (15 new for the planner/parsers), build + lint + format clean, main.js in sync.
  • Live checks against the running 10.0.2 two-node setup: listing query returns hash + filename on the member node (our-trips), and the member-side P2P byte-read returns the author's real prose — which is how the shared_to stripping issue was caught.

@jakepel03 jakepel03 self-assigned this Aug 3, 2026
@jakepel03
jakepel03 force-pushed the materialize-shared-notes-69 branch from 3b7349c to a255ece Compare August 3, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Materialize shared project notes as vault files, kept fresh automatically

1 participant