Skip to content

build: restore libc discriminator on linux lockfile entries#1163

Merged
carlos-alm merged 3 commits into
mainfrom
build/1160-libc-lockfile
May 19, 2026
Merged

build: restore libc discriminator on linux lockfile entries#1163
carlos-alm merged 3 commits into
mainfrom
build/1160-libc-lockfile

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

  • Restore the libc field on @optave/codegraph-linux-{arm64-gnu,x64-gnu,x64-musl} entries in package-lock.json. npm 11 silently strips this field on npm install, even though the published packages declare it (npm view @optave/codegraph-linux-x64-musl libc'musl').
  • Add scripts/verify-lockfile-libc.mjs and wire it into the lint CI job before the npm install step, so any PR (including Dependabot bumps) that lands a lockfile missing the discriminator now fails fast.

Without the discriminator, npm cannot disambiguate linux-x64-gnu vs linux-x64-musl when resolving from the lockfile, so the wrong native binary may load on Alpine/musl hosts.

Investigation: the strip behavior is reproducible with npm 11.6.0 even after npm cache clean --force, and affects other napi-rs projects (e.g. @biomejs/cli-linux-* entries in this same lockfile). There is no root-package.json field that constrains libc on optional deps, so the only robust fix is to commit the field directly and guard regressions in CI.

Closes #1160

Test plan

  • node scripts/verify-lockfile-libc.mjs passes on the new lockfile
  • Manually stripped libc and re-ran the verifier — exits 1 with a clear message naming each missing entry
  • Confirmed npm 11.6.0 strips libc on npm install --package-lock-only --ignore-scripts (which is why the CI step runs before install)
  • CI lint job passes on the PR

npm 11 silently strips the `libc` field from @optave/codegraph-linux-*
entries in package-lock.json on `npm install`, even though the published
packages declare it correctly. Without the discriminator, npm cannot tell
linux-x64-gnu apart from linux-x64-musl when resolving the lockfile, so
the wrong native binary may load on Alpine/musl hosts.

Restore the field and add a CI guard (run before `npm install` in the
lint job) that fails any PR which lands a lockfile missing the
discriminator — Dependabot bumps and contributor installs would
otherwise silently regress this again.

Closes #1160
@claude
Copy link
Copy Markdown

claude Bot commented May 19, 2026

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


PR Review Complete ✅

Reviewing PR #1163: build: restore libc discriminator on linux lockfile entries

Root Cause Analysis

Problem Being Solved: npm 11+ silently strips libc discriminator fields from Linux optional dependencies in package-lock.json, causing npm to potentially install wrong native binaries (glibc vs musl) on Alpine/musl hosts. This is a real platform compatibility issue that can cause runtime failures.

Why This Approach: Direct field restoration + CI verification guard is justified because:

  1. No root package.json field can constrain libc on optional deps
  2. The issue affects multiple napi-rs projects (not just codegraph)
  3. CI verification before npm install catches regressions from Dependabot/contributor changes
  4. Matches documented behavior in .claude/skills/release/SKILL.md indicating this is a known issue

Risk Assessment: Low risk - addresses real compatibility issue with appropriate safeguards

Phase 2: Configuration Change Detection ✅

No HIGH-RISK changes detected:

  • CI workflow addition is defensive (catches regressions)
  • No linting rules relaxed or build config modified
  • Script is verification-only, no behavioral changes

Phase 3: Test Integrity ✅

No test integrity concerns:

  • Verification script has clear exit behavior (exit 1 on failure)
  • Manual testing documented in PR description
  • No existing tests weakened or removed

Phase 4: Code Quality ✅

scripts/verify-lockfile-libc.mjs:47 security review:

  • ✅ Uses readFileSync with hardcoded path - safe
  • ✅ No command injection vectors
  • ✅ Clear error messages with actionable guidance
  • ✅ Proper exit codes (0 success, 1 failure)
  • ✅ No external dependencies beyond Node.js built-ins

CI integration:

  • ✅ Positioned correctly BEFORE npm install step
  • ✅ Appropriate timeout and error handling
  • ✅ Clear rationale in comments

package-lock.json changes:

  • ✅ Verified all 3 Linux packages have correct libc fields restored:
    • @optave/codegraph-linux-arm64-gnu: ["glibc"]
    • @optave/codegraph-linux-x64-gnu: ["glibc"]
    • @optave/codegraph-linux-x64-musl: ["musl"]

Phase 5: Backlog Compliance

  • Zero-dep: ✅ - No new runtime dependencies
  • Foundation-aligned: ✅ - Fully aligned with zero-infrastructure principle
  • Problem-fit: 2/5 - Platform compatibility fix, doesn't directly help AI agents navigate codebases but ensures tool works correctly across Linux distributions
  • Breaking: No - Purely defensive, no API/behavior changes
  • Tier: 1 (zero-dep ✓ + foundation-aligned ✓)

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Well-executed fix for a real platform compatibility issue. Clean implementation with appropriate verification and no risk to existing functionality. The CI guard ensures the fix stays effective over time. Problem-fit is moderate since this is infrastructure maintenance rather than core functionality, but the fix is necessary and well-implemented.

Strengths:

  • Addresses documented platform compatibility issue
  • Robust verification approach with CI integration
  • Clean, secure implementation with no external dependencies
  • Clear error messages and documentation

No blocking concerns identified.


@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 19, 2026

Greptile Summary

This PR restores the libc discriminator field on the three @optave/codegraph-linux-* entries in package-lock.json (stripped silently by npm 11) and adds a lightweight CI guard to prevent the regression from recurring.

  • package-lock.json: libc: ["glibc"] restored on arm64-gnu and x64-gnu; libc: ["musl"] restored on x64-musl — values match the published package metadata and the verifier's EXPECTED_LIBC map.
  • scripts/verify-lockfile-libc.mjs: New script that reads the lockfile via an __dirname-anchored path and asserts each expected entry carries the correct libc array, exiting 1 with an actionable error if not.
  • .github/workflows/ci.yml: Verifier is wired into the lint job before npm install, ensuring it validates the committed lockfile state and not the post-install copy that npm 11 would have already stripped.

Confidence Score: 5/5

Safe to merge — restores three lockfile fields and adds a focused CI guard with no changes to runtime application code.

The lockfile edits are mechanical field restorations. The verifier script is self-contained, reads a fixed path, and has a clear pass/fail contract. The CI placement (before npm install) is the correct ordering to catch the regression on the committed file. No application logic is touched.

No files require special attention.

Important Files Changed

Filename Overview
scripts/verify-lockfile-libc.mjs New verifier script that reads package-lock.json via an __dirname-anchored path and checks that the three expected @optave/codegraph-linux-* entries carry the correct libc array. Logic and error messages are correct; one minor comment inaccuracy (claims npm run lint runs it, but it does not).
.github/workflows/ci.yml Adds a Verify lockfile libc discriminators step to the lint job, placed deliberately before npm install so it validates the committed lockfile state rather than the post-install (potentially stripped) state. Placement and rationale are correct.
package-lock.json Restores the libc field to the three @optave/codegraph-linux-{arm64-gnu,x64-gnu,x64-musl} entries; values (glibc, glibc, musl) match what the verifier script expects.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Checkout repo\nlockfile has libc field] --> B[Setup Node.js 22]
    B --> C[node scripts/verify-lockfile-libc.mjs]
    C --> D{libc field\npresent & correct?}
    D -- YES --> E[npm install\nnpm 11 strips libc on disk]
    D -- NO --> F[Exit 1\nPR blocked]
    E --> G[npx @biomejs/biome check]
    G --> H[lint job passes]
Loading

Fix All in Claude Code

Reviews (4): Last reviewed commit: "fix: resolve lockfile path relative to s..." | Re-trigger Greptile

Comment thread scripts/verify-lockfile-libc.mjs Outdated
'@optave/codegraph-linux-x64-musl': 'musl',
};

const lock = JSON.parse(readFileSync('package-lock.json', 'utf8'));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 CWD-relative lockfile path breaks non-root invocations

readFileSync('package-lock.json', 'utf8') resolves against the process working directory. Running node scripts/verify-lockfile-libc.mjs from the scripts/ subdirectory (a natural mistake) throws ENOENT: no such file or directory, open 'package-lock.json' with no hint of the real problem. In CI this is fine since the step always runs from the repo root, but a contributor running it locally from the wrong directory gets a confusing error rather than a clear failure message.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — fixed in b72df7e. The script now resolves package-lock.json relative to import.meta.url so it works from any CWD (repo root, scripts/ subdirectory, or anywhere else). Verified manually from all three locations.

Comment on lines +13 to +17
const EXPECTED_LIBC = {
'@optave/codegraph-linux-arm64-gnu': 'glibc',
'@optave/codegraph-linux-x64-gnu': 'glibc',
'@optave/codegraph-linux-x64-musl': 'musl',
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 arm64-musl not covered by the verifier

The CI parity job's inline Node script already maps linux-arm64-musl@optave/codegraph-linux-arm64-musl, suggesting the package is expected to ship. If that package is added to the lockfile in a future PR, the verifier won't catch npm 11 stripping its libc: ["musl"] field — the same silent regression this PR is designed to prevent. Adding it to EXPECTED_LIBC now (even if the package is currently missing from the lockfile, the missing from package-lock.json branch handles that gracefully) would make the guard future-proof.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good future-proofing thought, but adding @optave/codegraph-linux-arm64-musl to EXPECTED_LIBC today would actually break CI: the package isn't in package.json's optionalDependencies yet, so it's absent from package-lock.json, and the current verifier treats a missing entry as a hard failure (failures.push(${pkgName}: missing from package-lock.json)), not a graceful skip.

The CI parity-job mapping references the package optimistically, but it's not actually shipped today. I've opened #1168 to track adding it to EXPECTED_LIBC the moment it lands in optionalDependencies, and to consider whether the "missing" branch should be relaxed to a warn-and-skip so future additions can be made future-proof without immediately failing.

Use import.meta.url to find package-lock.json regardless of the
process CWD. Previously running 'node scripts/verify-lockfile-libc.mjs'
from the scripts/ subdirectory failed with a confusing ENOENT instead
of running the actual check.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm carlos-alm merged commit 610c697 into main May 19, 2026
29 checks passed
@carlos-alm carlos-alm deleted the build/1160-libc-lockfile branch May 19, 2026 22:24
@github-actions github-actions Bot locked and limited conversation to collaborators May 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build: restore libc field on @optave/codegraph-linux-* entries in package-lock.json

1 participant