Skip to content

fix(chart): close the CLIENT_ENV + channelTags vocabularies, and correct a false schema doc - #695

Merged
LukasWodka merged 3 commits into
developfrom
fix/1723-close-env-vocabulary
Aug 13, 2026
Merged

fix(chart): close the CLIENT_ENV + channelTags vocabularies, and correct a false schema doc#695
LukasWodka merged 3 commits into
developfrom
fix/1723-close-env-vocabulary

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

⚠️ NEEDS A CALL FROM @LukasWodka BEFORE MERGE — see "Blast radius" below.
Finding 1 turns an open vocabulary into a closed one. That is breaking for any
edge currently deploying an out-of-vocabulary CLIENT_ENV. I believe failing
closed is right and consistent with the chart's own conventions, but it is a
policy call, not a correctness one, and I am not making it unilaterally.
Findings 2 and 3 are unambiguous and could ship alone if you'd rather split.

Summary

Three findings from a mutable-tags sweep, all the same shape: the chart
documented a vocabulary it never enforced, and in one case documented a
fallback it does not have
. Follow-up to backend#1723, which fixed the
resolution and left the validation open.

Every claim below was verified by rendering the real chart, each with a control
proving the opposite input behaves differently. Helm v4.1.1, values
client/ci/bm-values.yaml, base origin/develop @ ead58c6.


1. env.CLIENT_ENV had no enum — the important one

tracebloc.clientEnv normalized three aliases and passed anything else
through raw
. Measured on develop:

CLIENT_ENV=prod -> jobs-manager:prod pods-monitor:prod resource-monitor:prod INGESTOR_IMAGE_DIGEST="sha256:05e1249…"
CLIENT_ENV=prd -> jobs-manager:prd pods-monitor:prd resource-monitor:prd INGESTOR_IMAGE_DIGEST="" <-- pin GONE
CLIENT_ENV=qa -> jobs-manager:qa pods-monitor:qa resource-monitor:qa INGESTOR_IMAGE_DIGEST=""
CLIENT_ENV=Prod -> jobs-manager:Prod pods-monitor:Prod resource-monitor:Prod INGESTOR_IMAGE_DIGEST=""

Published tags, checked against Docker Hub 2026-08-12 — no prd, no qa, no Prod:

tracebloc/jobs-manager ['arm-canary', 'dev', 'prod', 'staging', 'stg']
tracebloc/pods-monitor ['arm-canary', 'dev', 'latest', 'prod', 'staging', 'stg']
tracebloc/resource-monitor ['arm-canary', 'dev', 'prod', 'staging', 'stg']

The clearest demonstration is a one-letter typo.development is an alias;
develop is not:

CLIENT_ENV=development -> tag: dev INGESTOR_IMAGE_TAG="dev" SERVICE_DB_ACCOUNTS="1"
CLIENT_ENV=develop -> tag: develop INGESTOR_IMAGE_TAG="0.8" SERVICE_DB_ACCOUNTS=(absent)

Four things break at once, none of them loudly: a control-plane tag that does
not exist, images.ingestor.channelTags missed, serviceDbAccountsByEnv
missed so no service DB account is provisioned, and the prod digest pin
dropped (it applies only where the env resolves to exactly prod). That last
pair is backend#1752 reconstructed from a typo — and it matters more now that
the 0.8 float has moved past the edgeuser ceiling (backend#1853).

The only validator that existed was client-runtimejobs_manager.py's
sys.exit(1) on "Unknown CLIENT_ENV" — which lives inside the container that
cannot start
, so it cannot help.

Fix: an enum in values.schema.json (primary gate) plus a fail in
tracebloc.clientEnv (backstop — the enum is only checked where the packaged
schema is read, and --skip-schema-validation skips it). Failing closed matches
the chart's own conventions: it already fails on placeholder clientId, empty
training CIDRs, non-alphanumeric service passwords, perDatasetPvcs without
clusterScope, and a missing metrics API.

Accepted vocabulary — the complete list:

valueresolves to
devdev
stgstg
prodprod
developmentdev
stagingstg
productionprod
"" / unsetprod

Everything else is refused.

2. channelTags accepted arbitrary keys

Proven with the control, on develop:

CLIENT_ENV=staging channelTags.staging=0.7 -> INGESTOR_IMAGE_TAG "stg" <-- the key is IGNORED
CLIENT_ENV=staging channelTags.stg=0.7 -> INGESTOR_IMAGE_TAG "0.7" <-- takes effect
channelTags.totallyBogusKey=9.9 -> validates fine, silently inert

The lookup is on the resolved env, so only dev/stg/prod can ever
match. The same word "staging" is normalized in one place and meaningless one
key over — a customer writing the alias gets silence.
Fix:additionalProperties: false.

3. A schema description that was false

values.schema.json said the mysql-client tag "Empty falls back to
env.CLIENT_ENV"
. The template is .Values.images.mysqlClient.tag | default "prod":

CLIENT_ENV=dev -> mysql-client:prod
CLIENT_ENV=stg -> mysql-client:prod
CLIENT_ENV=prod -> mysql-client:prod

Published tags (Docker Hub, 2026-08-12) — no dev, no stg:

['8.0', '8.4', '8.4-528d7cee…', '8.4-5af5e835…', '8.4-87a7b276…', '8.4-b9c6b7a8…', 'latest', 'prod']

So the doc was not merely imprecise, it was an instruction to break the edge.
And it costs more than a failed pull — an env-derived tag is unrecognized by
tracebloc.mysqlEngineMajor, so the mysql-format-guard silently stands
down
:

mysqlClient.tag=prod -> TB_EXPECTED_ENGINE="5.7" <-- armed
mysqlClient.tag=dev -> TB_EXPECTED_ENGINE="unknown" <-- disarmed
mysqlClient.tag=stg -> TB_EXPECTED_ENGINE="unknown"
mysqlClient.tag=8.4 -> TB_EXPECTED_ENGINE="8.4"

Worth noting: values.yaml already said this correctly ("mysql-client is
only published under the prod tag — it has no dev/staging variants, so we
decouple it from env.CLIENT_ENV"). The two files contradicted each other and
the schema — the copy Helm shows customers — held the false half. Description
corrected; the template is right and is left alone.


Blast radius — the part that needs your call

Closing an open vocabulary is breaking for any edge currently deploying an
out-of-vocabulary value
. Such an edge is already broken — it is pulling
control-plane tags that do not exist, running with no service DB account, and
has no prod digest pin — but the failure moves:

beforeafter
where it failspod start (ImagePullBackOff, or sys.exit(1) inside the container)helm upgrade / helm install, with a message naming the accepted values
the fleet auto-upgradeproceeds, edge stays brokenthe upgrade fails and the edge stays on its current release

That second row is the real risk and the reason I am not merging this myself:
the auto-upgrade CronJob runs helm upgrade --reset-then-reuse-values, so a
misconfigured edge's next auto-upgrade would start failing. It would fail
visibly, which is the point — but it is a behaviour change on live edges.

I could not find such an edge from inside this repo: every CLIENT_ENV
value anywhere in the tree is one of the six accepted spellings (the only
exceptions were two test fixtures deliberately exercising the pass-through, both
handled here). arm-canary is a published image tag but is referenced nowhere
in the repo as a CLIENT_ENV. Confirming no live edge is out of vocabulary is
outside what I can check
— that needs a look at the actual installed values,
and it is the thing I would want checked before this merges.

If you'd rather not take that on now: findings 2 and 3 are non-breaking and
can ship on their own.

Tests

The gates cannot be asserted from helm-unittest — verified, not assumed: it
validates values against the packaged schema and reports a violation as a
plugin-level error rather than a template failure, so failedTemplate
cannot catch it, and it exposes no flag to skip validation and reach the
helper's fail. So they are exercised from
scripts/tests/chart-env-vocabulary.sh, wired into make check and the
helm-ci lint job. Every rejection is paired with an accept control on the
same command line
, and matched against the specific error text rather than
merely a non-zero exit.

== env.CLIENT_ENV: the six accepted spellings plus empty all resolve ==
ok CLIENT_ENV unset -> tracebloc/jobs-manager:prod
ok CLIENT_ENV='' -> tracebloc/jobs-manager:prod
ok CLIENT_ENV=dev -> tracebloc/jobs-manager:dev
ok CLIENT_ENV=stg -> tracebloc/jobs-manager:stg
ok CLIENT_ENV=prod -> tracebloc/jobs-manager:prod
ok CLIENT_ENV=development -> tracebloc/jobs-manager:dev
ok CLIENT_ENV=staging -> tracebloc/jobs-manager:stg
ok CLIENT_ENV=production -> tracebloc/jobs-manager:prod
== env.CLIENT_ENV: everything else is refused at install time ==
ok CLIENT_ENV=prd (rejected: values don't meet the specifications of the schema)
ok CLIENT_ENV=qa (rejected: ...)
ok CLIENT_ENV=Prod (rejected: ...)
ok CLIENT_ENV=PROD (rejected: ...)
ok CLIENT_ENV=produktion (rejected: ...)
ok CLIENT_ENV=develop (rejected: ...)
ok CLIENT_ENV=stage (rejected: ...)
ok CLIENT_ENV=test (rejected: ...)
ok CLIENT_ENV=<tab> (rejected: ...)
== the template fail is a real backstop, not decoration ==
ok CLIENT_ENV=prd with the schema skipped (rejected: is not a recognized environment)
ok CLIENT_ENV=staging with the schema skipped -> tracebloc/jobs-manager:stg
== images.ingestor.channelTags: keys are closed ==
ok channelTags.dev -> value: "9.9"
ok channelTags.stg -> value: "9.9"
ok channelTags.prod -> value: "9.9"
ok channelTags.staging (rejected: ...)
ok channelTags.development (rejected: ...)
ok channelTags.production (rejected: ...)
ok channelTags.dev-1 (rejected: ...)
ok channelTags.PROD (rejected: ...)
ok channelTags.totallyBogus (rejected: ...)
chart-env-vocabulary: all 28 checks passed

Mutation-checked — each guard is independently load-bearing:

MUT A: drop the enum (keep the helper fail) -> 9 of 28 checks FAILED (= the 9 CLIENT_ENV rejects)
MUT B: drop additionalProperties on channelTags -> 6 of 28 checks FAILED (= the 6 bad keys)
MUT C: drop the helper fail (keep the enum) -> 1 of 28 checks FAILED (= the skip-schema backstop)
restored -> all 28 checks passed

MUT C is the one that matters: it shows the backstop case is not just
re-testing the enum.

make check (shell parse + shellcheck + 3 drift guards + helm lint, 5 value files):

check-facts: all installer facts match scripts/spec/facts.env.
== tracebloc style guard ==
ok: style + terminology clean
1 chart(s) linted, 0 chart(s) failed (x5)
chart-env-vocabulary: all 28 checks passed
==> check: green

make helm-unittest — 5 new cases pin the mysql-client behaviour the corrected
description now describes:

Charts: 1 passed, 1 total
Test Suites: 30 passed, 30 total
Tests: 389 passed, 389 total

Mutation-checked too — someone "fixing" the template to match the old false doc
gets caught, and the prod control correctly stays green because prod is
indistinguishable either way:

MUT D: make the mysql tag env-derived, as the old doc claimed
Tests: 2 failed, 387 passed, 389 total
- an empty tag renders :prod on a dev edge, not :dev
- an empty tag renders :prod on a stg edge, not :stg

make helm-template — all four platforms render; shellcheck -S warning -x on
the new script is clean.

Manifest:scripts/gen-manifest.sh --check passes and needs no
regeneration — the manifest is the installer bootstrap's integrity surface
(scripts/install.sh's fetch list), and a CI-only test script is correctly not
in it. Confirmed by reading the FILES array rather than assuming.

Type

  • Bug fix
  • Breaking change (finding 1 only)
  • Documentation

Notes for the reviewer


Note

High Risk
Closing CLIENT_ENV is a breaking change: fleet auto-upgrade on edges with out-of-vocabulary values will fail at helm upgrade instead of proceeding with a broken cluster.

Overview
Closes undocumented open vocabularies on the client Helm chart so bad env.CLIENT_ENV and images.ingestor.channelTags keys fail at install/upgrade instead of silently becoming wrong image tags, missed lookups, and dropped prod digest pins.

values.schema.json adds a CLIENT_ENV enum (six spellings + empty) and channelTags with additionalProperties: false. tracebloc.clientEnv adds a fail backstop when schema validation is skipped. The mysql-client tag description is corrected to match the template: empty tag always falls back to prod, not CLIENT_ENV.

scripts/tests/chart-env-vocabulary.sh exercises both gates via helm template (paired accept/reject controls); wired into make check / helm-ci and shellcheck. Helm unittest cases are updated (illegal produktion removed; mysql empty-tag → :prod pinned). Chart version 1.9.34 → 1.9.36.

Reviewed by Cursor Bugbot for commit 8c33546. Bugbot is set up for automated code reviews on this repo. Configure here.

…ect a false schema doc
Three findings from a mutable-tags sweep, all in the same place: the chart
documented a vocabulary it never enforced, and in one case documented a
fallback it does not have. Follow-up to backend#1723, which fixed the
resolution and left the validation open.
1. env.CLIENT_ENV had no `enum`. tracebloc.clientEnv normalized three aliases
and passed anything else through RAW. `CLIENT_ENV: prd` rendered
jobs-manager:prd, pods-monitor:prd and resource-monitor:prd — tags no
producer publishes — missed images.ingestor.channelTags, missed
serviceDbAccountsByEnv, AND silently dropped the prod digest pin, which
applies only where the env resolves to exactly "prod". Load-bearing in four
places, validated in none. The only validator was client-runtime
jobs_manager.py's sys.exit(1) on "Unknown CLIENT_ENV" — inside the container
that cannot start.
Now closed by an `enum` (the primary gate) plus a `fail` in
tracebloc.clientEnv (the backstop, for --skip-schema-validation and any
repackaging without the schema).
2. channelTags accepted arbitrary keys. `channelTags.staging: 0.7` on a
staging edge validated fine and was then ignored — CLIENT_ENV=staging
normalizes to stg and the lookup reads channelTags.stg — while
`channelTags.stg: 0.7` took effect. The same word, normalized in one place
and meaningless one key over. `additionalProperties: false`.
3. The mysql-client tag description said "Empty falls back to env.CLIENT_ENV".
The template is `| default "prod"`, and dev/stg/prod all render
:prod. tracebloc/mysql-client publishes 8.0, 8.4, four 8.4-<sha> builds,
latest and prod — no dev, no stg — so a reader who believed it and set an
env-derived tag would pull a nonexistent image AND disarm the
mysql-format-guard, which reads "unknown" for an unrecognized tag. Note
values.yaml already stated this correctly; the schema — the copy Helm shows
customers — held the false half. Description corrected; the template is
right and is left alone.
BREAKING for any edge deploying an out-of-vocabulary CLIENT_ENV. Such an edge
is already broken — it is pulling tags that do not exist — but it now fails at
`helm upgrade` rather than at pod start. See the PR body.
Tests: the gates cannot be asserted from helm-unittest, which treats a schema
violation as a plugin-level error rather than a template failure and offers no
way to skip validation and reach the `fail`. So they are exercised from
scripts/tests/chart-env-vocabulary.sh (28 checks, every rejection paired with
an accept control on the same command line), wired into `make check` and the
helm-ci lint job. Five helm-unittest cases pin the mysql-client behaviour the
corrected description now describes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@LukasWodkaLukasWodka self-assigned this Aug 12, 2026
Comment threadscripts/tests/chart-env-vocabulary.sh Outdated
… hiding it in a word list
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

Two notes on this PR's CI, both worth knowing before you read the red marks.

1. The red checks are a GitHub release-CDN incident, not this change. Every failure is a download step, and I confirmed it per-job rather than assuming:

  • Template render (oc) — the Helm template — oc step succeeded; the job died in Install kubeconform (version + digest pinned) on curl: (56) Connection died, tried 5 times before giving up.
  • PATH persist — * — dies fetching the CLI release asset: curl: (22) The requested URL returned error: 503 against github.com/tracebloc/cli/releases/download/v0.10.5/..., then Error: failed to download SHA256SUMS — release may be malformed.

Every check that actually exercises this diff is green: Helm lint (which now runs the new vocabulary step), Helm unit tests, Template render aks/bm/eks, Lint, Source-of-truth drift, quality/shellcheck, quality/house-rules, and the chart version bump gate. I re-ran the failed jobs once; they re-failed on the same download steps, so it needs a re-run when the CDN recovers rather than a code change.

2. Adding a file under scripts/ pulls the whole installer matrix onto this PR.installer-tests.yaml is path-filtered on scripts/**, so scripts/tests/chart-env-vocabulary.sh brings the 9-distro prereq + PATH-persist + Pester matrix into scope — which is why #694 (chart files only) does not run them and this one does.

I kept the script there deliberately: chart tooling in this repo already lives in scripts/ (chart-version-guard.sh, index-invariants.sh, resolve-ingestor-digest.sh), and the alternative — client/tests/ — is packaged into the published tarball, since client/.helmignore excludes only editor/VCS junk. I would rather pay CI minutes than ship a test script to customers. Happy to move it if you would rather narrow the path filter instead, but that seemed like an unrelated change to CI policy to bundle in here.

Comment thread.github/workflows/helm-ci.yaml
Comment threadMakefile
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

Independently reproduced, and it compounds with backend#1853

Rendered the real chart on origin/develop at ead58c6 with the same CI values file the release workflow uses:

clientEnv value INGESTOR_IMAGE_TAG digest pin SERVICE_DB_ACCOUNTS
development "dev" (none — correct at dev) present
develop "0.8" NONE ABSENT
prod "0.8" sha256:05e124945a2e… absent (correct: prod is false)
prd "0.8" NONE absent

So a one-letter typodevelop for development — moves an edge off the dev channel onto the prod float, with no digest pin and no service-DB-account provisioning. prd for prod keeps the float and silently drops the pin. That confirms every consequence claimed here.

The part that raises the severity

I filed backend#1853 earlier today: the 0.8 float now resolves to 0.8.8, which removes the legacy edgeuserDB_USER fallback (_require_env("DB_USER") at config.py:156, vs os.environ.get("DB_USER","edgeuser") at v0.8.4:128). Resolved live: 0.8sha256:4beb85da… → identical to 0.8.8.

Put the two together:

a typo'd clientEnv renders tag 0.8and no SERVICE_DB_ACCOUNTS → pulls 0.8.8 → Config() raises on the missing DB_USERevery ingestion on that edge fails before reading a byte.

Until today that same typo landed on 0.8.4, which still had the fallback, so it degraded quietly instead of failing. The window where this is merely latent closed with the 0.8.8 release. Worth reflecting in the PR body — this is no longer only a "renders an unpublished tag" problem.

On my own verification

My first two render attempts reported "no INGESTOR_IMAGE_TAG for any env, including prod", which would have contradicted this PR. Both were wrong for my own reasons: I set clientEnv instead of env.CLIENT_ENV, and I had 2>/dev/null on the helm call, which hid Error: storageClass.provisioner is required when storageClass.create is true — the render was failing outright and I was grepping an empty string.

Recording that because it is the same shape as the bug class this whole epic is about: a check that passes (or in this case, "finds nothing") because it was never connected to anything. The fix was to stop suppressing stderr and to fail loudly on a non-render, which is what the new scripts/tests/chart-env-vocabulary.sh does by pairing every rejection with an accept control on the same command line.

Verified separately

  • No tracebloc/requests-proxy image exists — the demotion from four repositories to three is correct.
  • The values.schema.json / values.yaml disagreement on the mysql-client fallback is real, and values.yaml is the one telling the truth.

…d#1723)
- chart-env-vocabulary.sh: capture helm --help then match, so grep -q
cannot SIGPIPE helm under pipefail and misread the flag as absent
(the capture-then-match rule already used for the usermod help probe).
- helm-ci.yaml: add scripts/tests/chart-env-vocabulary.sh to the push +
pull_request paths filters, so a PR touching only that script still
runs the gate it owns.
- installer-tests.yaml: add the script to the static shellcheck set
(error + warning), re-syncing CI with the Makefile SHELLCHECK_FILES.
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8c33546. Configure here.

Comment threadclient/tests/ingestor_channel_tag_test.yaml
@LukasWodka
LukasWodka requested review from shujaatTracebloc and removed request for saadqbalAugust 13, 2026 06:10

@shujaatTraceblocshujaatTracebloc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Verified all four Bugbot findings rather than trusting the resolve — three are genuinely fixed, and I'm accepting the fourth's deferral.

Bugbot fixes, checked in the tree

  1. Help probe under pipefail → now capture-then-match: _helm_help="$(helm template --help 2>&1 || true)" then grep -q <<<"$_helm_help". No pipe, so no SIGPIPE misbranch. Fixed ✓
  2. Vocabulary test missing from CI paths → added to both the push and pull_request filters, not just one ✓
  3. Shellcheck list driftchart-env-vocabulary.sh added to the Makefile's SHELLCHECK_FILESand to both invocations in installer-tests.yaml (error and advisory). Both sides in sync ✓
  4. Fallback test cannot prove path → resolved as intended, not fixed. I checked the claim it rests on and it holds:client/tests/ingestor_channel_tag_test.yaml:93 really does have a images.ingestor.channelTags: null case, so the fallback-fired path has independent coverage. Combined with helm-unittest's deep-merge making "one entry absent, others present" inexpressible, strengthening the prod case would couple it to #694's merge order for no new coverage. Reasonable trade — not reopening.

Two things to handle at merge time

The chart version assumes #694 lands first.develop is at 1.9.34; #6941.9.35, this → 1.9.36. That only works in that order. If this merges first, #694 hits a conflict on the same version/appVersion lines and has to re-bump to .37 — and the two PRs share three files (Chart.yaml, _helpers.tpl, ingestor_channel_tag_test.yaml), so the second one through needs a rebase regardless. Worth flagging because #694 is on a different reviewer, so nobody is watching the ordering from both sides.

additionalProperties: false on channelTags is a breaking chart change. The chart's own values.yaml only uses dev/stg/prod, so nothing here breaks itself ✓ — but the PR's own rationale is that channelTags.staging: "0.8.2""validated fine and was then ignored", which means it may exist in a live edge's values. Those edges now fail at helm upgrade rather than silently ignoring the key. That's the correct outcome and the point of the change, but it deserves a line in Deployment notes so a rollout doesn't discover it by surprise.

On the design

Putting the enum in values.schema.jsonand a fail in tracebloc.clientEnv is right, and the reason given is the part that matters: the enum only binds where the packaged schema is read, and --skip-schema-validation or a repackage without the schema walks past it. Since the helper is already the single chokepoint every consumer goes through, the backstop costs nothing and closes the hole the enum can't.

The justification for fail over pass-through is the strongest argument in the PR — an unrecognised value wasn't graceful degradation, it silently reconfigured the edge in four places at once (three control-plane tags at unpublished names, a missed channelTags lookup, a missed serviceDbAccountsByEnv lookup, and a dropped prod digest pin, since the pin only applies where the env resolves to exactly prod). And noting that the only existing validator was jobs_manager.py's sys.exit(1)inside the container that can't start is exactly why failing at helm upgrade is the right layer.

chart-env-vocabulary.sh earns being a shell test rather than a helm-unittest suite, and the reason is stated concretely (plugin 0.5.2 reports a schema violation as a plugin-level error, so failedTemplate can't assert it, and there's no flag to skip validation and reach the fail). Two details I'd have asked for and didn't have to:

  • every reject paired with an accept control on the same command line, matched against specific error text rather than just non-zero exit — a rejection test that failed to render for an unrelated reason would otherwise pass for free
  • the --skip-schema-validation gate self-skips on the pinned helm 3.15.4 and turns on for anyone on 3.16+, with the skip announced rather than silent, so bumping the pin activates it with no edit here

BAD_ENVS choosing prd, Prod and develop is well-judged — an abbreviation, a capitalisation, and an alias one letter off development are what people actually type. Keeping the whitespace-only case out of the array so the tab survives word-splitting is a nice touch.

The mysql_test.yaml additions are the sleeper value here: the schema said "Empty falls back to env.CLIENT_ENV" when the template is | default "prod", and the five new cases pin why that doc had teeth beyond a failed pull — an env-derived tag is unrecognised by tracebloc.mysqlEngineMajor, so the mysql-format-guard stands down at unknown instead of staying armed at 5.7. Asserting the believing-the-old-doc case and the real-fallback control is what makes that provable rather than asserted.

@LukasWodka
LukasWodka merged commit 3eb89c5 into developAug 13, 2026
74 of 78 checks passed
@LukasWodka
LukasWodka deleted the fix/1723-close-env-vocabulary branch August 13, 2026 06:52
Sign up for freeto 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.

2 participants

@LukasWodka@shujaatTracebloc