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)