From 90fbc240afe68cb7a0895958d238cf7585b9fc71 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 19 Sep 2026 13:40:56 -0400 Subject: [PATCH] vault_sync_daemon: mirror full /vault structure forward, not just JD-shaped folders Forward (/vault->/data) mirroring was gated to only AREA/CATEGORY/ID-shaped names, so arbitrary sub-structure Ryan creates inside an ID (e.g. dated trip folders under F.21.21) never propagated to /data. Removed the name-shape gate; the existing parent-must-exist check is sufficient safety, plus an explicit '0 System area' exclusion since that tree has no /data root at all. --- vault_sync_daemon.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/vault_sync_daemon.py b/vault_sync_daemon.py index ad1e120..0595726 100644 --- a/vault_sync_daemon.py +++ b/vault_sync_daemon.py @@ -167,11 +167,24 @@ def _under_data_exempt(rel_path): def handle_vault_created(path): """ - A new AREA/CATEGORY/ID-shaped folder appeared in /vault (e.g. created - via Obsidian, not the `vault` CLI) with no /data counterpart yet. - Mirror it: create the matching empty folder in /data. This is the - forward-create leg that was missing — only move/delete were wired up - originally, so a brand-new folder (like "R.6 Test") never propagated. + A new folder appeared in /vault (e.g. created via Obsidian, not the + `vault` CLI). Mirror it: create the matching empty folder in /data. + This is the forward-create leg that was missing — only move/delete + were wired up originally, so a brand-new folder (like "R.6 Test") + never propagated. + + Full 1:1 structural mirror, NOT limited to JD-shaped (AREA/CATEGORY/ID) + names (confirmed with Ryan 2026-09-19): once inside an ID's territory + Ryan organizes arbitrary sub-structure (e.g. dated trip folders under + an ID like "F.21.21 All short trips"), and expects /data to match that + structure too, not just the JD skeleton. The only safety gate is that + the /data PARENT must already exist — this naturally still excludes + "0 System area" (which has no /data root at all, by design) and any + other genuinely orphaned branch, without needing a name-shape check. + Reverse (/data -> /vault) intentionally keeps its stricter JD-shape-only + gate (see handle_data_created) — /data is the hand-sorted blob side + with far more incidental subfolders, so stubbing a /vault note for + every one of those would be noise; there's no such asymmetry forward. """ if not os.path.isdir(path): return @@ -180,9 +193,8 @@ def handle_vault_created(path): if not _debounced("vault_created", path): return rel = os.path.relpath(path, VAULT) - base = os.path.basename(path) - if not (ID_RE.match(base) or CAT_RE.match(base) or vl.AREA_RE.match(base)): - return # not a JD-shaped folder — ignore (e.g. "Documents" subfolder) + if rel.split(os.sep)[0] == vl.SYSTEM_META: + return # "0 System area" never mirrors to /data, by design data_path = os.path.join(DATA, rel) if os.path.isdir(data_path): return # already mirrored (duplicate event or pre-existing)