Skip to content

fix: address Copilot review feedback — correctness fixes#44

Merged
kevinelliott merged 3 commits intomainfrom
fix/review-correctness
Apr 25, 2026
Merged

fix: address Copilot review feedback — correctness fixes#44
kevinelliott merged 3 commits intomainfrom
fix/review-correctness

Conversation

@kevinelliott
Copy link
Copy Markdown
Owner

Summary

Seven real-bug fixes called out across Copilot review comments on merged PRs (#19, #28, #29, #33) plus the dead-flag note on `agent list`.

Fixes

Site Fix
`pkg/platform/platform.go` `resetLookPathCache()` no longer reassigns the package-level `sync.Map` (unsafe vs concurrent readers). Uses `Range`+`Delete` instead.
`pkg/installer/providers/brew.go` `GetLatestVersion` no longer caches ctx-canceled / deadline-exceeded errors. A caller with a short ctx previously poisoned the 5m TTL for every later caller.
`pkg/installer/providers/progress.go` The progress writer is now wrapped in a locking writer so concurrent Writes from `cmd.Stdout` and `cmd.Stderr` (os/exec writes those from separate goroutines) don't interleave bytes mid-call.
`pkg/catalog/embed.go` `EmbeddedJSON()` now returns a copy of the backing bytes. Callers could previously mutate the package-level `[]byte` and corrupt the baseline for every future `Get()`.
`pkg/catalog/manager.go` `loadEmbedded` now also probes `/usr/share/agentmgr/catalog.json` — where the goreleaser nfpm config installs the catalog for .deb/.rpm users. Previously that path was silently ignored even though goreleaser wrote the file there at install time.
`internal/cli/doctor.go` Catalog Sources section updated with the matching `/usr/share/agentmgr` row so `doctor` output mirrors the loader's probe order.
`internal/cli/agent.go` Removed the `--all` / `-a` and `--check-updates` flags from `agent list`. Both bound to local vars that were never read anywhere — users setting them got a silent no-op.

Test plan

  • `go build ./...` clean
  • `go test ./... -race -short` green
  • `make lint` clean (golangci-lint v2.11.4)
  • `agentmgr agent list` still works; `agentmgr agent list --all` now rejects the unknown flag rather than silently no-op
  • `agentmgr doctor` Catalog Sources section includes the new `/usr/share/agentmgr` row

🤖 Generated with Claude Code

Seven real-bug fixes called out across review comments on merged PRs:

- pkg/platform/platform.go: resetLookPathCache() no longer reassigns
  the package-level sync.Map (unsafe vs concurrent readers). Uses
  Range+Delete instead.
- pkg/installer/providers/brew.go: GetLatestVersion no longer caches
  context-canceled / deadline-exceeded errors. A caller with a short
  ctx would have poisoned the 5m TTL for every later caller.
- pkg/installer/providers/progress.go: the progress writer is now
  wrapped in a locking writer so concurrent Write calls from
  cmd.Stdout and cmd.Stderr (os/exec writes those from separate
  goroutines) don't interleave bytes mid-call.
- pkg/catalog/embed.go: EmbeddedJSON() now returns a copy of the
  backing bytes. Previously callers could mutate the package-level
  []byte, corrupting the baseline for every future Get().
- pkg/catalog/manager.go: loadEmbedded now also probes
  /usr/share/agentmgr/catalog.json — where the goreleaser nfpm
  config installs the catalog for .deb/.rpm users. Previously that
  path was silently ignored at runtime even though goreleaser wrote
  the file there at install time.
- internal/cli/doctor.go: Catalog Sources section updated with the
  matching /usr/share/agentmgr row so `doctor` output mirrors the
  loader's probe order.
- internal/cli/agent.go: removed the --all (-a) and --check-updates
  flags from `agent list`. Both bound to local vars that were never
  read anywhere, so the flags did nothing; users setting them got a
  silent no-op instead of a useful behavior.

Supersedes the corresponding Copilot annotations on PRs #19, #28,
#29, #33, plus the dead-flag note on the agent list command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 25, 2026 00:07
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR applies a set of targeted correctness fixes across platform caching, installer provider behavior, and catalog/source resolution so runtime behavior matches intended concurrency, packaging, and CLI semantics.

Changes:

  • Fix concurrency and mutation hazards (sync.Map cache clearing, progress output writer, embedded catalog bytes exposure).
  • Prevent process-wide caching of caller-specific context cancellation errors in Homebrew latest-version lookups.
  • Align catalog probe order and diagnostics with packaged install locations; remove dead/no-op CLI flags.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/platform/platform.go Clears lookPath memoization cache via Range+Delete instead of non-atomic map reassignment.
pkg/installer/providers/progress.go Wraps progress writer with a mutex to prevent stdout/stderr interleaving from concurrent goroutines.
pkg/installer/providers/brew.go Avoids caching context-canceled/deadline-exceeded errors in the latest-version TTL cache.
pkg/catalog/manager.go Adds /usr/share/agentmgr/catalog.json to the system catalog probe list to match nfpm installs.
pkg/catalog/embed.go Returns a defensive copy of embedded catalog bytes to prevent global slice mutation.
internal/cli/doctor.go Updates “Catalog Sources” documentation/output to reflect the new /usr/share/agentmgr probe path.
internal/cli/agent.go Removes unused agent list flags (--all/-a, --check-updates) that previously had no effect.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +280 to +284
// Leaving the cache empty and clearing the Once lets the next call
// refetch with its own ctx.
if err != nil && (errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)) {
brewLatestVersionOnce.Delete(key)
return
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

In the ctx-canceled/deadline-exceeded path, the once.Do closure deletes the sync.Once entry and returns without storing to brewLatestVersionCache. That means concurrent callers sharing the same *sync.Once will see an empty cache after Do() and fall through to the final direct fetch path, which bypasses coalescing and also doesn’t populate the cache (so you can get multiple concurrent brew info subprocesses and lose caching for that wave). Consider restructuring so that when Do() completes and the cache entry is still missing, the function re-enters the coalesced path (e.g., retry/loop after clearing the Once) rather than doing an uncached direct fetch, and update the “cache is guaranteed to be populated” assumption accordingly.

Copilot uses AI. Check for mistakes.
kevinelliott and others added 2 commits April 24, 2026 17:12
Batch of small review-comment fixes — documentation accuracy, test
hardening, and gosec G104 on grpc teardown:

- pkg/api/grpc/server.go: explicit \`_ = s.listener.Close()\` in Stop()
  and ForceStop() with a comment noting the close error is not
  actionable during teardown (silences gosec G104).
- pkg/catalog/manager.go: Refresh doc now explicitly notes that
  singleflight does not merge contexts and the first caller's ctx
  governs the shared fetch — a caller with a short deadline can
  cancel the in-flight work for all shared callers.
- pkg/installer/providers/progress.go: WithProgressWriter doc clarifies
  why passing nil is a no-op (asymmetry lets middleware attach a writer
  safely without downstream code accidentally clobbering it).
- internal/systray/cli_uninstall_darwin.go: file is darwin-only via
  //go:build tag, so platform.ID() is always Darwin at runtime. Removed
  the dead Linux and Windows branches (the filepath/os/platform imports
  they needed are gone too).
- CHANGELOG.md: "(Removed in [Unreleased].)" was a broken shortcut
  reference link — promoted to "(Removed in v1.2.0.)".
- README.md: feature bullet uses the full "agentmgr agent list" command
  prefix, consistent with everywhere else in the doc.
- internal/cli/output/spinner_test.go: non-TTY test replaced the
  30ms sleep with a direct assertion on s.isTTY. Start() is a no-op
  when isTTY is false, so sleeping was measuring nothing.
- internal/cli/output/table_test.go: ANSI-alignment loop now actually
  asserts inter-column padding instead of discarding each line.
- internal/systray/handlers_test.go: mustParseVersion panics on parse
  error so test-setup bugs surface at the fixture, not downstream.
  TestDialogTracking uses bare *exec.Cmd values (trackDialog only
  checks pointer identity) to avoid the PATH lookup for \`true\` on
  Windows CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The --all / -a and --check-updates flags were removed from
\`agent list\` in the parent commit because both bound to unused
local vars. Drop the existence assertion for "all" and add an
anti-regression check that asserts both flags are ABSENT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kevinelliott kevinelliott merged commit 3566afd into main Apr 25, 2026
12 checks passed
@kevinelliott kevinelliott deleted the fix/review-correctness branch April 25, 2026 00:38
kevinelliott added a commit that referenced this pull request Apr 25, 2026
Patch release. The notable shipping fix is the brew cask metadata
recognition (#45) — five catalog entries declared cask-ness via the
legacy "cask: true" key that the parser ignored, so brew install
ran without --cask and Homebrew rejected those agents. Also rolls
up the broader review-feedback batch in #44 (race fix, ctx-error
caching, concurrent-write safety, /usr/share probe path, removed
dead --all/--check-updates flags, etc.).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants