Core concepts
ControlManager owns the cycle
One object runs select → route → validate → gate → execute → gate → commit → audit.Nodes are selected; state is advanced
The control layer can select multiple nodes because capabilities may run in parallel or sequence. It does not select multiple states.
After selected nodes finish, results propose state updates. Gates check legality; the backend commits at most one transition per step.
Control flow
- Proposal is not permission — validators and the transition table decide.
- Exactly one current state; at most one commit per plan step.
- Fail-closed gates before commit, even after successful execution.
- Every graph has exactly one dedicated fallback node.
- Input is evidence, not authority.
input -> candidate selection -> router proposal -> plan validation
-> execution -> guards / transition checks -> one state commit
-> audit recordBackend-owned control (preferred)
When BackendClient credentials are configured, the backend owns selection, routing, validation, and commits. The client receives opaque execute steps (node ids only), runs local handlers, and posts results. Responses never include topology, candidates, scores, providers, or model names.
POST /api/v1/control/runs
<- status=awaiting_execution, step.nodes=[...]
execute local handlers
POST /api/v1/control/runs/{run_id}/results
<- next step | completed | rejectedOffline fallback
Without backend credentials, ControlManager uses DeterministicRouter locally: walk outgoing edges by label priority, or propose the dedicated fallback when nothing is legal.
Implemented by ControlManager in neosyntropy-framework and /api/v1/control/runs in neo_syntropy_backend.