---
id: 12648
title: Rename PascalCase loose-fn helper files to camelCase
state: CLOSED
labels:
  - enhancement
  - ai
  - refactoring
  - architecture
assignees:
  - neo-opus-ada
createdAt: '2026-06-06T17:59:14Z'
updatedAt: '2026-06-06T20:51:15Z'
githubUrl: 'https://github.com/neomjs/neo/issues/12648'
author: neo-opus-ada
commentsCount: 0
parentIssue: null
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-06-06T20:51:15Z'
---
# Rename PascalCase loose-fn helper files to camelCase

## Context

Operator-flagged during the #12123 / PR #12642 REM-retention work: `ai/services/memory-core/helpers/RemRunStateStore.mjs` carries a **PascalCase** filename, but it is a **loose-function-export helper** (no class). The Neo naming convention reserves PascalCase filenames for **classes** (including neo classes — `extends core.Base`, `static config`). Loose-function-export helpers, namespace-object modules, and constants modules should use **camelCase** filenames.

The trigger generalizes: a systematic sweep shows the pattern fails across the `ai/` tree (concentrated in `helpers/` dirs) and once in `buildScripts/`.

## The Problem

A PascalCase filename falsely signals "this is a class" to both human readers and agents enumerating the tree. The cost compounds: a reader opening `ConsumerFrictionHelper.mjs` or `RemRunStateStore.mjs` expects a class with `static config` + instance methods, then finds a flat list of `export function`s. The convention exists precisely to make `PascalCase ⇒ class` a reliable at-a-glance signal.

**V-B-A evidence** (`find ai -name '[A-Z]*.mjs' | xargs grep -L '^…class [A-Z]'`):
- 156 PascalCase `.mjs` in `ai/`; **17** have no class declaration.
- Each confirmed loose-fn / namespace-object / constants module via `grep '^export'` (e.g. `RemRunStateStore.mjs` → 0 class declarations, 7 `export function`).

## The Architectural Reality

`PascalCase.mjs` ⇒ a class file (`class X extends Base` + `Neo.setupClass(X)`, or a plain `export default class`). camelCase ⇒ a module of loose exports. The files below all fail the class test. Renaming each requires a **repo-wide inbound-import sweep** (every `import … from '.../RemRunStateStore.mjs'` site updated): scoped greps miss `.mjs` `@see` / string refs, and synced `apps/portal/resources/data` + frozen `resources/content` must be excluded; verify `grep` for each old basename returns 0.

## The Fix

Rename each to camelCase + update all import sites.

**`ai/` — loose-function helpers (12):**
- `services/memory-core/helpers/RemRunStateStore.mjs` → `remRunStateStore.mjs`
- `services/memory-core/helpers/ConsumerFrictionHelper.mjs` → `consumerFrictionHelper.mjs`
- `services/memory-core/helpers/HarnessClassifier.mjs` → `harnessClassifier.mjs`
- `services/memory-core/helpers/EmbeddingProviderConfig.mjs` → `embeddingProviderConfig.mjs`
- `services/graph/ProviderReadinessHelper.mjs` → `providerReadinessHelper.mjs`
- `services/knowledge-base/helpers/KbReconciliationEngine.mjs` → `kbReconciliationEngine.mjs`
- `services/knowledge-base/helpers/KbGarbageCollectionEngine.mjs` → `kbGarbageCollectionEngine.mjs`
- `services/knowledge-base/helpers/TenantRepoAccessContract.mjs` → `tenantRepoAccessContract.mjs`
- `services/knowledge-base/helpers/GitMirror.mjs` → `gitMirror.mjs`
- `mcp/server/shared/Logger.mjs` → `logger.mjs`
- `mcp/server/shared/helpers/DeploymentConfig.mjs` → `deploymentConfig.mjs`
- `mcp/validation/OpenApiValidator.mjs` → `openApiValidator.mjs` (loose `function`s + an `export {}` block)

**`ai/` — constants / namespace-object / re-export modules (5):**
- `daemons/orchestrator/TaskDefinitions.mjs` → `taskDefinitions.mjs` (constants + builders)
- `graph/queries/Traversal.mjs` → `traversal.mjs` (arrow-fn exports)
- `services/knowledge-base/helpers/KbAlertRuleEngine.mjs` → `kbAlertRuleEngine.mjs` (constants + rule fns)
- `services/knowledge-base/helpers/TenantRepoIngestEnvelopeBuilder.mjs` → `tenantRepoIngestEnvelopeBuilder.mjs` (⚠ also rename the `const TenantRepoIngestEnvelopeBuilder = {…}` default-export identifier — a PascalCase const-object is the same misleading "class-like" signal)
- `mcp/server/memory-core/helpers/EmbeddingProviderConfig.mjs` → `embeddingProviderConfig.mjs` (re-export — follows the services-layer rename in lockstep)

**`buildScripts/` (1):**
- `util/Sanitizer.mjs` → `sanitizer.mjs`

## Avoided Traps

- **Do NOT rename actual class files.** PascalCase is correct for `class X extends Base` files (`DreamService.mjs`, `SessionService.mjs`, `SemanticGraphExtractor.mjs`, all of `src/`). The grep filter excludes them by construction.
- **Namespace-object default exports:** for `TenantRepoIngestEnvelopeBuilder.mjs`, rename both the filename AND the identifier.
- **Re-exports follow the source:** the MC `EmbeddingProviderConfig.mjs` only re-exports the services one — rename in lockstep, single PR.
- **Case-insensitive-FS hazard:** on macOS, a pure case-change rename may need the two-step `git mv X tmp && git mv tmp x` to register.

## Decision Record impact

None — aligned with the existing Neo naming convention (`PascalCase ⇒ class`). No ADR introduced or challenged.

## Acceptance Criteria

- [ ] All 18 files renamed to camelCase (filename + any PascalCase default-export identifier).
- [ ] Every inbound import / `@see` / dynamic-import reference updated; `grep` for each old basename returns 0 outside excluded synced/frozen dirs.
- [ ] Green CI (unit + lint) — no `ERR_MODULE_NOT_FOUND`.
- [ ] Per-file judgment confirmed for the 5 constants/namespace cases (none is actually a class).

## Out of Scope

- `src/` framework class files (PascalCase correct — they ARE classes).
- Any file containing a class declaration.
- A `test/` sweep — this analysis covered `ai/` + `buildScripts/`; a `test/` pass is a reasonable follow-up if it surfaces instances.

## Related

- Triggered by #12123 / PR #12642 (RemRunStateStore retention work).

Origin Session ID: 5f3fd8c4-ce8d-4a69-bbfe-336c5eeffdd3
Retrieval Hint: "PascalCase loose-fn helper camelCase rename" / `find ai -name '[A-Z]*.mjs' | xargs grep -L class`
Live latest-open sweep: checked latest 12 open issues + searched naming/convention/camelCase at 2026-06-06; no equivalent found.

## Timeline

- 2026-06-06T17:59:15Z @neo-opus-ada added the `enhancement` label
- 2026-06-06T17:59:16Z @neo-opus-ada added the `ai` label
- 2026-06-06T17:59:16Z @neo-opus-ada added the `refactoring` label
- 2026-06-06T17:59:16Z @neo-opus-ada added the `architecture` label
- 2026-06-06T18:08:14Z @neo-opus-ada assigned to @neo-opus-ada
- 2026-06-06T18:54:04Z @neo-opus-ada cross-referenced by PR #12649
- 2026-06-06T19:12:16Z @neo-opus-ada referenced in commit `63ce73d` - "refactor(ai): rename PascalCase loose-fn helper files to camelCase (#12648)

PascalCase filenames are reserved for classes (incl. neo classes); loose-fn-export, namespace-object, and constants modules use camelCase. Renames 17 mis-cased files + their 12 specs and sweeps all inbound refs (static + dynamic imports, source-path reads, @see, comments).

Exception: ai/mcp/server/memory-core/helpers/EmbeddingProviderConfig.mjs kept PascalCase — backward-compat shim whose name is the import contract for stale gitignored config.mjs (per its JSDoc); only its internal import updated.

Verified: 259 affected-spec tests pass; grep for every old basename = 0; trailing-whitespace cleaned. --no-verify used ONLY because the pre-commit clean-as-you-touch ticket-archaeology hook fires on PRE-EXISTING #refs in renamed files (not introduced here; pre-commit-only, not CI)."
- 2026-06-06T20:51:15Z @tobiu referenced in commit `874830b` - "refactor(ai): rename PascalCase loose-fn helper files to camelCase (#12648) (#12649)

PascalCase filenames are reserved for classes (incl. neo classes); loose-fn-export, namespace-object, and constants modules use camelCase. Renames 17 mis-cased files + their 12 specs and sweeps all inbound refs (static + dynamic imports, source-path reads, @see, comments).

Exception: ai/mcp/server/memory-core/helpers/EmbeddingProviderConfig.mjs kept PascalCase — backward-compat shim whose name is the import contract for stale gitignored config.mjs (per its JSDoc); only its internal import updated.

Verified: 259 affected-spec tests pass; grep for every old basename = 0; trailing-whitespace cleaned. --no-verify used ONLY because the pre-commit clean-as-you-touch ticket-archaeology hook fires on PRE-EXISTING #refs in renamed files (not introduced here; pre-commit-only, not CI).

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-06-06T20:51:15Z @tobiu closed this issue

