Skip to content

merge-queue batch q-1785729479 - #730

Closed
matt82198 wants to merge 19 commits into
mainfrom
integrate/q-1785729479
Closed

merge-queue batch q-1785729479#730
matt82198 wants to merge 19 commits into
mainfrom
integrate/q-1785729479

Conversation

@matt82198

Copy link
Copy Markdown
Owner

Merge-queue batch built by tools/merge_queue.py.

Members: #717, #689, #696, #702, #712, #716, #723

Members are closed only after git merge-base --is-ancestor proves their content landed on main.

matt82198 and others added 19 commits August 2, 2026 20:45
Add ci_job_status tool to read-only MCP server for querying GitHub Actions
run history: status, conclusion, duration, flake signal. Tool spawns gh CLI
with 10s timeout (no shell:true), parses deterministic JSON, handles errors
gracefully. Includes test fixtures for normal history, empty history
(never_executed=true), and gh failure → structured error. All tests pass.

- mcp/server.mjs: Add getCIJobStatus() + tool registration
- mcp/CLAUDE.md: Document tool contract + test strategy
- tests/mcp-ci-status.test.mjs: 4 test cases (init, normal, empty, error)
- tests/mcp-fleet.test.mjs: Update tool count from 11 to 12

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s restored

The 0.7.2 section was fabricated. Commit 2f52f39 authored it as a near-verbatim
copy of the 0.7.1 section's PR list -- #638, #636, #643, #645, #647 all shipped in
0.7.1, none of them in v0.7.1..v0.7.2. The one change that actually shipped in
0.7.2 (the /api/state cache-staleness fix, #668) appeared nowhere in it.

Ground truth, `git log v0.7.1..v0.7.2 --oneline`, four commits:

  e061f2b Merge pull request #669 from matt82198/release/0.7.2
  a00deb7 release: 0.7.2
  a87c396 Merge pull request #668 from matt82198/fix/api-state-empty-section-cache
  fa29fb8 fix: /api/state served a collector's empty default instead of real data

The section is rewritten from that: one substantive fix plus release metadata.

The same commit also rewrote the 0.7.0 section's historical test count from 254 to
266. 254 was the at-tag truth -- the section was authored at 366a7fc as "254 tests
(25 Node + 13 Shell + 216 Python)", and PR #644 ("correct test count to 254") had
verified it for that release. Rewriting a shipped release's numbers to match a
later suite falsifies the record; 254 is restored with a dated footnote pointing
currency at the README.

0.7.1 was cross-checked against `git log v0.7.0..v0.7.1` and is substantively
accurate, but two citations were wrong and are corrected: #654 was CLOSED (the
merge-train UTF-8 change shipped as c6e465b inside batch #667), and the
portability-gate/remote-identity work is 502ccfa, not #667 itself (#667 is the
integration batch PR). Complexity-reduction claims verified and now cited
(#637, #664, #658, #662, #663).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uts + fail-closed testCmds

The first-wave replay kit documented a command that does not exist and pasted
output nobody ever ran. Three verified defects, all fixed against real runs.

c1 -- broken documented command. Both docs told adopters to run
`python tools/wave_templates.py validate <path>`. That subcommand takes only
`--template {saas,data,library,all}` and exits 2 with "unrecognized arguments"
on a file path, so the walkthrough's own validation step failed as written.
The real standalone-manifest validator is `tools/wave_manifest_lint.py <path>`
(also reachable as `aesop wave manifest-lint <path>`). Both docs now use it,
explain why the old form fails, and keep the `--template all` form where
preset validation is actually what is wanted.

c2 -- fabricated output. The "Expected Output" block claimed a checkmark,
"Items: 5", and per-slug file counts. `validate_manifest` returns None and the
snippet prints one line: "Manifest is valid". Every output block in both docs
is now captured from a real run, or is explicitly labelled an estimate. The
duration tables said "honest expected duration" while reporting numbers nobody
measured; they now say so. The jq inspect step (whose pasted output was not
even jq's format, and which needed a tool the docs never listed) is replaced
with a python one-liner whose real output is pasted.

c4 -- fail-open testCmds. Four of five gates passed before any work was done,
so they would have blessed an empty PR:
  - enable-skipped-test  echoed "Still skipped" and exited 0 while skipped
  - fix-doc-links        only ran `test -f` on the two files it was editing
  - add-eslint-config    grepped package.json for "lint", which already
                         matches "eslint" in devDependencies
  - simplify-util-fns    ran a suite that was green before the refactor
All four are rewritten to fail pre-work: assert no .skip marker remains and the
suite passes; resolve every relative markdown link against the filesystem;
require a real `lint` script and run `npm run lint` for real; require the
`Refactor goal:` marker the prompt already asked for plus a green suite.
Prompts updated so each gate is a stated contract, not a surprise.

Rather than assert fail-closedness in prose -- the exact failure mode being
fixed -- examples/first-wave-baseline/verify-testcmds.sh executes it: it builds
a fixture repo in the pre-work state, runs each testCmd verbatim out of
wave-manifest.json, applies the five fixes, and reruns them. Pre-work all 5
exit non-zero, post-work all 5 exit zero. Verified it detects regressions by
restoring an old fail-open testCmd and confirming it reports FAIL-OPEN.

Remaining limitation stated plainly instead of papered over: the refactor item
can prove the file was touched and the tests are green, but not that the
refactor improved anything. That stays a human review call.

Also adds the [ISOLATION: sibling worktree] marker to all 5 prompts, clearing
the linter's prompt_sanity warnings.

Verified: wave_manifest_lint exit 0; validate_manifest exit 0; verify-testcmds
exit 0; secret_scan, claudemd_lint/sync, watcher, portability, subprocess,
prompt-hygiene, coverage, suite-count, gates-wired, ci-gate-runability,
shell-syntax all exit 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate inventory (PR #709) found four guardrail tools on main invoked by
nothing -- unit-tested, documented, grading nothing. Three are wired as
real shard-0 CI gates; the fourth is recorded as deliberately unwired.

- sibling_import_check.py --check
- fixture_intent_check.py --root .
- port_fidelity_check.py --check --root .

git_identity_check.py stays unwired: its subject is a managed target
repo's *local* git identity, and a GitHub Actions runner clone sets only
a --global one, so it reports mismatch on every CI run (verified exit 1).
Softening it with --mode warn or continue-on-error would recreate the
decoration this sweep removes.

hooks/CLAUDE.md documented 8 pre-push checks while pre-push-policy.sh
runs 9 -- check_test_suite_count() was undocumented. Added and renumbered.

tests/test_ci_workflow_lint.py gains four assertions: the steps exist
with exact invocations, they are shard-0 scoped and never
continue-on-error, and every tool in the orphan inventory is either
wired or explicitly excepted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The nightly stats-refresh job had concluded FAILURE on every one of its
last four runs (2026-07-30..08-02) with no signal anywhere, letting
stats.json drift 200+ commits stale and red-line the stats freshness gate
on every open PR in the repo.

Three stacked defects, each hidden behind the one before it:

1. `gh pr create --label "chore"` - the repo had no `chore` label and gh
   resolves labels BEFORE opening the PR, so the command exited 1 and no
   PR was ever created. Four orphan branches, zero PRs.
2. Actions was not permitted to create pull requests
   (`can_approve_pull_request_reviews: false`), so even with the label
   present `gh pr create` failed with "GitHub Actions is not permitted to
   create or approve pull requests".
3. The date-suffixed branch scheme (`chore/stats-refresh-<date>`) aborted
   on any re-run: switching to an existing branch is refused while the
   regenerated stats.json sits dirty in the working tree.

Fixes:
- Labels are attached best-effort AFTER the PR exists, never passed to
  `gh pr create`, so a cosmetic label can no longer fail the job. The
  `merge-queue` label is added too, handing routine stats bumps to the
  merge-queue advancer instead of a human.
- One coalescing branch (`chore/stats-refresh`) replaced in place, so
  there is exactly one open stats PR at a time and re-runs are idempotent.
- The push takes an explicit lease (`--force-with-lease=<ref>:<sha>`)
  computed from a fetched remote-tracking ref, and falls back to a plain
  create when the branch does not exist yet.

Failure visibility (the wall for the wall): nothing watches a scheduled
workflow's conclusion, which is why four failures were silent. The job now
opens a deduplicated tracking issue on failure (comments on repeats rather
than spamming) and closes it again on success. An issue needs no push
access and no branch-protection exception, and it outlives log retention.

Repo settings changed in this lane (reversible, one API call):
`can_approve_pull_request_reviews` set to true. Branch protection is
untouched - `enforce_admins` and all five required status checks stand,
and `required_approving_review_count` is 0, so the "approve" half of that
setting grants no bypass power.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pend path)

`python tools/cost_ceiling.py --check` on a fresh tree WROTE to the state tree.
Call chain: check() -> read_ledger_total_tokens() -> fleet_ledger.parse_ledger_rows()
-> ensure_ledger_header(), which mkdir'd <state>/ledger/ and wrote OUTCOMES-LEDGER.md
just for asking "how much have we spent?". Check modes must never mutate.

Fix is at the source, in fleet_ledger.parse_ledger_rows(): drop the
ensure_ledger_header() call and return [] when the ledger is absent. Chosen over
patching cost_ceiling because parse_ledger_rows is the shared reader behind
cost_ceiling, cost_projection AND state_store/read_api.read_ledger_rows -- all
three inherited the write, and all three already document "returns empty list if
the file is missing". ensure_ledger_header() is now documented as WRITE-PATH-ONLY
and still runs from append_ledger_line/harvest/rotate, so appends create the
header exactly as before.

TDD: 6 new tests failed first, then passed.
- tests/test_cost_ceiling.py::TestCheckModeIsReadOnly -- API + CLI + daily +
  windowed check() leave a state-tree snapshot byte-identical; plus a
  "read-only is not blind" test proving an existing ledger is still summed.
- tests/test_fleet_ledger_append.py::TestLedgerReadPathIsReadOnly -- reader
  purity for parse_ledger_rows/summary, and REGRESSION coverage that
  append_ledger_line + append_wave still create the header (and append_wave
  stays idempotent) now that the reader no longer materializes it.

Contract preserved: a missing ledger is still spend=0 / exit 0 (never trips on a
fresh install); an UNREADABLE ledger still raises into the fail-safe path
(exceeded=True, tripped=False). Absent means zero; unreadable means stop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tests/test_traps.py::TestCIDriftTrap::test_ci_workflow_files_are_valid_yaml
lexes workflow files line by line and rejects any non-comment line holding
an odd number of double quotes. It has no notion of YAML block scalars,
shell line continuations or heredocs, so the previous revision tripped it
on ten lines that were nonetheless valid for Actions: multi-line
double-quoted PR/issue bodies, backslash-continued gh invocations, and jq
filters with escaped quotes nested inside double quotes.

Rewritten so every line balances its own double quotes, with no change in
behaviour:

- PR body and failure-issue body are built with unquoted heredocs into
  $RUNNER_TEMP and passed via --body-file, so the prose lines carry no
  quotes at all and interpolation still works.
- gh invocations are single lines; the PR title moved to single quotes.
- The issue-dedup jq filter reads the title through jq's env.* rather than
  nesting escaped quotes, which removes the last odd-quote line.
- A comment at the top of the file records the trap's rule so the next
  editor does not rediscover it the hard way.

Verified: the exact failing test passes, the full tests/test_traps.py suite
passes (14), ci_workflow_lint / workflow_model_linter / ci_gate_runability /
verify_gates_wired / encoding_lint all pass, and both heredocs were dry-run
through bash to confirm they render flush-left after YAML dedent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Pipe-join the sub-bullet field lists for fleet_instances,
fleet_multibox_summary, and ci_job_status into dense single lines.
No contract information removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This PR adds tests/mcp-ci-status.test.mjs; verify_test_suite_count.py
expects the documented count to match discovery.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@matt82198

Copy link
Copy Markdown
Owner Author

Dissolving merge-queue batch: ci (0) is not green

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.

1 participant