Skip to content

fix(ci): use commit-count versioning for dev builds and benchmarks#173

Closed
carlos-alm wants to merge 8 commits intomainfrom
fix/dogfood-missing-branch-compare
Closed

fix(ci): use commit-count versioning for dev builds and benchmarks#173
carlos-alm wants to merge 8 commits intomainfrom
fix/dogfood-missing-branch-compare

Conversation

@carlos-alm
Copy link
Contributor

Summary

  • Dev builds always produced 2.4.1-dev.<sha> because patch was hardcoded to PATCH + 1 from package.json. Now uses git rev-list to count commits since the release tag, giving monotonically increasing versions (2.4.1, 2.4.5, 2.4.15, etc.)
  • Benchmark scripts now use getBenchmarkVersion() (shared scripts/bench-version.js) which uses git describe to detect dev vs release state, preventing dev/dogfood benchmark runs from overwriting release data in historical reports
  • Added fetch-depth: 0 to the compute-version checkout so git history and tags are available

Changes

File Change
.github/workflows/publish.yml Replace PATCH+1 with git rev-list commit counting, add fetch-depth: 0
scripts/bench-version.js New shared helper — getBenchmarkVersion(pkgVersion, cwd)
scripts/benchmark.js Use benchVersion instead of pkg.version
scripts/incremental-benchmark.js Same
scripts/query-benchmark.js Same
scripts/embedding-benchmark.js Same
scripts/token-benchmark.js Same

Test plan

  • Verify node -e "import { getBenchmarkVersion } from './scripts/bench-version.js'; console.log(getBenchmarkVersion('2.4.0', '.'))" outputs 2.4.0-dev.N+hash (not 2.4.0)
  • Verify on a tagged commit it returns the clean version
  • Trigger a dev build via push to main and confirm version increments past .1

github-actions bot and others added 4 commits February 28, 2026 01:39
The branch-compare command was registered in cli.js and its exports
added to index.js, but the implementation file src/branch-compare.js
was never created. This caused two issues:

1. `codegraph branch-compare` crashed with ERR_MODULE_NOT_FOUND
2. `import('@optave/codegraph')` crashed entirely because index.js
   has a top-level re-export from the missing file, making the
   programmatic API completely unusable

Remove the dead references until an implementation exists.

Closes #166
The branch-compare command was registered in cli.js and index.js but
src/branch-compare.js was never committed — it was lost as untracked
files in the fix/complexity-sql-sanitize worktree. Recovered the full
implementation (568 lines) and integration test (192 lines, 7 tests)
from git object 22c8185.

This restores the cli.js command and index.js exports that were removed
in 746aa65, now that the implementation file exists. Updated the dogfood
report to reflect the recovery (no bugs found, rating 8.5/10).

Closes #166

Impact: 13 functions changed, 4 affected
Dev builds always produced 2.4.1-dev.<sha> because PATCH was hardcoded
to +1 from package.json. Now uses git rev-list to count commits since
the release tag, giving monotonically increasing versions like 2.4.5,
2.4.15, etc.

Benchmark scripts now use getBenchmarkVersion() (via git describe) to
detect dev vs release state, preventing dev runs from overwriting
release benchmark data in historical reports.

Impact: 2 functions changed, 6 affected
The bench-config.js local mode returned 'dev' as the version string.
Now uses getBenchmarkVersion() to derive a proper semver from git state,
so all 4 benchmark scripts that use bench-config get dev-aware versions.

Impact: 1 functions changed, 4 affected
@carlos-alm carlos-alm force-pushed the fix/dogfood-missing-branch-compare branch from 0d364d0 to 70b83b1 Compare February 28, 2026 08:42
@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Conducted comprehensive review of versioning and benchmarking changes:

  • Phase 1: Root Cause Analysis - Understand the problem being solved
  • Phase 2: Configuration Change Detection - Scrutinize CI workflow modifications
  • Phase 3: Test Integrity - Check for any test weakening or rule relaxation
  • Phase 4: Code Quality Review - Examine implementation details and potential issues
  • Final Assessment - Provide structured rating and recommendation

Root Cause Analysis

Problem Being Solved: Dev builds always produced 2.4.1-dev.<sha> because patch version was hardcoded to PATCH + 1 from package.json, creating non-monotonic versions. Benchmark scripts used pkg.version directly, causing dev runs to overwrite release data in historical reports.

Why This Approach: The solution correctly addresses both issues:

  1. Monotonic versioning: Uses git rev-list --count to count commits since last release tag, ensuring increasing version numbers
  2. Benchmark isolation: New getBenchmarkVersion() uses git describe to detect dev vs release state, preventing data pollution

Risk Assessment: LOW RISK - Well-scoped changes that improve CI reliability without breaking changes.

Critical Concerns

None detected. This is a solid engineering solution that:

Solves real problems: Fixes hardcoded versioning and benchmark data conflicts
Uses safe APIs: execFileSync with proper argument arrays (no shell injection risk)
Handles errors gracefully: Multiple try/catch blocks with fallbacks
Maintains consistency: All benchmark scripts updated through shared bench-config.js
No test modifications: No tests weakened or expectations lowered
Proper git safety: Added fetch-depth: 0 to ensure tag history is available

Technical Review

CI Workflow Changes (.github/workflows/publish.yml)

  • Lines 72-84: Replaced hardcoded PATCH + 1 with git rev-list --count logic ✅
  • Line 48: Added fetch-depth: 0 to ensure git history/tags are available ✅
  • Logic is sound: Falls back to COMMITS=1 if release tag doesn't exist ✅

New Benchmark Version Helper (scripts/bench-version.js)

  • Clean implementation: Uses git describe to differentiate release vs dev commits ✅
  • Security: Uses execFileSync with argument arrays (no shell injection) ✅
  • Error handling: Graceful fallbacks if git commands fail ✅
  • Output format: Clear version-dev.N+hash format that won't conflict with releases ✅

Shared Integration (scripts/lib/bench-config.js)

  • Smart design: All benchmark scripts now use shared getBenchmarkVersion()
  • Consistent behavior: Local mode uses git state, npm mode uses installed version ✅
  • All scripts updated: Verified benchmark.js, incremental-benchmark.js, query-benchmark.js, embedding-benchmark.js, token-benchmark.js all use this ✅

Code Quality

  • Well-documented: Clear comments explaining the versioning logic
  • Proper error handling: Multiple fallback layers
  • No magic numbers: Clear variable names and logic flow
  • Consistent patterns: Follows existing codebase conventions

Minor Observations

  1. PR description mismatch: Description mentions updating 5 benchmark scripts, but only 1 was changed directly (others inherit from bench-config.js) - this is actually better design
  2. Test plan: The test plan in the PR description is actionable and comprehensive
  3. Commit organization: Clean commit history with logical separation of concerns

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: This is a well-engineered solution that fixes real CI/benchmark issues without introducing risk. The shared configuration approach is cleaner than updating each script individually. The git-based versioning logic is sound and handles edge cases appropriately. No security concerns, no test integrity issues, and no configuration rules relaxed.

Excellent work on improving the CI reliability and preventing benchmark data pollution.


@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 28, 2026

Greptile Summary

This PR replaces hardcoded PATCH+1 dev versioning with commit-count based versioning, ensuring monotonically increasing versions and preventing benchmark data collisions between dev and release builds.

Key improvements:

  • Dev builds now produce 2.4.5-dev.abc1234 (where 5 = patch + commits since tag) instead of always 2.4.1-dev.abc1234
  • Workflow and benchmark scripts use identical two-step strategy: git describe to find nearest tag, then git rev-list to count commits
  • All benchmark scripts (benchmark.js, incremental-benchmark.js, query-benchmark.js, embedding-benchmark.js) inherit the fix through bench-config.js
  • Added fetch-depth: 0 so git tags are available in CI

Issue found:

  • No-tags fallback in bench-version.js produces 2.4.1-dev but workflow produces 2.4.1-dev.abc1234 (missing SHA suffix)

Confidence Score: 4/5

  • Safe to merge with one minor edge-case inconsistency
  • Core versioning logic is sound and properly addresses the main issue of monotonically increasing dev versions. The no-tags fallback inconsistency only affects repos with zero tags (rare edge case). All benchmark scripts correctly integrate the new version helper.
  • Pay attention to scripts/bench-version.js fallback logic alignment

Important Files Changed

Filename Overview
.github/workflows/publish.yml Added fetch-depth: 0 and implemented commit-count versioning using git describe + git rev-list, replacing hardcoded PATCH+1 logic
scripts/bench-version.js New shared helper implementing same two-step git strategy as workflow; fallback for no-tags case matches patch increment but missing SHA suffix
scripts/lib/bench-config.js Integrated getBenchmarkVersion() to derive version from git state instead of hardcoded "dev" label
scripts/token-benchmark.js Uses getBenchmarkVersion() to compute benchVersion and outputs it instead of pkg.version

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Start([Version Computation]) --> Event{Event Type}
    
    Event -->|release/workflow_dispatch| StableVer[Use tag or input version]
    Event -->|push to main| DevVer[Dev Build Path]
    
    DevVer --> FindTag{git describe finds tag?}
    FindTag -->|Yes| CountCommits[git rev-list tag..HEAD --count]
    FindTag -->|No| NoTagFallback[COMMITS=1, use pkg.json]
    
    CountCommits --> CalcPatch1[DEV_PATCH = TAG_PATCH + COMMITS]
    NoTagFallback --> CalcPatch2[DEV_PATCH = PKG_PATCH + 1]
    
    CalcPatch1 --> AddSHA[Append -dev.SHORT_SHA]
    CalcPatch2 --> AddSHA
    
    AddSHA --> DevResult[MAJOR.MINOR.DEV_PATCH-dev.SHA]
    StableVer --> StableResult[MAJOR.MINOR.PATCH]
    
    DevResult --> Output([Output Version])
    StableResult --> Output
    
    style FindTag fill:#e1f5ff
    style DevResult fill:#fff4e1
    style StableResult fill:#e8f5e9
Loading

Last reviewed commit: 6618822

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

16 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 28, 2026

Additional Comments (1)

scripts/bench-version.js
Workflow uses v${CURRENT} (from package.json) to construct the tag name, while bench-version.js uses git describe (finds most recent tag). If package.json version is bumped but not yet tagged, they'll produce different commit counts.

Example: If package.json shows "2.5.0" but latest tag is "v2.4.0", workflow looks for "v2.5.0" tag (doesn't exist → fallback COMMITS=1), while getBenchmarkVersion would count from "v2.4.0".

Both now use git describe --tags --match "v*" to find the nearest
release tag and count commits from it. Previously publish.yml
constructed the tag from package.json (v${CURRENT}) while
bench-version.js used git describe, which would diverge if
package.json was bumped but not yet tagged.

Impact: 1 functions changed, 0 affected
@carlos-alm
Copy link
Contributor Author

@greptileai

@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @carlos-alm's task —— View job


Re-reviewing PR #173

Following the 4-phase review structure to address Greptile's concerns about version computation inconsistencies:

Todo List

  • Phase 1: Root Cause Analysis - Understand the problem being solved
  • Phase 2: Configuration Change Detection - Scrutinize CI workflow modifications
  • Phase 3: Test Integrity - Check for any test weakening or rule relaxation
  • Phase 4: Code Quality Review - Examine implementation details and potential issues
  • Final Assessment - Provide structured rating and recommendation

Root Cause Analysis

Problem Being Solved: Dev builds always produced 2.4.1-dev.<sha> because patch version was hardcoded to PATCH + 1 from package.json, creating non-monotonic versions. Benchmark scripts used pkg.version directly, causing dev runs to overwrite release data in historical reports.

Why This Approach: The solution correctly addresses both issues:

  1. Monotonic versioning: Uses git rev-list --count to count commits since last release tag, ensuring increasing version numbers
  2. Benchmark isolation: New getBenchmarkVersion() uses git describe to detect dev vs release state, preventing data pollution

Risk Assessment: LOW RISK - Well-scoped changes that improve CI reliability without breaking changes.

Configuration Change Detection

No concerning configuration changes detected:

  • No linting rules disabled or relaxed (biome.json unchanged)
  • No test timeouts increased or coverage thresholds lowered
  • No build configuration modified
  • CI workflow changes are legitimate improvements, not workarounds

Test Integrity Check

No test weakening detected:

  • No test files modified in this PR
  • No assertions removed or made less strict
  • No tests skipped or marked conditional

Code Quality Review

⚠️ Critical Issue: Version Computation Inconsistency

Greptile's concern about inconsistent versioning logic is valid and serious:

Workflow Logic (.github/workflows/publish.yml:72-74):

RELEASE_TAG=$(git describe --tags --match "v*" --abbrev=0 2>/dev/null || echo "")
if [ -n "$RELEASE_TAG" ]; then
  COMMITS=$(git rev-list "${RELEASE_TAG}..HEAD" --count)

bench-version.js Logic (lines 20, 32):

const desc = execFileSync('git', ['describe', '--tags', '--match', 'v*', '--always'], ...)
const dev = desc.match(/^v(\d+)\.(\d+)\.(\d+)-(\d+)-g([0-9a-f]+)$/);

The Problem: These use different git describe approaches:

  • Workflow: --abbrev=0 gets the exact tag, then separately counts commits with git rev-list
  • bench-version.js: No --abbrev=0, parses the full describe output like v2.5.0-3-gc50f7f5

When This Breaks: If there are multiple tags or if the git history is complex, these could produce different commit counts, leading to version mismatches between CI builds and benchmark runs.

Other Code Quality Issues

Security: Uses execFileSync with proper argument arrays (no shell injection risk)
Error Handling: Good try/catch blocks with fallbacks
Documentation: Clear comments explaining logic
⚠️ Consistency: The version computation inconsistency is the primary concern

Final Recommendation

  • Rating: ⭐⭐☆☆☆ (2/5)
  • Action: REQUEST CHANGES
  • Reasoning: While this PR solves a real problem and is well-implemented overall, the version computation inconsistency identified by Greptile could cause subtle bugs where CI builds and benchmark runs produce different version numbers. Both the workflow and bench-version.js should use the same git strategy to ensure version consistency across all contexts. The workflow approach (using --abbrev=0 + git rev-list) is more explicit and robust, and should be mirrored in the JavaScript implementation.

Required Fix: Update bench-version.js to use the same two-step approach as the workflow: first find the exact release tag with git describe --tags --match "v*" --abbrev=0, then count commits with git rev-list.


Comment on lines +42 to +43
// Fallback: no git or no tags — use package.json version with dev suffix
return `${pkgVersion}-dev`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fallback diverges from publish.yml when no tags exist. The workflow produces ${MAJOR}.${MINOR}.${PATCH+1}-dev.${SHA} but this returns ${pkgVersion}-dev (no SHA, different patch). Consider aligning both to handle the no-tags edge case consistently.

Suggested change
// Fallback: no git or no tags — use package.json version with dev suffix
return `${pkgVersion}-dev`;
// Fallback: no git or no tags — match publish.yml's no-tags behavior
const parts = pkgVersion.split('.');
if (parts.length === 3) {
const [major, minor, patch] = parts;
const devPatch = Number(patch) + 1;
return `${major}.${minor}.${devPatch}-dev`;
}
return `${pkgVersion}-dev`;

When no git tags exist, bench-version.js now produces PATCH+1 (e.g.
"2.5.1-dev") matching publish.yml's fallback, instead of the bare
"2.5.0-dev" which diverged.

Impact: 1 functions changed, 0 affected
@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @carlos-alm's task —— View job


Reviewing PR #173

Following the 4-phase review structure to analyze this CI versioning fix:

Todo List

  • Phase 1: Root Cause Analysis - Understand the problem being solved
  • Phase 2: Configuration Change Detection - Scrutinize CI workflow modifications
  • Phase 3: Test Integrity - Check for any test weakening or rule relaxation
  • Phase 4: Code Quality Review - Examine implementation details and potential issues
  • Final Assessment - Provide structured rating and recommendation

Root Cause Analysis

Problem Being Solved: Dev builds always produced 2.4.1-dev.<sha> because patch version was hardcoded to PATCH + 1 from package.json, creating non-monotonic versions. Benchmark scripts used pkg.version directly, causing dev runs to overwrite release data in historical reports.

Why This Approach: The solution correctly addresses both issues:

  1. Monotonic versioning: Uses git rev-list --count to count commits since last release tag, ensuring increasing version numbers
  2. Benchmark isolation: New getBenchmarkVersion() uses git describe to detect dev vs release state, preventing data pollution

Risk Assessment: LOW RISK - Well-scoped changes that improve CI reliability without breaking changes.

Critical Concerns

⚠️ Version Computation Inconsistency

Greptile correctly identified a serious version computation inconsistency between the workflow and bench-version.js:

Workflow Logic (.github/workflows/publish.yml:72-74):

RELEASE_TAG=$(git describe --tags --match "v*" --abbrev=0 2>/dev/null || echo "")
if [ -n "$RELEASE_TAG" ]; then
  COMMITS=$(git rev-list "${RELEASE_TAG}..HEAD" --count)

bench-version.js Logic (lines 20, 32):

const desc = execFileSync('git', ['describe', '--tags', '--match', 'v*', '--always'], ...)
const dev = desc.match(/^v(\d+)\.(\d+)\.(\d+)-(\d+)-g([0-9a-f]+)$/);

The Problem: These use different git describe approaches:

  • Workflow: --abbrev=0 gets the exact tag, then separately counts commits with git rev-list
  • bench-version.js: No --abbrev=0, parses the full describe output like v2.5.0-3-gc50f7f5

When This Breaks: If there are multiple tags or if the git history is complex, these could produce different commit counts, leading to version mismatches between CI builds and benchmark runs.

Final Recommendation

  • Rating: ⭐⭐☆☆☆ (2/5)
  • Action: REQUEST CHANGES
  • Reasoning: While this PR solves a real problem and is well-implemented overall, the version computation inconsistency identified by Greptile could cause subtle bugs where CI builds and benchmark runs produce different version numbers. Both the workflow and bench-version.js should use the same git strategy to ensure version consistency across all contexts. The workflow approach (using --abbrev=0 + git rev-list) is more explicit and robust, and should be mirrored in the JavaScript implementation.

Required Fix: Update bench-version.js to use the same two-step approach as the workflow: first find the exact release tag with git describe --tags --match "v*" --abbrev=0, then count commits with git rev-list.


Refactor getBenchmarkVersion to use --abbrev=0 + git rev-list (same
as publish.yml) instead of parsing full git describe output. Both
now use identical steps: find tag, count commits, get short SHA.

Impact: 1 functions changed, 0 affected
@carlos-alm
Copy link
Contributor Author

@greptileai

@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @carlos-alm's task —— View job


Claude is reviewing PR #173

Todo List

  • Phase 1: Root Cause Analysis - Understand the problem being solved
  • Phase 2: Configuration Change Detection - Scrutinize CI workflow modifications
  • Phase 3: Test Integrity - Check for any test weakening or rule relaxation
  • Phase 4: Code Quality Review - Examine implementation details and potential issues
  • Final Assessment - Provide structured rating and recommendation

Phase 1: Root Cause Analysis

Problem Being Solved: Dev builds always produced 2.4.1-dev.<sha> because patch version was hardcoded to PATCH + 1 from package.json, creating non-monotonic versions. Benchmark scripts used pkg.version directly, causing dev runs to overwrite release data in historical reports.

Why This Approach: The solution correctly addresses both issues:

  1. Monotonic versioning: Uses git rev-list --count to count commits since last release tag, ensuring increasing version numbers
  2. Benchmark isolation: New getBenchmarkVersion() uses git describe to detect dev vs release state, preventing data pollution

Risk Assessment: LOW RISK - Well-scoped changes that improve CI reliability without breaking changes.

Phase 2: Configuration Change Detection

No concerning configuration changes detected:

  • No linting rules disabled or relaxed (biome.json unchanged)
  • No test timeouts increased or coverage thresholds lowered
  • No build configuration modified
  • CI workflow changes are legitimate improvements, not workarounds

Phase 3: Test Integrity Check

No test weakening detected:

  • No test files modified in this PR
  • No assertions removed or made less strict
  • No tests skipped or marked conditional

Phase 4: Code Quality Review

Version Computation Logic - FIXED

The version computation inconsistency that Greptile flagged has been resolved in the latest commits:

Workflow Logic (.github/workflows/publish.yml:72-74):

RELEASE_TAG=$(git describe --tags --match "v*" --abbrev=0 2>/dev/null || echo "")
if [ -n "$RELEASE_TAG" ]; then
  COMMITS=$(git rev-list "${RELEASE_TAG}..HEAD" --count)

bench-version.js Logic (lines 23, 30):

const tag = execFileSync('git', ['describe', '--tags', '--match', 'v*', '--abbrev=0'], ...)
const commits = Number(
  execFileSync('git', ['rev-list', `${tag}..HEAD`, '--count'], { cwd, ...GIT_OPTS }).trim(),
);

✅ Both now use identical two-step approach: First find the exact release tag with --abbrev=0, then count commits with git rev-list. This ensures version consistency between CI builds and benchmark runs.

Other Code Quality Checks

Security: Uses execFileSync with proper argument arrays (no shell injection risk)
Error Handling: Good try/catch blocks with fallbacks
Documentation: Clear comments explaining logic
Consistency: Both implementations now follow the same git strategy

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: This is a well-engineered solution that fixes real CI/benchmark issues without introducing risk. The version computation inconsistency that Greptile initially flagged has been properly resolved - both the workflow and bench-version.js now use the same two-step git approach ensuring version consistency. The shared configuration approach in bench-config.js is cleaner than updating each script individually. No security concerns, no test integrity issues, and no configuration rules relaxed.

Excellent work on improving CI reliability and preventing benchmark data pollution.


View job

Comment on lines +49 to +55
// Fallback: no git or no tags — match publish.yml's no-tags behavior (PATCH+1)
const parts = pkgVersion.split('.');
if (parts.length === 3) {
const [major, minor, patch] = parts;
return `${major}.${minor}.${Number(patch) + 1}-dev`;
}
return `${pkgVersion}-dev`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No-tags fallback missing SHA suffix. When no tags exist, publish.yml produces 2.4.1-dev.abc1234 but this returns 2.4.1-dev.

Suggested change
// Fallback: no git or no tags — match publish.yml's no-tags behavior (PATCH+1)
const parts = pkgVersion.split('.');
if (parts.length === 3) {
const [major, minor, patch] = parts;
return `${major}.${minor}.${Number(patch) + 1}-dev`;
}
return `${pkgVersion}-dev`;
// Fallback: no git or no tags — match publish.yml's no-tags behavior (PATCH+1-dev.SHA)
const parts = pkgVersion.split('.');
if (parts.length === 3) {
const [major, minor, patch] = parts;
try {
const hash = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd, ...GIT_OPTS }).trim();
return `${major}.${minor}.${Number(patch) + 1}-dev.${hash}`;
} catch {
return `${major}.${minor}.${Number(patch) + 1}-dev`;
}
}
return `${pkgVersion}-dev`;

@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @carlos-alm's task —— View job


Claude finished reviewing PR #173

Todo List

  • Phase 1: Root Cause Analysis - Understand the problem being solved
  • Phase 2: Configuration Change Detection - Scrutinize CI workflow modifications
  • Phase 3: Test Integrity - Check for any test weakening or rule relaxation
  • Phase 4: Code Quality Review - Examine implementation details and potential issues
  • Final Assessment - Provide structured rating and recommendation

Phase 1: Root Cause Analysis

Problem Being Solved: Dev builds always produced 2.4.1-dev.<sha> because patch version was hardcoded to PATCH + 1 from package.json, creating non-monotonic versions. Benchmark scripts used pkg.version directly, causing dev runs to overwrite release data in historical reports.

Why This Approach: The solution correctly addresses both issues:

  1. Monotonic versioning: Uses git rev-list --count to count commits since last release tag, ensuring increasing version numbers
  2. Benchmark isolation: New getBenchmarkVersion() uses git describe to detect dev vs release state, preventing data pollution

Risk Assessment: LOW RISK - Well-scoped changes that improve CI reliability without breaking changes.

Phase 2: Configuration Change Detection

No concerning configuration changes detected:

  • No linting rules disabled or relaxed (biome.json unchanged)
  • No test timeouts increased or coverage thresholds lowered
  • No build configuration modified
  • CI workflow changes are legitimate improvements, not workarounds

Phase 3: Test Integrity Check

No test weakening detected:

  • No test files modified in this PR
  • No assertions removed or made less strict
  • No tests skipped or marked conditional

Phase 4: Code Quality Review

Version Computation Logic - FIXED

The version computation inconsistency that Greptile flagged has been resolved in the latest commits:

Workflow Logic (.github/workflows/publish.yml:72-74):

RELEASE_TAG=$(git describe --tags --match "v*" --abbrev=0 2>/dev/null || echo "")
if [ -n "$RELEASE_TAG" ]; then
  COMMITS=$(git rev-list "${RELEASE_TAG}..HEAD" --count)

bench-version.js Logic (lines 23, 30):

const tag = execFileSync('git', ['describe', '--tags', '--match', 'v*', '--abbrev=0'], ...)
const commits = Number(
  execFileSync('git', ['rev-list', `${tag}..HEAD`, '--count'], { cwd, ...GIT_OPTS }).trim(),
);

✅ Both now use identical two-step approach: First find the exact release tag with --abbrev=0, then count commits with git rev-list. This ensures version consistency between CI builds and benchmark runs.

Other Code Quality Checks

Security: Uses execFileSync with proper argument arrays (no shell injection risk)
Error Handling: Good try/catch blocks with fallbacks
Documentation: Clear comments explaining logic
Consistency: Both implementations now follow the same git strategy

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: This is a well-engineered solution that fixes real CI/benchmark issues without introducing risk. The version computation inconsistency that Greptile initially flagged has been properly resolved - both the workflow and bench-version.js now use the same two-step git approach ensuring version consistency. The shared configuration approach in bench-config.js is cleaner than updating each script individually. No security concerns, no test integrity issues, and no configuration rules relaxed.

Excellent work on improving CI reliability and preventing benchmark data pollution.


View job

carlos-alm added a commit that referenced this pull request Mar 1, 2026
Merges PR #173 (commit-count versioning for dev builds) and fixes a bug
where embedding, query, and incremental benchmark reports were never
persisted. The "Check for changes" step used `git diff` which only
detects modifications to tracked files — newly created report files
(untracked) were invisible, so the PR was never created. Now also checks
for untracked files via `git ls-files --others`.
carlos-alm added a commit that referenced this pull request Mar 1, 2026
…196)

* fix(cli): remove branch-compare references to non-existent module

The branch-compare command was registered in cli.js and its exports
added to index.js, but the implementation file src/branch-compare.js
was never created. This caused two issues:

1. `codegraph branch-compare` crashed with ERR_MODULE_NOT_FOUND
2. `import('@optave/codegraph')` crashed entirely because index.js
   has a top-level re-export from the missing file, making the
   programmatic API completely unusable

Remove the dead references until an implementation exists.

Closes #166

* fix: recover branch-compare implementation from lost worktree files

The branch-compare command was registered in cli.js and index.js but
src/branch-compare.js was never committed — it was lost as untracked
files in the fix/complexity-sql-sanitize worktree. Recovered the full
implementation (568 lines) and integration test (192 lines, 7 tests)
from git object 22c8185.

This restores the cli.js command and index.js exports that were removed
in 746aa65, now that the implementation file exists. Updated the dogfood
report to reflect the recovery (no bugs found, rating 8.5/10).

Closes #166

Impact: 13 functions changed, 4 affected

* fix(ci): use commit-count versioning for dev builds and benchmarks

Dev builds always produced 2.4.1-dev.<sha> because PATCH was hardcoded
to +1 from package.json. Now uses git rev-list to count commits since
the release tag, giving monotonically increasing versions like 2.4.5,
2.4.15, etc.

Benchmark scripts now use getBenchmarkVersion() (via git describe) to
detect dev vs release state, preventing dev runs from overwriting
release benchmark data in historical reports.

Impact: 2 functions changed, 6 affected

* fix(bench): integrate getBenchmarkVersion into shared bench-config

The bench-config.js local mode returned 'dev' as the version string.
Now uses getBenchmarkVersion() to derive a proper semver from git state,
so all 4 benchmark scripts that use bench-config get dev-aware versions.

Impact: 1 functions changed, 4 affected

* fix(ci): align version strategy between publish.yml and bench-version.js

Both now use git describe --tags --match "v*" to find the nearest
release tag and count commits from it. Previously publish.yml
constructed the tag from package.json (v${CURRENT}) while
bench-version.js used git describe, which would diverge if
package.json was bumped but not yet tagged.

Impact: 1 functions changed, 0 affected

* fix(bench): align no-tags fallback with publish.yml behavior

When no git tags exist, bench-version.js now produces PATCH+1 (e.g.
"2.5.1-dev") matching publish.yml's fallback, instead of the bare
"2.5.0-dev" which diverged.

Impact: 1 functions changed, 0 affected

* fix(bench): use same two-step git strategy as publish.yml

Refactor getBenchmarkVersion to use --abbrev=0 + git rev-list (same
as publish.yml) instead of parsing full git describe output. Both
now use identical steps: find tag, count commits, get short SHA.

Impact: 1 functions changed, 0 affected

* fix(bench): include SHA in no-tags fallback to match publish.yml

Impact: 1 functions changed, 0 affected

* fix(ci): save all benchmark reports and use git-based dev versioning

Merges PR #173 (commit-count versioning for dev builds) and fixes a bug
where embedding, query, and incremental benchmark reports were never
persisted. The "Check for changes" step used `git diff` which only
detects modifications to tracked files — newly created report files
(untracked) were invisible, so the PR was never created. Now also checks
for untracked files via `git ls-files --others`.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@carlos-alm
Copy link
Contributor Author

Closing — all changes were already squash-merged into main via #196. Greptile's review comments (no-tags fallback divergence, missing SHA suffix, version strategy inconsistency) were all addressed in the later commits on this branch before the squash merge.

@carlos-alm carlos-alm closed this Mar 2, 2026
carlos-alm added a commit that referenced this pull request Mar 2, 2026
* fix(cli): remove branch-compare references to non-existent module

The branch-compare command was registered in cli.js and its exports
added to index.js, but the implementation file src/branch-compare.js
was never created. This caused two issues:

1. `codegraph branch-compare` crashed with ERR_MODULE_NOT_FOUND
2. `import('@optave/codegraph')` crashed entirely because index.js
   has a top-level re-export from the missing file, making the
   programmatic API completely unusable

Remove the dead references until an implementation exists.

Closes #166

* fix: recover branch-compare implementation from lost worktree files

The branch-compare command was registered in cli.js and index.js but
src/branch-compare.js was never committed — it was lost as untracked
files in the fix/complexity-sql-sanitize worktree. Recovered the full
implementation (568 lines) and integration test (192 lines, 7 tests)
from git object 22c8185.

This restores the cli.js command and index.js exports that were removed
in 746aa65, now that the implementation file exists. Updated the dogfood
report to reflect the recovery (no bugs found, rating 8.5/10).

Closes #166

Impact: 13 functions changed, 4 affected

* fix(ci): use commit-count versioning for dev builds and benchmarks

Dev builds always produced 2.4.1-dev.<sha> because PATCH was hardcoded
to +1 from package.json. Now uses git rev-list to count commits since
the release tag, giving monotonically increasing versions like 2.4.5,
2.4.15, etc.

Benchmark scripts now use getBenchmarkVersion() (via git describe) to
detect dev vs release state, preventing dev runs from overwriting
release benchmark data in historical reports.

Impact: 2 functions changed, 6 affected

* fix(bench): integrate getBenchmarkVersion into shared bench-config

The bench-config.js local mode returned 'dev' as the version string.
Now uses getBenchmarkVersion() to derive a proper semver from git state,
so all 4 benchmark scripts that use bench-config get dev-aware versions.

Impact: 1 functions changed, 4 affected

* fix(ci): align version strategy between publish.yml and bench-version.js

Both now use git describe --tags --match "v*" to find the nearest
release tag and count commits from it. Previously publish.yml
constructed the tag from package.json (v${CURRENT}) while
bench-version.js used git describe, which would diverge if
package.json was bumped but not yet tagged.

Impact: 1 functions changed, 0 affected

* fix(bench): align no-tags fallback with publish.yml behavior

When no git tags exist, bench-version.js now produces PATCH+1 (e.g.
"2.5.1-dev") matching publish.yml's fallback, instead of the bare
"2.5.0-dev" which diverged.

Impact: 1 functions changed, 0 affected

* fix(bench): use same two-step git strategy as publish.yml

Refactor getBenchmarkVersion to use --abbrev=0 + git rev-list (same
as publish.yml) instead of parsing full git describe output. Both
now use identical steps: find tag, count commits, get short SHA.

Impact: 1 functions changed, 0 affected

* fix(bench): include SHA in no-tags fallback to match publish.yml

Impact: 1 functions changed, 0 affected

* fix(ci): save all benchmark reports and use git-based dev versioning

Merges PR #173 (commit-count versioning for dev builds) and fixes a bug
where embedding, query, and incremental benchmark reports were never
persisted. The "Check for changes" step used `git diff` which only
detects modifications to tracked files — newly created report files
(untracked) were invisible, so the PR was never created. Now also checks
for untracked files via `git ls-files --others`.

* fix(bench): add timeout and remove redundant stdio option

Add 10s timeout to GIT_OPTS to prevent execFileSync from hanging
on git operations. Remove redundant stdio config (already the default).

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
carlos-alm added a commit that referenced this pull request Mar 2, 2026
`--no-incremental` full rebuilds didn't clear the `function_complexity`
table, causing orphaned rows to accumulate across rebuilds as node IDs
get reassigned. Add `DELETE FROM function_complexity` to the full-rebuild
purge sequence alongside the existing node_metrics/edges/nodes deletions.

Fixes #173

Impact: 1 functions changed, 11 affected
carlos-alm added a commit that referenced this pull request Mar 2, 2026
`--no-incremental` full rebuilds didn't clear the `function_complexity`
table, causing orphaned rows to accumulate across rebuilds as node IDs
get reassigned. Add `DELETE FROM function_complexity` to the full-rebuild
purge sequence alongside the existing node_metrics/edges/nodes deletions.

Fixes #173

Impact: 1 functions changed, 11 affected
@carlos-alm carlos-alm deleted the fix/dogfood-missing-branch-compare branch March 3, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant