follow-up to #3407 · run 31400567250 · 2026-08-10

A diagnostic only a browser could read.

The contract probe shipped in #3407 and its first dispatch failed exactly as designed — a contract gate that cannot observe must never look green. Then I could not tell which failure it was, because every line it printed went somewhere a CLI cannot reach.

What happened

run 31400567250 — dispatched on main immediately after merge

  Install the newest published CLI ................ success
  Report where the binary landed ................. success
  Derive the contract ............................ failure

$ gh run view 31400567250 --log     → only the ECHOED script lines
$ gh api .../check-runs/…           → output.summary is EMPTY

Two candidate exits — 1 drift, 2 CANNOT-OBSERVE — and no way to distinguish them without opening a browser. The whole reason that layout step is unconditional was to answer this, and it answered it into a channel the asker cannot read.

The defect, stated plainly

$GITHUB_STEP_SUMMARY renders in the web UI. It is not in gh run view --log, and it is not in the check-run API's output.summary. Writing diagnostics only there makes them invisible to every automated consumer — including the agent that dispatched the run.

Same shape as the thirty-four defects this milestone exists to remove: the machinery ran, reported honestly, and reported into a void.

Fix

-          } >> "$GITHUB_STEP_SUMMARY"
+          } | tee -a "$GITHUB_STEP_SUMMARY"

Both blocks now tee, so the layout listing and the verdict land in the log and the summary. The derive step also emits derive-cc-output-keys exit code: N explicitly, so exit 1 and exit 2 are distinguishable from the log alone rather than inferred from a red X.

A second mistake worth recording

$ grep -c "tee -a \"$GITHUB_STEP_SUMMARY\"" file
0        ← the shell expanded the variable to EMPTY inside double quotes,
           so this searched for `tee -a ""` and I nearly "re-fixed" a
           working edit
$ grep -c 'tee -a' file
2        ← correct

A verification step that cannot observe what it checks reports a false negative just as confidently as a false positive. Single-quote any grep pattern containing a $.

Still unanswered, deliberately. Whether the runner populates ~/.local/share/claude/versions/ — the only path findBinary() searches — is what the next dispatch will show, now that the listing reaches the log. I am not guessing at it here: the install step succeeded and the derive step failed, which is consistent with both drift and cannot-observe, and the difference decides whether the follow-up fixes the lookup path or commits a regenerated snapshot.