---
id: 11846
title: 'Sub 10: Cross-daemon services bucket (ai/services/graph/ + ai/services/ingestion/)'
state: CLOSED
labels:
  - enhancement
  - ai
  - refactoring
  - architecture
assignees:
  - neo-opus-ada
createdAt: '2026-05-23T13:54:05Z'
updatedAt: '2026-06-07T17:14:54Z'
githubUrl: 'https://github.com/neomjs/neo/issues/11846'
author: neo-opus-ada
commentsCount: 0
parentIssue: 11831
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy:
  - '[x] 11844 Sub 8: Orchestrator-cluster co-location (ai/daemons/orchestrator/) + daemon.mjs naming + test mirror + package.json'
blocking: []
closedAt: '2026-05-23T15:44:48Z'
---
# Sub 10: Cross-daemon services bucket (ai/services/graph/ + ai/services/ingestion/)

## Parent Epic

#11831 — Sub 10 of Epic (folder-structure cleanup; cross-daemon services bucket).

## Scope

Move cross-daemon services (no single daemon owns them) into thematic `ai/services/{graph,ingestion}/` folders. These services serve multiple consumers (orchestrator + sub-daemons + scripts).

## Source moves

`ai/daemons/services/` → `ai/services/graph/`:
- `GapInferenceEngine.mjs`
- `GoldenPathSynthesizer.mjs`
- `GraphMaintenanceService.mjs`
- `LazyEdgeDrainer.mjs`
- `SemanticGraphExtractor.mjs`
- `TopologyInferenceEngine.mjs`

`ai/daemons/services/` → `ai/services/ingestion/`:
- `ConceptDiscoveryService.mjs`
- `ConceptIngestor.mjs`
- `IssueIngestor.mjs`
- `MemorySessionIngestor.mjs`

After this Sub: `ai/daemons/services/` is EMPTY and can be removed (Orchestrator's private services already moved to `ai/daemons/orchestrator/services/` in Sub 8; sub-daemon services moved to per-daemon folders in Sub 9). Verify no stale services remain before removing the folder.

## Test moves (mirror source)

`test/playwright/unit/ai/daemons/services/` → `test/playwright/unit/ai/services/graph/`:
- `GoldenPathSynthesizer.spec.mjs`
- `LazyEdgeDrainer.spec.mjs`
- `SemanticGraphExtractor.spec.mjs`

`test/playwright/unit/ai/daemons/services/` → `test/playwright/unit/ai/services/ingestion/`:
- `ConceptDiscoveryService.spec.mjs`
- `ConceptIngestor.spec.mjs`
- `IssueIngestor.spec.mjs`
- `MemorySessionIngestor.spec.mjs`

(GapInferenceEngine, GraphMaintenanceService, TopologyInferenceEngine specs don't currently exist.)

## package.json

(none affected — cross-daemon services have no direct npm entry-script targets)

## .github/workflows

(none affected)

## Integration tests

Audit + update any integration tests referencing `ai/daemons/services/{Concept,Issue,Memory,Gap,GoldenPath,Graph,Lazy,Semantic,Topology}*` → `ai/services/{graph,ingestion}/*`.

## Acceptance Criteria

1. 10 source moves completed.
2. ~7 test moves completed.
3. Cross-codebase imports updated.
4. `ai/daemons/services/` removed (empty after Sub 8 + Sub 9 + Sub 10).
5. All affected unit + integration specs pass.

## Depends on

Sub 8 #11844 + Sub 9 (must merge first — they free `ai/daemons/services/` of orchestrator-private + sub-daemon-specific files).

**Authored by:** [Claude Opus 4.7] (Claude Code)

## Timeline

- 2026-05-23T13:54:06Z @neo-opus-ada assigned to @neo-opus-ada
- 2026-05-23T13:54:06Z @neo-opus-ada added the `enhancement` label
- 2026-05-23T13:54:06Z @neo-opus-ada added the `ai` label
- 2026-05-23T13:54:06Z @neo-opus-ada added the `refactoring` label
- 2026-05-23T13:54:06Z @neo-opus-ada added the `architecture` label
- 2026-05-23T13:55:26Z @neo-opus-ada added parent issue #11831
- 2026-05-23T13:57:02Z @neo-opus-ada marked this issue as being blocked by #11844
- 2026-05-23T14:14:11Z @neo-opus-ada referenced in commit `f81d189` - "refactor(agentos): orchestrator-cluster co-location ai/daemons/orchestrator/ + daemon.mjs (#11844)

Sub 8 of Epic #11831. Move Orchestrator's cluster into self-contained
ai/daemons/orchestrator/{,services/} folder. Entry-script renamed to
daemon.mjs (folder context provides daemon identity).

13 source moves + 12 test moves (mirror structure) + ai/services.mjs +
7 buildScripts/ai/ consumer-import updates + package.json ai:orchestrator
path update.

Tests: 119/119 pass (6.6s).

Subsequent subs filed: Sub 9 #11845, Sub 10 #11846, Sub 11 #11847, Sub 12 #11848."
- 2026-05-23T14:14:46Z @neo-opus-ada cross-referenced by PR #11849
- 2026-05-23T14:57:05Z @tobiu referenced in commit `6cc9179` - "refactor(agentos): orchestrator-cluster co-location ai/daemons/orchestrator/ + daemon.mjs (#11844) (#11849)

* refactor(agentos): orchestrator-cluster co-location ai/daemons/orchestrator/ + daemon.mjs (#11844)

Sub 8 of Epic #11831. Move Orchestrator's cluster into self-contained
ai/daemons/orchestrator/{,services/} folder. Entry-script renamed to
daemon.mjs (folder context provides daemon identity).

13 source moves + 12 test moves (mirror structure) + ai/services.mjs +
7 buildScripts/ai/ consumer-import updates + package.json ai:orchestrator
path update.

Tests: 119/119 pass (6.6s).

Subsequent subs filed: Sub 9 #11845, Sub 10 #11846, Sub 11 #11847, Sub 12 #11848.

* test(agentos): update laneC spec HeavyMaintenanceLeaseService path post-move (#11844)

Sub 8 #11844 moved HeavyMaintenanceLeaseService into
ai/daemons/orchestrator/services/. laneCManualScriptLeaseAdoption.spec.mjs
content-verifies that buildScripts/ai/{runSandman,syncKnowledgeBase,backup,
syncGithubWorkflow}.mjs import the lease service from the canonical path.
2 path assertions updated (regex on line 61 + toContain on line 173) to
match the new location.

The 7 laneC test failures were entirely path-string assertions; tests pass
post-update. Other 21 unit-test failures observed are PRE-EXISTING flakes
unrelated to Sub 8 (verified via git stash baseline) — grid/vdom/checkSunsetted
tests fail on origin/dev too, separate test-isolation/timing concerns.

* fix(agentos): update MailboxService.spec dynamic import for SwarmHeartbeatService post-move (#11844)

Sub 8 co-located SwarmHeartbeatService into ai/daemons/orchestrator/services/
but my static-import sweep regex (`from '...'`) missed dynamic `await import(...)`
call-sites. CI unit job 26335211375 caught: MailboxService.spec.mjs:49
`await import('../../../../../../ai/daemons/SwarmHeartbeatService.mjs')`
threw `Cannot find module`.

Fix: insert `/orchestrator/services` into the dynamic-import path. Local
re-run: 59/59 tests pass.

V-B-A miss anchor: prior turn claimed "Sub 8 introduces ZERO new failures
with NEO_TEST_SKIP_CI=true"; CI's full unit run without that flag exposed
the stale dynamic-import. Next sweep tooling for cross-cutting moves must
cover dynamic `await import()` call-sites, not just static `from '...'`.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T15:18:44Z @neo-opus-ada cross-referenced by PR #11850
- 2026-05-23T15:34:48Z @neo-opus-ada cross-referenced by PR #11851
- 2026-05-23T15:44:48Z @tobiu closed this issue
- 2026-05-23T16:01:17Z @neo-opus-ada cross-referenced by PR #11852
- 2026-05-23T17:00:28Z @neo-opus-ada cross-referenced by PR #11853
- 2026-06-07T08:16:43Z @neo-gpt cross-referenced by #11831

