Repository navigation
test(stack): report which condition failed in ST-50 owner and ST-64 - #35
Merged
Merged
Conversation
ST-50 "owner rotation interrupted after the database change and resumed" and ST-64 each failed once in CI (runs 40186923380 and 40176460595) and passed on rerun, but their reports could not say why: ST-50 printed only the last two lines of the successful resume, and ST-64 printed exit codes without the output of the commands. ST-50 now evaluates and reports every condition (both exit codes, the pending file, the new and the old login with psql's last message, the migrate job's result and any leftover files) plus the container lifecycle line, and shows the stderr of both rotation commands when it fails. ST-64 also reports the exit codes of the finishing rotation and of the recovering make up, and shows the stderr of the finishing rotation, the killed make up and the recovery when it fails. The checks themselves are unchanged; the old login must still be refused.
… check login_result treated a login as successful only when psql's combined stdout and stderr was exactly "1". A psql warning on stderr next to the returned row would have made a working old owner password count as refused (a looser check than login_ok) and a working new one fail. login_result now uses login_ok's criterion (a line "1" on stdout) and keeps stderr for the diagnostic only; login_ok is defined through it so the two cannot diverge. U-25 in tests/devenv/unit.sh checks both against stubbed answers (row, row plus warning, refusal, docker error, no answer, missing or empty password file).
knittingcode
added a commit
that referenced
this pull request
Oct 25, 2026
knittingcode
added a commit
that referenced
this pull request
Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes two intermittent failures of
tests/app/stack.shreport their cause. The root cause has not been identified yet: the CI output does not contain the information needed, and the failures did not reproduce locally. Only test code changes: no check is removed or loosened.rot=137/000/yes up=6/000/yes/0. Themake upthat should be killed after the migrations (FLOWCRM_DEVENV_FAULT=up-after-migrations:kill) exited 6 instead of 137, and the migration was not applied. It passed on rerun.Motivation and technical context
Neither report could say which condition failed:
&&and printstail -n 2of the resume.What the evidence shows:
Exit 6 in ST-64:
make upstops with exit 6 (EX_SAFETY) before the migrations only through these paths:check_roles→gate_failed, for role-state exits 10, 11 or 14;protect_for(gate write, or an edge that could not be stopped);ensure_secrets;require_owned_project;The observed
000andblocked(edge down, gate present, no migration) fitcheck_roles→gate_failedand aprotect_forrefusal. Which one it was is not in the log.Timing of the ST-50 failure: it took 8.2 s, against 9.1–9.6 s in passing runs. That suggests a condition before the migrate-job check failed, perhaps the exit code of the interrupted rotation, but it is not proof.
Common pattern: both failures came a few seconds after a db recreation by
refresh_secret_mounts(make upafter ST-50'srotate-after-promote, and the rotation finished before ST-64'smake up).Investigation (local, Docker Desktop; evidence in the task notes)
e03d151: 8 + 8 iterations, 16/16 passed. Instrumented ST-64 on266c729: 2/2 passed. Container IDs show that themake upin ST-64 does not recreate the db: it had been up for about 7 s whencheckran.docker compose ps --quiet edgestill lists the edge right afterdocker compose stop edgereturns (which would triggerprotect_for's "could not be stopped"). 150 stop/ps cycles: 0 occurrences.flowcrm-db-roles statefails on a healthy db right after a recreation (a role-state failure). A 0.2 s poller ran during 10 full rotations, each recreating db and api. All 8 anomalies were while the old container was shutting down or being removed, or the new one was stillstarting, which devenv waits out. Against a healthy db that was not being replaced: 0. A psql error insidestatealso makescheckexit 2 (EX_DOCKER), not 6.Neither hypothesis reproduced, so no change to
bin/devenvis proposed: changing fail-closed code without a confirmed cause would risk weakening it.Implementation
ST-50 owner: every condition is evaluated and reported:
rotate-after-dband of the resume;login_result;doctrine:migrations:up-to-dateresult with its last lines;lifecycleline (container identity and secret-mount comparison).On failure it shows the stderr of both rotation commands. The old login must still be refused, and a missing file no longer counts as a refusal.
login_resultandlogin_okshare one criterion: a login succeeded when psql printed the row (a line1on stdout), whatever it wrote to stderr. stderr is kept for the diagnostic only, andlogin_okis defined throughlogin_result. (The first version compared psql's combined stdout and stderr with1: a warning on stderr next to the returned row would have made a working old password count as refused, which is looser thanlogin_ok.) New unit checks U-25 intests/devenv/unit.shcover a returned row, a row with a stderr warning, another row, a refusal, a docker error, no answer, and a missing or empty password file.ST-64: the report adds the exit codes of the finishing rotation and of the recovering
make up. On failure it shows the stderr of the finishing rotation, the killedmake upand the recovery.Testing performed
bash -n; ShellCheck v0.11.0 (the CI image) on every script CI checks: no findings.tests/devenv/unit.sh: 287 passed locally. Against a copy ofstack.shwith the firstlogin_resultcriterion, U-25 fails 2 cases (the stderr warning and no answer).Diagnostics check: the full stack suite ran locally (Docker Desktop) on a scratch copy of
b33ad129in which one condition of each check was forced false (old = okin ST-50 owner,migrated = 2in ST-64). Both failed and named the violated condition:rc=143/0 pending=none new=ok old=psql: error: ... FATAL: password authentication failed for user "flowcrm_owner" migrate=ok leftovers=none db=..., followed by the stderr of both rotations;rot=137/000/yes finish=0 up=137/000/yes/1 recovery=0, followed by the stderr of the finish, the killedmake upand the recovery.Every other application check passed. ST-34 is not part of a Docker Desktop run. Two CLEAN checks failed because other disposable stacks running at the same time were removed during the run.
CI run 40208960751 on
b33ad129: success (unit 288/288, application stack 121/121 including ST-50 owner and ST-64, production-like 38/38).Security considerations
bin/devenvis unchanged, and no assertion was relaxed.Known limitations