Summary
git-ai debug's attribution self-check reports failure on machines where attribution is demonstrably healthy, in every configuration we tested (v1.6.20 release binary, macOS/arm64). We were using it to triage a cohort of genuinely-broken installs and found it cannot distinguish broken from healthy — it fails on both, with different messages.
Evidence
1. Healthy machine, enterprise config (allow_repositories + http notes backend + async_mode):
Attribution self-check: failed - attribution self-check failed
timed out after 3.0s waiting for checkpoint persistence: only 0 checkpoint(s) visible, expected at least 1
daemon status for repo: latest_seq=5, last_error=<none>
This machine's attribution provably works: local notes-db has 280 rows and grows with every commit, and its commits are attributed on the backend. A second (genuinely broken) machine produces the identical output — the check can't tell them apart. Notably the daemon's own event log shows checkpoint start/checkpoint done for the self-check repos, so the checkpoint is processed — read_checkpoint_count (working log for base "initial") just never sees it within the 3s DEBUG_CHECK_TIMEOUT.
2. Pristine isolated environment, upstream-default config (no feature flags, default git_notes backend), same release binary — fails deterministically (4/4 runs), one stage later:
Attribution self-check: failed - attribution self-check failed
timed out after 3.9s waiting for expected attribution via git_notes backend for <sha> in .../debug-self-checks/configured-git-...:
unexpected attribution for line 2: got untracked, expected known_human
Repro (isolated HOME + per-run daemon, nothing touches the real install):
W="$(mktemp -d)"; H="$W/home"; mkdir -p "$H/.git-ai" "$W/s"
printf '[user]\n\tname = AB\n\temail = ab@example.com\n[init]\n\tdefaultBranch = main\n' > "$H/.gitconfig"
echo '{ "telemetry_oss": "off", "disable_version_checks": true, "disable_auto_updates": true }' > "$H/.git-ai/config.json"
E=( "HOME=$H" "GIT_CONFIG_GLOBAL=$H/.gitconfig" "GIT_CONFIG_NOSYSTEM=1"
"GIT_AI_DAEMON_HOME=$H" "GIT_AI_DAEMON_CONTROL_SOCKET=$W/s/c.sock"
"GIT_AI_DAEMON_TRACE_SOCKET=$W/s/t.sock" )
env "${E[@]}" git-ai bg run & sleep 2
env "${E[@]}" git-ai debug --skip-trace2-checks | grep -A2 'Attribution self-check'
3. Adding feature_flags: {async_mode: true, rewrite_stash: true} to the isolated config reproduces the same stage-2 failure — so the flags aren't the discriminator; the check appears simply unable to pass within its time budget.
Impact
- Enterprise operators cannot use
git-ai debug to triage attribution-dead installs (we have a cohort of 27 machines with zero notes written; the self-check output on them is indistinguishable from healthy machines).
- Users who run
git-ai debug see "attribution self-check failed" and reasonably conclude git-ai is broken when it isn't.
Suspected causes / suggestions
DEBUG_CHECK_TIMEOUT (3s) looks far too tight for real-world daemons: on corp macOS endpoints, security tooling adds 90–250ms per process spawn and the check's flow spawns many; our failures are all timeout-shaped (3.0–3.9s), and daemon telemetry shows the checkpoints/notes do land — later.
- The two stages fail independently (
checkpoint persistence under enterprise config, blame attribution under defaults) — worth reporting which stages passed and how long each took, so a slow-pass is distinguishable from a dead install.
- Consider polling to success with a generous ceiling (30s?) and reporting elapsed time, rather than a hard 3s fail.
Environment: git-ai 1.6.20 (release), macOS Darwin 25.5.0 arm64 (M-series), git 2.55.0.
Summary
git-ai debug's attribution self-check reports failure on machines where attribution is demonstrably healthy, in every configuration we tested (v1.6.20 release binary, macOS/arm64). We were using it to triage a cohort of genuinely-broken installs and found it cannot distinguish broken from healthy — it fails on both, with different messages.Evidence
1. Healthy machine, enterprise config (allow_repositories + http notes backend + async_mode):
This machine's attribution provably works: local notes-db has 280 rows and grows with every commit, and its commits are attributed on the backend. A second (genuinely broken) machine produces the identical output — the check can't tell them apart. Notably the daemon's own event log shows
checkpoint start/checkpoint donefor the self-check repos, so the checkpoint is processed —read_checkpoint_count(working log for base"initial") just never sees it within the 3sDEBUG_CHECK_TIMEOUT.2. Pristine isolated environment, upstream-default config (no feature flags, default
git_notesbackend), same release binary — fails deterministically (4/4 runs), one stage later:Repro (isolated HOME + per-run daemon, nothing touches the real install):
3. Adding
feature_flags: {async_mode: true, rewrite_stash: true}to the isolated config reproduces the same stage-2 failure — so the flags aren't the discriminator; the check appears simply unable to pass within its time budget.Impact
git-ai debugto triage attribution-dead installs (we have a cohort of 27 machines with zero notes written; the self-check output on them is indistinguishable from healthy machines).git-ai debugsee "attribution self-check failed" and reasonably conclude git-ai is broken when it isn't.Suspected causes / suggestions
DEBUG_CHECK_TIMEOUT(3s) looks far too tight for real-world daemons: on corp macOS endpoints, security tooling adds 90–250ms per process spawn and the check's flow spawns many; our failures are all timeout-shaped (3.0–3.9s), and daemon telemetry shows the checkpoints/notes do land — later.checkpoint persistenceunder enterprise config,blame attributionunder defaults) — worth reporting which stages passed and how long each took, so a slow-pass is distinguishable from a dead install.Environment: git-ai 1.6.20 (release), macOS Darwin 25.5.0 arm64 (M-series), git 2.55.0.