LearnNewsExamplesServices
Frontmatter
id11833
titleSub 1: Orchestrator masterclass-reference refactor (4-way Service-DI + 2-value chain + configure() removal)
stateClosed
labels
enhancementairefactoringarchitecture
assigneesneo-opus-ada
createdAtMay 23, 2026, 1:21 PM
updatedAtJun 7, 2026, 7:14 PM
githubUrlhttps://github.com/neomjs/neo/issues/11833
authorneo-opus-ada
commentsCount0
parentIssue11831
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[x] 11832 Sub 6: Neo.util.Env THIN substrate primitive (lift EnvConfig.mjs parsers to src/util/Env.mjs)
blocking[]
closedAtMay 23, 2026, 3:10 PM

Sub 1: Orchestrator masterclass-reference refactor (4-way Service-DI + 2-value chain + configure() removal)

Closed v13.0.0/archive-v13-0-0-chunk-13 enhancementairefactoringarchitecture
neo-opus-ada
neo-opus-ada commented on May 23, 2026, 1:21 PM

Parent Epic

#11831Sub 1 of 6 (primary lane; DEPENDS ON Sub 6 for Neo.util.Env).

Scope

Refactor ai/daemons/Orchestrator.mjs (~1000 lines → ~400-500 lines target) into masterclass-reference shape per Epic #11831 ACs 1-7. Sets the pattern for all subsequent daemon refactors (Sub 4 propagation).

Acceptance Criteria

Inherits Epic #11831 ACs 1-7 directly. Specifically:

  1. AC1 — Drop cargo-cult _-suffix configs (~30 properties without hooks → drop _). Keep _ only for class-system-managed reactive collaborators with real hooks (cadenceEngine_, processSupervisorService_).
  2. AC2 — 2-value chain for every operator-tunable interval/timeout/threshold/boolean: Env.parseNumber(process.env.X, 'X') ?? AiConfig.namespace.X. No options.X, no DEFAULT_X constant, no env-alias chain.
  3. AC4 — 4-way Service-DI classification:
    • (A) cadenceEngine_ reactive with beforeSetCadenceEngine + ClassSystemUtil.beforeSetInstance(value, CadenceEngine, {defaults}) + afterSetCadenceEngine lifecycle wiring
    • (B) processSupervisorService_ reactive with beforeSetProcessSupervisorService (parent-sourced config injection) + parent afterSet* propagation hooks for dataDir/taskDefinitions/taskStateService/healthService/spawnFn. Stable logger seam processSupervisorWriteLog (avoid per-call .bind() allocation). Explicit removal of processSupervisorService.set({...this...}) context-replay block in start().
    • (C) healthService direct import + instance field (after audit confirms no lifecycle need)
    • (D) summarySweepIntervalMs / pollIntervalMs / etc. — lazy getters, no class config slot
  4. AC5 — configure(options) REMOVED as runtime-policy resolver.
  5. AC7 — Test coverage of parent-config-propagation via afterSet* (NOT via start() context replay).

Implementation snippet (per Discussion #11828 body AFTER section)

import { CadenceEngine }            from '../services/CadenceEngine.mjs';
import { ProcessSupervisorService } from '../services/ProcessSupervisorService.mjs';
import HealthService                 from '...';
import ClassSystemUtil               from '../../src/util/ClassSystem.mjs';
import Env                           from '../../src/util/Env.mjs';

class Orchestrator extends Base {
    static config = {
        className: 'Neo.ai.daemons.Orchestrator',
        cadenceEngine_: null,
        processSupervisorService_: null
    }

    processSupervisorWriteLog = (level, msg) => this.writeLog(level, msg)
    healthService = HealthService

    beforeSetCadenceEngine(value, oldValue) {
        oldValue?.destroy?.();
        return ClassSystemUtil.beforeSetInstance(value, CadenceEngine, {});
    }

    beforeSetProcessSupervisorService(value) {
        return ClassSystemUtil.beforeSetInstance(value, ProcessSupervisorService, {
            dataDir         : this.dataDir,
            taskDefinitions : this.taskDefinitions,
            taskStateService: this.taskStateService,
            healthService   : this.healthService,
            writeLog        : this.processSupervisorWriteLog,
            spawnFn         : this.spawnFn
        });
    }

    afterSetTaskDefinitions(value) {
        if (this.processSupervisorService) this.processSupervisorService.taskDefinitions = value;
    }
    // ... other afterSet* propagation hooks per parent-config audit

    start() {
        this.processSupervisorService.recoverTasks();
    }

    get summarySweepIntervalMs() {
        return Env.parseNumber(process.env.NEO_ORCHESTRATOR_SUMMARY_SWEEP_INTERVAL_MS, 'NEO_ORCHESTRATOR_SUMMARY_SWEEP_INTERVAL_MS')
            ?? AiConfig.orchestrator.intervals.summarySweepMs;
    }
}

Test injection patterns (per refactor)

  • AiConfig.data mutation: AiConfig.data.orchestrator.intervals.summarySweepMs = 600000
  • Env var with try/finally restore: process.env.NEO_ORCHESTRATOR_X = '600000'; try { ... } finally { delete process.env.NEO_ORCHESTRATOR_X }
  • Service-DI: direct instance override orchestrator.healthService = mockHealthService

Files (touched)

  • ai/daemons/Orchestrator.mjs (refactor ~1000 lines → ~400-500)
  • ai/daemons/TaskDefinitions.mjs (delete 8 DEFAULT_X_INTERVAL_MS constants)
  • test/playwright/unit/ai/daemons/Orchestrator.spec.mjs (refactor createTestOrchestrator() for new injection patterns; add parent-config-propagation tests)
  • (Sub 3 picks up downstream parser-surface deletions)

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

tobiu referenced in commit 07e4389 - "feat(util): Neo.util.Env substrate primitive for env-var parsing (#11832) (#11838) on May 23, 2026, 2:15 PM
tobiu referenced in commit 86bd0c6 - "feat(agentos): bump swarmHeartbeatMs default 5m → 15m (#11840) (#11841) on May 23, 2026, 2:39 PM
tobiu referenced in commit 27f7a65 - "refactor(agentos): Orchestrator masterclass-reference (4-way Service-DI + Neo.util.Env + configure() removal) (#11833) (#11842) on May 23, 2026, 3:10 PM
tobiu closed this issue on May 23, 2026, 3:10 PM
tobiu referenced in commit 7e7adb2 - "refactor(agentos): delete obsolete CadenceEngine.parseInterval + PrimaryRepoSyncService.parseEnabledFlag (#11835) (#11843) on May 23, 2026, 3:28 PM
tobiu referenced in commit 193b5f5 - "test(orchestrator): add Sub-1 invariant + config-precedence + propagation coverage (#11834) (#11945) on May 25, 2026, 7:49 AM