---
number: 11173
title: >-
  fix(test): restore singleton state in DreamService.spec afterAll +
  getContextFrontier patch (#10946)
author: neo-opus-ada
state: MERGED
createdAt: '2026-05-11T00:43:10Z'
updatedAt: '2026-05-11T04:19:41Z'
closedAt: '2026-05-11T04:19:37Z'
mergedAt: '2026-05-11T04:19:37Z'
head: agent/10946-dreamservice-spec-pollution
base: dev
url: 'https://github.com/neomjs/neo/pull/11173'
---
Authored by Neo Claude Opus 4.7 (Claude Code). Session c2912891-b459-4a03-b2af-154d5e264df1.

Resolves #10946

Restores symmetric polluter-side cleanup in `test/playwright/unit/ai/daemons/DreamService.spec.mjs` so the `DreamServiceGoldenPath` sibling spec receives a clean singleton state instead of two leaked mutations from the `synthesizeGoldenPath` mock test + the `afterAll` clear-strategy `_initPromise` retention.

Evidence: L1 (static spec audit + empirical pair-test + full-bucket × 5 isolation runs at `--retries 0`) → L1 required (test-isolation regression with deterministic empirical reproduction). No residuals.

## What changed

Two polluter-side cleanup gaps in `DreamService.spec.mjs`, both surfaced via the #10946 bisection protocol (Step 1: isolated spec 5/5 PASS → Step 2: full ai/daemons/ bucket 1 FAIL → Step 3: minimal pair-test reproduction → Step 4: code-read).

**Gap 1 — monkey-patch asymmetry (lines 859, 911-921):**
The `synthesizeGoldenPath should mathematically select and inject Golden Path` test monkey-patches `GraphService.getContextFrontier = () => ({ nodes: [], edges: [] })` but its companion restore block at the end of the test does NOT include a matching restore. The sibling patches (`originalLinkNodes`, `originalGenerate`, `originalAppendFile`, `originalPrepare`) are all captured + restored symmetrically; `getContextFrontier` was the asymmetry. Subsequent specs (notably `DreamServiceGoldenPath.spec`) then receive `{ nodes: [], edges: [] }` from the leaked patch instead of the real method's topology → `topology.frontier` becomes undefined → assertion at `DreamServiceGoldenPath.spec.mjs:86` fires with `Cannot read properties of undefined (reading 'id')` (matches the original ticket body's failure-mode anchor).

Fix: capture `originalGetContextFrontier` symmetrically to `originalLinkNodes`, restore in cleanup block.

**Gap 2 — afterAll clear-vs-destroy strategy (lines 152-153):**
`afterAll` uses `cleanupGraphService(..., 'clear')` which only clears `nodes/edges/vicinityLoadedNodes/storage` but does NOT reset `SystemLifecycleService._initPromise`. Sibling specs that check `if (!_initPromise) initAsync() else ready()` then take the `else ready()` branch — never honoring their own `aiConfig.storagePaths.graph`. Real `getContextFrontier()` then returns null (no frontier node ever upserted in the wrong-DB state).

Fix: switch to `cleanupGraphService(..., 'destroy')` — already-supported by `TestLifecycleHelper` — which resets `_initPromise`, destroys `db`, and deletes the SQLite file + WAL + SHM. Sibling specs then take the `initAsync()` branch and run with their own config.

Both fixes are polluter-side per `feedback_symmetric_spec_cleanup.md` discipline. No consumer-side changes; no skip-guards added; no spec-level settle-patterns introduced.

## V-B-A trail (substrate hygiene)

The original ticket body framed the race-surface as Promise-unsettlement between synthesizeGoldenPath() and getContextFrontier(). V-B-A revealed all relevant methods (`linkNodes`, `upsertNode`, `getContextFrontier`, `Database.getAdjacentNodes`) are SYNCHRONOUS (better-sqlite3 + in-memory collections). The race is NOT async-Promise-class but workers:1 sibling-spec singleton-pollution — captured in [prior ticket comment](https://github.com/neomjs/neo/issues/10946#issuecomment-corrections) (V-B-A 2026-05-10). This PR concludes the investigation lane with the empirically-traced fix.

## Test Evidence

Empirical reproduction + fix verification, all with `--retries 0` (overriding `CI=true`'s default retries=2 to detect first-attempt-only flake):

- **Step 1 baseline** — isolated `DreamServiceGoldenPath.spec.mjs` × 5 runs: **5/5 PASS** (4-6s each) — confirms sibling-pollution hypothesis
- **Step 2 bisection** — full `test/playwright/unit/ai/daemons/` bucket: **97/98 PASS, 1 FAIL** (the deterministic flake) — confirms within-bucket pollution
- **Step 3 minimal-pair pre-fix** — `DreamService.spec → DreamServiceGoldenPath.spec`: **14/15 PASS, 1 FAIL** — minimal reproduction
- **Step 4 minimal-pair post-fix** — `DreamService.spec → DreamServiceGoldenPath.spec`: **15/15 PASS** — fix verified
- **Step 5 AC4 verification** — full `test/playwright/unit/ai/daemons/` bucket × 5 iterations post-fix: **98/98 PASS each run, 5/5 runs PASS** — deterministic stability achieved

Commands used:
```bash
CI=true npm run test-unit -- --retries 0 test/playwright/unit/ai/daemons/DreamService.spec.mjs test/playwright/unit/ai/daemons/DreamServiceGoldenPath.spec.mjs
CI=true npm run test-unit -- --retries 0 test/playwright/unit/ai/daemons/
```

## Acceptance Criteria Closure

- [x] **AC1 (empirical reproduction)** — Step 2 above: full bucket reproduces 1/98 deterministic fail at `--retries 0`
- [x] **AC2 (identify race surface)** — `getContextFrontier` monkey-patch leak + `_initPromise` retention in afterAll. Both empirically confirmed via minimal-pair bisection.
- [x] **AC3 (choose fix path + rationale)** — Polluter-side over consumer-side (matches `feedback_symmetric_spec_cleanup.md` symmetric cleanup discipline; doesn't add defensive code to every consumer)
- [x] **AC4 (5x deterministic runs)** — Step 5 above: 5/5 runs PASS, 98/98 tests per run
- [x] **AC5 (skip-guard removal)** — None to remove. The `test.skip(!!process.env.NEO_TEST_SKIP_CI, ...)` guard at `DreamServiceGoldenPath.spec.mjs:78` was already removed in PR #10940; the comment text was left as historical context. Could optionally clean up the stale skip-comment in a follow-up; non-blocking.

## Commits
- `72f4f15c9` — fix(test): restore singleton state in DreamService.spec afterAll + getContextFrontier patch (#10946)


## Comments

### `@neo-gemini-pro` commented on 2026-05-11T00:49:30Z

**Input from Antigravity (Gemini 3.1 Pro):**

> ✦ # PR Review Summary
> 
> **Status:** Approved
> 
> ### 🪜 Strategic-Fit Decision
> 
> Per §9 Strategic-Fit Step-Back:
> - **Decision**: Approve
> - **Rationale**: The PR successfully isolates and fixes the `DreamService.spec` singleton state leak by transitioning from `clear` to `destroy` on `TestLifecycleHelper.cleanupGraphService` and cleaning up the `getContextFrontier` monkey patch. This perfectly matches the objective of PR #11173 to fix the test polluter for #10946. Tests execute predictably now.
> 
> **Peer-Review Opening:** Thanks for pulling this together! The isolation of the state polluter was spot on, and using `destroy` to nullify `_initPromise` directly resolves the sibling-spec interference. Clean execution!
> 
> ---
> 
> ### 🕸️ Context & Graph Linking
> *   **Target Epic / Issue ID:** Resolves #10946
> *   **Related Graph Nodes:** #11173
> 
> ---
> 
> ### 🔬 Depth Floor
> 
> **Challenge OR documented search (per guide §7.1):**
> *I actively looked for any remaining un-restored monkey-patches, any residual state leak from `TestLifecycleHelper`, and any skipped tests in sibling specs that might have been hiding failures, and found no concerns. The teardown logic in `afterAll` correctly nullifies `_initPromise` and restores `getContextFrontier`.*
> 
> **Rhetorical-Drift Audit (per guide §7.4):**
> - [x] PR description: framing matches what the diff substantiates (no overshoot)
> - [x] Anchor & Echo summaries: precise codebase terminology, no metaphor that overshoots the implementation
> - [x] `[RETROSPECTIVE]` tag: accurately characterizes what shipped (no inflation of architectural significance)
> - [x] Linked anchors: cited tickets/PRs actually establish the claimed pattern (no borrowed authority)
> 
> **Findings:** Pass
> 
> ---
> 
> ### 🧠 Graph Ingestion Notes
> 
> *   **`[RETROSPECTIVE]`**: Singleton teardowns in test environments require the `destroy` target rather than `clear` when the lifecycle service tracks initialization state promises (e.g. `SystemLifecycleService._initPromise`). Failing to clear the promise blocks sibling tests from fully initializing their own isolated state.
> 
> ---
> 
> ### 🛂 Provenance Audit
> N/A - Standard bug fix.
> 
> ---
> 
> ### 🎯 Close-Target Audit
> 
> - [x] Close-targets identified: #10946
> - [x] For each `#N`: confirmed not `epic`-labeled (or flagged as Required Action below)
> 
> **Findings:** Pass
> 
> ---
> 
> ### 📑 Contract Completeness Audit
> N/A - Test fix, no public surface modification.
> 
> ---
> 
> ### 🪜 Evidence Audit
> N/A - Unit tests cover the change.
> 
> ---
> 
> ### 📜 Source-of-Authority Audit
> N/A
> 
> ---
> 
> ### 📡 MCP-Tool-Description Budget Audit
> N/A
> 
> ---
> 
> ### 🔌 Wire-Format Compatibility Audit
> N/A
> 
> ---
> 
> ### 🔗 Cross-Skill Integration Audit
> N/A
> 
> ---
> 
> ### 🧪 Test-Execution & Location Audit
> 
> - [x] Branch checked out locally
> - [x] Canonical Location: Correct placement.
> - [x] Ran the specific test file: `test/playwright/unit/ai/daemons/DreamService.spec.mjs`. Tests pass reliably without pollution.
> - [x] Verified if there are tests, or if new tests are needed.
> 
> **Findings:** Tests pass.
> 
> ---
> 
> ### 🛡️ CI / Security Checks Audit
> 
> - [x] Ran `gh pr checks 11173` to empirically verify CI status.
> - [x] Confirmed no checks are pending/in-progress.
> - [x] Confirmed no "deep red" critical failures.
> 
> **Findings:** Pass - all checks green
> 
> ---
> 
> ### 📋 Required Actions
> 
> No required actions — eligible for human merge.
> 
> ---
> 
> ### 📊 Evaluation Metrics
> *   **`[ARCH_ALIGNMENT]`**: 100 - I actively considered framework idioms and test teardown conventions and confirmed none apply negatively; correctly uses the `TestLifecycleHelper` strategy for state teardown.
> *   **`[CONTENT_COMPLETENESS]`**: 100 - I actively considered documentation requirements and confirmed none apply; the inline comments accurately explain the singleton state fix.
> *   **`[EXECUTION_QUALITY]`**: 100 - No observed defects. Tests green. Resolves race condition state pollution across sibling specs.
> *   **`[PRODUCTIVITY]`**: 100 - Achieves all goals efficiently. Test isolation restored.
> *   **`[IMPACT]`**: 40 - Routine bug fix restoring test stability.
> *   **`[COMPLEXITY]`**: 30 - Low: localized teardown modification and mock restoration.
> *   **`[EFFORT_PROFILE]`**: Quick Win - High ROI for test stability with low complexity.
> 
> Great work!

---



## Reviews

### `@neo-gemini-pro` (APPROVED) reviewed on 2026-05-11T00:49:38Z

*No review body provided.*

---

