From 13219d1d55732c2eeaecc084c796351ce4950a67 Mon Sep 17 00:00:00 2001 From: pi Date: Tue, 4 Aug 2026 16:49:02 +0200 Subject: [PATCH] docs(agents): Gitea API jobs endpoint takes id, not run_number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GET /api/v1/repos/{owner}/{repo}/actions/runs/{n}/jobs expects the internal run `id`, not the `run_number` the UI shows as `#239`. The two diverge widely (id=534 was run_number=238) and the wrong key does NOT error — it silently returns another run's jobs. This cost a wrong conclusion while verifying that a push to main no longer triggers image builds: querying .../runs/238/jobs returned docs-check/validate-base/validate-omos, which made a lint.yml run look like it had built images. Corrected by reading `id` from the run listing. Records the two reliable patterns in the existing "Gitea API access" section: filter the runs listing on head_sha to learn authoritatively which runs a commit triggered, then key the jobs endpoint by that id. Also notes that counting runs per commit is the cheapest assertion of the trigger model (2 runs before the split, 1 after), and that lint.yml's actionlint job can take 6–15 min because it apt-installs shellcheck in-container — so a still-running lint is not a problem signal. --- AGENTS.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 20eca17..fa40d97 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -154,6 +154,36 @@ the token matters mainly for private repos or rate-limit headroom; its lifecycle is host-managed, so there is nothing to revoke after use. Never echo the token value (including into logs). +**Gotcha — the jobs endpoint takes the internal `id`, NOT the `run_number` the +UI shows as `#239`.** The two diverge widely (`id=534` was `run_number=238`), +and `GET .../actions/runs//jobs` does **not** error — it silently +returns the jobs of a *different* run. This cost a wrong conclusion once: while +verifying that a push no longer triggers builds, querying `.../runs/238/jobs` +returned `docs-check`/`validate-base`/`validate-omos`, making a `lint.yml` run +look like it had built images. Always read `id` from the run listing and use +that. Two reliable patterns: + +```bash +# Authoritative: which runs did MY commit trigger? Filter on head_sha — do not +# trust ordering or run numbering. +curl -sS -H "Authorization: token $GITEA_ACCESS_TOKEN" \ + "$GITEA_HOST/api/v1/repos/joakimp/opencode-devbox/actions/runs?limit=20" \ + | jq --arg sha "$(git rev-parse HEAD)" \ + '.workflow_runs[] | select(.head_sha==$sha) | {id, run_number, path, event, status, conclusion}' + +# Then the per-job breakdown, keyed by the id from above (NOT run_number) +curl -sS -H "Authorization: token $GITEA_ACCESS_TOKEN" \ + "$GITEA_HOST/api/v1/repos/joakimp/opencode-devbox/actions/runs//jobs" \ + | jq '.jobs[] | {name, status, conclusion}' +``` + +Counting runs per commit is also the cheapest way to assert the trigger model +from the previous section: commits before the split show **2** runs +(`lint.yml` + `validate.yml`), commits after show **1** (`lint.yml`). Note +`lint.yml` is cheap in CPU but not always in wall-clock — its `actionlint` job +`apt-get install`s shellcheck inside the container and has taken 6–15 min on a +busy runner, so a still-`in_progress` lint run is not evidence of a problem. + ## Testing changes The smoke test (`scripts/smoke-test.sh`) is the canonical check and runs automatically in CI. To run locally: