Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ec7c832
feat: add read-only actions queue health evidence
seonghobae Aug 19, 2026
5950d6f
fix(queue-health): retry transient PR identity reads
seonghobae Aug 19, 2026
f92f08e
fix: use cross-repository queue health credentials
seonghobae Aug 19, 2026
3196c2d
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 20, 2026
3f7c33b
Merge protected main into queue health evidence
seonghobae Aug 20, 2026
47bb2bc
fix(actions): bound queue run response size
seonghobae Aug 20, 2026
8b914ef
fix(actions): bound queue collector failure modes
seonghobae Aug 20, 2026
a6ac262
fix(queue-health): isolate repository collection errors
seonghobae Aug 20, 2026
94e41c6
docs(queue-health): cite evidence boundaries
seonghobae Aug 20, 2026
7bbd133
docs(ci): complete fixture constructor coverage
seonghobae Aug 20, 2026
4467d5a
docs(tests): complete queue health test docstrings
seonghobae Aug 20, 2026
af65a69
Merge branch 'main' into codex/pr1142-current-main-successor
opencode-agent[bot] Aug 20, 2026
8fcb9b1
Merge current main into actions queue health
seonghobae Aug 21, 2026
2df6b86
fix(queue-health): accept collector snapshot identities
seonghobae Aug 21, 2026
77557e9
fix(ci): reject incomplete paginated queue evidence
seonghobae Aug 21, 2026
31dde70
Merge branch 'main' into codex/pr1142-current-main-successor
opencode-agent[bot] Aug 21, 2026
2d857f6
fix(queue-health): count duplicate lanes by run
seonghobae Aug 21, 2026
6469a76
Merge branch 'main' into codex/pr1142-current-main-successor
opencode-agent[bot] Aug 21, 2026
db2c4c0
Merge branch 'main' into codex/pr1142-current-main-successor
seonghobae Aug 21, 2026
92c419b
Merge branch 'main' into codex/pr1142-current-main-successor
opencode-agent[bot] Aug 21, 2026
efa7788
Merge branch 'main' into codex/pr1142-current-main-successor
opencode-agent[bot] Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/actions-queue-health.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: GitHub Actions queue health

on:
schedule:
- cron: "7 * * * *"

concurrency:
group: github-actions-queue-health
cancel-in-progress: false

permissions:
contents: read
actions: read
pull-requests: read

jobs:
collect:
name: Collect exact-head queue evidence
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
actions: read
pull-requests: read
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1
with:
egress-policy: audit

- name: Checkout trusted queue-health source
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Collect read-only repository and runner evidence
env:
GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN }}
run: |
if [ -z "${GH_TOKEN:-}" ]; then
echo "::error::PR_REVIEW_MERGE_TOKEN or OPENCODE_APPROVE_TOKEN is required for cross-repository queue reads."
exit 1
fi
echo "::add-mask::$GH_TOKEN"
python3 scripts/ci/actions_queue_health.py \
--allowlist config/actions_queue_health_repositories.json \
--output-json "$RUNNER_TEMP/actions-queue-health.json" \
--output-html "$RUNNER_TEMP/actions-queue-health.html"

- name: Upload queue-health evidence
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: github-actions-queue-health-${{ github.run_id }}
path: |
${{ runner.temp }}/actions-queue-health.json
${{ runner.temp }}/actions-queue-health.html
if-no-files-found: error
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@ Semantic Versioning where the repository publishes a release.

## [Unreleased]

### Fixed

- Count duplicate Actions queue lanes by distinct workflow runs so matrix or multi-job runs do not appear as false concurrent-run duplicates.

### Added

- Added a read-only hourly GitHub Actions queue-health report for the central
repository, TEPP, naruon, and contextual-orchestrator, with exact pull-request
head classification, runner-assignment evidence, bounded queue-age SLO
warnings, deterministic JSON, accessible HTML, and no cancellation or merge
mutation.
- Added an hourly organization commercial-readiness coordinator that discovers writable repositories, honors enabled dedicated writer leases and fully paginated live writer runs, refetches exact repository/workflow/run/PR state before dispatch, rotates bounded review-repair and opt-in NVIDIA OpenCode product-development targets, fails nonzero on fleet-wide inspection or dispatch outages, retains three-day JSON receipts, and keeps the existing 15-minute merge scheduler authoritative.
- Added a dedicated Quarantine Sandbox Runtime hourly caller at minute 14 that targets protected `develop`, dispatches at most one exact-head repair, applies a two-hour same-head retry floor, preserves non-cancelling single-flight execution, and maps only the established scheduler credentials with job-scoped OIDC.
- Added a dedicated OriginWeave hourly caller that invokes the product-neutral central scheduler with the exact repository, protected `main` branch, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, job-scoped OIDC, and only the established scheduler credentials.
Expand Down Expand Up @@ -36,6 +45,11 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Retry one transient incomplete pull-request identity response after a bounded
delay, reject path-traversal repository segments, and isolate repository-scoped
API or pagination failures into explicit incomplete-evidence report entries so
healthy repositories remain observable without turning partial evidence into a
passing merge decision.
- Refused PR Review Merge Scheduler head mutations, `update-branch` and the last-push approval head restamp, whenever the resolved mutation credential is the workflow `GITHUB_TOKEN`. GitHub starts no workflow run for events created with that credential, so the moved head collected no current-head required checks and the PR stayed permanently `BLOCKED` with a `github-actions[bot]` merge commit that no later scheduler run could repair, because the branch was no longer behind. The scheduler now waits with `head_mutation_credential_upgrade` guidance naming `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, and the OpenCode app token exchange.
- Parsed `opencode.jsonc` as JSONC (stripping `//` and `/* */` comments outside string literals) in the reasoning-effort guard and its contract tests, instead of raw `json.loads`, which rejected the file the moment it carried its first explanatory comment (added for the `contextual-orchestrator` provider block) with `Expecting property name enclosed in double quotes`. Comment markers inside string values, such as the `$schema` URL, are left untouched.
- Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109).
Expand Down
8 changes: 8 additions & 0 deletions config/actions_queue_health_repositories.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"repositories": [
"ContextualWisdomLab/.github",
"ContextualWisdomLab/TEPP",
"ContextualWisdomLab/contextual-orchestrator",
"ContextualWisdomLab/naruon"
]
}
64 changes: 64 additions & 0 deletions docs/doctoring/actions-queue-health.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# GitHub Actions queue-health evidence

The scheduled `actions-queue-health.yml` workflow reads a fixed allowlist of
CWL repositories once per hour and publishes a JSON report plus a keyboard-
readable HTML report as an artifact. The collector uses only `gh api` reads
through the configured cross-repository `PR_REVIEW_MERGE_TOKEN` or
`OPENCODE_APPROVE_TOKEN`; it fails visibly when neither credential is present.
It does not cancel runs, mutate branches, dispatch workflows, or alter merge
gates, and it never relies on the central repository's scoped `GITHUB_TOKEN`
for sibling-repository reads.

The report schema is `actions.queue_health.v1`. Each observed run records its
repository, pull-request number, head SHA, event, run attempt, concurrency
group (or an explicit unavailable marker), queue age, job state, and runner
assignment. A run is `current_head` only when its linked open pull request and
head SHA match. Stale linked runs are `obsolete`; runs without a pull-request
link are `unlinked`. Queued evidence remains incomplete even when a report is
successfully produced.

Queued runs use run-level evidence because GitHub has not assigned their jobs;
only current-head `in_progress` runs make the additional jobs API read needed
to inspect a concrete runner assignment.

List endpoints use GitHub CLI pagination with at most 20 pages. Pull-request
and job lists use pages of 100 records; workflow-run lists use pages of 50 so a
large Actions queue does not require one oversized response. An incomplete,
malformed, or larger response is recorded as repository-scoped incomplete
evidence and the collector continues with the remaining allowlisted
repositories; it never silently claims that the visible page is the whole
queue. The JSON and HTML reports expose each collection error explicitly.

Every external `gh api` read has a 30-second subprocess timeout, and the
collector job has a 30-minute execution ceiling. A timeout is typed as
incomplete queue evidence rather than success. A pull-request response missing
head or base identity gets one typed retry after a one-second delay; a second
incomplete response remains an explicit repository error. Repository names
reject `.` and `..` path segments. Offline snapshots also reject duplicate
repository entries before counting runs so repeated input cannot inflate the
reported queue.

The default queue-age SLO is 900 seconds. A current-head job that remains
unassigned beyond that limit produces a warning and an explicit manual action
to inspect runner capacity, billing, runner-group policy, environment
approval, and concurrency saturation. The workflow intentionally remains
read-only and fail-closed when GitHub API or runner evidence is unavailable.
Paged API reads are not atomic; changing totals are retained only when the
collected records cover the largest observed total, and the report remains
explicitly an observation rather than a merge decision.

The allowlist is deliberately explicit in
`config/actions_queue_health_repositories.json`; adding a repository requires
review of its governance and data boundary. This first slice does not claim
that a queued run is obsolete or safe to cancel.

## References

GitHub. (n.d.). *REST API endpoints for workflow runs*. Retrieved August 20,
2026, from https://docs.github.com/en/rest/actions/workflow-runs

Internet Engineering Task Force. (2022). *HTTP semantics* (RFC 9110).
https://www.rfc-editor.org/rfc/rfc9110

OWASP Foundation. (n.d.). *Path traversal*. Retrieved August 20, 2026, from
https://owasp.org/www-community/attacks/Path_Traversal
1 change: 1 addition & 0 deletions organization_commercial_readiness_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def __init__(
repositories: list[dict[str, Any]],
snapshots: dict[str, list[RepositorySnapshot | Exception]],
) -> None:
"""Initialize the deterministic repository and snapshot responses."""
self.repositories = repositories
self.snapshots = snapshots
self.dispatched_repairs: list[tuple[str, str]] = []
Expand Down
Loading
Loading