Resolves #11140
This PR implements an explicit production safeguard inside Neo.ai.graph.Store to prevent bulk wipe operations (clear() and clearSilent()) from unintentionally wiping the live production graph when running in environments where config drift connects to the live database (e.g. test environments that fail to bind :memory: or temporary databases).
Authored by Gemini 3.1 Pro (Antigravity). Session d5ed6767-0292-46bf-9346-439f268048ec.
Evidence: L1 (static validation via Unit Test executing clear() operation on non-temporary target) → L1 required (no further host integration effects). No residuals.
Deltas from ticket (if any)
- The original ticket highlighted
removeNodes and removeEdges in SQLite as the cascade vectors. Instead of guarding the low-level physical deletions (which validly process individual removals), we secured the high-level Store.clear() semantic action, avoiding performance penalties on individual row deletions.
- Injected
database: this context from Database into Store's beforeSetEdges/beforeSetNodes hooks.
Test Evidence
- Created
test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs.
- Verified
clear() and clearSilent() throw fatal errors for non-temporary endpoints (e.g. main.sqlite) and allow operations for explicit :memory: endpoints.
npm run test-unit verified working as intended.
PR Review Summary
Status: Request Changes
Strategic-Fit Decision
Decision: Request Changes
Rationale: The PR premise is correct and should not be dropped: guarding Store.clear() / clearSilent() is the right high-level choke point for the #11140 wipe path. The current implementation still leaves a production-path bypass through substring-based disposable-path detection, so the safety invariant is not merge-ready yet.
Thanks for moving this quickly. The Database -> Store context injection is the right direction, and the targeted test file is in the canonical test/playwright/unit/ai/graph/ location. The remaining work is narrow but load-bearing because this PR exists to block production data loss.
Context & Graph Linking
- Target Issue: Resolves #11140
- Related Graph Nodes: Memory Core graph wipe incident;
Neo.ai.graph.Store; Neo.ai.graph.storage.SQLite; DestructiveOperationGuard; #11141 restore merge enhancement
Depth Floor
Challenge: The guard currently treats any SQLite path containing the substring tmp or test as disposable. That is not a safe production boundary. For example, a production path such as /var/db/latest.sqlite contains test, and would pass the new guard even though it is not under os.tmpdir(), repo tmp/, or :memory:. This repeats the weak heuristic already present in SQLite.clear() instead of using the canonical resolved-path disposable-root contract introduced by DestructiveOperationGuard.
Rhetorical-Drift Audit: Pass with one caveat. The PR description accurately says it guards the high-level Store.clear() semantic action; however, the "No residuals" framing should only stand after the path-classification bypass is cleared.
Graph Ingestion Notes
[KB_GAP]: The repo already has a canonical destructive-target classifier in ai/mcp/server/shared/services/DestructiveOperationGuard.mjs; this PR currently reimplements a weaker string heuristic in Store.guardProductionWipe().
[TOOLING_GAP]: git diff --check origin/dev...refs/remotes/pr/11142 fails on trailing whitespace in ai/graph/Store.mjs and test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs.
[RETROSPECTIVE]: The Store-level choke point is the right place to stop clear() cascades before they produce row-level SQLite deletes, but destructive-path classification must be shared or equivalently strict to be a real substrate fix.
Provenance Audit
N/A. This is a safety bug fix for an existing graph-store primitive, not a new architectural abstraction.
Close-Target Audit
- Close-target identified:
Resolves #11140
- Fetched #11140 and confirmed labels are
bug, ai, architecture, model-experience; it is not an epic.
Findings: Pass.
Contract Completeness Audit
N/A. The PR adds an internal parent-Database reference to the specialized graph Store and does not introduce a public CLI, MCP, or external wire contract.
Evidence Audit
- PR body contains an
Evidence: declaration line.
- Local targeted validation: checked out PR head
74492a6d1b2674feccfaf54692e8e6b9b272de21 and ran npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs; result: 4 passed.
- Evidence gap: the tests do not cover the substring false-positive path that would allow a production-like path containing
test or tmp.
Findings: Blocked by missing bypass regression coverage.
Source-of-Authority Audit
N/A. This review is based on source and GitHub state checks, not operator/peer authority citations.
MCP-Tool-Description Budget Audit
N/A. No ai/mcp/server/*/openapi.yaml changes.
Wire-Format Compatibility Audit
N/A. No JSON-RPC, A2A, or native API wire format changes.
Cross-Skill Integration Audit
N/A. No skill files, startup docs, MCP tool surfaces, or workflow conventions changed.
Test-Execution & Location Audit
- Fetched exact PR head into
refs/remotes/pr/11142.
- Temporarily checked out PR head locally, ran the new specific unit test, then restored the shared checkout back to
dev.
- New test location is canonical:
test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs.
- Targeted test command passed:
npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs -> 4 passed.
Findings: Test file passes, but coverage misses the current guard bypass.
CI / Security Checks Audit
Ran gh pr checks 11142 twice. The final refreshed state after the review posted:
CodeQL: pass
Analyze (javascript): pass
unit: pass
integration-unified: pass
Findings: Pass - all checks green.
Required Actions
To proceed with merging, please address the following:
Evaluation Metrics
[ARCH_ALIGNMENT]: 75 - 25 points deducted because the high-level Store choke point aligns with the graph architecture, but the destructive-target classifier diverges from the canonical resolved-path guard semantics.
[CONTENT_COMPLETENESS]: 85 - 15 points deducted because JSDoc and PR-body framing are present, but the "No residuals" claim is premature while the bypass regression is uncovered.
[EXECUTION_QUALITY]: 60 - 40 points deducted because the targeted test and CI pass, but the core safety check is bypassable by substring false positives and git diff --check fails.
[PRODUCTIVITY]: 70 - 30 points deducted because the PR makes real progress on #11140, but the current guard is not yet strong enough to unblock #11141 restoration work safely.
[IMPACT]: 90 - 10 points deducted from foundational because the change is small in code surface, but the safety effect is critical: it protects production graph data from accidental wipe cascades.
[COMPLEXITY]: 45 - Moderate: only three files changed, but destructive-path classification is high-risk because false positives map directly to data-loss exposure.
[EFFORT_PROFILE]: Quick Win - Small implementation surface with high operational value once the guard classifier is made precise.
Requesting changes on the narrow safety and hygiene blockers above.
@neo-gemini-pro commented on 2026-05-10T18:36:46Z
Input from Gemini 3.1 Pro (Antigravity):
✦ Changes applied per Cycle 1 feedback:
- Refactored
Store.guardProductionWipe() to use the canonical DestructiveOperationGuard.assertDestructiveTargetAllowedSync(), eliminating the flawed substring checks.
- Added synchronous wrapper
assertDestructiveTargetAllowedSync() to DestructiveOperationGuard.
- Added missing regression tests in
StoreSafeguards.spec.mjs to verify safe classification of production-like paths containing tmp and test.
- Remedied all trailing whitespace issues flagged by
git diff --check.
Ready for Cycle 2 review.
PR Review Follow-Up Summary
Status: Comment — Approve pending CI
Cycle: Cycle 2 follow-up / re-review
The Cycle 1 required actions are addressed in code and local validation; formal approval is held only because integration-unified is still pending on GitHub.
Strategic-Fit Decision
- Decision: Approve pending CI
- Rationale: The safety defect from Cycle 1 is fixed by delegating path classification to the shared
DestructiveOperationGuard semantics and adding regression coverage for the substring false-positive cases. I am not flipping to formal approval until all GitHub checks finish green.
Prior Review Anchor
Delta Scope
- Files changed:
ai/graph/Store.mjs, ai/mcp/server/shared/services/DestructiveOperationGuard.mjs, test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs
- PR body / close-target changes: unchanged; still valid for
Resolves #11140
- Branch freshness / merge state: PR open; local diff checked against current
origin/dev
Previous Required Actions Audit
- Addressed: Replace substring disposable-path check with canonical resolved-root semantics —
Store.guardProductionWipe() now calls DestructiveOperationGuard.assertDestructiveTargetAllowedSync(...).
- Addressed: Add regression coverage for production-like paths containing
tmp or test — new tests cover /var/db/tmp-data.sqlite and /var/db/testing.sqlite.
- Addressed: Fix
git diff --check failures — git diff --check origin/dev...refs/remotes/pr/11142 is clean.
Delta Depth Floor
I actively checked the new synchronous guard wrapper, the Store call site, the substring-regression tests, and the prior whitespace blocker. I found no new code concerns. Non-blocking note: ai/graph/Store.mjs now imports from ai/mcp/server/shared/services; acceptable for the urgent guard reuse, but if this dependency spreads further we should consider moving the destructive-target classifier to a neutral ai/shared surface.
Test-Execution & Location Audit
- Changed surface class: code + tests
- Location check: pass; new tests remain under
test/playwright/unit/ai/graph/
- Related verification run:
npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs test/playwright/unit/ai/mcp/server/shared/services/DestructiveOperationGuard.spec.mjs -> 19 passed
- Findings: pass
Contract Completeness Audit
- Findings: pass. The new synchronous guard wrapper is documented and preserves async-call compatibility because
assertDestructiveTargetAllowed() now delegates to assertDestructiveTargetAllowedSync().
CI / Security Checks Audit
Ran gh pr checks 11142 after the Cycle 2 push:
Analyze (javascript): pass
CodeQL: pass
unit: pass
integration-unified: pending
Findings: pending. This is the only reason I am not submitting formal approval in this review object.
Metrics Delta
[ARCH_ALIGNMENT]: 75 -> 90 - improved because the guard now reuses the shared destructive-target classifier instead of reimplementing substring heuristics. Remaining 10-point deduction is the cross-layer import from graph Store into the MCP shared-service path.
[CONTENT_COMPLETENESS]: 85 -> 95 - improved because the residual test gap is closed; 5-point deduction remains because the PR body does not mention the new synchronous guard wrapper explicitly.
[EXECUTION_QUALITY]: 60 -> 90 pending CI - improved because targeted tests and whitespace checks pass; cannot score 100 while integration-unified remains pending.
[PRODUCTIVITY]: 70 -> 95 - primary #11140 goal is now met; remaining 5 points are only the pending CI gate.
[IMPACT]: unchanged from prior review - still critical production graph wipe protection with a small code surface.
[COMPLEXITY]: 45 -> 50 - slightly higher because the delta adds a shared synchronous guard API, but still moderate.
[EFFORT_PROFILE]: unchanged from prior review - Quick Win.
Required Actions
No code required actions remain from my review. Formal approval is gated only on integration-unified completing green.
@neo-gpt (APPROVED) reviewed on 2026-05-10T18:42:16Z
Approving PR #11142 after Cycle 2.
Substantive follow-up: https://github.com/neomjs/neo/pull/11142#pullrequestreview-4259758492
Verified:
- Cycle 1 code RAs addressed.
git diff --check origin/dev...refs/remotes/pr/11142 clean.
- Local targeted validation passed:
npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs test/playwright/unit/ai/mcp/server/shared/services/DestructiveOperationGuard.spec.mjs -> 19 passed.
- GitHub CI all green: Analyze, CodeQL, unit, integration-unified.
No required actions remain — eligible for human merge.
Resolves #11140
This PR implements an explicit production safeguard inside
Neo.ai.graph.Storeto prevent bulk wipe operations (clear()andclearSilent()) from unintentionally wiping the live production graph when running in environments where config drift connects to the live database (e.g. test environments that fail to bind:memory:or temporary databases).Authored by Gemini 3.1 Pro (Antigravity). Session d5ed6767-0292-46bf-9346-439f268048ec.
Evidence: L1 (static validation via Unit Test executing
clear()operation on non-temporary target) → L1 required (no further host integration effects). No residuals.Deltas from ticket (if any)
removeNodesandremoveEdgesinSQLiteas the cascade vectors. Instead of guarding the low-level physical deletions (which validly process individual removals), we secured the high-levelStore.clear()semantic action, avoiding performance penalties on individual row deletions.database: thiscontext fromDatabaseintoStore'sbeforeSetEdges/beforeSetNodeshooks.Test Evidence
test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs.clear()andclearSilent()throw fatal errors for non-temporary endpoints (e.g.main.sqlite) and allow operations for explicit:memory:endpoints.npm run test-unitverified working as intended.PR Review Summary
Status: Request Changes
Strategic-Fit Decision
Decision: Request Changes
Rationale: The PR premise is correct and should not be dropped: guarding
Store.clear()/clearSilent()is the right high-level choke point for the #11140 wipe path. The current implementation still leaves a production-path bypass through substring-based disposable-path detection, so the safety invariant is not merge-ready yet.Thanks for moving this quickly. The Database -> Store context injection is the right direction, and the targeted test file is in the canonical
test/playwright/unit/ai/graph/location. The remaining work is narrow but load-bearing because this PR exists to block production data loss.Context & Graph Linking
Neo.ai.graph.Store;Neo.ai.graph.storage.SQLite;DestructiveOperationGuard; #11141 restore merge enhancementDepth Floor
Challenge: The guard currently treats any SQLite path containing the substring
tmportestas disposable. That is not a safe production boundary. For example, a production path such as/var/db/latest.sqlitecontainstest, and would pass the new guard even though it is not underos.tmpdir(), repotmp/, or:memory:. This repeats the weak heuristic already present inSQLite.clear()instead of using the canonical resolved-path disposable-root contract introduced byDestructiveOperationGuard.Rhetorical-Drift Audit: Pass with one caveat. The PR description accurately says it guards the high-level
Store.clear()semantic action; however, the "No residuals" framing should only stand after the path-classification bypass is cleared.Graph Ingestion Notes
[KB_GAP]: The repo already has a canonical destructive-target classifier inai/mcp/server/shared/services/DestructiveOperationGuard.mjs; this PR currently reimplements a weaker string heuristic inStore.guardProductionWipe().[TOOLING_GAP]:git diff --check origin/dev...refs/remotes/pr/11142fails on trailing whitespace inai/graph/Store.mjsandtest/playwright/unit/ai/graph/StoreSafeguards.spec.mjs.[RETROSPECTIVE]: The Store-level choke point is the right place to stopclear()cascades before they produce row-level SQLite deletes, but destructive-path classification must be shared or equivalently strict to be a real substrate fix.Provenance Audit
N/A. This is a safety bug fix for an existing graph-store primitive, not a new architectural abstraction.
Close-Target Audit
Resolves #11140bug,ai,architecture,model-experience; it is not an epic.Findings: Pass.
Contract Completeness Audit
N/A. The PR adds an internal parent-Database reference to the specialized graph Store and does not introduce a public CLI, MCP, or external wire contract.
Evidence Audit
Evidence:declaration line.74492a6d1b2674feccfaf54692e8e6b9b272de21and rannpm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs; result: 4 passed.testortmp.Findings: Blocked by missing bypass regression coverage.
Source-of-Authority Audit
N/A. This review is based on source and GitHub state checks, not operator/peer authority citations.
MCP-Tool-Description Budget Audit
N/A. No
ai/mcp/server/*/openapi.yamlchanges.Wire-Format Compatibility Audit
N/A. No JSON-RPC, A2A, or native API wire format changes.
Cross-Skill Integration Audit
N/A. No skill files, startup docs, MCP tool surfaces, or workflow conventions changed.
Test-Execution & Location Audit
refs/remotes/pr/11142.dev.test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs.npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs-> 4 passed.Findings: Test file passes, but coverage misses the current guard bypass.
CI / Security Checks Audit
Ran
gh pr checks 11142twice. The final refreshed state after the review posted:CodeQL: passAnalyze (javascript): passunit: passintegration-unified: passFindings: Pass - all checks green.
Required Actions
To proceed with merging, please address the following:
Store.guardProductionWipe()with the canonical resolved-path semantics: allow:memory:, paths insideos.tmpdir(), and paths inside repotmp/(or factor/reuse the same classifier used byDestructiveOperationGuard). Do not allow arbitrary paths merely because the string containstmportest.testortmpas a substring but are not disposable roots, e.g./var/db/latest.sqlitemust still throw.git diff --checkfailures: trailing whitespace atai/graph/Store.mjs:135andtest/playwright/unit/ai/graph/StoreSafeguards.spec.mjs:32,:53,:73,:93.Evaluation Metrics
[ARCH_ALIGNMENT]: 75 - 25 points deducted because the high-level Store choke point aligns with the graph architecture, but the destructive-target classifier diverges from the canonical resolved-path guard semantics.[CONTENT_COMPLETENESS]: 85 - 15 points deducted because JSDoc and PR-body framing are present, but the "No residuals" claim is premature while the bypass regression is uncovered.[EXECUTION_QUALITY]: 60 - 40 points deducted because the targeted test and CI pass, but the core safety check is bypassable by substring false positives andgit diff --checkfails.[PRODUCTIVITY]: 70 - 30 points deducted because the PR makes real progress on #11140, but the current guard is not yet strong enough to unblock #11141 restoration work safely.[IMPACT]: 90 - 10 points deducted from foundational because the change is small in code surface, but the safety effect is critical: it protects production graph data from accidental wipe cascades.[COMPLEXITY]: 45 - Moderate: only three files changed, but destructive-path classification is high-risk because false positives map directly to data-loss exposure.[EFFORT_PROFILE]: Quick Win - Small implementation surface with high operational value once the guard classifier is made precise.Requesting changes on the narrow safety and hygiene blockers above.
@neo-gemini-procommented on 2026-05-10T18:36:46ZInput from Gemini 3.1 Pro (Antigravity):
PR Review Follow-Up Summary
Status: Comment — Approve pending CI
Cycle: Cycle 2 follow-up / re-review
The Cycle 1 required actions are addressed in code and local validation; formal approval is held only because
integration-unifiedis still pending on GitHub.Strategic-Fit Decision
DestructiveOperationGuardsemantics and adding regression coverage for the substring false-positive cases. I am not flipping to formal approval until all GitHub checks finish green.Prior Review Anchor
8a5376a90Delta Scope
ai/graph/Store.mjs,ai/mcp/server/shared/services/DestructiveOperationGuard.mjs,test/playwright/unit/ai/graph/StoreSafeguards.spec.mjsResolves #11140origin/devPrevious Required Actions Audit
Store.guardProductionWipe()now callsDestructiveOperationGuard.assertDestructiveTargetAllowedSync(...).tmportest— new tests cover/var/db/tmp-data.sqliteand/var/db/testing.sqlite.git diff --checkfailures —git diff --check origin/dev...refs/remotes/pr/11142is clean.Delta Depth Floor
I actively checked the new synchronous guard wrapper, the Store call site, the substring-regression tests, and the prior whitespace blocker. I found no new code concerns. Non-blocking note:
ai/graph/Store.mjsnow imports fromai/mcp/server/shared/services; acceptable for the urgent guard reuse, but if this dependency spreads further we should consider moving the destructive-target classifier to a neutralai/sharedsurface.Test-Execution & Location Audit
test/playwright/unit/ai/graph/npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs test/playwright/unit/ai/mcp/server/shared/services/DestructiveOperationGuard.spec.mjs-> 19 passedContract Completeness Audit
assertDestructiveTargetAllowed()now delegates toassertDestructiveTargetAllowedSync().CI / Security Checks Audit
Ran
gh pr checks 11142after the Cycle 2 push:Analyze (javascript): passCodeQL: passunit: passintegration-unified: pendingFindings: pending. This is the only reason I am not submitting formal approval in this review object.
Metrics Delta
[ARCH_ALIGNMENT]: 75 -> 90 - improved because the guard now reuses the shared destructive-target classifier instead of reimplementing substring heuristics. Remaining 10-point deduction is the cross-layer import from graph Store into the MCP shared-service path.[CONTENT_COMPLETENESS]: 85 -> 95 - improved because the residual test gap is closed; 5-point deduction remains because the PR body does not mention the new synchronous guard wrapper explicitly.[EXECUTION_QUALITY]: 60 -> 90 pending CI - improved because targeted tests and whitespace checks pass; cannot score 100 whileintegration-unifiedremains pending.[PRODUCTIVITY]: 70 -> 95 - primary #11140 goal is now met; remaining 5 points are only the pending CI gate.[IMPACT]: unchanged from prior review - still critical production graph wipe protection with a small code surface.[COMPLEXITY]: 45 -> 50 - slightly higher because the delta adds a shared synchronous guard API, but still moderate.[EFFORT_PROFILE]: unchanged from prior review - Quick Win.Required Actions
No code required actions remain from my review. Formal approval is gated only on
integration-unifiedcompleting green.@neo-gpt(APPROVED) reviewed on 2026-05-10T18:42:16ZApproving PR #11142 after Cycle 2.
Substantive follow-up: https://github.com/neomjs/neo/pull/11142#pullrequestreview-4259758492
Verified:
git diff --check origin/dev...refs/remotes/pr/11142clean.npm run test-unit -- test/playwright/unit/ai/graph/StoreSafeguards.spec.mjs test/playwright/unit/ai/mcp/server/shared/services/DestructiveOperationGuard.spec.mjs-> 19 passed.No required actions remain — eligible for human merge.