LearnNewsExamplesServices
Frontmatter
titlefeat(ai): add deployment-state bridge snapshot (#13926)
authorneo-gpt
stateMerged
createdAtJun 23, 2026, 6:32 PM
updatedAtJun 23, 2026, 9:18 PM
closedAtJun 23, 2026, 9:17 PM
mergedAtJun 23, 2026, 9:17 PM
branchesdevcodex/13926-deployment-state-bridge
urlhttps://github.com/neomjs/neo/pull/13935
contentTrust
projected
quarantined0
signals[]
Merged
neo-gpt
neo-gpt commented on Jun 23, 2026, 6:32 PM

Resolves #13926

Related: #13860, #13914, #13920, #13924

Adds a graph-independent deployment-state bridge: the internal orchestrator can write a bounded, allowlisted snapshot through the existing deployment runtime holder, while public KB and MC MCP surfaces only get read-only snapshot tools. The public tools do not receive Docker socket, shell, exec, restart, daemon-route, write-actuator authority, or caller-selected file paths; they read only the Tier-1 AiConfig.orchestrator.deploymentStateBridge.snapshotPath leaf.

Evidence: L2 (unit coverage plus real KB/MC toolService dispatch against a wedged-model/unhealthy-memory snapshot fixture) -> L3 required (post-merge deployment smoke against the private overlay and shared snapshot mount). Residual: live deployment smoke [#13926].

Deltas from ticket

  • Added public KB/MC read dispatch coverage over the deployment-state snapshot fixture.
  • Corrected the bridge config shape after ADR 0019 + Base/Neo review: DeploymentStateBridgeService no longer has a bridgeConfig_ / bridgeConfig pass-through, and deployment-state tests no longer mutate the shared AiConfig singleton.
  • Preserved the Base/Neo initial reactive service wiring fix: the bridge receives containerHealthDiagnosisService during startup via the generated getter/setter path, with regression coverage in Orchestrator.spec.mjs.

Test Evidence

  • node --check ai/services/memory-core/helpers/deploymentStateBridgeStore.mjs
  • node --check ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs
  • node --check ai/daemons/orchestrator/Orchestrator.mjs
  • node --check ai/mcp/server/knowledge-base/toolService.mjs
  • node --check ai/mcp/server/memory-core/toolService.mjs
  • node --check test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs
  • npm run test-unit -- test/playwright/unit/ai/services/memory-core/helpers/deploymentStateBridgeStore.spec.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs -> 5 passed
  • npm run test-unit -- test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs -> 29 passed
  • npm run test-unit -- test/playwright/unit/ai/services/memory-core/helpers/deploymentStateBridgeStore.spec.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/config.template.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs -> 42 passed
  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.invariants.spec.mjs -> 77 passed
  • npm run ai:lint-config-template-ssot
  • npm run agent-preflight -- ai/config.template.mjs ai/daemons/orchestrator/Orchestrator.mjs ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs ai/mcp/server/knowledge-base/openapi.yaml ai/mcp/server/knowledge-base/toolService.mjs ai/mcp/server/memory-core/openapi.yaml ai/mcp/server/memory-core/toolService.mjs ai/services/memory-core/helpers/deploymentStateBridgeStore.mjs test/playwright/fixtures/aiConfigDefaults.mjs test/playwright/unit/ai/config.template.spec.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/services/memory-core/helpers/deploymentStateBridgeStore.spec.mjs
  • npm run agent-preflight -- ai/mcp/server/knowledge-base/toolService.mjs ai/mcp/server/memory-core/toolService.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs
  • npm run agent-preflight -- ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs ai/mcp/server/knowledge-base/openapi.yaml ai/mcp/server/knowledge-base/toolService.mjs ai/mcp/server/memory-core/openapi.yaml ai/mcp/server/memory-core/toolService.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs
  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs -> 31 passed
  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.invariants.spec.mjs -> 78 passed
  • npm run agent-preflight -- ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs
  • git diff --check

Post-Merge Validation

  • Private deployment overlay enables NEO_DEPLOYMENT_STATE_BRIDGE_ENABLED, gives orchestrator a writer path, and mounts the same NEO_DEPLOYMENT_STATE_BRIDGE_SNAPSHOT_PATH read-only into KB and MC.
  • Private deployment overlay sets NEO_DEPLOYMENT_STATE_BRIDGE_ALLOWED_SERVICES to the intended deployment service keys.
  • Live deployment smoke reads KB and MC get_deployment_state_snapshot while the model runner is wedged and Memory Core is unhealthy or graph-unavailable, proving KB remains a current-state path when healthy.

Commits

  • 113be5c900 - feat(ai): add deployment-state bridge snapshot (#13926)
  • 0ba1ecf999 - test(ai): cover deployment-state MCP read path (#13926)
  • 16a0bd2ff1 - fix(ai): align deployment bridge with reactive config (#13926)
  • 6ae9203474 - fix(ai): align deployment-state bridge config shape (#13926)
  • b768ca26cb - fix(ai): remove deployment bridge config seam (#13926)

Authored by Euclid (GPT-5, Codex Desktop). Session f5e75eee-e7a1-4bf2-b8bf-4ab58d9ec932.

Author update — reactive config cleanup

Fixed the Base config-shape issue on the #13935 head. DeploymentStateBridgeService now keeps inert injected dependencies as plain configs:

  • runtimeAccessService
  • diagnosisService
  • nowFn
  • writeLog

These do not need generated reactive accessors or hook dispatch. The orchestrator-owned deploymentStateBridgeService_ remains reactive because Orchestrator has beforeSet* / afterSet* wiring for that service.

Commit: 004a20df14fix(ai): keep deployment bridge injections non-reactive (#13926)

Validation run locally:

  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs → 2 passed
  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs → 55 passed
  • git diff --check → passed

Review request remains assigned to @neo-opus-grace.


neo-gpt
neo-gpt commented on Jun 23, 2026, 6:54 PM

Author update after operator review:

  • Read src/core/Base.mjs, src/Neo.mjs, and ADR 0019 again.
  • Removed the new bridgeConfig_ / bridgeConfig pass-through; the bridge now reads Tier-1 AiConfig.orchestrator.deploymentStateBridge.* leaves at the use site.
  • Removed defensive AiConfig.orchestrator?.deploymentStateBridge || {} reads from the KB/MC tool services; missing config now fails loud per ADR 0019.
  • Fixed initial reactive-service setup: the bridge now receives containerHealthDiagnosisService even when afterSetContainerHealthDiagnosisService fires with oldValue === undefined during construction/startup.
  • Added a regression test for that Base/Neo initial reactive propagation path.

Validation after rebasing on current origin/dev:

  • npm run test-unit -- test/playwright/unit/ai/services/memory-core/helpers/deploymentStateBridgeStore.spec.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/config.template.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs -> 42 passed.
  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.invariants.spec.mjs -> 78 passed.
  • npm run agent-preflight -- ai/daemons/orchestrator/Orchestrator.mjs ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs ai/mcp/server/knowledge-base/toolService.mjs ai/mcp/server/memory-core/toolService.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs -> passed.

neo-gpt
neo-gpt commented on Jun 23, 2026, 7:52 PM

Author update after the Base/Neo + ADR 0019 correction:

  • Pushed b768ca26cb535a226422e755231a8cfbf510b4ad.
  • Removed DeploymentStateBridgeService.bridgeConfig_ and the cfg accessor; the service now reads AiConfig.orchestrator.deploymentStateBridge at the actual use sites.
  • Removed the deployment-state AiConfig.setEnvOverride() test path; the MCP dispatch test writes/restores the configured snapshot file and calls KB/MC tools without caller-selected paths or singleton mutation.
  • Kept the initial reactive wiring fix: beforeSetDeploymentStateBridgeService() intentionally reads this.containerHealthDiagnosisService, relying on the Base/Neo.createConfig() pending-config getter path to instantiate the service during startup.

Fresh validation:

  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs -> 31 passed.
  • npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.invariants.spec.mjs -> 78 passed.
  • npm run ai:lint-config-template-ssot -> passed.
  • npm run agent-preflight -- ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs test/playwright/unit/ai/daemons/orchestrator/services/DeploymentStateBridgeService.spec.mjs test/playwright/unit/ai/mcp/server/McpServerListToolsSmoke.spec.mjs -> passed.
  • git diff --check -> passed.

CI is running on the pushed head.


neo-gpt
neo-gpt commented on Jun 23, 2026, 8:47 PM
tobiu
tobiu APPROVED reviewed on Jun 23, 2026, 9:17 PM

No review body provided.