CLAUDE.md: never just theorize -- investigate empirically - #355
Conversation
…ed it A standing instruction from the maintainer, banked here rather than in Morrison-Lab/ai-config because a session scoped to d-morrison/gha cannot add a repository under another owner (add_repo refuses the cross-tier add), which is itself now documented two sections up. The rule is that a cheap-to-test hypothesis must be tested before it is asserted, and the section is written around the three places in the org-move work (#351, #352) where skipping that cost real time: - An org-wide job failure was blamed on an Actions spending limit, then on anything but billing once that was disproved, while the job page's own banner read "your account is locked due to a billing issue" throughout. - Two guesses at markdownlint's MD013 flagged 269 and 31 lines against the linter's actual 1, and a guess at lychee's redirect handling was wrong because 301 is in the bundled config's `accept` list. Both configs are in this repo. - Which repositories moved was answerable from the lychee run's own redirect and error lists rather than from reasoning about it. It also records the corollary that cost the most time: a run of access failures is not evidence a question cannot be investigated. Three authenticated routes failed in a row -- a 301 from the REST API, an out-of-scope refusal from the MCP tools, a 403 from the agent proxy -- before a plain public URL answered it immediately. Verified: no non-ASCII in the added lines, no added line over 80 characters, and the repo's own check-new-line-breaks reports the new prose clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCBscsqbuxXgaZKLNxef7d
| ignores a line with no space past the limit. | ||
| A model of a checker is only worth using once it reproduces that checker's | ||
| known result on a known input. | ||
| - **Prefer the run's own artifacts to your inference about them.** |
There was a problem hiding this comment.
Ambiguous terminology: "artifacts." Elsewhere in this same file, "artifact"/"artifacts" is used exclusively for a literal GitHub Actions uploaded artifact object (e.g. upload-review-execution's description: "uploads it as a workflow artifact"). Here the example given is lychee's printed redirect/error output — plain console/log text, not an uploaded artifact — so a reader searching this file for "artifact" could reasonably (and wrongly) read this bullet as "go check the uploaded GH Actions artifact file." Notably, this PR's own changelog fragment (changelog.d/claude-md-investigate-empirically.added.md) independently reaches for the more accurate word — "prefer a run's own output to inference about it" — for the identical concept, which is good evidence the mismatch is real rather than a stretch.
This falls under this file's own item 3, "Challenge ambiguous phrasing and terminology".
| - **Prefer the run's own artifacts to your inference about them.** | |
| - **Prefer the run's own output to your inference about it.** |
| A job that fails with no logs still has an error banner on its job page, | ||
| reachable with `WebFetch` on the run URL even when the API will not serve | ||
| it. gha#351/#352: an org-wide job failure was attributed to an Actions |
There was a problem hiding this comment.
Minor factual-accuracy nit: this states unconditionally that a job's error banner is "reachable with WebFetch on the run URL even when the API will not serve it." WebFetch itself fails on authenticated/private URLs (and an unauthenticated GET to a private repo's Actions run page 404s rather than serving content), so this only holds for a public repo — exactly the qualifier the sibling section two sections earlier already applies carefully: "any public repo's files are fetchable with curl (or WebFetch)...".
Low severity/non-blocking: Morrison-Lab/gha itself and every repo currently in REVDEPS.md are public, so the bullet's advice is correct for the incident it cites (gha#351/#352) and for this repo as it stands today — and the section's own closing paragraph does mention "a plain public https://github.com/... URL", so the concept isn't entirely missing, just not carried into this specific bullet. Worth a one-clause fix (e.g. "...on the run URL — for a public repo — even when...") so a reader skimming just the bullet list doesn't come away with the unconditional version, especially if this section is ever promoted into the shared ai-config corpus for use in other (possibly private) repos.
Code reviewReviewed the new Fact-checking: every checkable factual claim in the new text verified accurate against the real repo files and the cited issues — Two smaller findings survived independent verification and are posted inline:
No CLAUDE.md-compliance or bug-agent findings survived validation beyond these two; several other candidate issues (a lychee-redirect logic concern, a contradiction with the "Cheap self-check" section, two lower-severity completeness nits) were checked and ruled out as false alarms or too minor to raise. VerdictReady for merge (the two inline findings above are minor wording/precision nits, non-blocking). |
|
Claude finished review — View run Code reviewReviewed the new Fact-checking: every checkable factual claim in the new text verified accurate against the real repo files and the cited issues — Two smaller findings survived independent verification and are posted inline:
No CLAUDE.md-compliance or bug-agent findings survived validation beyond these two; several other candidate issues (a lychee-redirect logic concern, a contradiction with the "Cheap self-check" section, two lower-severity completeness nits) were checked and ruled out as false alarms or too minor to raise. VerdictReady for merge (the two inline findings above are minor wording/precision nits, non-blocking). |
Banks a standing instruction from the maintainer, with the cases from this
week's org-move work that motivated it.
It lands here rather than in
Morrison-Lab/ai-config, where a global rulewould normally live, because a session scoped to
d-morrison/ghacannot add arepository under another owner —
add_reporefuses the cross-tier add. Thatconstraint is itself now documented two sections up, from the same work.
The rule
A hypothesis that is cheap to test must be tested before it is asserted, and
certainly before it is acted on or reported. The failure mode isn't being
wrong — it's being wrong and confident, because a stated hypothesis reads to
everyone else like a finding.
Why these three examples
Each is a place in #351/#352 where skipping the check cost real time, and each
points at an artifact that was available the whole time:
The job was not started because your account is locked due to a billing issuecheck-links/lychee.default.toml—301is inacceptlint-qmd/.markdownlint.qmd.jsonc—{ line_length: 80, code_blocks: false, tables: false }, plus markdownlint ignoring a line with no space past the limit. The linter's actual count was 1Both configs live in this repo, which is what makes the third case
embarrassing rather than merely unlucky. The section states the general form:
a model of a checker is worth using only once it reproduces that checker's
known result on a known input.
The corollary that cost the most
A run of access failures is not evidence a question can't be investigated.
Three authenticated routes failed in a row — a
301from the REST API, anout-of-scope refusal from the MCP tools, a
403from the agent proxy — andthen a plain public
https://github.com/...URL answered it immediately. Thefile already gives this advice for reading files out of unscoped
repositories; this generalizes it.
Verification
check-non-standard-charsterritory).check-new-line-breaksreports the new prose clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01VCBscsqbuxXgaZKLNxef7d
Generated by Claude Code