Installed framework tools on sb-it-1-dt are stale: ci-queue-wait null-statuses fix exists on origin/next, not on the host #1345

Open
opened 2026-08-20 23:48:18 +00:00 by fred · 0 comments
Collaborator

Attribution

Found and diagnosed by @veronica. Filed by @fred at her request. The control set below is
hers, re-run by me; she asked not to re-derive it.

Correction (@veronica, 2026-08-21), narrowing my own line: the original text here said she
was blocked from filing at all. That was too strong and it was my generalisation, not her claim.
What was measured: issue-list.sh is a tea-only wrapper and exits 1 in ~/src/mosaic-stack
(#1342). Wrappers that carry a REST fallback are unaffected — issue-view.sh -i 1345 returns
rc=0 from that same tree, and issue-create.sh has the same fallback, so she could probably
have filed this herself. That was not proven and will not be: proving it costs a junk issue.

Summary

The framework tools installed at ~/.config/mosaic/tools/ on sb-it-1-dt are behind origin/next. A bug that is already fixed upstream is still live on this host, and there is no mechanism that told anyone.

The symptom that exposed it: ci-queue-wait.sh exits rc=3 state=malformed on a commit that simply has no CI status.

Version evidence

Copy Lines
~/.config/mosaic/tools/git/ci-queue-wait.sh (installed) 494
origin/next:packages/mosaic/framework/tools/git/ci-queue-wait.sh 507

The 13-line delta contains the fix.

Installed, line 55:

raw_statuses = payload.get("statuses", [])
...
if not isinstance(raw_statuses, list) or not isinstance(raw_state, str):
    print("malformed")

origin/next, lines 55-61:

# Gitea returns "statuses": null (not []) for a commit with zero status
# contexts. dict.get() only substitutes the default when the key is ABSENT.
raw_statuses = payload.get("statuses", [])
if raw_statuses is None:
    raw_statuses = []

if not isinstance(raw_statuses, list) or not isinstance(raw_state, str):

origin/next also carries a regression test, test-ci-queue-wait-no-status.sh. Neither is present on this host.

The underlying bug (fixed upstream, live here)

Gitea returns "statuses": null, not [], for a commit with zero status contexts. dict.get(k, default) substitutes the default only when the key is absent. The key is present with value null, so None survives and fails the isinstance(..., list) check. Result: malformed on a perfectly normal no-CI commit.

Controls (veronica's, three payloads through the exact installed parser)

Payload Parser output
401 error body {message, url} no-status
Real 200, no-CI, "statuses": null malformed
Empty / non-JSON malformed

Decisive point: a 401 cannot produce malformed. An error body is still a dict, the key is genuinely absent, the default applies. This refutes the auth-failure hypothesis (mine, @fred's — I filed it wrong and she caught it before it reached an issue). Her usc token returns 200.

Swap control: substituting only origin/next's ci-queue-wait.sh, changing nothing else, gives rc=0 state=no-status on the same commit.

The defect being filed

Not an auth failure. Not a parser bug — the parser is already correct upstream.

The installed framework tools on this host are stale, and nothing detects or reports that. Every seat on sb-it-1-dt is running against tool copies of unknown age. The parser bug is the instance; the drift is the defect.

Suggested direction

  1. A version stamp the tools can report and a check that compares installed vs. origin/next, so drift is visible without a line count.
  2. Whatever installs ~/.config/mosaic/tools/ should be part of a routine that runs, not a one-time seed.

Not done, deliberately

Neither of us ran mosaic update. Three sessions share this host mid-campaign; that is an operator call, not a seat's.

## Attribution **Found and diagnosed by @veronica.** Filed by @fred at her request. The control set below is hers, re-run by me; she asked not to re-derive it. **Correction (@veronica, 2026-08-21), narrowing my own line:** the original text here said she was blocked from filing at all. That was too strong and it was my generalisation, not her claim. What was measured: `issue-list.sh` is a tea-only wrapper and exits 1 in `~/src/mosaic-stack` (#1342). Wrappers that carry a REST fallback are unaffected — `issue-view.sh -i 1345` returns rc=0 from that same tree, and `issue-create.sh` has the same fallback, so she could probably have filed this herself. That was not proven and will not be: proving it costs a junk issue. ## Summary The framework tools installed at `~/.config/mosaic/tools/` on `sb-it-1-dt` are **behind `origin/next`**. A bug that is already fixed upstream is still live on this host, and there is no mechanism that told anyone. The symptom that exposed it: `ci-queue-wait.sh` exits `rc=3 state=malformed` on a commit that simply has no CI status. ## Version evidence | Copy | Lines | |---|---| | `~/.config/mosaic/tools/git/ci-queue-wait.sh` (installed) | **494** | | `origin/next:packages/mosaic/framework/tools/git/ci-queue-wait.sh` | **507** | The 13-line delta contains the fix. Installed, line 55: ```python raw_statuses = payload.get("statuses", []) ... if not isinstance(raw_statuses, list) or not isinstance(raw_state, str): print("malformed") ``` `origin/next`, lines 55-61: ```python # Gitea returns "statuses": null (not []) for a commit with zero status # contexts. dict.get() only substitutes the default when the key is ABSENT. raw_statuses = payload.get("statuses", []) if raw_statuses is None: raw_statuses = [] if not isinstance(raw_statuses, list) or not isinstance(raw_state, str): ``` `origin/next` also carries a regression test, `test-ci-queue-wait-no-status.sh`. Neither is present on this host. ## The underlying bug (fixed upstream, live here) Gitea returns `"statuses": null`, not `[]`, for a commit with zero status contexts. `dict.get(k, default)` substitutes the default only when the key is **absent**. The key is present with value `null`, so `None` survives and fails the `isinstance(..., list)` check. Result: `malformed` on a perfectly normal no-CI commit. ## Controls (veronica's, three payloads through the exact installed parser) | Payload | Parser output | |---|---| | 401 error body `{message, url}` | `no-status` | | Real 200, no-CI, `"statuses": null` | **`malformed`** | | Empty / non-JSON | `malformed` | Decisive point: **a 401 cannot produce `malformed`.** An error body is still a dict, the key is genuinely absent, the default applies. This refutes the auth-failure hypothesis (mine, @fred's — I filed it wrong and she caught it before it reached an issue). Her usc token returns 200. Swap control: substituting **only** `origin/next`'s `ci-queue-wait.sh`, changing nothing else, gives `rc=0 state=no-status` on the same commit. ## The defect being filed Not an auth failure. Not a parser bug — the parser is already correct upstream. **The installed framework tools on this host are stale, and nothing detects or reports that.** Every seat on `sb-it-1-dt` is running against tool copies of unknown age. The parser bug is the instance; the drift is the defect. ## Suggested direction 1. A version stamp the tools can report and a check that compares installed vs. `origin/next`, so drift is visible without a line count. 2. Whatever installs `~/.config/mosaic/tools/` should be part of a routine that runs, not a one-time seed. ## Not done, deliberately Neither of us ran `mosaic update`. Three sessions share this host mid-campaign; that is an operator call, not a seat's.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1345