fix(driver): the pin would have walked every fire into a probe-hang — gate on onboarding (#558) - #667
Merged
Conversation
… gate on onboarding (#558) TWO DEFECTS IN #666, one of which would have taken the V1 loop down on the first fire after the reconcile. Found by reading 76ee405, which landed on dev while #666 was in review. DEFECT 1 — the pin walks into a dead checkout. A pin worktree is BY CONSTRUCTION a path Claude Code has never seen, and an un-onboarded checkout makes headless `claude -p` block on a trust dialog it cannot display. Every model probe then hangs to its timeout (120s x2 x3 models ~= 12 min) and the driver refuses with "NO usable model in prefs" — which reads as a quota outage, not as the harness fault it is. That had just cost the motoko mission its whole first unattended fire (charter V22). Measured here before writing any code: onboarded=true /Users/voightkampff/dev/sunholo-data/ailang onboarded=ABSENT /Users/voightkampff/.ailang-driver-pin/v1 <- the pin target So #666, the moment the shared clone received it, would have converted a working-but-stale loop into a dead one. Stale-but-working strictly beats fresh-and-dead, so the pin now reads projects[<wt>].hasCompletedProjectOnboarding from ~/.claude.json and REFUSES when it is absent — reported on both human channels like every other pin failure, with the exact one-line human fix in the message. Undeterminable (no jq) is treated as un-onboarded on purpose: pinning blind risks 12 minutes of hung probes, refusing costs staleness that is already reported. jq is /usr/bin/jq, inside launchd's default PATH. It gates on hasCompletedProjectOnboarding, NOT the hasTrustDialogAccepted the error text names: 76ee405 measured ailang-world at trust=false/onboarded=true and WORKING, which is the control proving the flag the message points at is not the gate. Test 8 pins both arms so a future edit cannot quietly switch to the wrong flag and stay green. DEFECT 2 — a fix that disables itself after one use. Worktree existence was decided by string-matching `git worktree list`, but git records the RESOLVED realpath, so on any path reached through a symlink (/var -> /private/var, the macOS everyday case) the match silently fails, fire 2 takes the `add` branch against an existing directory, and the pin refuses from then on. Loud, but permanently useless. Now decided by asking the worktree itself. Caught by the new repeat-fire test, not by review — the first suite only ever fired once. CONSEQUENCE FOR DEPLOYMENT: reconciling the shared clone is now safe with no further action — the pin declines and says why. Pinning switches ON when a human runs, once per checkout: cd ~/.ailang-driver-pin/<mission> && claude TESTED: 48 assertions (31 + 17), `make test-launchd-drivers`, bash 3.2.57, CI job on macOS. New: un-onboarded => refuse + fire still runs + never reports pinned; trust-flag-alone does NOT satisfy while onboarding-flag does; no-jq fails safe; second consecutive fire pins. The happy path runs against a synthetic ~/.claude.json in a fake HOME rather than with the check disabled, so a gate regressed to always-refuse fails tests 1-6 and one regressed to always-allow fails 7. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
sunholo-voight-kampff
added a commit
that referenced
this pull request
Aug 12, 2026
…ng is the discriminator" was wrong
The counterfactual arrived and refuted it. Mark set hasTrustDialogAccepted=true
and left hasCompletedProjectOnboarding ABSENT; the 10:32 fire then probed
`controller=claude-opus-5 via probe ok` and iteration 1 ran to rc=0.
ailang trust=T onboarded=T works
ailang-world trust=F onboarded=T works
ailang-motoko trust=F onboarded=absent FAILED
ailang-motoko trust=T onboarded=absent WORKS <- the counterfactual
So EITHER flag suffices and motoko simply had neither. The error message's own
advice ("accept the trust dialog, or set hasTrustDialogAccepted") was correct,
and my "NOT the flag the error names" claim was not.
The reasoning error is the part worth keeping: I had three config snapshots and
picked the variable that CORRELATED, with no way to test the counterfactual.
ailang-world licensed "trust=false can work"; it never licensed "trust=true
alone cannot". With N=3 and no counterfactual, a correlation is not a mechanism
— the guide now carries that as a caution beside the fix.
Onboarding IS separately load-bearing for the #558 driver pin: PR #667 (landed
by this mission's iteration 1) gates the pin root on it, after finding the pin
would otherwise walk every fire into this same probe-hang.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #666. Two defects, one of which would have taken the V1 loop down on the first fire after the reconcile. Found by reading
76ee4056c, which landed on dev while #666 was in review.Defect 1 — the pin walks into a dead checkout
A pin worktree is by construction a path Claude Code has never seen, and an un-onboarded checkout makes headless
claude -pblock on a trust dialog it cannot display. Every model probe then hangs to its timeout (120s × 2 × 3 models ≈ 12 min) and the driver refuses withNO usable model in prefs— which reads as a quota outage, not as the harness fault it is. That had just cost the motoko mission its entire first unattended fire (charter V22).Measured before writing any code:
So #666, the moment the shared clone received it, would have converted a working-but-stale loop into a dead one. Stale-but-working strictly beats fresh-and-dead, so the pin now refuses when
projects[<wt>].hasCompletedProjectOnboardingis absent — reported on both human channels like every other pin failure, with the exact one-line fix in the message. Undeterminable (nojq) counts as un-onboarded on purpose: pinning blind risks 12 minutes of hung probes; refusing costs staleness that is already reported.It gates on
hasCompletedProjectOnboarding, not thehasTrustDialogAcceptedthe error text names —76ee4056cmeasuredailang-worldat trust=false/onboarded=true and working, the control proving the named flag is not the gate. Test 8 pins both arms so a future edit cannot quietly switch to the wrong flag and stay green.Defect 2 — a fix that disables itself after one use
Worktree existence was decided by string-matching
git worktree list, but git records the resolved realpath, so on any path reached through a symlink (/var→/private/var, the macOS everyday case) the match silently fails. Fire 1 pins; fire 2 hitsworktree addon an existing directory and refuses — from then on, permanently. Loud, but useless. Now decided by asking the worktree itself.Caught by the new repeat-fire test, not by review: the original suite only ever fired once.
Consequence for deployment
Reconciling the shared clone is now safe with no further action — the pin declines and says why. Pinning switches on when a human runs, once per checkout:
Testing
48 assertions (31 + 17),
make test-launchd-drivers, bash 3.2.57, CI job on macOS. New coverage: un-onboarded → refuse + fire still runs + never reports pinned; trust-flag-alone does not satisfy while onboarding-flag does; no-jqfails safe; second consecutive fire pins.The happy path runs against a synthetic
~/.claude.jsonin a fakeHOMErather than with the check disabled — so a gate regressed to always-refuse fails tests 1–6, and one regressed to always-allow fails test 7.🤖 Generated with Claude Code