--- id: netkingdom-playbook-capability-contract type: standard title: "NetKingdom Playbook Capability Contract v0.2" domain: netkingdom status: proposed version: "0.2" created: "2026-09-27" updated: "2026-09-27" scope: meta-orchestration supersedes: - canon/standards/playbook-capability-contract_v0.1.md adr: - docs/adr/ADR-0012-playbook-capability-contract-ownership.md schema: - canon/schemas/playbook-capability-declaration_v0.1.schema.json related: - NK-WP-0040 - history/2026-09-23-railiance-clock-identity-and-layer-review.md --- # NetKingdom Playbook Capability Contract v0.2 Everything in v0.1 stands unchanged except where this document says otherwise. v0.1 remains `accepted` and governs declaration conformance; this document adds the execution-attribution receipt as a proposed amendment. It becomes conformance-checked only once `NK-WP-0040-T02` lands the schema, evidence-holder agreement with audit-core and Railiance, and the corresponding validator addition. Until then, no declaration is required to emit a receipt. ## Purpose The Playbook Capability Contract is the declared interface between NetKingdom meta-orchestration and Railiance execution playbooks. It lets a playbook state: - which capability it provisions; - which parameters it exposes, including defaults, constraints, and security sensitivity; - which resources and responsibilities it claims; - which trust states it requires or satisfies; - how it is published into a catalog; - the execution-attribution receipt one run of it emits. NetKingdom consumes declarations to select playbooks, choose safe parameter overrides, sequence trust states, and build a responsibility map. Railiance owns the playbooks and execution mechanics. ## Ownership NetKingdom owns this contract. Railiance publishes conformant declarations. Execution stays in Railiance. See ADR-0012. ## File Convention Declaration files SHOULD live in the publishing repo at: ```text capabilities/playbooks/.yaml ``` Each file describes one playbook or one stable playbook entry point. A playbook with materially different modes may publish multiple declarations if those modes provide different capabilities or expose different security-sensitive parameters. ## Top-Level Shape ```yaml apiVersion: netkingdom.io/playbook-capability/v0.1 kind: PlaybookCapabilityDeclaration metadata: id: railiance-infra.bootstrap-host name: Railiance S1 host bootstrap owner: railiance-infra repo: railiance-infra domain: railiance contract_version: "0.1" spec: playbook: {} capabilities: [] parameters: [] responsibilities: [] trust: {} catalog: {} ``` ## Capability Vocabulary `spec.capabilities[].id` MUST be one of the controlled vocabulary values below. Capability ids are stable comparison keys. | Capability id | Tier | Meaning | | --- | --- | --- | | `s1.os-baseline` | S1 | Host provisioning, OS convergence, hardening, and substrate access baseline | | `s1.secret-bootstrap` | S1 | Bootstrap secret material, SOPS/age handling, emergency material placement | | `s2.cluster-runtime` | S2 | Kubernetes runtime, ingress, networking, admission, and cluster access | | `s3.platform-services` | S3 | Databases, caches, object storage, brokers, and shared platform services | | `c0.bootstrap-identity` | C0 | Local/bootstrap identity before runtime IAM exists | | `c1.lightweight-sso` | C1 | key-cape lightweight SSO profile implementation | | `c2a.light-2fa` | C2a | Lightweight built-in second factor such as TOTP/WebAuthn | | `c2b.token-authority` | C2b | privacyIDEA or equivalent token authority | | `c3.runtime-secrets` | C3 | OpenBao or equivalent runtime secret authority | | `c4.fine-grained-authorization` | C4 | flex-auth and delegated PDP readiness | | `c5.enterprise-federation` | C5 | expanded-mode Keycloak, enterprise federation, or SAML brokering | | `c6.self-optimizing-audit` | C6 | audit feedback loops, drift surfacing, and continuous adaptation | The `S*` entries align to Railiance stack layers. The `C*` entries align to the NetKingdom capability progression. A declaration may list more than one capability only when the same playbook entry point truly provides each one. ## Resource Kinds Every capability and responsibility claim references one or more resource kinds: | Resource kind | Meaning | | --- | --- | | `identities` | humans, service accounts, agents, groups, tenants, and assurance evidence | | `roles_scopes_policies` | roles, scopes, policy packages, protected-system registrations, decision records | | `secrets_credentials` | bootstrap material, runtime secrets, dynamic credentials, leases, credential rotations | | `infrastructure_resources` | hosts, runtime, networking, platform services, storage, and deployment substrate | ## Parameter Declarations Each parameter entry has this shape: ```yaml - name: swapfile_size_mb type: integer required: false default: 4096 constraints: minimum: 0 maximum: 65536 sensitivity: operational tuning_authority: netkingdom_tunable description: Swap size applied by the bootstrap playbook. ``` Allowed `type` values: - `string` - `integer` - `number` - `boolean` - `array` - `object` Allowed `sensitivity` values: - `public` - safe to display and tune freely. - `operational` - affects behavior or sizing, not secret material. - `security_sensitive` - affects security posture and requires platform review. - `secret_reference` - points to secret material but must not contain the secret value itself. Allowed `tuning_authority` values: - `playbook_default` - NetKingdom should rely on the playbook default. - `netkingdom_tunable` - NetKingdom may override for a scenario. - `platform_only` - only platform-control-plane authority may override. - `tenant_tunable` - tenant-scoped scenario owners may override within constraints. - `forbidden` - declaration exposes the value for audit only; callers may not override it. Security-sensitive and secret-reference parameters MUST NOT be `tenant_tunable`. Secret-reference defaults must be references or paths, not plaintext secret values. For executable validation, a `secret_reference` value MUST be a non-whitespace URI such as `openbao://kv/platform/example` or `kubernetes://namespace/name#key`, or an explicit absolute/relative path beginning with `/`, `./`, or `../`. Bare strings are rejected because the composer cannot distinguish them from secret values. Supported constraints: | Constraint | Applies to | Meaning | | --- | --- | --- | | `enum` | all scalar types | value must be one of the listed values | | `minimum` / `maximum` | integer, number | numeric bounds | | `min_items` / `max_items` | array | array length bounds | | `pattern` | string | regular expression the value must match | ## Responsibility Claims Responsibility entries feed the responsibility map. They do not transfer execution ownership to NetKingdom. ```yaml - resource_kind: infrastructure_resources owner: railiance-infra resources: - server:target_hosts - os-baseline repo_owns: Provisioning, convergence, and verification mechanics. netkingdom_orchestrates: Whether this substrate capability is selected, and which security posture is required. ``` `owner` names the repo or provider that holds execution ownership. `repo_owns` explains the implementation responsibility. `netkingdom_orchestrates` explains the meta-orchestration responsibility. ## Trust States And Readiness Declarations use the trust-state vocabulary from the platform architecture: - `bare_host_trust` - `cluster_trust` - `bootstrap_secret_trust` - `bootstrap_identity_trust` - `runtime_secret_trust` - `runtime_identity_trust` - `runtime_authorization_trust` - `tenant_onboarding_trust` Each declaration lists states it requires and states it satisfies: ```yaml trust: requires: - state: bare_host_trust readiness_checks: [] satisfies: - state: bootstrap_secret_trust readiness_checks: - id: sops-age-material-present description: SOPS/age material is present for bootstrap secrets. evidence: ansible role sops_agent converged successfully ``` Readiness checks are evidence obligations. The declaration names the check; the Railiance playbook or verification tooling performs it. ## Catalog And Consumption Model A catalog is an index of declarations. For v0.1, the catalog mechanism is file-based: 1. Railiance repos publish declarations under `capabilities/playbooks/*.yaml`. 2. NetKingdom or a future catalog job discovers those files from known orchestrated repos. 3. The validator checks each declaration against this contract. 4. A scenario states required capability ids and parameter overrides. 5. NetKingdom selects declarations that provide the required capabilities. 6. NetKingdom applies only allowed parameter overrides, rejecting out-of-range, tenant-forbidden, or security-unsafe overrides. 7. NetKingdom composes the responsibility and trust-state claims into a scenario responsibility map and readiness sequence. The declaration is not an execution plan. It is the interface that lets a separate playbook runner execute safely. ## Scenario Shape The validator supports a small scenario file for single-provider conformance demos: ```yaml id: scenario:s1-host-bootstrap-reference authority: platform requires: capabilities: - s1.os-baseline parameter_overrides: railiance-infra.bootstrap-host: target_hosts: - railiance01 swapfile_size_mb: 8192 ``` Allowed scenario authorities are `platform`, `netkingdom`, and `tenant`. Tenant authority cannot override `platform_only`, `security_sensitive`, or `secret_reference` parameters. The demo composer refuses ambiguous providers and overrides aimed at unselected declarations. Deterministic multi-provider selection, explicit provider pins, trust sequencing, responsibility maps, and owner-routed readiness handoffs are defined by `security-scenario-composition_v0.1.md` and implemented by `tools/security-scenario-composer/`. Use that contract for operational planning; the demo path does not authorize or execute playbooks. ## Execution Attribution Receipt (proposed) Raised by the railiance-clock identity review (`history/2026-09-23-railiance-clock-identity-and-layer-review.md`, Ruling 1). IAM Profile v0.3 defines who acts. This contract's responsibility claims define what is selected and who is responsible. Neither defines the record that ties **one execution** to its actor chain, artifact, and result. This section is that record's field list. It is a proposal: it does not obligate any declaration to emit a receipt until conformance is enforced per `NK-WP-0040-T02`. A receipt is a single, non-secret, structured record describing one completed (or failed) execution of a declared capability. It never embeds bearer credentials — tokens, secret values, or role response bodies. Unknown attribution is recorded as an explicit `unknown`, never inferred from path strings, repository ownership, or convenience defaults. ### Fields | Field | Meaning | | --- | --- | | `initiator.iss` / `initiator.sub` | Issuer and subject of the initiating actor, from its IAM Profile token | | `delegation` | The delegation reference (`actor_sub` / `act.sub`) when the initiator acted through a delegating agent; absent, not `unknown`, when there was no delegation | | `executing_workload` | The authoritative workload binding (Tenancy Posture `workload_identity`, proposed) that ran the playbook | | `runtime_principal` | The runtime credential's principal identity (e.g. service account, agent runtime identity) that executed it, distinct from the workload binding | | `tenant` | The tenant the execution acted for | | `environment` | The environment the execution ran in | | `run_id` | A stable, unique identifier for this one execution | | `source_commit` | The source commit of the executed playbook or declaration | | `artifact_digest` | The content digest of the executed artifact (image, package, or script) | | `target` | The inventory reference of what the execution acted on | | `action` | The action taken against the target | | `decision_refs` | Decision and approval record identifiers that authorized the execution, where one was required | | `time_interval.start` / `time_interval.end` | The attributed start and end of the execution | | `time_interval.clock_source` | The clock the interval was measured against | | `time_interval.bound` | The interval's precision bound, when one exists (e.g. clock skew tolerance); absent when no bound is established, never fabricated | ### Emission and custody (open) Who emits the receipt, who holds it as evidence, and how a consumer validates one are not decided by this section. `NK-WP-0040-T02` routes that decision to audit-core (candidate evidence holder, per the security layer model's Evidence role) and Railiance (candidate emitter, since it executes). The receipt schema under `canon/schemas/` and its validator land together with that agreement, not before it. ### Non-goals - This is not an authorization decision record. `decision_refs` points at one; it does not restate it. - This is not a substitute for the Playbook Capability Contract's responsibility claims or trust-state readiness checks, which describe what a declaration is allowed to do, not what one run of it did. - This does not create a fourth IAM principal type. `executing_workload` and `runtime_principal` name existing principals and bindings; they do not grant anything by themselves (railiance-clock review, Ruling 1). ## Conformance A declaration conforms when it passes: ```text tools/playbook-capability-contract/playbook_contract_validator.py ``` The validator checks: - top-level API version and kind; - required metadata; - controlled capability ids and tiers; - resource-kind vocabulary; - parameter type/default/constraint/sensitivity/tuning rules; - responsibility claims; - trust-state and readiness-check shape; - catalog publication metadata; - optional scenario selection and parameter override compatibility. The execution-attribution receipt above is not yet enforced by this validator; see `NK-WP-0040-T02`. ## Reference Adoption The reference declaration for v0.1 is in: ```text ../railiance-infra/capabilities/playbooks/railiance-infra.bootstrap-host.yaml ``` It describes the existing Railiance S1 Ansible bootstrap playbook and can be selected by the sample scenario in: ```text examples/playbook-capability-contract/scenario-s1-host-bootstrap.yaml ```