os.homedir() reads USERPROFILE on Windows and never HOME, so the
isolation setup and every test that moved home were still resolving the
developer's real home directory. Fixtures came back empty, real sessions
leaked into counts, and the code under test wrote plans, receipts and a
sync ledger into the real ~/.config/codeburn during a run.
USERPROFILE now joins the redirected variables and a shared setHome()
helper moves HOME and USERPROFILE together; every spawn env carries both.
The remaining Windows-only failures were POSIX-shaped fixtures: chmod
tricks that only toggle a read-only attribute on NTFS, pid 1 as an
always-alive lock holder, splitting paths on '/', bare tar, mode-bit
expectations, and per-file timeouts too short for the cost of a tsx spawn.
Each gets a platform-aware equivalent so nothing is skipped on Windows and
the POSIX branches stay byte-for-byte what they were.
Full run on Windows: 267 files passed, 2 skipped, 3592 tests passed.
Before-merge items:
1. HTTPS enforced on every remote endpoint (RFC 8252 §8.3): baseUrl,
issuer, authorization/token/revocation endpoints, and the traces
endpoint all reject non-https, with a loopback (127.0.0.1/::1/
localhost) exception for offline tests and local dev. Enforcement is
central (assertHttps) — the browser-open guard is no longer the only
check whose failure was swallowed.
2. Credential store test isolation: CODEBURN_SYNC_TOKEN_STORE=file
forces the file store (honors HOME) so the offline suite never
touches the real macOS login keychain. Set in the e2e suite.
3. Golden pins for deriveSpanId/deriveTraceId/deriveDeviceId with fixed
inputs and expected hex — the idempotency contract depends on these
encodings being stable across releases; a green-tests encoding change
would silently double-count history on span-ID-keyed backends.
getDeviceId refactored over a pure deriveDeviceId(host, user).
Smaller review items:
- Callback server: ready promise resolves the actually-bound port from
the listening event (kills the 100ms-sleep race after port fallback);
Connection: close on all responses + closeAllConnections() on
shutdown (pooled keep-alive sockets from a closed server could
swallow requests aimed at a later server on the same port); error
handler guarded so a post-bind error can never rebind to a different
port than advertised; optional ports param ([0] = ephemeral) removes
fixed-port contention between parallel test workers.
- fetchOidcConfig verifies the issuer claim matches the fetch origin
(OIDC Discovery §4.3 mix-up defense).
- partialSuccess.rejectedSpans wrapped in Number() — proto3 int64 JSON
mapping sends strings from strict protojson servers; += would
concatenate.
- Ledger writes are atomic (temp + rename); corrupt-ledger recovery and
no-tmp-left-behind tests added; XDG_CACHE_HOME honored (ledger is
reconstructible state, not config).
- Mock IdP now implements /oauth2/authorize (registers PKCE challenge,
302s to redirect_uri) and verifies S256 code_verifier + single-use
codes at the token endpoint. The e2e drives the real redirect flow
and asserts wrong-verifier and code-reuse are rejected — PKCE binding
is now exercised end to end.
- sync reset calls clearLedger() instead of reimplementing the path.
- push sets exit code 1 on rate-limited/server-error outcomes so cron
and script callers can detect incomplete pushes.
Deferred (noted for fast-follow): macOS 'security -i' stdin mode
(untestable on this Linux box), ai.cost_estimated as a real
ParsedApiCall flag (touches core parser types).
Sync suite: 81 passing (5x stable), 5 developer-only.
AI-Origin: human