fix(telemetry): the CLI never looks where Windows installs spool (backend#2377) - #555
Conversation
…kend#2377) `installerSpoolFiles` searched $TMPDIR, $HOME and /tmp for the installer's pre-log fallback spool. Windows sets neither of the first two — USERPROFILE is its home variable and [IO.Path]::GetTempPath() resolves TMP/TEMP — so the search reduced to /tmp, a path that does not exist there. `client/scripts/lib/telemetry.ps1` `Get-TelemetryFallbackSpool` writes to $USERPROFILE, else $HOME, else GetTempPath(). Every Windows pre-log install failure was therefore written and never collected: exactly the class the fallback exists for, since validate_config and early_data_dir_guard run before there is a log or a data dir. The candidate list is now named and documented against both producers, and the dedup uses filepath.Clean so a trailing separator collapses on either platform rather than sending one install outcome twice. Residual, stated rather than hidden: the producers live in tracebloc/client, so nothing in this repo's CI can prove the list still agrees with them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
saqlainsyed007
left a comment
There was a problem hiding this comment.
Verified against the code and the producers' chains — clean fix.
The spool search was TMPDIR → HOME → /tmp, but the PowerShell installer writes to USERPROFILE → HOME → TMP/TEMP, and Windows sets neither TMPDIR nor usually HOME — so it reduced to /tmp, which doesn't exist there, and every Windows pre-log install failure was spooled and never collected (exactly the class the fallback exists for: validate_config/early_data_dir_guard run before any log). Adding USERPROFILE/TEMP/TMP closes it, and filepath.Clean (not TrimRight("/")) correctly dedups a trailing separator on both platforms.
The test earns its keep: TestInstallerSpoolFilesFindsTheFallbackOnEveryHomeVariable writes the five var names independently of installerFallbackDirVars, so a typo in the production list can't be mirrored into the test and pass anyway (rule 9); one subtest per var with only that var set makes each assertion about that var, not the environment. The cross-repo residual (producers live in tracebloc/client, kept in step by review until a shared fixture) is stated, not hidden. CI green, no threads. LGTM.
Summary
Closes tracebloc/backend#2377. Part of the backend#1872 telemetry epic.
installerSpoolFiles(internal/cli/telemetry_installer_spool.go) looked for the installer's pre-log fallback spool in$TMPDIR,$HOMEand/tmp. The PowerShell installer writes it to$USERPROFILE, else$HOME, else[IO.Path]::GetTempPath()(i.e.TMP/TEMP) —client/scripts/lib/telemetry.ps1,Get-TelemetryFallbackSpool. Windows sets neitherTMPDIRnor, usually,HOME, so the search reduced to/tmp, which does not exist there.Result: Windows pre-log install failures were spooled and never delivered. That is precisely the class the fallback exists for —
validate_configandearly_data_dir_guardrun before there is a log or a data dir, so the fallback file is their only record. The data-dir spool was unaffected: this function already resolves that one throughos.UserHomeDir(), which isUSERPROFILEon Windows. The glob was fine too —tracebloc-telemetry-*already matches the twin's.jsonlsuffix.Type
Bug fix.
Changes
installerFallbackDirVars— the candidate variables, named once and documented against both producers' fallback chains (telemetry.sh_telemetry_fallback_dirandtelemetry.ps1Get-TelemetryFallbackSpool), with the residual stated in the code: those producers live intracebloc/client, so nothing in this repo's CI can prove the list still agrees with them. Review rule until the two repos share a fixture.filepath.Cleanreplacesstrings.TrimRight(dir, "/")for dedup, so a trailing separator collapses on Windows too. Two spellings of one directory would forward the same install outcome twice in one batch.Test plan
Three new tests in
internal/cli/telemetry_installer_spool_test.go:TestInstallerSpoolFilesFindsTheFallbackOnEveryHomeVariable— a subtest per variable, each setting only that variable. The five names are written down independently ofinstallerFallbackDirVars, deliberately: a test that feeds the production list back into itself is self-consistent and would plant a typo rather than catch one.TestInstallerFallbackDirVarsAreAllSearched— totality. Catches the opposite failure: a name added to the vocabulary and never wired into the loop.TestInstallerSpoolFilesDedupesATrailingSeparator— guards thefilepath.Clean.Mutation-proved, with the anchor asserted applied each time (the diff was printed per mutation, so an inert mutation could not pass for coverage):
"USERPROFILE"from the list…OnEveryHomeVariable/USERPROFILE{"TMPDIR","HOME"}/USERPROFILE,/TEMP,/TMP, totality, dedupeinstallerFallbackDirVars[:len-1]/TMP, totalityseen[dir]checkRestored and green afterwards.
Ran locally (go1.26.6, darwin/amd64):
gofmt -lclean,go vet ./...clean,go build ./...,go test ./... -count=1→ 18 packages ok, 0 FAIL.Could not run locally:
golangci-lint(not installed on this machine — CI'sgolangci.ymlcovers it), and the Windows path semantics themselves.filepath.Cleanon darwin does not treat\as a separator, so the Windows half of the dedup change is exercised by construction rather than by execution; thebuild.ymlcross-platform matrix compiles it, and the behavioural fix (searchingUSERPROFILE/TEMP/TMPat all) is fully covered on any platform.Checklist
develop🤖 Generated with Claude Code
Note
Low Risk
Narrow path-discovery fix for installer telemetry drain, with tests. No auth, ingest, or filtering-logic changes.
Overview
The CLI now finds the installer's pre-log fallback spool on Windows.
installerSpoolFilespreviously only searched$TMPDIR,$HOME, and/tmp, so Windows writes under$USERPROFILE/$TEMP/$TMPwere never drained.Candidate dirs now come from
installerFallbackDirVars(TMPDIR,HOME,USERPROFILE,TEMP,TMP) plus bash's literal/tmp. Dedup usesfilepath.Cleanso a trailing separator does not send the same install outcome twice.Tests pin each env var independently, assert every declared name is actually searched, and cover trailing-separator dedup.
Reviewed by Cursor Bugbot for commit dd34cba. Bugbot is set up for automated code reviews on this repo. Configure here.