---
id: 11005
title: Align Neo classNames with flat SDK locations (M6 follow-up sweep)
state: CLOSED
labels:
  - enhancement
  - ai
  - refactoring
  - architecture
  - model-experience
assignees:
  - neo-opus-ada
createdAt: '2026-05-09T10:14:16Z'
updatedAt: '2026-05-12T02:09:06Z'
githubUrl: 'https://github.com/neomjs/neo/issues/11005'
author: neo-opus-ada
commentsCount: 2
parentIssue: 10986
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-05-09T11:18:07Z'
---
# Align Neo classNames with flat SDK locations (M6 follow-up sweep)

## Context

Filed 2026-05-09 after @tobiu caught a substrate-discipline failure on PR [#11001](https://github.com/neomjs/neo/pull/11001) Cycle review (MC migration sub-4 of M6 epic [#10986](https://github.com/neomjs/neo/issues/10986)): all 4 M6 sub-issues (#10991 KB, #10993 GH-WF, #10994 NL, #10996 MC) physically moved service classes from `ai/mcp/server/<server>/services/` to the flat `ai/services/<server>/` SDK boundary BUT did not update the corresponding `Neo.setupClass()` className strings.

Result: the four M6-migrated server families now have **systemic drift between file location and Neo class registry namespace**:

- File at `ai/services/memory-core/GraphService.mjs`
- className still `Neo.ai.mcp.server.memory-core.services.GraphService`

Operator's framing: *"if you did not update neo classNames, inside the migration, this is an utter failure and requires new tickets."*

The cited rationale on M6 sub-issues — *"Renaming MC services or class names — physical move only"* — was misread. "Physical move only" was meant to constrain the migration to physical relocation **including** namespace alignment, not to forbid namespace updates. Per Neo conventions (`@class Neo.<path>` mirrors file path; KB indexing, Native Edge Graph hierarchy traversal, and class-introspection tooling all rely on this mirror), a physical move without namespace update violates the convention.

## The Problem

54-ish className strings across 4 server families now lie about their location. Concrete fallout:

1. **Knowledge Base indexing** — `mcp__neo-mjs-knowledge-base__get_class_hierarchy` and `query_documents` rely on className-to-file-path resolution. Stale className causes wrong-file lookups or empty results.
2. **Native Edge Graph hierarchy** — class-tree traversal in NEG uses className as the canonical identifier; child-class-of-X queries on the old namespace will return migrated classes that no longer live there.
3. **Agent introspection tooling** — `inspect_class` and `get_method_source` derive expected file paths from className; agents will fail to resolve OR resolve to the wrong path expectation.
4. **Documentation drift** — every JSDoc `@class Neo.ai.mcp.server.<server>.services.X` and `@member className=...` block in the 54 affected classes is now structurally wrong. KB doc pipeline ingests these as authoritative.
5. **Future-reader confusion** — humans + agents navigating from `ai/services/memory-core/GraphService.mjs` see className `Neo.ai.mcp.server.memory-core.services.GraphService`, then can't reverse-derive the new location.

The runtime DOES NOT crash because Neo's class registry uses className as a registry key (string-equality lookup), not as a path-derivation rule. So CI passed for KB + GH-WF + NL merges and currently passes for MC PR #11001. The drift is silent at runtime, loud in tooling and documentation surfaces.

## The Architectural Reality

Neo's `Neo.setupClass(Class)` uses `Class.config.className` as the registry key under `globalThis.Neo`. Two consumers depend on className-mirrors-path:

- `Neo.create('Neo.ai.X.Y.Z')` resolves the class via the registry; works regardless of file location IF the registry was populated correctly. Migration-time module loading still triggers `Neo.setupClass`, so the class IS in the registry. But the registry key now disagrees with the file system.
- `learn/agentos/CodebaseOverview.md` + ChromaDB-indexed source content map className → file path for documentation/AI tooling. KB embeddings include `@class` JSDoc tags as semantic anchors. Stale anchors mis-direct semantic search.

Neo conventions per `learn/guides/fundamentals/CodebaseOverview.md` and `core/Base.mjs` JSDoc precedent: **className mirrors file path**. The physical migration should preserve that mirror. Sub-issues #10991/#10993/#10994/#10996 all violated it.

**Affected files (per `grep -h "className.*Neo\.ai" ai/services/<server>/*.mjs`):**

| Server | className count | OLD prefix | NEW prefix (target) |
|---|---|---|---|
| Knowledge Base | ~10 | `Neo.ai.mcp.server.knowledge-base.services.X` | `Neo.ai.services.knowledge-base.X` |
| GitHub Workflow | ~13 | `Neo.ai.mcp.server.github-workflow.services.X` (+ `.sync.X`, `.queries.X`) | `Neo.ai.services.github-workflow.X` (+ `.sync.X`, `.queries.X`) |
| Neural Link | ~9 | `Neo.ai.mcp.server.neural-link.services.X` | `Neo.ai.services.neural-link.X` |
| Memory Core | ~22 | `Neo.ai.mcp.server.memory-core.services.X` (+ `.lifecycle.X`, `.managers.X`) | `Neo.ai.services.memory-core.X` (+ `.lifecycle.X`, `.managers.X`) |

Total: ~54 className strings + corresponding `@member className=...` JSDoc tags.

## The Fix

Mechanical regex sweep across the 4 affected `ai/services/<server>/` directories:

For each migrated service:
1. Update `className: 'Neo.ai.mcp.server.<server>.services.X'` → `className: 'Neo.ai.services.<server>.X'`
2. Update `@member {String} className='Neo.ai.mcp.server.<server>.services.X'` JSDoc tag (paired)
3. Update `@class Neo.ai.mcp.server.<server>.services.X` JSDoc tag (where present)
4. Preserve sub-namespaces:
   - MC `.services.lifecycle.X` → `.lifecycle.X`
   - MC `.managers.X` → `.managers.X`
   - GH-WF `.services.sync.X` → `.sync.X`
   - GH-WF `.services.queries.X` → `.queries.X`

Per-server regex examples:

```bash
# Memory Core flat services (top-level)
sed -i '' "s|Neo\.ai\.mcp\.server\.memory-core\.services\.|Neo.ai.services.memory-core.|g" ai/services/memory-core/*.mjs
# (then specific sub-namespace passes for lifecycle/managers, etc.)
```

Recommended approach: write a one-shot `buildScripts/ai/_align_classnames.mjs` migration helper (mirroring the M6 migration script pattern), run it, delete in same PR.

**No runtime-behavior change.** The Neo class registry repopulates under the new keys at `Neo.setupClass()`; consumers using `Neo.create('Neo.ai.X.Y.Z')` need their references updated only if they explicitly hardcoded the old fully-qualified namespace (rare; the SDK-aliasing layer in `ai/services.mjs` is the proper consumer interface).

## Acceptance Criteria

- [ ] **AC1:** All ~54 `className: '...'` config strings updated across the 4 M6-migrated server directories (`ai/services/{knowledge-base,github-workflow,neural-link,memory-core}/`).
- [ ] **AC2:** All paired `@member {String} className='...'` JSDoc tags updated to match (1:1 with AC1).
- [ ] **AC3:** All `@class Neo.ai.mcp.server.<server>.services.X` JSDoc tags updated to `@class Neo.ai.services.<server>.X` form.
- [ ] **AC4:** Sub-namespace structure preserved: MC `.lifecycle.X` + `.managers.X`; GH-WF `.sync.X` + `.queries.X`.
- [ ] **AC5:** No runtime regressions: full `npm run test-unit` baseline pre/post comparison; full `npm run test-integration` for affected scopes; expected delta = 0 new failures.
- [ ] **AC6:** Hardcoded old-namespace references in consumer code (other `ai/`, `buildScripts/ai/`, `test/playwright/` directories) audited via `grep -rn "Neo\.ai\.mcp\.server\.<server>\.services"` — every match either updated or explicitly justified as a string-literal that survives className renames (e.g., wire-format strings, error-message templates).
- [ ] **AC7:** KB index re-built post-merge (`npm run ai:build-kb` or equivalent) so semantic search picks up the new className anchors. Verify via `ask_knowledge_base(query='GraphService class')` — top result should reference `Neo.ai.services.memory-core.GraphService`, not the old namespace.
- [ ] **AC8:** Test-spec assertion sweep: any `expect(X.className).toBe('Neo.ai.mcp.server...')` or similar regex-literal assertion updated (mirrors the bulk-migration regex-edge-case from PR #11001 fix `0be1f622d`).
- [ ] **AC9:** Native Edge Graph re-ingestion: confirm class-hierarchy queries (`mcp__neo-mjs-neural-link__get_class_hierarchy`) return the migrated classes under the new namespace prefix.

## Out of Scope

- **Renaming the SHORT class name** (e.g., `GraphService → SomethingElse`). Convention preserved.
- **Reshaping the SDK aliasing layer** (`Memory_*`, `KB_*`, `GH_*`, `NeuralLink_*` aliases in `ai/services.mjs`). Aliases are stable consumer API.
- **Changing `Neo.setupClass()` semantics or class-registry behavior**. Pure data update.
- **Consolidating the per-server namespaces** (e.g., flattening `memory-core` and `knowledge-base` into a unified `services` namespace). Server-family identity preserved.
- **Updating the OLD `Neo.ai.mcp.server.<server>` namespace in non-migrated code** (config.mjs, logger.mjs, openapi.yaml, Server.mjs, shared/ helpers — these stay at server level and keep the original namespace).

## Avoided Traps / Gold Standards Rejected

- **Rejected: hold M6 epic closeout until className sweep lands.** The four physical migrations are independently shippable; merging them without className alignment is a known-narrow gap that this ticket explicitly captures. M6 closes on physical-move-complete.
- **Rejected: retroactively patch className updates into PR [#11001](https://github.com/neomjs/neo/pull/11001) (open at filing time).** Scope-creep during cross-family review; would force re-review on a now-clean PR. Better to merge #11001 as-is (consistent with KB+GH-WF+NL precedent) and close the systemic gap in this dedicated follow-up.
- **Rejected: per-server follow-up tickets (4 separate sub-issues).** Single-ticket scope is mechanical regex sweep across 4 dirs; splitting creates artificial coordination overhead without granularity benefit.
- **Rejected: fold this into the v13 release-gate ticket [#11003](https://github.com/neomjs/neo/issues/11003).** That's a Dockerized remote MCP transport proof; mixing a cosmetic-namespace sweep with a release-gate test bloats both.

## Related

- **Parent epic:** [#10986](https://github.com/neomjs/neo/issues/10986) — Migrate Tier-1 MCP services to flat SDK boundary (M6). Drift originates here. Linked as **Related** rather than sub-issue, since M6 closes on the physical migrations regardless.
- **Migrated PRs that introduced the drift:**
  - [#10995](https://github.com/neomjs/neo/pull/10995) — KB (#10991), MERGED
  - [#10997](https://github.com/neomjs/neo/pull/10997) — GH-WF (#10993), MERGED
  - [#10998](https://github.com/neomjs/neo/pull/10998) — NL (#10994), MERGED
  - [#11001](https://github.com/neomjs/neo/pull/11001) — MC (#10996), OPEN at filing
- **Strategic anchor:** [`learn/agentos/v13-path.md`](https://github.com/neomjs/neo/blob/dev/learn/agentos/v13-path.md) §3 D4 + §4 M6
- **Convention reference:** `learn/guides/fundamentals/CodebaseOverview.md` (className-mirrors-file-path); `src/core/Base.mjs` `setupClass` registry-key behavior

Origin Session ID: `c2912891-b459-4a03-b2af-154d5e264df1`

Retrieval Hint: `query_raw_memories(query="M6 SDK migration className drift Neo.ai.mcp.server.services flat namespace alignment KB GH-WF NL MC follow-up sweep")`

## Timeline

- 2026-05-09T10:14:17Z @neo-opus-ada added the `enhancement` label
- 2026-05-09T10:14:17Z @neo-opus-ada added the `ai` label
- 2026-05-09T10:14:17Z @neo-opus-ada added the `refactoring` label
- 2026-05-09T10:14:17Z @neo-opus-ada added the `architecture` label
- 2026-05-09T10:14:18Z @neo-opus-ada added the `model-experience` label
- 2026-05-09T10:14:18Z @neo-opus-ada added the `release:v13` label
- 2026-05-09T10:14:24Z @neo-opus-ada added parent issue #10986
### @neo-opus-ada - 2026-05-09T10:17:28Z

**Input from Claude Opus 4.7 (Claude Code 1M-context):**

> ❋ ## Calibration delta from @tobiu
> 
> Two corrections to the original ticket body:
> 
> ### 1. Sequencing constraint — wait for in-flight M6 PRs to merge
> 
> The sweep MUST run **after** the still-open M6 PRs merge into `dev`:
> 
> - PR [#11001](https://github.com/neomjs/neo/pull/11001) (MC migration #10996) — currently in cross-family review with @neo-gpt, all CI green, mergeStateStatus CLEAN.
> - PR [#11004](https://github.com/neomjs/neo/pull/11004) (v13 release-gate test #11003, technically not className-affected but Gemini iterating on Cycle 3) — does not block this sweep specifically, but tracking for swarm bandwidth.
> 
> Running the sweep on a branch forked off current `dev` while #11001 is open would:
> - Create merge conflicts at every `ai/services/memory-core/*.mjs` file in #11005's branch (since #11001 also touches them post-rebase).
> - Force #11005's sweep to land on each in-flight feature branch separately, multiplying coordination overhead.
> - Risk a partial-state where some servers' classNames are aligned and others are not, depending on which migration PR shipped when.
> 
> **Correct sequence:** merge #11001 → run sweep on top of clean dev → file PR for #11005. KB + GH-WF + NL are already merged so they accept the sweep cleanly; only the MC family is the in-flight gate.
> 
> ### 2. Concrete occurrence count per file — 3, not 1
> 
> Each affected class file carries the className string in **3 distinct surfaces** (per @tobiu):
> 
> 1. **Module-level JSDoc comment** — `@class Neo.ai.mcp.server.<server>.services.X` (above the class declaration)
> 2. **Config JSDoc tag** — `@member {String} className='Neo.ai.mcp.server.<server>.services.X'` (above the `static config` block)
> 3. **Config value** — `className: 'Neo.ai.mcp.server.<server>.services.X',` (inside the `static config = { ... }` block)
> 
> So with ~54 migrated classes:
> - ~54 × 3 = **~162 base string updates** in source files
> - + cross-reference `@see` JSDoc tags pointing to migrated classes (variable per file)
> - + error-message / log-statement strings that embed className (audit via grep, AC6)
> - + test-spec assertions on className (audit via grep, AC8)
> 
> A single regex substitution per server-namespace covers all 3 forms in one pass since they share the same fully-qualified namespace prefix. Per-server bash sketch:
> 
> ```bash
> # Memory Core flat services (top-level)
> find ai/services/memory-core -maxdepth 1 -name '*.mjs' \
>   -exec sed -i '' "s|Neo\.ai\.mcp\.server\.memory-core\.services\.|Neo.ai.services.memory-core.|g" {} +
> 
> # MC lifecycle subdir
> find ai/services/memory-core/lifecycle -name '*.mjs' \
>   -exec sed -i '' "s|Neo\.ai\.mcp\.server\.memory-core\.services\.lifecycle\.|Neo.ai.services.memory-core.lifecycle.|g" {} +
> 
> # MC managers subdir (different prefix — sibling of services/, not nested)
> find ai/services/memory-core/managers -name '*.mjs' \
>   -exec sed -i '' "s|Neo\.ai\.mcp\.server\.memory-core\.managers\.|Neo.ai.services.memory-core.managers.|g" {} +
> 
> # (Repeat per server with appropriate sub-namespace handling)
> ```
> 
> Practical implementation — Node script (mirrors the `_migrate_mc_test_paths.mjs` pattern from PR #11001 which respected `claudeMd §11`'s sed-ban): write `buildScripts/ai/_align_classnames.mjs`, run it, delete in same PR.
> 
> ### AC corrections
> 
> - **AC1** restated: All ~54 affected classes get 3 className occurrences updated (module `@class` JSDoc + config `@member` JSDoc + config value), totaling ~162 base updates.
> - **AC2 + AC3** are now subsumed by the corrected AC1 (the 3-occurrence pattern was previously framed as separate ACs; consolidating).
> - AC4-AC9 unchanged.
> 
> ### Lane claim
> 
> Per `feedback_lead_role_decision_thresholds` and the natural sequencing: I'll execute the sweep myself once #11001 merges, unless @neo-gemini-pro or @neo-gpt explicitly claims the lane. No need for a parallel claim cycle — the prerequisite is the merge gate, not bandwidth allocation right now.
> 
> Origin Session ID: `c2912891-b459-4a03-b2af-154d5e264df1`

- 2026-05-09T10:20:24Z @neo-gpt cross-referenced by PR #11001
### @neo-opus-ada - 2026-05-09T10:21:57Z

**Input from Claude Opus 4.7 (Claude Code 1M-context):**

> ❋ ## Calibration delta #2 — full top-level JSDoc surface audit
> 
> @tobiu prompted "what about top level class comments => intents?". Audited all 4 M6-migrated server directories; confirmed the canonical 3-per-class pattern is the **base case**, with additional conditional namespace-string surfaces in top-level JSDoc that share the same regex prefix.
> 
> ### Five surface types (not three)
> 
> | # | Surface | Location | Mandatory per class? | Updates per regex pass? |
> |---|---|---|---|---|
> | 1 | `@class Neo.ai.X.Y.Z` | Module-level JSDoc above class declaration | Yes (Neo convention) | Yes — same prefix |
> | 2 | `@extends Neo.ai.X.Y.Z` | Module-level JSDoc, when subclassing another migrated class | Conditional | Yes — same prefix (when applicable) |
> | 3 | `@see Neo.ai.X.Y.Z` | Module-level JSDoc cross-references | Conditional | Yes — same prefix (when applicable) |
> | 4 | `@member {String} className='Neo.ai.X.Y.Z'` | JSDoc above the `static config` block | Yes (Neo convention) | Yes — same prefix |
> | 5 | `className: 'Neo.ai.X.Y.Z',` | Inside `static config = { ... }` | Yes (Neo convention) | Yes — same prefix |
> 
> The `@summary` + descriptive prose (the actual **intent description** of what the class IS / DOES) is location-agnostic and does NOT need updating. Those paragraphs describe semantic role, not namespace location, so they survive the migration unchanged.
> 
> ### Audit numbers across all 4 server families
> 
> ```
> Server         | @class | @extends | @see (in-scope) | stale tags
> ---------------+--------+----------+-----------------+-----------
> knowledge-base |    9   |    0     |  2 (1 cross-NL) |    11
> github-workflow|   15   |    0     |  0              |    15
> neural-link    |    8   |    0     |  0              |     8
> memory-core    |   20   |    1     | 10 (intra-MC)   |    31
> ---------------+--------+----------+-----------------+-----------
> TOTAL          |   52   |    1     | 12              |    65
> ```
> 
> The 3-per-class canonical pattern multiplies the @class count: **52 × 3 = 156 base updates** + **13 conditional updates** (1 @extends + 12 in-scope @see) = **~169 total string substitutions** across all 4 servers.
> 
> ### MUST-NOT-TOUCH negative scope
> 
> The substitution must explicitly NOT rewrite namespace strings pointing at non-migrated surfaces:
> 
> - `@see Neo.ai.mcp.server.shared.services.X` — `RequestContextService`, `AuthMiddleware`, `DestructiveOperationGuard` (cross-server shared infrastructure; stays at server level).
> - `@see Neo.ai.mcp.server.<server>.Server#X` — `Server.mjs` stays at server level per the M6 sub-issues' explicit boundary.
> - `@see Neo.ai.mcp.server.<server>.config` / `.logger` — config and logger files stay at server level.
> 
> The per-server-namespace regex prefix `Neo.ai.mcp.server.<server>.{services,managers}.` naturally excludes `shared`, `Server.`, `config`, `logger` because those paths don't match the prefix shape. Audit step (AC6 in the original ticket body) verifies via `grep -rn "Neo\.ai\.mcp\.server\.<server>"` that surviving matches all hit MUST-NOT-TOUCH cases.
> 
> ### Substitution ordering nuance
> 
> For each server, the `Node` migration script (`buildScripts/ai/_align_classnames.mjs`, mirrors the M6 test-path migration helper pattern) MUST process longer-prefix patterns BEFORE shorter ones to avoid premature flattening:
> 
> **Memory Core (3 sub-namespaces):**
> 1. `Neo.ai.mcp.server.memory-core.services.lifecycle.` → `Neo.ai.services.memory-core.lifecycle.` (run FIRST)
> 2. `Neo.ai.mcp.server.memory-core.managers.` → `Neo.ai.services.memory-core.managers.` (run SECOND — sibling subdir)
> 3. `Neo.ai.mcp.server.memory-core.services.` → `Neo.ai.services.memory-core.` (run LAST — top-level catch-all)
> 
> **GitHub Workflow (3 sub-namespaces):**
> 1. `Neo.ai.mcp.server.github-workflow.services.sync.` → `Neo.ai.services.github-workflow.sync.` (run FIRST)
> 2. `Neo.ai.mcp.server.github-workflow.services.queries.` → `Neo.ai.services.github-workflow.queries.` (run SECOND)
> 3. `Neo.ai.mcp.server.github-workflow.services.` → `Neo.ai.services.github-workflow.` (run LAST)
> 
> **Knowledge Base + Neural Link (single-level):**
> 1. `Neo.ai.mcp.server.knowledge-base.services.` → `Neo.ai.services.knowledge-base.` (single pass)
> 2. `Neo.ai.mcp.server.neural-link.services.` → `Neo.ai.services.neural-link.` (single pass)
> 
> (KB has its own `source/` subdir if applicable — check at sweep time.)
> 
> ### Updated AC1
> 
> Restating with the broader scope:
> 
> - [ ] **AC1 (revised):** All ~169 namespace-string occurrences updated across the 4 M6-migrated server directories, covering the 5 surface types (mandatory: @class, @member, className value; conditional: @extends, in-scope @see). The @summary / prose intent description in module-level JSDoc requires NO update (location-agnostic).
> 
> ACs 2–9 unchanged.
> 
> ### Recap of execution gating
> 
> Sweep fires post-merge of PR [#11001](https://github.com/neomjs/neo/pull/11001). Lane: my queue unless @neo-gemini-pro or @neo-gpt explicitly claims it. Implementation: Node script `buildScripts/ai/_align_classnames.mjs` (mirrors `_migrate_mc_test_paths.mjs` pattern from PR #11001), run-then-delete in same PR, respects `claudeMd §11` sed-ban via `fs.writeFileSync` rather than `sed -i`.
> 
> Origin Session ID: `c2912891-b459-4a03-b2af-154d5e264df1`

- 2026-05-09T10:41:42Z @neo-opus-ada referenced in commit `220ff9d` - "chore: untrack accidentally-committed sent-to-cull.jsonl runtime artifact (#11005)

The previous #11005 commit accidentally included `sent-to-cull.jsonl` —
a runtime artifact written by `MailboxService.mjs:259`'s persistence-error
fallback path during the className sweep's unit-test verification run. The
file is per-user telemetry (#10347 Phase 1 diagnostic) and never belongs
in version control.

Removes the file from the index and adds an explicit gitignore rule with
provenance comment.

Co-Authored-By: neo-opus-ada <neo-opus-ada@neomjs.com>"
- 2026-05-09T10:42:52Z @neo-opus-ada cross-referenced by PR #11007
- 2026-05-09T11:18:08Z @tobiu referenced in commit `54600d7` - "refactor(ai-services): align Neo classNames with flat SDK locations across M6 servers (#11005) (#11007)

* refactor(ai-services): align Neo classNames with flat SDK locations across M6 servers (#11005)

Sweep ~211 namespace-string occurrences across 76 files in the 4 M6-migrated
server families (KB, GH-WF, NL, MC) plus consumer-side @see / @link / test
describe-block references. Substitutions:

- Neo.ai.mcp.server.knowledge-base.services.X  → Neo.ai.services.knowledge-base.X
- Neo.ai.mcp.server.github-workflow.services.X → Neo.ai.services.github-workflow.X
- Neo.ai.mcp.server.neural-link.services.X     → Neo.ai.services.neural-link.X
- Neo.ai.mcp.server.memory-core.services.X     → Neo.ai.services.memory-core.X
- Neo.ai.mcp.server.memory-core.managers.X     → Neo.ai.services.memory-core.managers.X

Bare-prefix substitution naturally collapses nested subdirs:
- .services.lifecycle.X → .lifecycle.X (MC lifecycle)
- .services.sync.X      → .sync.X      (GH-WF syncers)
- .services.queries.X   → .queries.X   (GH-WF queries — no classNames present)

Scope coverage per file:
- Module-level @class JSDoc tag
- @extends JSDoc tag (when extending another migrated class)
- @see / @link JSDoc tag (when cross-referencing migrated classes)
- Config @member className=... JSDoc tag
- Config className value
- Test spec describe-block strings + @see comments
- learn/agentos/decisions/ doc reference

MUST-NOT-TOUCH preserved by regex shape:
- Neo.ai.mcp.server.shared.services.* (shared cross-cutting)
- Neo.ai.mcp.server.<server>.{Server,config,logger} (non-migrated server-level)

Manual fix beyond the regex: ai/daemons/DreamService.mjs:35 — module @class
JSDoc previously misclassified DreamService under memory-core.services. Per
its actual config (className: 'Neo.ai.daemons.DreamService') and physical
location (ai/daemons/), the JSDoc is now corrected to match.

Test evidence: 625 passed / 0 failed / 3 conditionally skipped across
test/playwright/unit/ai/{services,mcp/server,daemons,scripts}/.

Co-Authored-By: neo-opus-ada <neo-opus-ada@neomjs.com>

* chore: untrack accidentally-committed sent-to-cull.jsonl runtime artifact (#11005)

The previous #11005 commit accidentally included `sent-to-cull.jsonl` —
a runtime artifact written by `MailboxService.mjs:259`'s persistence-error
fallback path during the className sweep's unit-test verification run. The
file is per-user telemetry (#10347 Phase 1 diagnostic) and never belongs
in version control.

Removes the file from the index and adds an explicit gitignore rule with
provenance comment.

Co-Authored-By: neo-opus-ada <neo-opus-ada@neomjs.com>

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-09T11:18:08Z @tobiu closed this issue
- 2026-05-09T11:22:25Z @neo-gemini-pro cross-referenced by #10986
- 2026-05-09T17:08:31Z @neo-gemini-pro cross-referenced by #11032
- 2026-05-09T21:15:33Z @neo-gemini-pro assigned to @neo-opus-ada
- 2026-05-12T02:09:06Z @neo-gemini-pro removed the `release:v13` label

