provisioning/.ontology/manifest.ncl
2026-05-12 02:40:14 +01:00

340 lines
19 KiB
XML

let m = import "ontology/defaults/manifest.ncl" in
m.make_manifest {
project = "provisioning",
repo_kind = 'Mixed,
description = "Multi-crate Rust platform for cloud infrastructure provisioning: typed Nickel schemas validated at the NCL layer, formula DAG execution engine, SOLID-enforced service boundaries, pluggable providers and taskservs, NATS-brokered orchestration, Cedar authorization, and full-architecture solo mode for single-operator deployments.",
consumption_modes = [
m.make_consumption_mode {
consumer = 'Developer,
needs = ['OntologyExport],
audit_level = 'Standard,
description = "Uses provisioning CLI and workspace definitions to manage infrastructure. Extends via providers and taskservs.",
},
m.make_consumption_mode {
consumer = 'Agent,
needs = ['OntologyExport, 'JsonSchema],
audit_level = 'Quick,
description = "Reads .ontology/core.ncl to understand constraints and boundaries. Uses CLI and orchestrator APIs for infrastructure operations.",
},
],
layers = [
m.make_layer {
id = "schemas",
paths = ["schemas/"],
committed = true,
description = "Nickel type schemas for all infrastructure configuration: providers, workspaces, platform services, extensions.",
},
m.make_layer {
id = "core",
paths = ["core/"],
committed = true,
description = "CLI, libraries, plugins, Nushell scripts — the user-facing surface of provisioning.",
},
m.make_layer {
id = "platform",
paths = ["platform/"],
committed = true,
description = "Orchestrator, Control Center, Vault, Extension Registry — the control plane services.",
},
m.make_layer {
id = "catalog",
paths = ["catalog/"],
committed = true,
description = "Providers, taskservs, clusters, components, domain artifacts — IaC building block catalog and federated integration domain contracts.",
},
m.make_layer {
id = "config",
paths = ["config/", "templates/"],
committed = true,
description = "Default configuration files and infrastructure templates.",
},
m.make_layer {
id = "self-description",
paths = [".ontology/"],
committed = true,
description = "Provisioning consuming on+re: axioms, tensions, practices, state, gates, ADRs.",
},
],
operational_modes = [
m.make_op_mode {
id = "dev",
visible_layers = ["schemas", "core", "platform", "catalog", "config", "self-description"],
description = "Full development view — all layers visible.",
},
m.make_op_mode {
id = "platform-focus",
visible_layers = ["schemas", "platform", "config"],
description = "Platform engineering focus — schemas, platform services, and configuration.",
},
m.make_op_mode {
id = "catalog-focus",
visible_layers = ["schemas", "catalog", "config"],
description = "Catalog development focus — schemas, providers, taskservs, components, and configuration.",
},
],
config_surface = m.make_config_surface {
config_root = ".typedialog/provisioning/",
entry_point = "config.ncl",
kind = 'TypeDialog,
contracts_path = ".typedialog/provisioning/schemas",
overrides_dir = ".typedialog/provisioning/generated",
sections = [
m.make_config_section {
id = "provisioning",
file = "config.ncl",
contract = "schemas/provisioning-config.ncl",
description = "Root workspace configuration generated by TypeDialog — project metadata, services, database, deployment target, network, storage, monitoring, security.",
rationale = "Consumer projects declare what infrastructure they need via an interactive TypeDialog form. The NCL output is the single source of truth fed to the orchestrator. TypeDialog fragments (database-postgres, deployment-k8s, etc.) ensure only valid combinations are generated.",
mutable = true,
consumers = [
m.make_config_consumer { id = "orchestrator", kind = 'RustStruct, ref = "provisioning_orchestrator::config::OrchestratorConfig", fields = ["services", "deployment", "database"] },
m.make_config_consumer { id = "configure-nu", kind = 'NuScript, ref = ".typedialog/provisioning/configure.nu" },
m.make_config_consumer { id = "ci-woodpecker", kind = 'CiPipeline, ref = ".woodpecker/ci.yml" },
],
},
m.make_config_section {
id = "database",
file = "schemas/database.ncl",
contract = "schemas/database.ncl",
description = "Database type and connection parameters — supports sqlite, postgres, surrealdb, mysql. Generated into the root config via TypeDialog database-* fragments.",
rationale = "Database configuration is the most provider-specific section. TypeDialog fragments enforce valid parameter combinations per engine (e.g. journal_mode only valid for SQLite).",
mutable = false,
consumers = [
m.make_config_consumer { id = "orchestrator", kind = 'RustStruct, ref = "provisioning_orchestrator::config::OrchestratorConfig", fields = ["database"] },
],
},
m.make_config_section {
id = "deployment",
file = "schemas/deployment.ncl",
contract = "schemas/deployment.ncl",
description = "Deployment target — docker-compose or kubernetes. Drives which taskservs are activated and which providers are called.",
rationale = "Deployment target selection is the primary branching decision in workspace execution. TypeDialog deployment-docker and deployment-k8s fragments capture the full parameter space for each target.",
mutable = false,
consumers = [
m.make_config_consumer { id = "orchestrator", kind = 'RustStruct, ref = "provisioning_orchestrator::config::OrchestratorConfig", fields = ["deployment"] },
],
},
m.make_config_section {
id = "monitoring",
file = "schemas/monitoring.ncl",
contract = "schemas/monitoring.ncl",
description = "Observability configuration — metrics, logging, alerting. Optional; defaults from .typedialog/provisioning/defaults/monitoring-defaults.ncl.",
mutable = false,
consumers = [
m.make_config_consumer { id = "orchestrator", kind = 'RustStruct, ref = "provisioning_orchestrator::config::OrchestratorConfig", fields = ["monitoring"] },
],
},
],
},
capabilities = [
m.make_capability {
id = "formula-dag-execution",
name = "Formula DAG Execution Engine",
summary = "Typed DAG-based workflow execution with topological parallelism, retry, and rollback.",
rationale = "Positional task arrays collapse on dependency ambiguity and lack parallelism signals. Formula nodes declare depends_on, on_error, parallel, max_retries — enabling the orchestrator to derive a topological execution plan without imperative scripting.",
how = "Workspace TOML declares Formula nodes; orchestrator's formula.rs converts to DependencyGraph via topological sort; BatchExecutor executes ready nodes in parallel via NATS work queues.",
artifacts = ["schemas/lib/formula.ncl", "platform/crates/orchestrator/src/formula.rs", "platform/crates/orchestrator/src/batch.rs"],
adrs = ["adr-016-workspace-formula-dag"],
nodes = ["formula-dag-execution"],
},
m.make_capability {
id = "workspace-contract",
name = "Typed Workspace Contracts",
summary = "Nickel-validated workspace definitions that compose providers, taskservs, and ingredients into infrastructure DAGs.",
rationale = "Raw TOML workspace files have no type safety — invalid configs surface as runtime errors. Nickel schemas catch structural errors at write time, before any provider API is called.",
how = "CLI validates workspace TOML against schemas/config/workspace_config/ contracts via nickel export before submitting to orchestrator. Orchestrator re-validates on receipt.",
artifacts = ["schemas/config/workspace_config/", "core/crates/", "examples/workspaces/"],
nodes = ["workspace-contract"],
},
m.make_capability {
id = "provider-plugin-system",
name = "Provider Plugin System",
summary = "25-function pluggable interface for infrastructure providers — add a provider without changing the platform.",
rationale = "Hardcoded provider logic makes multi-cloud support a fork, not an extension. The provider interface isolates provider specifics behind a stable contract.",
how = "Each provider implements the ProviderInterface trait (25 functions). Orchestrator dispatches operations via the interface; provider implementations are loaded from catalog/providers/.",
artifacts = ["catalog/providers/", "platform/crates/orchestrator/src/"],
nodes = ["provider-abstraction", "taskserv-pattern"],
},
m.make_capability {
id = "solo-mode-deployment",
name = "Solo Mode — Full-Architecture Single-Operator Deployment",
summary = "Run the full platform on a laptop: embedded SurrealDB (RocksDB), child NATS server, solo_auth_middleware replacing JWT+Cedar.",
rationale = "Simplified mono-binary for solo creates two divergent code paths. Solo mode keeps the same binaries and NATS subjects — scripts written for solo work in multi-user unchanged.",
how = "--mode solo flag activates solo_auth_middleware (auto-injects admin session), SurrealDB switches to kv-surrealkv (RocksDB), NATS starts as child process. service-manager.nu orchestrates startup.",
artifacts = ["platform/crates/control-center/src/middleware/", "platform/crates/orchestrator/src/nats.rs"],
adrs = ["adr-015-solo-mode-architecture"],
nodes = ["solo-mode"],
},
m.make_capability {
id = "nats-brokered-orchestration",
name = "NATS JetStream Orchestration",
summary = "All inter-service task dispatch via NATS JetStream work queues with at-least-once delivery and state machine tracking.",
rationale = "HTTP synchronous task dispatch couples orchestrator latency to provider API latency. NATS decouples dispatch from execution, enables fan-out to taskserv workers, and provides durable state even if a worker crashes mid-task.",
how = "Orchestrator publishes tasks to JetStream streams per provider type. Taskserv workers consume via pull consumers with ack/nack. Task state machine tracks pending → running → completed/failed in SurrealDB.",
artifacts = ["platform/crates/orchestrator/src/workflow.rs", "platform/crates/platform-nats/"],
adrs = ["adr-012-nats-event-broker"],
nodes = ["platform-dispatch"],
},
m.make_capability {
id = "nickel-config-hierarchy",
name = "Nickel-Validated Configuration Hierarchy",
summary = "5-level config precedence with NCL contracts: runtime args > env vars > user config > infra config > system defaults.",
rationale = "Ad-hoc env var overrides without schema validation cause silent misconfiguration. The Nickel merge layer validates every override level against the same contracts before deserialization.",
how = "platform-config's ConfigLoader trait runs collect_env_overrides() → nickel export → serde::Deserialize. Override files are written to config/*.overrides.ncl and merged via & at the entry point.",
artifacts = ["platform/crates/platform-config/src/format.rs", "schemas/config/"],
adrs = ["adr-013-surrealdb-global-store"],
nodes = ["config-hierarchy", "type-safety-nickel"],
},
m.make_capability {
id = "solid-enforcement",
name = "SOLID Boundary Enforcement",
summary = "6 compile-time and runtime SOLID boundaries: orchestrator-only provider calls, control-center-only auth, vault-only secrets.",
rationale = "Without enforced boundaries, authorization and secrets logic diffuses across services. ADR-014 documents 6 hard boundaries with 6 enforcement layers (compile-time, dev-time, pre-commit, CI, runtime, audit).",
how = "Clippy rules, grep CI checks, Cedar policies, and runtime middleware enforce the boundaries. solo_auth_middleware is the only documented auth bypass and requires --mode solo.",
artifacts = ["platform/crates/orchestrator/", "platform/crates/control-center/", "platform/secretumvault/"],
adrs = ["adr-014-solid-enforcement"],
nodes = ["solid-boundaries"],
},
],
requirements = [
m.make_requirement {
id = "rust",
name = "Rust toolchain",
kind = 'Tool,
env = 'Development,
version = "1.75+",
impact = "Platform services and CLI cannot compile.",
provision = "rustup toolchain install stable",
},
m.make_requirement {
id = "nushell",
name = "Nushell",
kind = 'Tool,
env = 'Both,
version = "0.110+",
impact = "Reflection modes, service-manager.nu, and CLI scripts cannot execute.",
provision = "cargo install nu",
},
m.make_requirement {
id = "nickel",
name = "Nickel",
kind = 'Tool,
env = 'Both,
version = "1.15+",
impact = "Schema validation and config export cannot run. platform-config's ConfigLoader cannot operate.",
provision = "cargo install nickel-lang-cli",
},
m.make_requirement {
id = "surrealdb",
name = "SurrealDB",
kind = 'Service,
env = 'Production,
version = "2.3+",
required = false,
impact = "Multi-user deployments cannot persist task state, Cedar policies, or audit logs. Solo mode uses embedded RocksDB.",
provision = "Deploy surrealdb container or binary; solo mode uses kv-surrealkv.",
},
m.make_requirement {
id = "nats-server",
name = "NATS Server (JetStream)",
kind = 'Service,
env = 'Both,
impact = "Orchestrator cannot dispatch tasks; taskserv workers cannot receive work items. Solo mode manages nats-server as a child process.",
provision = "Install nats-server in PATH for solo mode; deploy NATS cluster for multi-user.",
},
m.make_requirement {
id = "cedar-policy",
name = "Cedar policy engine",
kind = 'Infrastructure,
env = 'Production,
required = false,
impact = "Cedar-based authorization unavailable in multi-user mode. Solo mode uses solo_auth_middleware which bypasses Cedar entirely.",
provision = "Policies stored in SurrealDB; loaded by control-center at startup.",
},
],
critical_deps = [
m.make_critical_dep {
id = "surrealdb-crate",
name = "SurrealDB client crate",
ref = "surrealdb@3",
used_for = "Task state machine persistence, Cedar policy storage, audit log, workspace history.",
failure_impact = "All stateful operations (task tracking, policy evaluation, audit) stop. Solo mode continues via kv-surrealkv but loses SurrealDB WS protocol.",
mitigation = "Feature-gated: --no-default-features disables SurrealDB for dev builds. Solo mode uses embedded kv-surrealkv (RocksDB).",
},
m.make_critical_dep {
id = "async-nats",
name = "async-nats",
ref = "async-nats@0.46",
used_for = "All inter-service task dispatch, NATS JetStream work queues, taskserv worker consumers.",
failure_impact = "Orchestrator cannot dispatch workflows; taskserv workers go idle. Solo mode manages nats-server as child — child crash is fatal.",
mitigation = "Feature-gated via platform-nats crate. Solo mode restarts nats-server on SIGTERM.",
},
m.make_critical_dep {
id = "cedar-policy-crate",
name = "cedar-policy",
ref = "cedar-policy@4.8",
used_for = "Authorization decisions in control-center: policy evaluation, RBAC, resource-level access control.",
failure_impact = "All authorization decisions in multi-user mode fail closed. Solo mode unaffected (solo_auth_middleware bypasses Cedar).",
mitigation = "Compile-time link; no runtime loading. cedar-policy is the Cedar Reference Implementation — stable API surface.",
},
m.make_critical_dep {
id = "secretumvault",
name = "secretumvault",
ref = "secretumvault (local path ../../../Development/secretumvault)",
used_for = "Secrets management: age key management, Shamir threshold unsealing, secret storage for provider credentials.",
failure_impact = "Vault service cannot start; provider credential injection fails. All infrastructure operations that require provider API keys stop.",
mitigation = "Local path dependency — pinned to checkout. Solo mode uses filesystem backend (age key).",
},
m.make_critical_dep {
id = "axum",
name = "axum",
ref = "axum@0.8",
used_for = "HTTP API layer for orchestrator, control-center, extension-registry, ai-service, mcp-server.",
failure_impact = "All HTTP API surfaces become unavailable. CLI falls back to NATS direct where supported.",
mitigation = "axum@0.8 is maintained by the Tokio project; API stability is high.",
},
],
domain_provides = {
id = "provisioning-platform",
name = "Provisioning Platform",
schema_path = "reflection/schemas/",
impl_repo_kind = "DevWorkspace",
kind = 'Implicit,
description = "Workspace infrastructure contracts: cluster topology, state dimensions, gate membranes, and operational modes for DevWorkspace projects.",
},
registry_provides = m.make_registry_provides {
participant = "provisioning",
registries = m.make_registries_config {
default = "primary",
registries = [
m.make_registry_entry {
id = "primary",
endpoint = "reg.librecloud.online",
role = 'primary,
tls = true,
namespaces = {
own = ["domains/provisioning/", "modes/provisioning/"],
prefixes = ["domains/provisioning/", "modes/provisioning/"],
},
},
],
},
},
level = {
index = 'Domain,
name = "provisioning-domain",
parent = "ontoref-base",
},
}