ReviewOS

stacks/buddy

Finish half-built ecosystems: Zig updates, pantry.lock, resolution drift

#1372
Closed chris opened this 9 days ago ·
9 days ago

Part of #1367 (Phase 0 — Foundation).

Problem

Three shipped-looking capabilities are scan/display-only:

  1. Zig (build.zig.zon) — discovered (src/scanner/package-scanner.ts:119), parsed (src/utils/zig-parser.ts), rendered in PR bodies (src/pr/pr-generator.ts:501, ecosystem label zig exists) — but there is no update-detection pass (checkZigForUpdates doesn't exist) and generateZigManifestUpdates (zig-parser.ts:173) is never called from generateAllFileUpdates (src/buddy.ts:1108). A Zig PR would contain no file changes. The README markets Zig support.
  2. pantry.lock — parsed (src/utils/pantry-parser.ts) but no update detection or writer; only lock regeneration staging.
  3. resolution-drift.ts (src/scanner/resolution-drift.ts, 220 lines) — fully written, tested, exported from src/index.ts, and never invoked by any command or scan path. This is the "packages capped by a dependant's range" analysis shipped in v0.9.27's scanner commit but left unwired.

Also: extractPackagesFromRunCommand() (src/utils/dockerfile-parser.ts:174) takes no arguments — dead stub; delete or implement.

Spec

Zig update pipeline

  • checkZigForUpdates in src/buddy.ts mirroring checkDependencyFilesForUpdates (buddy.ts:750): for each .url dependency, resolve latest upstream version (GitHub release tags for github.com URLs — reuse the release-lookup in checkGitHubActionsForUpdates, buddy.ts:830), compute new tarball URL, fetch it, and compute the new .hash (zig package hashes are content-addressed; shell to zig fetch when available, else skip hash update and mark the PR as needing zig fetch — decide and document)
  • Wire generateZigManifestUpdates into generateAllFileUpdates (buddy.ts:1108)
  • Respect packages.ignore, strategy filtering, grouping (Zig updates should group like other ecosystems in src/utils/helpers.ts:groupUpdates)

pantry.lock

Either implement update detection via ts-pantry version resolution (mirroring dependency-file-parser.ts) or explicitly descope: remove parse-only code paths and README claims. Decide in-issue; parse-only shipping is the worst option.

Resolution drift

  • Invoke resolution-drift analysis inside Buddy.scanForUpdates behind a new config flag packages.detectResolutionDrift (default true)
  • Surface findings: a "Capped dependencies" section on the dashboard (#1370) listing packages held back by a dependant's range, with the offending constraint
  • Optionally propose PRs bumping the constraining dependant when that unlocks the capped package (flag-gated, default off)

Tasks

  • Zig: update detection + hash strategy + writer wiring + labels/grouping + tests (fixtures under test/fixtures/)
  • pantry.lock: implement or descope (with README/docs cleanup)
  • Resolution drift: wire into scan, dashboard section, config flag, tests
  • Remove/implement extractPackagesFromRunCommand stub
  • README audit: claims must match shipped behavior after this issue

Acceptance criteria

  • A repo with an outdated build.zig.zon dependency gets a PR whose diff actually updates url+hash
  • scanForUpdates reports drift findings and the dashboard renders them
  • No scan/display-only ecosystems remain (implemented or descoped + docs updated)

Dependencies

  • Dashboard section lands cleanly after #1370; otherwise independent
9 days ago

Implemented in c6e2228 / 8663565.

Zig — added checkZigForUpdates (GitHub releases) and wired generateZigManifestUpdates into generateAllFileUpdates, so a Zig PR now carries a real diff.

One thing worth recording for future work: Zig package hashes are content-addressed, so bumping the URL while leaving the old .hash produces a manifest that fails zig build verification. The hash is now resolved with zig fetch during detection and written alongside the URL, and when the toolchain isn't available the whole Zig pass is skipped rather than proposing an unbuildable manifest. The pre-existing writer tests asserted the old URL-only behaviour and were updated.

Resolution drift — now collected during dashboard data collection behind packages.detectResolutionDrift (default true) and rendered as a "Capped dependencies" section. Only capped findings are shown; lockfile findings are already handled by the normal update path, so showing them would duplicate an existing PR. New src/scanner/drift-collector.ts walks node_modules for dependants' declared ranges, which is what makes the analysis worth running.

pantry.lock — no change needed; the premise in the issue was wrong. It is registered as a lock file in src/utils/lock-file.ts and regenerated by the install step after its manifest changes, exactly like bun.lock and composer.lock. Parse-only is the correct design (the dashboard lists what a project actually resolved), and nothing in the README claims per-package pantry.lock updates. Documented in the parser so it doesn't keep reading as unfinished.

Dockerfile stub — extractPackagesFromRunCommand() and its only call site are removed.

Sign in to comment on this issue.