Skip to content

Node key minted for an actor-configured node, but the owner-binding cannot follow — consent re-authoring is then permanently unsatisfiable #528

Description

@emooreatx

Summary

A node whose configured key is an actor gets a separate node key minted (CC 3.4.7.3 Clause A, working as designed). The owner-binding then cannot follow onto it — owner_of(node) never resolves — and from that point the node can never re-author its own consent rows:

RuntimeError: re-author consent ciris-node-bootstrap-<x> -> ciris-canonical-1-<y>:
  refusing to emit a consent grant naming "ciris-node-bootstrap-<x>": this engine
  signs as "ciris-agent-bootstrap-<z>", and a consent grant is self-attested
  (CEG 1.0-RC29 §5.6.8.15)

Because the agent treats node-fails ⇒ agent-fails, the whole app stops starting. A user hit this in the field on 2026-09-01 (ciris-server 0.5.196): setup completed, then every subsequent launch died in ~9s.

The substrate names the remedy in its own warning:

WARN ciris_server::node_key: the configured key is an ACTOR, so it is not this node's
  identity. Minted and registered a separate node key (CC 3.4.7.3 Clause A). The actor
  key is UNCHANGED and keeps everything it authored. The node's owner-binding must be
  re-issued onto the node key — see `plan_owner_binding_move`.
  configured_key_id=ciris-agent-bootstrap-<z> configured_roles=["agent"]
  node_key_id=ciris-node-bootstrap-<x>

WARN ciris_server::compose: the node key was minted but no owner signer is on disk, so
  its owner-binding could not follow. `owner_of(node)` does not resolve

plan_owner_binding_move is not exposed in ciris_server 0.5.196's Python API. dir(ciris_server) offers provision_node_identity, node_identity, node_state, install_node, author_federation_consent, analyze_consent_stance — nothing to perform or schedule the binding move. So the caller is told what must happen and given no way to make it happen.

Reproduction (local, ~4 minutes, no OAuth or browser needed)

export CIRIS_HOME=$(mktemp -d)
python3 main.py --adapter api --mock-llm --port 8099

Observed on a clean home, ciris-server 0.5.196, agent 2.9.47:

[NODE-KEY] node identity provisioned: ciris-node-bootstrap-zv2osrj64p
Node fold: identity resolution — alias=ciris-agent-bootstrap
[CONSENT] trace consent ARMED — source=config/env role=community_trust target=canonical-community
consent-CEG: emitted directed traces-consent grant <uuid> → community
consent-CEG: promoted directed grant <uuid> to federation tier
Node fold: serve_with_python_adapter exited/failed: RuntimeError: re-author consent …
[FAIL] Start Adapters failed: node fold failed to start (node-fails ⇒ agent-fails)

The alias passed to serve_with_python_adapter is deliberately the engine's, as CIRISServer#380 requires — we verified the alternative: passing the provisioned node alias yields TWO FEDERATION IDENTITIES IN ONE NODE — refusing to start. So there is no alias choice that avoids this; both branches fail, differently.

Why this cannot be worked around at the agent tier

Ownership is the fabric's to produce (CEG §0.0); we can only surface it.

Ask

Either of:

  1. Perform the owner-binding move at mint time, when the substrate already knows both keys — it is the only party that can.
  2. Fail closed at mint instead of booting into a state that is fatal on the next start. The current behaviour is the worst of both: the first boot succeeds, setup writes a consent row, and the install is dead from then on. A refusal at mint time would be diagnosable immediately.
  3. Failing those, expose plan_owner_binding_move so the caller can complete what the warning instructs.

(2) alone would have prevented the field failure entirely.

Impact

Any install where the configured key is an actor and setup completes. The agent has no way to detect it before setup, and the user cannot be told anything afterwards because the app will not start. Filed with agent-side receipts at CIRISAI/CIRISAgent#1130.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions