State & errors¶
The state machines that enforce the pipelines, the state store that tracks the installed version, and the error types.
.xdeploy state machine¶
xcore_agent.agent.state
¶
TERMINAL_STATES = frozenset({DeploymentState.SUCCEEDED, DeploymentState.FAILED, DeploymentState.ROLLED_BACK})
module-attribute
¶
TRANSITIONS: dict[DeploymentState, tuple[DeploymentState, ...]] = {DeploymentState.PENDING: (DeploymentState.AUTHENTICATING,), DeploymentState.AUTHENTICATING: (DeploymentState.REQUESTING_ARTIFACT, DeploymentState.FAILED), DeploymentState.REQUESTING_ARTIFACT: (DeploymentState.DOWNLOADING, DeploymentState.FAILED), DeploymentState.DOWNLOADING: (DeploymentState.VERIFYING_SIGNATURE, DeploymentState.FAILED), DeploymentState.VERIFYING_SIGNATURE: (DeploymentState.OBTAINING_KEY, DeploymentState.FAILED), DeploymentState.OBTAINING_KEY: (DeploymentState.DECRYPTING, DeploymentState.FAILED), DeploymentState.DECRYPTING: (DeploymentState.EXTRACTING, DeploymentState.FAILED), DeploymentState.EXTRACTING: (DeploymentState.VERIFYING_MANIFEST, DeploymentState.FAILED), DeploymentState.VERIFYING_MANIFEST: (DeploymentState.VALIDATING_PROJECT, DeploymentState.FAILED), DeploymentState.VALIDATING_PROJECT: (DeploymentState.RESOLVING_PLUGINS, DeploymentState.FAILED), DeploymentState.RESOLVING_PLUGINS: (DeploymentState.RESOLVING_SEQUENCE, DeploymentState.FAILED), DeploymentState.RESOLVING_SEQUENCE: (DeploymentState.INSTALLING, DeploymentState.FAILED), DeploymentState.INSTALLING: (DeploymentState.HEALTHCHECKING, DeploymentState.FAILED, DeploymentState.ROLLED_BACK), DeploymentState.HEALTHCHECKING: (DeploymentState.NOTIFYING, DeploymentState.FAILED, DeploymentState.ROLLED_BACK), DeploymentState.NOTIFYING: (DeploymentState.SUCCEEDED, DeploymentState.FAILED), DeploymentState.SUCCEEDED: (), DeploymentState.FAILED: (), DeploymentState.ROLLED_BACK: ()}
module-attribute
¶
DeploymentState
¶
Bases: str, Enum
Source code in xcore_agent/agent/state.py
PENDING = 'pending'
class-attribute
instance-attribute
¶
AUTHENTICATING = 'authenticating'
class-attribute
instance-attribute
¶
REQUESTING_ARTIFACT = 'requesting_artifact'
class-attribute
instance-attribute
¶
DOWNLOADING = 'downloading'
class-attribute
instance-attribute
¶
VERIFYING_SIGNATURE = 'verifying_signature'
class-attribute
instance-attribute
¶
OBTAINING_KEY = 'obtaining_key'
class-attribute
instance-attribute
¶
DECRYPTING = 'decrypting'
class-attribute
instance-attribute
¶
EXTRACTING = 'extracting'
class-attribute
instance-attribute
¶
VERIFYING_MANIFEST = 'verifying_manifest'
class-attribute
instance-attribute
¶
VALIDATING_PROJECT = 'validating_project'
class-attribute
instance-attribute
¶
RESOLVING_PLUGINS = 'resolving_plugins'
class-attribute
instance-attribute
¶
RESOLVING_SEQUENCE = 'resolving_sequence'
class-attribute
instance-attribute
¶
INSTALLING = 'installing'
class-attribute
instance-attribute
¶
HEALTHCHECKING = 'healthchecking'
class-attribute
instance-attribute
¶
NOTIFYING = 'notifying'
class-attribute
instance-attribute
¶
SUCCEEDED = 'succeeded'
class-attribute
instance-attribute
¶
FAILED = 'failed'
class-attribute
instance-attribute
¶
ROLLED_BACK = 'rolled_back'
class-attribute
instance-attribute
¶
Marketplace state machine¶
xcore_agent.agent.marketplace_state
¶
State machine for MarketplaceDeploymentRunner — deliberately separate
from state.DeploymentState. The real Marketplace flow has no auth exchange,
no DEK/decrypt step, and loads its install plan from a local operator file
instead of from inside the artifact, so it is a materially different sequence
of security-relevant stages, not a subset of the .xdeploy one.
MARKETPLACE_TERMINAL_STATES = frozenset({MarketplaceDeploymentState.SUCCEEDED, MarketplaceDeploymentState.FAILED, MarketplaceDeploymentState.ROLLED_BACK})
module-attribute
¶
MARKETPLACE_TRANSITIONS: dict[MarketplaceDeploymentState, tuple[MarketplaceDeploymentState, ...]] = {MarketplaceDeploymentState.PENDING: (MarketplaceDeploymentState.FETCHING,), MarketplaceDeploymentState.FETCHING: (MarketplaceDeploymentState.VERIFYING_SIGNATURE, MarketplaceDeploymentState.FAILED), MarketplaceDeploymentState.VERIFYING_SIGNATURE: (MarketplaceDeploymentState.EXTRACTING, MarketplaceDeploymentState.FAILED), MarketplaceDeploymentState.EXTRACTING: (MarketplaceDeploymentState.LOADING_PLAN, MarketplaceDeploymentState.FAILED), MarketplaceDeploymentState.LOADING_PLAN: (MarketplaceDeploymentState.RESOLVING_SEQUENCE, MarketplaceDeploymentState.FAILED), MarketplaceDeploymentState.RESOLVING_SEQUENCE: (MarketplaceDeploymentState.INSTALLING, MarketplaceDeploymentState.FAILED), MarketplaceDeploymentState.INSTALLING: (MarketplaceDeploymentState.HEALTHCHECKING, MarketplaceDeploymentState.FAILED, MarketplaceDeploymentState.ROLLED_BACK), MarketplaceDeploymentState.HEALTHCHECKING: (MarketplaceDeploymentState.SUCCEEDED, MarketplaceDeploymentState.FAILED, MarketplaceDeploymentState.ROLLED_BACK), MarketplaceDeploymentState.SUCCEEDED: (), MarketplaceDeploymentState.FAILED: (), MarketplaceDeploymentState.ROLLED_BACK: ()}
module-attribute
¶
MarketplaceDeploymentState
¶
Bases: str, Enum
Source code in xcore_agent/agent/marketplace_state.py
PENDING = 'pending'
class-attribute
instance-attribute
¶
FETCHING = 'fetching'
class-attribute
instance-attribute
¶
VERIFYING_SIGNATURE = 'verifying_signature'
class-attribute
instance-attribute
¶
EXTRACTING = 'extracting'
class-attribute
instance-attribute
¶
LOADING_PLAN = 'loading_plan'
class-attribute
instance-attribute
¶
RESOLVING_SEQUENCE = 'resolving_sequence'
class-attribute
instance-attribute
¶
INSTALLING = 'installing'
class-attribute
instance-attribute
¶
HEALTHCHECKING = 'healthchecking'
class-attribute
instance-attribute
¶
SUCCEEDED = 'succeeded'
class-attribute
instance-attribute
¶
FAILED = 'failed'
class-attribute
instance-attribute
¶
ROLLED_BACK = 'rolled_back'
class-attribute
instance-attribute
¶
State store¶
xcore_agent.agent.state_store
¶
Tracks which project version is currently installed on this host.
Without this, the CI/CD watch loop (agent.watcher.Watcher) would have no
way to tell "Hub says v1.2.3 is latest" from "v1.2.3 is already what's
running here" and would redeploy on every single check.
InstalledState
dataclass
¶
Source code in xcore_agent/agent/state_store.py
StateStore
¶
Persists install state as <project_root>/.xcore/state.json — or,
with namespace set, <project_root>/.xcore/state-<namespace>.json.
namespace matters as soon as more than one deployment shares a
project_root (e.g. MarketplaceWatcher polling several independent
slugs against the same host): without it, every watcher reads/writes
the SAME file, so each poll clobbers the others' recorded version and
every watcher but the last-written-one redeploys on every single check,
mistaking a sibling's state for its own. Omit it (the default) for the
single-project-per-root case (agent.watcher.Watcher), which never had
this problem and keeps its existing state.json path unchanged.
Source code in xcore_agent/agent/state_store.py
__init__(project_root: Path, *, namespace: str | None = None) -> None
¶
read() -> InstalledState | None
¶
write(*, project_id: str, version: str) -> InstalledState
¶
Source code in xcore_agent/agent/state_store.py
Errors¶
xcore_agent.agent.errors
¶
DeploymentError
¶
AuthenticationError
¶
Bases: DeploymentError
Authentication against XCore Hub failed.
ArtifactError
¶
Bases: DeploymentError
Artifact could not be requested, downloaded, verified, or decrypted.
PublishError
¶
Bases: DeploymentError
A built artifact could not be uploaded to XCore Hub.
InstallError
¶
Bases: DeploymentError
A filesystem-level install step failed.
HealthcheckError
¶
Bases: DeploymentError
A plugin or project failed its post-install healthcheck.