Skip to content

skills(ground-claims): read a past run's code at that run's commit - #1319

Merged
max-sixty merged 3 commits into
mainfrom
skills/run-sha-diagnosis-35432041982
Sep 19, 2026
Merged

max-sixty merged 3 commits into
mainfrom
skills/run-sha-diagnosis-35432041982

Conversation

@tend-agent

@tend-agent tend-agent commented Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

A session diagnosing a past CI failure reads the repository from its checkout, which is at the current default branch — so an explanation of why a run failed can cite a branch, guard, or helper that did not exist when that run executed. Nothing downstream catches it: the SHA is real and the permalink resolves, so check_body_links.py passes and the wrong cause ships as a confident diagnosis.

ground-claims now carries the rule under Recurring hallucination shapes: resolve the run's head_sha, read the file at that SHA, and pin the body's links to it. The read goes through the contents API rather than git show <sha>:<path>, because the checkout holds only what a ref reaches — the head of a squash-merged or deleted PR branch is absent from it, which is most of the runs a session gets asked to explain, and a run in another repository is never there at all. git show also fails into the rule's own failure mode rather than out of it: the fatal: goes to stderr while a | grep -c downstream prints 0, indistinguishable from a genuine no-match, which reads as "the guard was absent at that run". The contents call is chained off the run lookup's exit status for the same reason: an empty $SHA makes ref= serve the default branch, with a clean exit and plausible content.

post-to-github's git rev-parse HEAD line is the instruction that supplied the wrong SHA, so it names the exception and points at that section rather than restating the rule.

Text only. uv run pytest -k skill passes, including test_skill_reference_citations_resolve, which is what validates the new cross-reference, and the recipe was run end-to-end against a run in this repo before it shipped.

Closes #1315

@tend-agent tend-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The git show <sha>:<path> half of the recipe is unavailable in the sessions that most need it, and where it fails it fails into the same wrong answer the rule exists to prevent.

fetch-depth: 0 fetches everything reachable from a ref, and nothing else. This repo squash-merges and deletes the branch, so a merged PR's head commit is reachable from no ref and is simply absent from the checkout — of the eight most recently merged PRs here, git cat-file -e <headRefOid> finds none of them. Default-branch runs are fine, which is ci-fix's case; a run on a PR branch is not, which is what review-runs, the notification drain, and a review session explaining an earlier run are usually looking at. review-reviewers never has the object at all — its checkout is a different repository from the runs it reads.

The failure mode is the part that matters. The absent object does not announce itself as absent:

$ git show dfdb610ef17e80e2c9839e7b244cc06e38f950ef:README.md
fatal: path 'README.md' exists on disk, but not in 'dfdb610ef17e80e2c9839e7b244cc06e38f950ef'

That message reads as "the file was not there at that commit". Piped — which is the idiom #1315 itself uses as its proof, git show "$s:scripts/verify_site.py" | grep -c 'rolling_out\|Retry-After' — the fatal goes to stderr and stdout carries 0, exit 0. A session reads 0 and concludes the guard did not exist when that run executed. That is the hallucination this rule was written to stop, now produced by the rule's own recipe, and with the same false confidence: a clean exit and a plausible number.

Fetching at the SHA has none of these cases, and covers the local-commit one too:

gh api "repos/{owner}/{repo}/contents/<path>?ref=$SHA" -H 'Accept: application/vnd.github.raw'

I'm pushing that as the recipe. post-to-github's cross-reference and the choice of ground-claims over ci-fix as the home both look right to me and I haven't touched them.

How the object absence was checked
$ for n in $(gh pr list --state merged --limit 8 --json number --jq '.[].number'); do
    sha=$(gh pr view $n --json headRefOid --jq .headRefOid)
    git cat-file -e "$sha" 2>/dev/null && echo "$n local" || echo "$n absent"
  done
1310 absent
1309 absent
1308 absent
1307 absent
1306 absent
1305 absent
1303 absent
1301 absent

The same SHA fetches fine over the API, which is why the replacement recipe holds where git show does not:

$ gh api "repos/{owner}/{repo}/contents/README.md?ref=dfdb610ef17e80e2c9839e7b244cc06e38f950ef" \
    -H 'Accept: application/vnd.github.raw' | head -1
<h1><img src="assets/logo-512.png" alt="tend logo" width="50" align="absmiddle">Tend</h1>

check_body_links.py is unaffected either way — it resolves a SHA through repos/{slug}/commits/{sha}, and a run head resolves there whether or not the branch still exists.

`git show <sha>:<path>` only resolves a commit the checkout holds, and
`fetch-depth: 0` holds only what a ref reaches — the head of a
squash-merged or deleted PR branch is absent, which is most of the runs
a session explains. It fails into the rule's own failure mode: the
`fatal:` goes to stderr while a `| grep -c` downstream prints `0`,
reading as "the guard was absent at that run".

The contents API at `?ref=<sha>` resolves in every case, including a
run in another repository.

@tend-agent tend-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things in the new recipe, both the shape the last commit set out to fix — a path that returns a plausible answer rather than failing.

An empty $SHA reads the default branch. If the run lookup fails and leaves $SHA empty, ref= with no value serves the repository's default branch and exits 0:

$ gh api "repos/max-sixty/tend/contents/README.md?ref=" -H 'Accept: application/vnd.github.raw' | head -1
<h1><img src="assets/logo-512.png" alt="tend logo" width="50" align="absmiddle">Tend</h1>

That is the reading the rule exists to prevent, arriving with a clean exit and content that looks right. /tend-ci-runner:review's posting recipe already guards the same shape — "Read the sha first and bail if it isn't there" — and chaining the contents call off the run lookup's exit status covers it here.

| grep -c exits 1, not 0. grep -c returns 1 when it selects no lines, so the pipeline's status is 1 whether the object was missing or the guard was genuinely absent:

$ git show <absent-sha>:README.md 2>/dev/null | grep -c Tend
0
$ echo $?
1

The argument survives — 0 on stdout is indistinguishable from a real no-match — but the exit status as stated is wrong, in the section telling the reader not to assert unrun tool behavior. Pushing both fixes.

One judgment call left alone: head_sha is the PR's head commit, not the merge commit a pull_request run checks out (refs/pull/N/merge), so for a PR-triggered run the file at that SHA can differ from the tree that actually executed when base moved after the branch point. Saying so costs a sentence in a skill that is meant to be brief, and for the code a diagnosis usually asks about the two read the same — so it seems a maintainer's call rather than mine.

@max-sixty
max-sixty merged commit ab827ca into main Sep 19, 2026
11 checks passed
@max-sixty
max-sixty deleted the skills/run-sha-diagnosis-35432041982 branch September 19, 2026 16:31
max-sixty pushed a commit to max-sixty/leaf that referenced this pull request Sep 21, 2026
Regenerates the nine `tend-*` workflows against tend 0.2.13 (from
0.2.11). The committed diff is only the pinned action ref and the `uv`
setup version (`0.12.13` → `0.12.17`); everything below rides in the
action and the plugin it loads.

## What changes for this repo

**A cancelled gating check no longer reads as green.**
`poll_pr_checks.py` now treats only `SUCCESS`, `NEUTRAL`, and `SKIPPED`
as green and exits 2 — unverified — on anything else
([max-sixty/tend#1323](max-sixty/tend#1323)).
Cancelled runs are routine here: main serializes the complete suite, so
a newer commit replaces the one waiting for its turn, and `running-tend`
already carries a rule for reading that shape. Under 0.2.11 a session
polling its own push could report such a check as verified; it now has
to say it could not verify.

**CI sessions ignore the bot's claude.ai account.** Skills, plugins, and
MCP connectors enabled on the `leaf-agent` account no longer load into
sessions that push and post as it
([max-sixty/tend#1328](max-sixty/tend#1328)).
Sessions run with this repo's skills and tend's own, and nothing else.

**`/tmp` is writable inside the sandbox**, as scratch private to the run
([max-sixty/tend#1324](max-sixty/tend#1324)). A
tool that hard-codes a `/tmp` path no longer needs an override;
`$TMPDIR` stays the documented place to write.

**The sandbox launch retries a transient bridge-socket failure**, up to
three attempts
([max-sixty/tend#1327](max-sixty/tend#1327)).
SRT gives socat 600 ms to bind, and a slow runner previously lost the
whole job before the agent started.

Three plugin-side fixes also land: `review-runs` can now cancel a run
parked in GitHub's `waiting` state that holds its concurrency group
without ever concluding
([#1320](max-sixty/tend#1320)); `ground-claims`
reads a past run's code at that run's commit rather than at the current
default branch ([#1319](max-sixty/tend#1319));
and `run-tend` corrects its list of instruction paths restored to the
base version on a PR
([#1311](max-sixty/tend#1311)).

## No configuration change needed

0.2.12 moved the agent into the job's own checkout through a
copy-on-write view, which would have changed where dependency setup
belongs. 0.2.13 reverts it
([#1339](max-sixty/tend#1339)): `setup:` and
`sandbox_setup:` behave as they did at 0.2.11, so `.config/tend.yaml` is
unchanged here. This repo pins no `model:`, so the harness default
applies as before.

Full comparison:
[0.2.11...0.2.13](max-sixty/tend@0.2.11...0.2.13).

Co-authored-by: leaf-agent <318509791+leaf-agent@users.noreply.github.com>
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.

ground-claims: a diagnosis reads the checkout, so a claim about what a past run executed cites code that did not exist then

2 participants