Upgrade, state migration and retention
Module Version Management changes the authoring contract. Use the chart, Control Plane, Data Plane, IAM, Runner, Console, CLI and provider revisions qualified together in the release notes. Upgrading only the Console or provider does not upgrade the server contract.
This upgrade breaks the authoring contract used by older clients. Existing identities and deployment snapshots are retained, but clients can no longer edit Module definitions in place. Update publishing clients and definitions to meet the conformance and output-declaration requirements before resuming Module publication.
What changes, and what remains readable
| Area | Before | Managed contract and required action |
|---|---|---|
| Module authoring | One mutable Module definition | Separate stable catalogue identity and complete immutable Version publication; transfer Terraform ownership, do not destroy the old Module |
| Version selection | Legacy Default identity | New canonical SemVer versions start Proposed; explicit stable promotion selects the Default; no implicit Proposed adoption |
| Updates | Edit executable fields in place | Publish a new complete version, including the output declaration; correcting a field never rewrites history |
| Lifecycle | Updating a Module can change deployment input | Promote, deprecate, mark Defective and restore are reasoned concurrency-checked commands; promotion does not deploy |
| Resource Types | Earlier clients may attempt contract edits | Immutable, unversioned interface; schema, description and developer-access changes need a new ID and new Module binding |
| Conformance | No declared input/provider/graph contract | Optional immutable module_contract; new publications are checked offline against its six interface fields |
| Outputs | Resource Type schema only | Every new managed publication for a nonempty Resource Type schema must provide an equal explicit output_schema, even without module_contract |
| External source | Mutable URLs may have been accepted | Exact immutable source revision required; digest optional, immutable when supplied, never proof of verification |
| Deletion | Automation may expect a clean catalogue | Published Versions/SemVers persist; archive Modules with history, explicitly retain referenced dependencies and import them on reuse |
| Permissions | Broad legacy Module grants | Equivalent old grants retained, new powers explicitly assigned within their allowed scopes |
| Go SDK consumers | Earlier source contracts under shared/v1 | Source-breaking Control Plane DTO updates use github.com/stellwerk-labs/platform-orchestrator-cp/shared/v2; select its separately published compatible module tag |
Existing opaque version IDs, history and captured deployment snapshots remain
readable. Legacy v0 does not gain a fabricated SemVer, digest, output declaration
or conformance proof. Exact historical deployment and rollback remain subject
to normal permissions and retained-source availability. This compatibility does
not permit old publishing clients to bypass the new publication requirements.
Existing installations
Back up the platform databases and the secret/key storage required for their recovery. Preserve Terraform/OpenTofu state, provider lock files, Helm values and the deployed component revisions. Keep backups protected; state can contain credentials and deployment outputs.
Use the release’s maintenance procedure to stop new mutating work and drain active Deployments before switching writers. Do not let legacy and managed Module writers mutate the database concurrently. Run the chart’s supported migrations, wait for service and Runner health, then verify existing identities, custom role permissions and a legacy deployment before reopening automation.
The migration preserves the old Default’s opaque identity as generation v0.
It does not invent a semantic version or artifact digest for historical data.
Existing deployments and exact history rollback continue to reference that
identity. The first complete stable managed publication is generation v1,
starts Proposed and becomes Default only after explicit promotion. From then
on, normal SemVer precedence applies. v0 and v1 are migration markers, not
strings to enter into semantic_version.
The upgrade preserves equivalent legacy custom-role grants: module_read
satisfies module.read and module.version.read; module_write satisfies
module.version.publish, module.version.promote and module.archive at its
existing organisation scope. Catalogue creation and metadata editing continue
to use module_write.
New powers require explicit assignments. Legacy exact grants do not add deprecation, Defective marking, restoration, Proposed use, Pin control, restricted recovery or add-on authority. Review these individually with the organisation’s policy and Project/Environment scope. Do not replace missing permissions with organisation Admin solely to bypass a failed check.
Terraform/OpenTofu ownership transfer
Use platform-orchestrator_module_catalogue_entry for stable catalogue identity
and platform-orchestrator_module_version for new immutable publications.
The legacy platform-orchestrator_module resource does not model that split.
Keep its existing server object; transfer state ownership without destroying it.
With automation paused, back up the state and replace the legacy resource
block with a catalogue entry having the same technical ID and Resource Type.
For example, an existing payments-redis Module becomes:
resource "platform-orchestrator_module_catalogue_entry" "redis" {
id = "payments-redis"
resource_type = "redis"
display_name = "Payments Redis"
}
Transfer only the intended address. These commands remove local ownership and import the same server object; they do not delete or republish it:
terraform state rm 'platform-orchestrator_module.redis'
terraform import 'platform-orchestrator_module_catalogue_entry.redis' payments-redis
terraform plan
Use the corresponding tofu commands when OpenTofu owns the state. Do not run
both tools against the same state concurrently. If import fails, restore the
old configuration and re-import the original Module into its old address;
resolve the failure before any apply. Keep the backup for recovery, but check
for newer state changes before restoring it.
Do not import the legacy v0 as a semantic-version resource. Keep its history
in the server, and publish the first complete managed version separately.
For an already-managed version, import uses <module-id>/<version-uuid> (an
exact SemVer may also resolve the version). Never publish a second object to
change a Terraform address.
Publication and lifecycle ownership
A version resource supplies the complete immutable definition:
resource "platform-orchestrator_module_version" "marker_1_0_0" {
module_id = platform-orchestrator_module_catalogue_entry.marker.id
semantic_version = "1.0.0"
definition = jsonencode({
module_source = "inline"
module_source_code = "output \"value\" { value = \"release-one\" }"
module_params = {}
module_inputs = {}
provider_mapping = {}
dependencies = {}
coprovisioned = []
output_schema = {
type = "object"
properties = { value = { type = "string" } }
}
})
}
This fragment assumes a marker catalogue entry bound to a Resource Type with
a string value output. It publishes Proposed and does not deploy or promote.
The explicit schema must equal the Resource Type schema as JSON, including
descriptions and constraints. Review the actual source interface and write the
schema yourself. The provider does not copy it automatically to pass validation.
Leave lifecycle_status omitted when the resource observes decisions made
through Console, CLI or an explicit lifecycle transaction. Keeping
lifecycle_status = "default" on historical versions instructs Terraform to
restore them after a newer version is promoted.
For Terraform-owned lifecycle transactions, use a reviewed fixed expected
revision. Do not reference a live resource_version expression as a permanent
transaction input: the command changes that revision and would keep changing
its own desired configuration. Keep receipts for completed commands and verify
a no-op plan after promotion, restoration and refresh.
Teardown and a later setup
Delete application Environments through normal destruction before removing their Runner or credentials. Published Module Versions remain permanently in Stellwerk; deleting their Terraform resources releases state ownership only. Deleting a catalogue entry with version history archives it through a reasoned command before releasing ownership. An eligible unused empty shell is deleted. Unrelated conflicts, such as an operation reservation, remain errors.
Referenced providers and Resource Types may also need retention. Set the
explicit deletion_policy = "retain" on those resources when the configuration
intends to keep dependencies of immutable history. The default delete still
reports blocked deletion. Retention does not archive a provider, revoke its
credentials or destroy infrastructure. Resource Type archival is a separate
reasoned operation that blocks new bindings while preserving existing Modules.
A later setup with the same IDs must import retained objects. Catalogue import
uses the Module slug, Resource Type import its ID, and provider import
<provider-type>.<provider-id>. Unarchive the Module with a reason before new
publication or adoption. Re-import an existing immutable version rather than
trying to republish its reserved SemVer. Use a new version for a changed
definition, or choose intentionally new catalogue IDs for an independent run.
Recovery boundary
The conformance migration adds nullable contract/declaration columns. It leaves
historical absence intact. A new module_contract cannot be retrofitted into an
existing immutable Resource Type; create a new Resource Type and Module instead.
Published versions are not rewritten to acquire output declarations or digests.
Application rollback and database migration rollback are different operations. A database Down migration that removes lifecycle or Pin tables destroys new history; a schema round-trip test does not make that a safe recovery procedure. After managed writes begin, use a verified compatible application revision or forward repair. Do not reinstall an older writer against new semantics. Keep additive conformance columns during application recovery. Their explicit Down path is safe without metadata loss only before new declarations exist; otherwise export them and treat removal as deliberate data loss, not routine application rollback.
Only restore a pre-upgrade backup under the documented recovery procedure with all writers stopped and an explicit decision about writes since the backup. Keep Module sources, infrastructure state and encryption keys required for deployment-history rollback. A demo factory reset is not an upgrade or public teardown procedure.