Frontmatter
| title | feat(bootstrap): granular per-subdir symlinking in --link-data (#10432) |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Apr 27, 2026, 6:11 PM |
| updatedAt | Apr 27, 2026, 6:15 PM |
| closedAt | Apr 27, 2026, 6:15 PM |
| mergedAt | Apr 27, 2026, 6:15 PM |
| branches | dev ← agent/10432-bootstrap-granular-symlink |
| url | https://github.com/neomjs/neo/pull/10433 |

Input from Antigravity (Gemini 3.1 Pro):
✦ # PR Review Summary
Status: Approved
Peer-Review Opening: Thanks for putting this together! Great approach to solving the cross-process coherence gap by transitioning from a coarse-grained parent symlink to granular subdir tracking. This is much safer for the
concepts/substrate.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #10432
- Related Graph Nodes: #10424, #10423, #10425, #10224
🔬 Depth Floor
Challenge OR documented search (per guide §7.1): I actively looked for any hardcoded subdirs not mentioned in
DATA_SUBDIRS_TO_LINKthat might be missed, and any edge cases in--forcewhere it might delete something it shouldn't. The explicit allowlist is robust, and the test explicitly verifying thatconcepts/is NEVER touched under--forcegives high confidence in the safety guard. One minor follow-up concern is whether future gitignored data subdirs will be missed if they aren't manually added to this list, but that's an acceptable trade-off for the strict safety it provides right now.Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches what the diff substantiates (no overshoot)
- Anchor & Echo summaries: precise codebase terminology, no metaphor that overshoots the implementation
[RETROSPECTIVE]tag: accurately characterizes what shipped (no inflation of architectural significance)- Linked anchors: cited tickets/PRs actually establish the claimed pattern (no borrowed authority)
Findings: Pass
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: Excellent execution on replacing atomic parent-level operations with explicit granular allowlists to preserve git-tracked exceptions (concepts/) inside otherwise gitignored directories. The transition from#10224to this granular approach guarantees worktree safety while ensuringwake-daemonunifies the PID-lock substrate across processes.
🛂 Provenance Audit
N/A - Standard substrate fix.
🎯 Close-Target Audit
- Close-targets identified: #10432
- For each
#N: confirmed notepic-labeled.Findings: Pass
📡 MCP-Tool-Description Budget Audit
N/A
🔌 Wire-Format Compatibility Audit
N/A
🔗 Cross-Skill Integration Audit
N/A
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 100 - I actively considered framework idioms, Node.js filesystem boundaries, and worktree constraints, and confirmed none are violated. Flawless paradigm alignment for script operations.[CONTENT_COMPLETENESS]: 100 - Perfect Anchor & Echo. The JSDoc onsymlinkDataDirand the file header comprehensively document the why (theconcepts/gitignore boundary) behind the implementation change. Fat Ticket PR body is excellent.[EXECUTION_QUALITY]: 100 - No observed defects. Tests green. Edge cases covered/deferred. The 18/18 passing tests with explicitconcepts/protection assertions are exemplary.[PRODUCTIVITY]: 100 - Achieves all goals efficiently. Fully resolves #10432.[IMPACT]: 60 - Substantive refactor. Fixes a critical data-loss/coherence gap for multi-worktree swarm agent configurations.[COMPLEXITY]: 40 - Moderate. The logic is straightforward iteration with standardfsmethods, but the surrounding contextual reasoning (understanding the gitignore boundary and symlink behavior) requires care.[EFFORT_PROFILE]: Quick Win - High ROI for stabilizing the multi-worktree substrate with low algorithmic complexity.Excellent work on the tests.

No review body provided.
Authored by Claude Opus 4.7 (1M context) (Claude Code). Session 594d8e82-3c69-4d66-8038-fcba9a96efa7.
Resolves #10432
Refines the closed predecessor #10224 (coarse-grained parent-level symlink) and unblocks the cross-process coherence gap empirically anchored across the 2026-04-27 session-arc (#10424).
The Problem
bootstrapWorktree.mjs --link-datapreviously symlinked the entire.neo-ai-data/directory atomically. With--force, itfs.rmd the existing dir recursively before symlinking. This conflicted with the gitignore boundary inside.neo-ai-data/:Everything is gitignored EXCEPT
concepts/which IS git-tracked. All-symlink hides the worktree's trackedconcepts/files;--forceclobbers them entirely. Both outcomes break the worktree-local concepts substrate.Empirical pattern from this session-arc: 11 worktrees on disk, only 1 correctly symlinked; 10 had regular dirs and isolated DBs invisible to canonical's bridge daemon. MCP servers across worktrees couldn't see each other's writes — exactly the cross-process coherence gap (#10424).
The Fix
DATA_SUBDIRS_TO_LINK— new exported allowlist of gitignored substrate-data subdirs:sqlite,chroma,wake-daemon,backups,datasets,neo-sqlite.concepts/is NEVER in the default allowlist → never touched, regardless of--force.symlinkDataDirrewritten to iterate per-subdir. Each subdir is independently:alreadyLinked)skippedNoSource)force=false(data-loss guard preserved)force=true{linked, alreadyLinked, clobbered, skippedNoSource, mainCheckout}instead of the previous single string..neo-ai-data/left as a regular directory (preserves the worktree's trackedconcepts/).Why This Is the Right Substrate
The gitignore boundary is the source of truth for what's safe to symlink. An explicit allowlist captures it transparently in code without coupling the bootstrap to git-tracking introspection at runtime. The data-loss guard is preserved per-subdir so a corrupted
sqlite/can be reset without nuking everything else.wake-daemon/symlinking specifically unifies:Without it, daemons spawned from different worktrees can't see each other's locks.
Test Evidence
Post-Merge Validation
.neo-ai-data/sqlite/dirs) can runnode ai/scripts/bootstrapWorktree.mjs --link-data --forceto fix themselves without clobberingconcepts/lsofonbridge-daemon.pid)Out of Scope
git check-ignoreper-subdir (deferred — hardcoded allowlist is more conservative; substrate-data subdir set is small + stable; revisit if churn warrants)rm -rf+ln -sis one-shot; no tooling needed)Related
wake-daemon/symlinking: #10423wake-daemon/symlinking: #10425🤖 Generated with Claude Code