Review rounds 2-3 + self-review on --attribution:
Credential egress (round 2):
- normalizeRemoteUrl: scp userinfo expressed as an optional regex group
let backtracking re-parse a credential prefix as host:path
(x-access-token:ghp_...@host/repo -> token in git.repo). Userinfo is
now split off at the first @ BEFORE any host matching.
- Positive validation (allow-list) as the final gate on EVERY branch:
host must be hostname-shaped, every path segment repo-shaped, total
identity <= 200 chars. Kills transport-helper remotes (ext:: leaks
local SSH key paths, codecommit:: leaks AWS profile names), residual
@, spaces/colons, and unbounded strings.
- sanitizePrLinks: links are rebuilt from origin + pathname — userinfo,
query strings, and fragments are dropped instead of passed through;
collapsed duplicates dedupe.
Attribution correctness (round 3 + self-review):
- Double-count fix with precise retraction semantics: when a commit
migrates to a later-parsed tighter-window session, the loser re-emits
git.commit_count=0. Empty records are emitted ONLY on a true loss in
THIS computation (lostCandidacy) — a commit that merely aged out of
the --since range was lost to nobody, and retracting it would
permanently zero a still-correct server-side count. The sync layer
additionally requires a prior ledgered state for the session.
- Session dedup key includes project + both window timestamps, so
ongoing sessions re-emit with corrected span times.
- Span end times clamped like the usage builder (never 0, never
earlier than start + 1ms).
- CLI mirrors the usage path on attribution push failures instead of
claiming success.
- Identity normalization: case-insensitive .git strip, doubled path
slashes collapse.
AI-Origin: human
Review findings on the --attribution PR:
- Privacy: sessions whose project path no longer resolves inherited the
cwd-fallback repo identity, egressing whatever (possibly confidential)
repo the user pushes from and falsely attributing its commits.
buildRepoGroups now tracks per-session identity provenance; the
attribution path excludes fallback sessions from commit attribution
entirely (no repo, no commits, PR links only) — they also can no
longer steal a commit from a genuine session's window.
- Privacy: Windows drive-letter paths (C:/..., C:\..., drive-relative)
parsed as scp-like remotes, emitting local filesystem paths as repo
identities. normalizeRemoteUrl rejects drive letters and
single-character hosts (dotless intranet hosts still accepted).
- Hardening: PR links are shape-checked before sending (https,
/org/repo/pull/N path, <=256 chars, max 20 per session) — upstream
parsers only truthiness-check them.
- Safety valve: MAX_ATTRIBUTION_PER_PUSH (10k) caps a first
--since all --attribution push; dry-run reports the cap.
- Tests: adversarial normalize corpus, cwd-fallback egress repro,
commit-stealing prevention, PR-link sanitization, and CLI-level tests
(mock IdP + collector): dry-run sends nothing to the traces endpoint,
flag-off emits no attribution span names on the wire.
- Docs: reconciled the 'never sent' wording with reality (PR links ride
even when repo is null; device_id/methodology/timestamps disclosed).
CHANGELOG Unreleased entry added.
AI-Origin: human
Expose the yield session-to-commit correlation through codeburn sync so
backends can join AI usage to git activity without local git hooks.
- yield: export normalizeRemoteUrl (host/org/repo; credentials, ports,
and .git stripped) and computeAttributionRecords, which reuses the
exact repo-grouping + tightest-window attribution from computeYield
(extracted into a shared buildRepoGroups) and joins in the normalized
origin remote and session prLinks.
- otlp: two new span types sharing the session traceId —
codeburn.session.attribution (git.repo, git.pr_links, git.commit_count)
and codeburn.commit (git.sha, git.in_main, git.was_reverted). Resource
attribute codeburn.attribution_methodology=timestamp-window marks the
attribution as inferred.
- push: generic send core reused by usage and attribution batches. Dedup
keys encode mutable state (inMain/wasReverted), so a state transition
re-sends the updated fact while identical states dedupe via the
existing sent-ledger.
- cli: opt-in --attribution flag on sync push (dry-run aware); commits
in repos with no network remote are never sent.
AI-Origin: human