CI/CD / Promotion and environment contracts / Lesson 9
Environments, configuration, and candidate promotion
Promote one candidate while making configuration and target identity explicit.
On this page
Lesson goals
- Separate package identity from environment configuration.
- Define approvals that bind to a specific candidate and target.
An environment is more than a name
Staging and production are labels for contracts involving endpoints, identities, configuration, data, dependencies, and operational ownership. Two jobs with different environment names can still address the same target if a variable is wrong. Conversely, identical packages can behave differently under different configuration. Parcel’s staging carrier endpoint is synthetic; production would require an independently controlled target. A release review should identify both intended environment and resolved destination before any authority is exercised. A friendly job name is not destination verification.
Keep configuration outside mutable packaging
Build Parcel’s package once, then combine it with reviewed environment-specific configuration at adoption. Values such as an endpoint or feature setting belong to a configuration contract; credentials require a separate secret channel. Record configuration revision without printing secrets. If the build embeds an environment endpoint, staging tests may not exercise the exact production package. Sometimes compile-time configuration is unavoidable, but then declare separate candidates and their evidence rather than claiming that one tested package was promoted unchanged.
Represent adoption as a pair
The following complete model compares package and configuration identity. Changing only configuration still produces a different adoption record and may justify validation or rollback. The string labels are synthetic and intentionally avoid fake hashes. In a real release record, immutable package digests and authenticated configuration revisions replace these labels. Do not include secret values in the identity record. Configuration identity should reveal what was selected while preserving the confidentiality of material used to realize it.
staging = {"package": "candidate-r7", "config": "staging-c3"}
production = {"package": "candidate-r7", "config": "production-c8"}
print(staging["package"] == production["package"])
print(staging == production)
True
False
The first result proves label equality within the model only. The second shows that package equality does not make environment configuration identical. No environment is queried or changed.
Bind approval to the decision
An approval should identify candidate, target, evidence, and any meaningful expiry or conditions. A generic approve button pressed before packaging cannot establish approval of unknown bytes. If a candidate changes while waiting, require the policy’s defined reapproval behavior rather than silently applying an earlier decision. Platform environment protections can delay jobs and limit access to environment secrets, but feature availability and bypass permissions vary. Review the actual repository and organization policy; declaring an environment field alone does not prove protection exists.
{"candidate":"candidate-r7","target":"production-lab","configuration":"production-c8","decision":"pending"}
This synthetic record requests a decision for a particular combination. It is not a deployment API payload, does not grant approval, and contains no endpoint or credential. Evidence links and verified identities would be required in an actual system.
Observe what was adopted
A successful promotion job may have submitted work without proving that every instance adopted it. Record target-side observations through the approved operational path: desired candidate, observed candidate, configuration identity, and health status. Diagnose differences before sending another release. Environment drift may involve a manual edit, an incomplete rollout, or a mistaken target. Rebuilding the package does not repair an untracked configuration change. Keep the boundary between release authorization, request acceptance, convergence, and user-visible health clear in both dashboards and incident notes.
Common errors and fixes
Staging approval authorizes a later different candidate.
- Why it happens
- The approval was not bound to artifact identity.
- How to fix it
- Require a decision for the actual candidate and target combination.
- Prevent it next time
- Invalidate stale decisions when material inputs change.
The production job resolves a staging endpoint.
- Why it happens
- Environment naming was trusted instead of effective configuration.
- How to fix it
- Verify target identity and configuration through the reviewed release path.
- Prevent it next time
- Keep environment ownership and destination checks explicit.
A successful submission is reported as complete adoption.
- Why it happens
- Control-plane acceptance was confused with runtime convergence.
- How to fix it
- Collect observed identity and health evidence separately.
- Prevent it next time
- Define completion criteria beyond command exit success.
Check your understanding
1. The package is unchanged but a timeout setting doubles. Is this a release-relevant change?
Show worked solution
Yes. The adoption contract changed even though package bytes did not. Review the setting’s effect, validate it appropriately, and retain configuration identity with the release record. A configuration rollback may be appropriate without rebuilding the package.
2. An approval waits overnight while dependencies are found vulnerable. Must old approval remain sufficient?
Show worked solution
The release policy should define evidence freshness and invalidation. Re-evaluate the candidate against the new information and obtain a new decision where required. An approval records a bounded judgment; it does not make future evidence irrelevant.
Key takeaways
- Identify candidate, configuration, and destination separately.
- Approval and observed adoption must refer to the same bounded decision.