You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A push to develop should not be able to change production content, and the deployment history should make production's stability legible at a glance.
Today production stability on develop-triggered runs rests on build determinism re-established by convention (a manual byte-for-byte check at #96 time), not on anything enforced by CI. The aim of this backlog item is to move that guarantee from convention to enforcement, and to set correct expectations in the GitHub Deployments UI.
Current state
This is documented, deliberate #96 behavior, not a regression — recording it so it can be hardened, not reverted.
GitHub Pages serves a single deployment artifact per origin, so deploy.yml builds both refs on every push to either branch: the build job checks out main -> site root (production) and develop -> /uat/ (unreleased preview), assembles one combined site/ artifact, and the deploy job (actions/deploy-pages) publishes it. actions/deploy-pages always records its deployment in the github-pages environment regardless of the triggering branch; the separate uat-environment bookkeeping job (added in #106, gated if: github.ref == 'refs/heads/develop') additionally records a uat environment entry.
Observed consequence (the trigger for this issue): a develop push refreshes both the github-pages and the uat environments at essentially the same instant, so the Deployments UI reads as if production redeployed on a develop-only change. Verified via the API — the two most recent develop pushes:
Env
ref
sha
created
github-pages
develop
c7458c9
2026-07-22T21:56:57Z
uat
develop
c7458c9
2026-07-22T21:57:09Z
github-pages
develop
5a20940
2026-07-22T21:43:16Z
uat
develop
5a20940
2026-07-22T21:43:31Z
Note the github-pages entries carry the triggering develop sha, not a main sha — the deploy step is inherently branch-agnostic.
What is actually safe today, and why it is only safe by convention:
But nothing in the pipeline re-verifies that on each develop-triggered run. If a future dependency bump, toolchain change, or non-deterministic build step made the main build differ, a develop push would silently republish altered production bytes. The guarantee is a manual check frozen in time, not an enforced invariant.
Proposed direction (to be designed at implementation time)
(a) Don't rebuild prod on develop-triggered runs. Reuse or cache the production build keyed by the main commit sha (e.g. actions/cache or an artifact keyed on the main HEAD sha), and only rebuild the main half when that sha actually changes. A develop-only run would then reassemble the artifact from the cached prod bytes, so it is structurally incapable of altering them.
(b) Enforce byte-stability in CI. Add a deploy-job step that asserts the assembled production root is byte-identical to the last main-triggered production build (compare a manifest of file hashes against a stored baseline), and fails the run loudly on any drift instead of silently publishing. This makes "a develop push cannot change prod bytes" a checked invariant rather than a convention.
(c) Document the Deployments-UI semantics. The github-pages entries appearing on develop pushes are inherent to Pages' single-artifact model and cannot be suppressed; the uat env record (ci(deploy): record develop deploys against a distinct uat environment #106) is what meaningfully marks develop-relevant deploys. A short note in CLAUDE.md / the workflow comments should set this expectation so the near-simultaneous refresh is not misread as an accidental prod redeploy.
Honest limitation: GitHub Pages exposes one deployment target per origin, so genuinely separate prod/uat deployment environments (distinct hosting per sub-path, each with its own independent history and gates) are not achievable on Pages. The sub-path split (/ vs /uat/) plus the uat bookkeeping env is the closest available; options (a)/(b) harden the coupling that this constraint forces, they do not remove it.
Acceptance criteria
A develop-triggered run cannot alter production bytes — enforced by CI (option (a) and/or (b)), not by convention.
If the assembled production root ever drifts from the last main-triggered build, the deploy run fails loudly rather than publishing the change.
The Deployments-UI semantics (why github-pages refreshes on develop pushes; what the uat env record means) are documented where a maintainer will see them.
Goal
A push to
developshould not be able to change production content, and the deployment history should make production's stability legible at a glance.Today production stability on develop-triggered runs rests on build determinism re-established by convention (a manual byte-for-byte check at #96 time), not on anything enforced by CI. The aim of this backlog item is to move that guarantee from convention to enforcement, and to set correct expectations in the GitHub Deployments UI.
Current state
This is documented, deliberate #96 behavior, not a regression — recording it so it can be hardened, not reverted.
GitHub Pages serves a single deployment artifact per origin, so
deploy.ymlbuilds both refs on every push to either branch: thebuildjob checks outmain-> site root (production) anddevelop->/uat/(unreleased preview), assembles one combinedsite/artifact, and thedeployjob (actions/deploy-pages) publishes it.actions/deploy-pagesalways records its deployment in thegithub-pagesenvironment regardless of the triggering branch; the separateuat-environmentbookkeeping job (added in #106, gatedif: github.ref == 'refs/heads/develop') additionally records auatenvironment entry.Observed consequence (the trigger for this issue): a develop push refreshes both the
github-pagesand theuatenvironments at essentially the same instant, so the Deployments UI reads as if production redeployed on a develop-only change. Verified via the API — the two most recent develop pushes:github-pagesc7458c9uatc7458c9github-pages5a20940uat5a20940Note the
github-pagesentries carry the triggeringdevelopsha, not amainsha — the deploy step is inherently branch-agnostic.What is actually safe today, and why it is only safe by convention:
mainref withSC_DEPLOY_ENVunset, and was verified byte-for-byte identical to the pre-Deploydevelopto a UAT/staging environment on GitHub Pages (sub-path) #96 build at that time.mainbuild differ, a develop push would silently republish altered production bytes. The guarantee is a manual check frozen in time, not an enforced invariant.Proposed direction (to be designed at implementation time)
maincommit sha (e.g.actions/cacheor an artifact keyed on themainHEAD sha), and only rebuild themainhalf when that sha actually changes. A develop-only run would then reassemble the artifact from the cached prod bytes, so it is structurally incapable of altering them.main-triggered production build (compare a manifest of file hashes against a stored baseline), and fails the run loudly on any drift instead of silently publishing. This makes "a develop push cannot change prod bytes" a checked invariant rather than a convention.github-pagesentries appearing on develop pushes are inherent to Pages' single-artifact model and cannot be suppressed; theuatenv record (ci(deploy): record develop deploys against a distinct uat environment #106) is what meaningfully marks develop-relevant deploys. A short note inCLAUDE.md/ the workflow comments should set this expectation so the near-simultaneous refresh is not misread as an accidental prod redeploy.Honest limitation: GitHub Pages exposes one deployment target per origin, so genuinely separate prod/uat deployment environments (distinct hosting per sub-path, each with its own independent history and gates) are not achievable on Pages. The sub-path split (
/vs/uat/) plus theuatbookkeeping env is the closest available; options (a)/(b) harden the coupling that this constraint forces, they do not remove it.Acceptance criteria
main-triggered build, the deploy run fails loudly rather than publishing the change.github-pagesrefreshes on develop pushes; what theuatenv record means) are documented where a maintainer will see them.developto a UAT/staging environment on GitHub Pages (sub-path) #96 guarantee, now automated).Backlog item, filed 2026-07-22. Not scheduled for a specific session.