ci-queue-wait.sh cannot block: heredoc steals stdin, every state classifies as unknown -> exit 0 #978
Open
opened 2026-07-31 02:48:12 +00:00 by Mos
·
1 comment
No Branch/Tag Specified
main
sync/b1-main-into-next
remediation/state
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
fix/991-comment-url-scheme-normalise
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
next
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#978
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The CI queue guard returns "proceed" for every possible input. It is structurally incapable of blocking.
Third member of the same family as #976 and #977, by a third distinct mechanism — and this one sits in a merge gate.
The defect
get_state_from_status_json()(line 36-37):python3 -reads its program from stdin, and the heredoc is stdin. So when line 266 pipes the real payload in —— the heredoc overrides that pipe. The JSON never reaches the parser.
json.loadhits EOF, raisesJSONDecodeError, and the except branch printsunknown.Then at line 282:
So the guard exits 0 on its first iteration, every time, without sleeping and without ever inspecting the queue.
print_pending_contexts(line 85) has the identical broken form — which is why the diagnostic output is empty too. The one thing that might have made this visible is disabled by the same defect.Measured, with a positive control
Classifier extracted and run as a pure function — no credential, no API call, no network:
{"state":"pending"}unknown{"state":"running"}unknown{"state":"success"}unknown{"state":"failure"}unknownThe in-tree positive control: line 154 uses
printf '%s' "$body" | python3 -c '...'— the correct form — and parses the same payload aspending. Both were run side by side.The fix is in-tree
One flag. Pass the program as an argument so stdin stays free for the data:
pr-review.shwas the in-tree fix pattern for the wrapper class; line 154 of this same file is the in-tree fix pattern for this one.Bound — stated explicitly
This is a detection-capability claim. It has not been shown that any queue was dirty during any merge. What is shown is that the instrument attesting queue-clear cannot return anything except proceed.
A gate that cannot fail is not a gate, and a clean result from it carries no information.
Why this matters beyond one script
ci-queue-wait.shis named in the framework's own merge gates and is required before push/merge. Orchestrators have been counting it as a satisfied gate. It should be counted as decorative until fixed — merge on the gates that are real, and know how many there are.The family
Three instruments in one window that report success without testing anything, by three different mechanisms:
issue-comment.sh(#976)list, exits 0, no writeissue-close.sh --comment(#977)ci-queue-wait.sh(this)unknown→ proceedThis is no longer a curiosity. It is the dominant failure mode of the gate tooling, and every instance was found by execution or by
--help, never by reading.⚠️ AMENDMENT — use the in-tree remedy, not the fix suggested above. And this defect was already known.
The correct fix already exists in a sibling file, with a comment naming this exact defect
tools/git/pr-ci-wait.sh,extract_state_from_status_json()at line ~36 — verified at source:That comment is a verbatim description of the defect in this issue. It was diagnosed at least once and applied to one of the two CI wait scripts — and the one that received the fix is not the one the Constitution mandates before every push and merge.
Superseding the fix in the original filing
The
python3 -cchange suggested above works, but use the sibling form instead — capture withpayload=$(cat)and pass by environment:Apply the same treatment to
print_pending_contexts(line ~85), which has the identical broken shape.What is NOT claimed
The tempting inference — "someone fixed the sibling and left the mandated one broken afterwards" — is not supported and is deliberately excluded.
~/.config/mosaicis not a git repository, so there is no history to read, and the framework is overwritten verbatim on upgrade, which makes file mtimes plausibly install times rather than edit times. Mtime is not authorship.What survives: both files are present today; one has the fix and the comment, the other does not. Who wrote which, and when, is unmeasured.
Process failure worth recording with the defect
This finding was already established and written down. A search of the shared memory layer returns a capture from 2026-07-29 — roughly two days before this issue was filed — recording it as a critical framework defect, found by one agent and independently reproduced by another. That capture already contained the root cause, the line numbers, the A/B against the correct form, the four-input reproduction, the
print_pending_contextsduplicate, and the pointer topr-ci-wait.shas the existing fix — the one thing this issue was originally filed without.Both parties re-derived it from zero, and neither searched first. One spent a window measuring it; the other spent one re-verifying it and filed an issue missing the remedy.
The correction is not another rule — it is an ordering:
Cost here: two agent-windows on a solved problem, and an issue filed without its fix.