Authoring conformant Module Versions
The Orchestrator validates each new Module Version against its Resource Type. This guide explains how to declare inputs, dependencies, provider mappings and outputs. The same publication contract applies through the API, CLI, Terraform/OpenTofu provider and Console.
Three different checks
- At publication, the Orchestrator validates the author’s complete JSON definition against the Resource Type interface. It checks the definition before creating a Proposed Version, lifecycle event or command receipt.
- During deployment planning and execution, the normal resource graph resolves dependencies and concrete values, then the Runner executes Terraform/OpenTofu. Publication does not prove a provider will accept the runtime configuration.
- Trusted artifact verification is deferred. A source revision, optional digest, output declaration or successful publication is not proof that remote code implements the declared interface. Versions remain Unverified.
The Orchestrator does not download Terraform modules, inspect variable/output blocks or execute providers to validate a publication. The author is responsible for a truthful complete definition and for testing the real source.
The Resource Type’s module contract
A Resource Type may declare an immutable module_contract. It applies to this
six-field document, not to the source, SemVer, lifecycle or release notes:
{
"module_inputs": {},
"module_params": {},
"provider_mapping": {},
"dependencies": {},
"coprovisioned": [],
"output_schema": {}
}
Maps and arrays are explicit. Parameter is_optional is its effective boolean
value. output_schema is omitted from this document only when the author omitted
the declaration. Without module_contract, the Orchestrator imposes no additional contract
restrictions on inputs or providers. To declare an unconstrained contract, use
{ "type": "object" }, not an empty contract object.
The contract is a bounded subset of an OpenAPI 3.0 Schema Object. Its root must
have type: object, and root properties/requirements may name only those six
fields. An array schema requires items.
Supported keywords are type, properties, required, additionalProperties,
items, enum, nullable, minimum, maximum, exclusiveMinimum,
exclusiveMaximum, multipleOf, minLength, maxLength, pattern, minItems,
maxItems, uniqueItems, minProperties, maxProperties, title, description,
allOf and not. additionalProperties accepts a boolean or schema. type
is a scalar OpenAPI type name, not an array of type names.
References, including local $ref, remote loading, defaults, other composition
such as oneOf/anyOf, unknown keywords and executable extensions are rejected.
The JSON encoding is limited to 64 KiB, 16 schema levels and 64 schema nodes.
Validation is deterministic and works offline. This is not full JSON Schema.
Example: a workload interface
This example Resource Type requires a fixed namespace and replica count,
a consumer-supplied image parameter, a Kubernetes provider mapping, a namespace
dependency and a dependent health-check resource. Before using it, register the
referenced k8s-namespace and service-healthcheck Resource Types and the
kubernetes.default provider. Their implementations and Module Rules are
separate prerequisites for an actual deployment.
Save this Resource Type body as application-workload.json:
{
"id": "application-workload",
"description": "A namespaced application workload with a health check",
"is_developer_accessible": true,
"output_schema": {
"type": "object",
"properties": { "endpoint": { "type": "string" } }
},
"module_contract": {
"type": "object",
"required": ["module_inputs", "module_params", "provider_mapping", "dependencies", "coprovisioned", "output_schema"],
"properties": {
"module_inputs": {
"type": "object",
"required": ["namespace", "replicas"],
"properties": {
"namespace": { "type": "string", "minLength": 1 },
"replicas": { "type": "integer", "minimum": 1, "maximum": 10 }
}
},
"module_params": {
"type": "object",
"required": ["image"],
"properties": {
"image": {
"type": "object",
"required": ["type", "is_optional"],
"properties": {
"type": { "type": "string", "enum": ["string"] },
"is_optional": { "type": "boolean", "enum": [false] }
}
}
}
},
"provider_mapping": {
"type": "object",
"required": ["kubernetes"],
"properties": { "kubernetes": { "type": "string", "pattern": "^kubernetes\\." } }
},
"dependencies": {
"type": "object",
"required": ["namespace"],
"properties": {
"namespace": {
"type": "object",
"required": ["type", "id"],
"properties": {
"type": { "type": "string", "enum": ["k8s-namespace"] },
"id": { "type": "string", "enum": ["runtime"] },
"params": { "type": "object" }
}
}
}
},
"coprovisioned": {
"type": "array",
"items": { "type": "object" },
"allOf": [{
"not": {
"type": "array",
"items": {
"not": {
"type": "object",
"required": ["type", "is_dependent_on_current"],
"properties": {
"type": { "type": "string", "enum": ["service-healthcheck"] },
"is_dependent_on_current": { "type": "boolean", "enum": [true] }
}
}
}
}
}]
},
"output_schema": { "type": "object" }
}
}
}
allOf combines constraints. The nested not means “there must be at least
one matching health-check item”. minItems: 1 alone would incorrectly accept
an unrelated resource. OpenAPI 3.0 has no contains, so this explicit expression
is needed. Keep such contracts bounded and test matching, missing and unrelated
co-provisioned items.
The following complete publication body demonstrates the interface with inline source. Its Terraform code declares inputs and an output but creates no workload. Replace it with a tested Kubernetes application implementation before using this Resource Type for real deployments.
semantic_version: 1.0.0
module_source: inline
module_source_code: |
variable "namespace" { type = string }
variable "replicas" { type = number }
variable "image" { type = string }
output "endpoint" { value = "${var.namespace}.svc.cluster.local" }
module_inputs:
namespace: "${resources.namespace.outputs.namespace}"
replicas: 2
module_params:
image:
type: string
is_optional: false
provider_mapping:
kubernetes: kubernetes.default
dependencies:
namespace:
type: k8s-namespace
id: runtime
params: {}
coprovisioned:
- type: service-healthcheck
params: {}
is_dependent_on_current: true
copy_dependents_from_current: false
output_schema:
type: object
properties:
endpoint:
type: string
release_notes: Initial interface authoring fixture, not a deployed application.
The namespace placeholder is validated as the literal string in the definition.
A type: integer contract would reject a placeholder string even if that
placeholder could resolve to a number later. A contract that permits placeholders
must permit their literal form. Concrete values are resolved through normal
deployment planning, not evaluated during publication.
Explicit output declarations
A new managed publication must include output_schema whenever its Resource
Type has a nonempty output schema, even without a module_contract. The
declaration must equal the Resource Type’s schema as JSON, including descriptions
and constraints. Object key order and insignificant whitespace do not matter.
This release checks equality. It does not determine whether a different schema
is compatible, so even a stricter declaration is rejected if it is unequal.
An empty Resource Type schema {} imposes no output constraint and permits
omission. { "type": "object" } is nonempty and requires an equal declaration.
Authors must write and review the declaration explicitly. The Orchestrator and its clients
must not copy a Resource Type schema into a missing Version declaration.
New Versions are complete immutable records. Stable-successor publication checks the successor before deprecating its prerelease; a rejected declaration creates no partial lifecycle event, successor or idempotency receipt. Legacy Versions without declarations remain unchanged; The Orchestrator does not fill in the missing data.
Review and diagnose
Use version comparison to inspect exact before and after inputs, parameters,
providers, graph structure and output declarations. The compact output marker
is output_schema_changed; an absent historical schema differs from {}.
A diff describes declarations, not proven runtime compatibility.
| HTTP 400 code | Meaning and action |
|---|---|
resource_type_contract_invalid | Correct an unsupported or malformed contract before creating the Resource Type |
module_resource_type_nonconformant | Correct the complete Module definition at the reported pointer/rule |
module_output_declaration_required | Explicitly supply the constrained output declaration |
module_output_contract_mismatch | Use an exactly equal output schema, or create a new Resource Type/Module for a different interface |
Diagnostics identify JSON pointers and rules without exposing input, source or output values, or credentials. Do not paste sensitive definitions into an issue to investigate an otherwise redacted error. See migration and retention before changing an existing installation’s authoring configuration.