Summary
git::build_trend computes a single shared first-parent timeline "so each point is an O(commits) lookup rather than its own walk", but since the #648 --as-of re-anchoring landed in build, every per-point build call now performs its own full first-parent walk — defeating the optimization the comment describes and making that comment stale.
Location
src/vcs/git/trend.rs:57-67 (the shared-timeline comment and drop(repo) / per-point build loop)
- Interacts with
src/vcs/git/mod.rs:101-119 (resolve_anchor → first_parent_timeline whenever options.as_of.is_some())
Evidence
build_trend builds the timeline once and explains the intent:
// One first-parent walk of the base reference yields every mainline
// tip and its time, so each point is an O(commits) lookup rather than
// its own walk.
let OpenRepo { repo, .. } = repo::open(root)?;
let tip = repo::resolve_commit(&repo, &base.reference)?.id;
let timeline = first_parent_timeline(&repo, tip)?;
drop(repo);
...
for &at in &stamps {
let Some(oid) = tip_at_or_before(&timeline, at) else { ... };
let index = build(root, &snapshot_options(base, oid, at))?; // re-walks!
...
}
snapshot_options always sets as_of = Some(at) (src/vcs/git/trend.rs:95-101). In build, any as_of triggers resolve_anchor, which unconditionally re-walks the first-parent timeline (src/vcs/git/mod.rs:106-110):
let Some(as_of) = options.as_of else { return Ok(Some(tip)); };
let timeline = trend::first_parent_timeline(repo, tip.id)?; // P extra walks
let Some(anchor) = trend::tip_at_or_before(&timeline, as_of) else { ... };
Git history confirms the comment is stale: at the trend feature's introduction (9624098b) build had no resolve_anchor/first_parent_timeline and did not re-walk, so "an O(commits) lookup rather than its own walk" was accurate. The #648 fix (cb12db79) added the per-as_of re-anchoring walk afterwards, defeating the shared-timeline optimization without updating the trend comment.
Net effect for P points: 1 + P first-parent walks instead of the documented 1. (The first-parent walk is cheap relative to each point's window walk in collect_events, so this is wasted work rather than a correctness defect.)
Expected Behavior
Either:
- Pass the already-resolved historical anchor
oid through to build so it skips the redundant first_parent_timeline re-walk (the comment then becomes true again), or
- Correct the comment to state that each point still performs its own first-parent walk inside
build.
Actual Behavior
build_trend resolves the timeline once and every per-point build resolves it again, while the comment claims the per-point work is only an O(commits) lookup.
Impact
VCS-git trend consumers (bca vcs --trend, web /vcs/trend, Python vcs.trend). The shared timeline gives no run-time benefit it claims to; a reader trusting the comment would mis-model the cost, and the redundant walks scale linearly with the requested point count (up to MAX_TREND_POINTS = 120).
Resolution
Corrected the stale trend.rs comment: the shared timeline only resolves each point's tip oid; each per-point build re-walks the first-parent timeline (O(points x commits) since #648). Commit a7e35ad.
Summary
git::build_trendcomputes a single shared first-parent timeline "so each point is an O(commits) lookup rather than its own walk", but since the #648--as-ofre-anchoring landed inbuild, every per-pointbuildcall now performs its own full first-parent walk — defeating the optimization the comment describes and making that comment stale.Location
src/vcs/git/trend.rs:57-67(the shared-timeline comment anddrop(repo)/ per-pointbuildloop)src/vcs/git/mod.rs:101-119(resolve_anchor→first_parent_timelinewheneveroptions.as_of.is_some())Evidence
build_trendbuilds the timeline once and explains the intent:snapshot_optionsalways setsas_of = Some(at)(src/vcs/git/trend.rs:95-101). Inbuild, anyas_oftriggersresolve_anchor, which unconditionally re-walks the first-parent timeline (src/vcs/git/mod.rs:106-110):Git history confirms the comment is stale: at the trend feature's introduction (
9624098b)buildhad noresolve_anchor/first_parent_timelineand did not re-walk, so "an O(commits) lookup rather than its own walk" was accurate. The #648 fix (cb12db79) added the per-as_ofre-anchoring walk afterwards, defeating the shared-timeline optimization without updating the trend comment.Net effect for P points:
1 + Pfirst-parent walks instead of the documented1. (The first-parent walk is cheap relative to each point's window walk incollect_events, so this is wasted work rather than a correctness defect.)Expected Behavior
Either:
oidthrough tobuildso it skips the redundantfirst_parent_timelinere-walk (the comment then becomes true again), orbuild.Actual Behavior
build_trendresolves the timeline once and every per-pointbuildresolves it again, while the comment claims the per-point work is only an O(commits) lookup.Impact
VCS-git trend consumers (
bca vcs --trend, web/vcs/trend, Pythonvcs.trend). The shared timeline gives no run-time benefit it claims to; a reader trusting the comment would mis-model the cost, and the redundant walks scale linearly with the requested point count (up toMAX_TREND_POINTS = 120).Resolution
Corrected the stale trend.rs comment: the shared timeline only resolves each point's tip oid; each per-point build re-walks the first-parent timeline (O(points x commits) since #648). Commit a7e35ad.