Skip to content

πŸ› make same-schema releases deployable, and derive umbrella subchart packaging - #686

Merged
jrosseel merged 4 commits into
developfrom
feat/derive-umbrella-subcharts
Aug 19, 2026
Merged

πŸ› make same-schema releases deployable, and derive umbrella subchart packaging#686
jrosseel merged 4 commits into
developfrom
feat/derive-umbrella-subcharts

Conversation

@jrosseel

Copy link
Copy Markdown
Collaborator

Two related deploy-path fixes: the one that makes 0.9.2 deployable at all, and the one that removes the chart-pin ceremony. Reopens the work from the closed #681 with the deploy fix added.

1. Same-schema releases are undeployable to a migrated silo (fixes #685)

Deploying 0.9.1 β†’ 0.9.2 to testv4 failed at the PostgreSQL privileges Job:

Database 'opencrane' is not an exact fresh or migrated 0.9.0 schema

apps/postgres/helm/templates/database-privileges-job.yaml accepts two database life-histories: a fresh install whose recorded origin equals the current release's protected baseline, or a migrated database proven against deploy-supplied previous-migration evidence. testv4 is neither: it legitimately reached schema 0.9.0 through the reviewed 0.8.0-to-0.9.0 migration, so its recorded origin is the older protected baseline and it needs the second path β€” but the deploy supplied no evidence.

Why no evidence: 0.9.1, 0.9.2 and 0.9.0 all declare schema 0.9.0, so resolveDatabaseTransition(0.9.2, 0.9.1) correctly returns kind=current, migration=null. The old fallback in k8s-deploy.sh then re-resolved the transition against 0.9.2's own previousRepositoryVersion (0.9.1) β€” another same-schema hop returning null again β€” and gave up. Every same-schema patch train was therefore undeployable to any already-migrated silo.

Two things I verified rather than assumed, both of which invalidated the first proposed fixes:

  • The resolver cannot be asked for older lineage: resolve(0.9.2, 0.8.1) errors with automatic database migration requires exact previous release '0.9.1', and it also requires the release version to equal the root package.json version. So "walk back and re-resolve" is not implementable, and the --from-release-version 0.8.1 workaround cannot run at all.
  • The evidence the database needs does exist in the manifests β€” it just belongs to release 0.9.0.

The fix adds resolveSchemaLineage(repositoryRoot, releaseVersion), which walks the release chain to the release that owns the migration producing the current schema and returns that migration's recorded evidence, exposed through scripts/release-versioning/schema-lineage.mjs. k8s-deploy.sh calls it only when the transition is current with no migration of its own.

Proof against the real chain:

$ node scripts/release-versioning/schema-lineage.mjs . 0.9.2
id: 0.8.0-to-0.9.0   fromSchemaVersion: 0.8.0   ownedByReleaseVersion: 0.9.0
sourceProtectedBaselineSha256s: [12505f3c…, 25bfc5d3…]

12505f3c… is exactly the origin digest testv4's database records, which is the value the Job's convergence gate compares against.

Deliberate constraints: the transition stays current (no migration is proposed or executed), the adjacent-minor policy is untouched, the convergence gate is not loosened, and the returned history sets carriedForwardThroughReleaseVersion: null so reporting history can never authorise a carry-forward override. The fresh-install path is unaffected β€” the fallback is gated on kind == current.

2. Derive umbrella subchart packaging (was #681)

Every subchart version bump required three synchronised edits β€” the umbrella Chart.yaml pin, Chart.lock, and the vendored charts/*.tgz β€” and a missed one blocked CI and deploys. All 15 umbrella dependencies are in-repo file:// charts, so the checked-out commit already fixes their sources; the pin ceremony recorded nothing git did not already hold.

  • The umbrella declares open constraints (">=0.0.0-0"), always accepting the version each app currently declares.
  • Chart.lock and charts/*.tgz are deleted and gitignored; packaging is derived at render time.
  • validateUmbrella keeps the one invariant that can still drift β€” every chart-bearing application must stay declared as an umbrella dependency β€” and drops the pin/lock/archive comparisons.
  • Two contracts that render the checkout rather than the disposable fixture get a shared ensure_umbrella_chart_dependencies helper.
  • Docs and the website Contributing pages updated.

External bootstrap charts stay pinned by version and digest; this changes in-repo charts only.

Validation

  • node scripts/release-versioning/schema-lineage.mjs . 0.9.2 returns the 0.8.0-to-0.9.0 evidence including the digest testv4 records
  • test:release-versioning 51/51, including two new tests: lineage recovery for a same-schema release, and no lineage for a schema never migrated into
  • run-helm-contracts.sh 21/21 from a clean checkout with charts/ and Chart.lock deleted first (the earlier ⚑ derive umbrella subchart packaging from in-repo sourcesΒ #681 run passed only because stale archives lingered on disk β€” that mistake is why this was re-validated from scratch)
  • check:release-versioning --base origin/develop PASS; shell syntax checked
  • test:database-migrations needs a local Docker daemon (removed with Colima today), so CI owns that proof

Next

Once merged, retry the testv4 0.9.1 β†’ 0.9.2 deploy β€” the silo is still serving a server image that predates the merged conversation-response-parser fix (#670), which is the "Chats are unavailable" symptom.

Every umbrella dependency is a file:// chart in this repository, so the
checked-out commit already fixes the exact sources. The umbrella now
declares open version constraints and the deploy fixture packages the
current sources at render time; the checked-in Chart.lock and vendored
archives are gone, and a chart version bump no longer requires touching
the umbrella at all. The release gate keeps the one invariant that can
still drift: every chart-bearing application must stay declared as an
umbrella dependency.
Two contracts render the repository chart directory rather than the
disposable fixture, so removing the vendored archives left them without
a charts/ directory. A shared helper packages the in-repo subcharts on
demand; charts/ and Chart.lock are derived and gitignored, so writing
them during a contract run is the intended model.
A release that changes no schema resolves to kind=current with no
migration, but a live database that reached that schema through a real
migration still records the transition, and the privileges Job compares
the database against exactly that record. The old fallback re-resolved
the transition against the release's own previous version β€” another
same-schema hop that returned null again β€” so the Job saw no evidence
and failed closed. Every same-schema patch was therefore undeployable to
an already-migrated silo, which is what blocked testv4 0.9.1 -> 0.9.2.

resolveSchemaLineage walks the release chain to the release that owns the
migration producing the current schema and returns its recorded
evidence. The transition stays current: no migration is proposed, no
adjacency policy is relaxed, and the reported history deliberately does
not authorise a carry-forward override.
The lineage resolver hands the deploy engine the owning release's evidence
for a release that changes no schema, which routes the current-release path
through the live convergence classifier where it used to skip it. Cover both
shapes a silo can be in under that evidence: bootstrapped fresh at the
current baseline with no history, and migrated into the schema by an earlier
release. CI now proves both stay deployable instead of reading incompatible.
@jrosseel
jrosseel merged commit 1707b46 into develop Aug 19, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deploy: same-schema patch upgrade fails the privileges convergence gate on an already-migrated silo

1 participant