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

AreaBeforeManaged contract and required action
Module authoringOne mutable Module definitionSeparate stable catalogue identity and complete immutable Version publication; transfer Terraform ownership, do not destroy the old Module
Version selectionLegacy Default identityNew canonical SemVer versions start Proposed; explicit stable promotion selects the Default; no implicit Proposed adoption
UpdatesEdit executable fields in placePublish a new complete version, including the output declaration; correcting a field never rewrites history
LifecycleUpdating a Module can change deployment inputPromote, deprecate, mark Defective and restore are reasoned concurrency-checked commands; promotion does not deploy
Resource TypesEarlier clients may attempt contract editsImmutable, unversioned interface; schema, description and developer-access changes need a new ID and new Module binding
ConformanceNo declared input/provider/graph contractOptional immutable module_contract; new publications are checked offline against its six interface fields
OutputsResource Type schema onlyEvery new managed publication for a nonempty Resource Type schema must provide an equal explicit output_schema, even without module_contract
External sourceMutable URLs may have been acceptedExact immutable source revision required; digest optional, immutable when supplied, never proof of verification
DeletionAutomation may expect a clean cataloguePublished Versions/SemVers persist; archive Modules with history, explicitly retain referenced dependencies and import them on reuse
PermissionsBroad legacy Module grantsEquivalent old grants retained, new powers explicitly assigned within their allowed scopes
Go SDK consumersEarlier source contracts under shared/v1Source-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.

Top