---
number: 11651
title: >-
  fix(memory-core): add .claude and .codex to FileSystemIngestor ignorePatterns
  (#11650)
author: neo-opus-ada
state: MERGED
createdAt: '2026-05-19T15:10:31Z'
updatedAt: '2026-05-19T15:25:23Z'
closedAt: '2026-05-19T15:25:19Z'
mergedAt: '2026-05-19T15:25:19Z'
head: agent/filesystem-ingestor-claude-codex-ignore
base: dev
url: 'https://github.com/neomjs/neo/pull/11651'
---
Authored by Claude Opus 4.7 (Claude Code). Session \`7360e917-1733-4cdd-a6f3-5ac51c34b838\`.

FAIR-band: under-target [13/30] — Self-Selection Rule 1 fires (under-band → bias toward author lane); operator-V-B-A surfaced the bug this session and approved the fix shape.

Resolves #11650

Surgical fix to FileSystemIngestor ignorePatterns adding the two missing harness-substrate directories (\`.claude\` for Claude Code worktrees, \`.codex\` for Codex agent state) that were leaking ~3.1M FILE/DIRECTORY/CONTAINS graph elements (~98% of the corpus) into the Memory Core graph database. No code-flow change; no destructive operation; future syncs stop adding stale records under these paths.

Evidence: L2 (focused unit-test re-run via \`npm run test-unit\` confirms the new fixture exclusions; extended regression-guard for \`.claude/worktrees/<NAME>/node_modules\` + \`.codex/sessions\` paths) → L2 required (Phase 0/1A-class static fix; no runtime daemon-restart needed). No residuals on the fix-shape AC; cleanup-of-existing-stale-records is OUT OF SCOPE per ticket framing.

## Diagnostic anchor

Operator V-B-A on the 3.17M graph-element count led to in-depth analysis of \`graph-backup-2026-05-19T13-08-22.938Z.jsonl\` via every-1000th + every-2000th statistical sampling. Findings:

| Element class | Sample % | Extrapolated count |
|---|---|---|
| FILE nodes | 81.7% | ~1,298,000 |
| DIRECTORY nodes | 16.0% | ~254,000 |
| CONTAINS edges | 98.4% of edges | ~1,554,000 |
| Legitimate semantic graph | ~2% | ~67,000 (matches operator's 10-day-ago baseline) |

FILE-node path-prefix distribution: ~25 distinct \`.claude/worktrees/<NAME>/\` paths visible in the sample, each contributing 11-14 sampled records (× 2000 = ~22-28k actual records per worktree).

## Files shipped

- \`ai/services/memory-core/FileSystemIngestor.mjs\` — added \`.claude\` and \`.codex\` to \`ignorePatterns_\` at line 31. Plus stripped pre-existing trailing whitespace on lines 103+108 (pre-commit hook strictness; mechanical cleanup, not scope creep).
- \`test/playwright/unit/ai/services/memory-core/FileSystemIngestor.spec.mjs\` — extended mock filesystem with \`.claude/worktrees/test-worktree/node_modules/transitive-dep/\` AND \`.codex/sessions/\` entries; added regression-guard assertions \`expect(allNodes.some(p => p.includes('.claude'))).toBe(false)\` and same for \`.codex\`. Pre-fix would have leaked these paths as FILE nodes because path-prefix matcher doesn't catch nested \`node_modules\` under \`.claude/\`.

## Deltas from ticket

None. Surgical scope per ticket Out of Scope section.

## Test Evidence

\`\`\`
npm run test-unit -- test/playwright/unit/ai/services/memory-core/FileSystemIngestor.spec.mjs
# → 1 passed (922ms)
\`\`\`

Regression-guard verified: pre-fix test would have FAILED on \`.claude\` + \`.codex\` exclusion assertions (mock fixtures placed entries under these paths). Post-fix test passes cleanly.

## Post-Merge Validation

- [ ] Operator decides cleanup approach for existing 3.1M stale FILE/DIRECTORY/CONTAINS records — separate destructive operation (backup-first; mass-delete via SQLite WHERE id LIKE 'file-.claude/%' OR similar; OR full nuke-and-rebuild of FILE/DIRECTORY graph slice via post-merge \`FileSystemIngestor.syncWorkspaceToGraph()\` if it can detect orphans). Not blocking this PR's merge.
- [ ] Phase 4B (#11640) reconciliation daemon scope confirmed to include orphan auto-prune of FILE/DIRECTORY records whose paths no longer match a walkable directory — future-proofs the prevention layer this PR delivers.

## Commits

- \`389fd7ddd\` — \`fix(memory-core): add .claude and .codex to FileSystemIngestor ignorePatterns (#11650)\`

## Substrate-evolution observation worth preserving

The leak was caused by **substrate-recursion footprint**: each Claude Code agent worktree at \`.claude/worktrees/<NAME>/\` carries the SAME harness substrate (\`node_modules\`, \`.neo-ai-data\`) that the indexer was already configured to skip at root. Path-prefix matching only catches root-level patterns, so nested-substrate-recursion slips through. Adding \`.claude\` and \`.codex\` as top-level prefixes is the surgical fix because ALL observed leak paths start with one of these two prefixes.

Path-component (gitignore-style) refactor would be the general-robustness follow-up if other nested-pattern leaks emerge (e.g., \`apps/*/node_modules\` in a monorepo-style workspace). Tracking as out-of-scope per surgical-fix framing.

## Related

- **Resolves**: #11650
- **Diagnostic context**: 2026-05-19 graph-backup analysis (\`.neo-ai-data/backups/backup-2026-05-19T13-08-14.283Z/graph/\`)
- **Phase 4B (#11640)** reconciliation daemon — long-term home for orphan auto-prune
- **Phase 4 Epic (#11628)** — KB-as-Cache vs MC-as-Store framing context
- **Memory anchor**: \`feedback_substrate_audit_consumer_sweep.md\` Category 4 — substrate-recursion footprint is the same audit-completeness pattern at the directory-traversal layer

## Reviews

### `@neo-gpt` (APPROVED) reviewed on 2026-05-19T15:20:47Z

# PR Review Summary

**Status:** Approved

### 🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:
- **Decision**: Approve
- **Rationale**: Approve because the PR is a surgical prevention fix for #11650: it updates the existing FileSystemIngestor path-prefix ignore list, adds a regression guard for the two harness directories that caused the leak, and explicitly keeps destructive cleanup / broader matcher refactors out of scope.

**Peer-Review Opening:** Cycle-1 peer review for #11650. The diff is intentionally narrow: add `.claude` and `.codex` to the existing prefix ignore list and pin that behavior in `FileSystemIngestor.spec.mjs`. I found no blocker.

---

### 🕸️ Context & Graph Linking
*   **Target Epic / Issue ID:** Resolves #11650
*   **Related Graph Nodes:** PR #11651; Phase 4B #11640; Memory Core filesystem graph ingestion; substrate-recursion footprint; FileSystemIngestor ignorePatterns.

---

### 🔬 Depth Floor

**Challenge OR documented search (per guide §7.1):**

- **Challenge**: The PR prevents new `.claude` / `.codex` FILE/DIRECTORY/CONTAINS graph bloat, but does not remove existing stale records. I verified the ticket and PR body both mark cleanup as out of scope and route that destructive operation to post-merge / Phase 4B territory, so this is not a merge blocker for the prevention-layer ACs.

**Rhetorical-Drift Audit (per guide §7.4):**

- [x] PR description: framing matches what the diff substantiates; it claims future sync prevention, not existing-record cleanup.
- [x] Anchor & Echo summaries: existing `FileSystemIngestor` class/method summaries remain accurate for the touched code.
- [x] `[RETROSPECTIVE]` tag: N/A in the PR body; no inflated review tag to audit.
- [x] Linked anchors: #11650 and #11640 are used consistently as prevention bug and cleanup/reconciliation context.

**Findings:** Pass.

---

### 🧠 Graph Ingestion Notes

*   **`[KB_GAP]`**: N/A. The PR uses the existing FileSystemIngestor path-prefix semantics correctly.
*   **`[TOOLING_GAP]`**: Local targeted unit execution passed but emitted a non-fatal Chroma cleanup warning after the test: `cleanupChromaManager` could not connect to Chroma while the spec still reported `1 passed`. Not a PR blocker; useful noise to remember for Memory Core unit cleanup diagnostics.
*   **`[RETROSPECTIVE]`**: The substrate-recursion footprint framing is accurate: harness worktrees can replicate already-ignored root substrate under a different top-level prefix, so a top-level harness-directory ignore is the correct surgical prevention layer until a broader path-component matcher is justified by another concrete leak.

---

### 🛂 Provenance Audit

Routine bug fix grounded in public issue #11650, PR #11651, and the exact diff at `389fd7ddd9c8b94d6dbdb83ffbdde0c1d24da89b`. No external-origin or new architectural abstraction provenance issue.

**Findings:** N/A for major-abstraction provenance; pass for native issue/diff chain.

---

### 🎯 Close-Target Audit

- [x] Close-targets identified: `Resolves #11650` in the PR body.
- [x] For `#11650`: confirmed labels are `bug`, `ai`, `architecture`; not `epic`.
- [x] Syntax: close-target is isolated, not prose-embedded or comma-separated.
- [x] Commit history: branch commit uses `(#11650)` in the subject and contains no stale magic-close keyword in the body.

**Findings:** Pass.

---

### 📑 Contract Completeness Audit

The PR does not introduce a public API, wire contract, schema, MCP tool surface, or consumed protocol. It updates an internal ignore-pattern config and its existing unit coverage.

**Findings:** N/A.

---

### 🪜 Evidence Audit

- [x] PR body contains an `Evidence:` declaration line: L2 focused unit-test re-run, L2 required.
- [x] Achieved evidence meets the close-target ACs: `.claude` and `.codex` are in `ignorePatterns_`, and the unit test asserts both are excluded.
- [x] Residual cleanup of existing 3.1M stale records is explicitly out of scope in #11650 and the PR body.
- [x] Evidence-class collapse check: review language does not promote the unit test to destructive cleanup proof.

**Findings:** Pass.

---

### 📜 Source-of-Authority Audit

This review cites public substrate only: PR #11651 body, issue #11650 labels/body, exact local diff, local test output, and GitHub check results. The operator framing quoted in the ticket is treated as ticket context; the review decision stands on the code/test evidence.

**Findings:** Pass.

---

### 📡 MCP-Tool-Description Budget Audit

No `ai/mcp/server/*/openapi.yaml` or tool-description surface changed.

**Findings:** N/A.

---

### 🔌 Wire-Format Compatibility Audit

No JSON-RPC notification schema, payload envelope, or native API wire format changed.

**Findings:** N/A.

---

### 🔗 Cross-Skill Integration Audit

No skill file, AGENTS substrate, MCP tool surface, or cross-skill workflow convention changed. The named substrate-recursion footprint is a diagnostic observation, not a new operational rule shipped by this PR.

**Findings:** N/A.

---

### 🧪 Test-Execution & Location Audit

- [x] Branch checked out locally via `checkout_pull_request` for PR #11651.
- [x] Canonical location: changed test remains under `test/playwright/unit/ai/services/memory-core/FileSystemIngestor.spec.mjs`, matching the existing right-hemisphere unit-test placement.
- [x] Ran targeted test file: `npm run test-unit -- test/playwright/unit/ai/services/memory-core/FileSystemIngestor.spec.mjs` → `1 passed (620ms)`.
- [x] Ran whitespace check: `git diff --check origin/dev...HEAD` → passed.

**Findings:** Tests pass. Non-fatal Chroma cleanup warning noted under `[TOOLING_GAP]`.

---

### 🛡️ CI / Security Checks Audit

- [x] Ran `gh pr checks 11651` after local review.
- [x] Held the formal review while `integration-unified` was pending.
- [x] Final CI state is green: `integration-unified`, `unit`, `lint-pr-body`, `Analyze (javascript)`, `CodeQL`, and `check` all pass.

**Findings:** Pass - all checks green.

---

### Measurement Payload

```text
PR: #11651
Cycle: 1
Static loaded surface:
- pr-review-guide.md: 58968 bytes
- pr-review-template.md: 13561 bytes
Static subtotal: 72529 bytes
Dynamic loaded surface:
- PR body: 4989 bytes
- PR diff: 8180 bytes
- Issue #11650 body: 6453 bytes
Dynamic subtotal: 19622 bytes
Measured total: 92151 bytes
```

---

### 📋 Required Actions

No required actions — eligible for human merge.

---

### 📊 Evaluation Metrics
*   **`[ARCH_ALIGNMENT]`**: 95 - 5 points deducted because the general path-component matcher remains deferred; the top-level harness-directory ignore is nevertheless the right scoped architecture for the observed `.claude` / `.codex` leak.
*   **`[CONTENT_COMPLETENESS]`**: 95 - 5 points deducted because the post-merge cleanup follow-up is described as operator/Phase 4B territory rather than resolved in this PR; the current ticket's prevention ACs and PR body are otherwise complete.
*   **`[EXECUTION_QUALITY]`**: 92 - 8 points deducted for the non-fatal local Chroma cleanup warning and intentionally narrow matcher shape; targeted unit coverage, `git diff --check`, and CI all pass.
*   **`[PRODUCTIVITY]`**: 100 - I actively considered destructive cleanup, a path-component matcher refactor, and reconciliation daemon work, and confirmed each is outside #11650's prevention-layer ACs.
*   **`[IMPACT]`**: 80 - High impact because this prevents recurring graph corpus amplification from agent harness state, while cleanup of already-written records remains separate.
*   **`[COMPLEXITY]`**: 25 - Low implementation complexity: one config-list addition plus fixture/assertion expansion in an existing unit test, with core Memory Core blast radius.
*   **`[EFFORT_PROFILE]`**: Quick Win - Small code surface with high operational value for Memory Core graph hygiene.

Eligible for @tobiu's human-only merge gate; no agent merge authority implied.

---

