Skip to content

fix(cli): align mops update with outdated, and say it rewrites mops.toml - #742

Merged
Kamirus merged 2 commits into
v3from
kamil-claude/v3-cmd-consistency
Aug 13, 2026
Merged

fix(cli): align mops update with outdated, and say it rewrites mops.toml#742
Kamirus merged 2 commits into
v3from
kamil-claude/v3-cmd-consistency

Conversation

@Kamirus

@Kamirus Kamirus commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Three consistency gaps between mops update and mops outdated, all of which make a scripted update quietly misbehave.

mops update reported failure and exited 0

$ mops update no-such-package
  Package "no-such-package" is not installed!
Before: $? = 0
After:  $? = 2

A typo in a scripted update looked like success. It now exits 2 — the same code mops outdated uses for "the check could not be completed" (#734) — for an unknown package and for a missing mops.toml. 1 is deliberately not reused: it means "updates are available", which cannot be a terminal state for a command whose job is to apply them.

The two commands could disagree about GitHub deps

#734 extracted getAvailableGithubUpdates precisely so outdated and update could not drift apart on what "out of date" means for a repo = "..." dependency — but update kept its own inline loop resolving branch heads, so the rule still existed twice. It now uses the helper. The helper needed no changes: it already carries the repo, branch, resolved head and dependency name, which is exactly enough to rebuild the pin URL.

Behaviour is preserved deliberately and specifically: the same add(url, { dev, lock: "skip" }, name) call, dev still derived from where the dependency is declared, the alias key still passed through as the manifest key, and a failed lookup still prints and lets the rest of the run continue. Two visible nuances: lookups now run concurrently rather than sequentially (same request count against GitHub's 60/hour limit), and lookup errors print after the re-pins rather than interleaved with them.

Neither --help nor the docs said it rewrites your manifest

mops update is cargo upgrade semantics — it rewrites mops.toml — not cargo update, which only touches the lockfile. #723 records the decision to keep the name (under exact pins there is only one update operation that can exist, so there is no ambiguity to resolve, and renaming would be breaking). The agreed remedy was to say so plainly, which neither the help text nor the doc page did:

$ mops update --help
Rewrite the versions in mops.toml to the highest semver-compatible ones within
the caret bound (does not cross major versions, or pre-1.0 minor versions)

Rewrites the new versions into mops.toml, and keeps mops.lock in sync.
GitHub dependencies are re-pinned to their branch head (one GitHub API call each).

Exit codes:
  0  mops.toml is up to date
  2  the update could not be run (no mops.toml, unknown [pkg])

Follow-up worth flagging

One divergence of the same family is left in place: update still exits 0 when a GitHub lookup fails — it prints Failed to update <name>: … and carries on — where outdated exits 2. Changing it would alter behaviour beyond the scope of aligning the "not installed" case, so it is called out rather than folded in.

Items 35, 36 and 37 in #723.

🤖 Generated with Claude Code

`mops update <not-installed-pkg>` printed `Package "<name>" is not installed!`
and exited 0, so a typo in a scripted update looked like success. It now exits 2
— the same code `mops outdated` uses for "the check could not be completed" —
for an unknown package and for a missing mops.toml. 1 is deliberately not used:
it means "updates are available", which cannot be a terminal state for update.

#734 extracted getAvailableGithubUpdates so outdated and update could not drift
apart on what "out of date" means for a repo = "..." dependency, but update kept
its own inline loop resolving branch heads. It now uses the helper, so the rule
exists once. The helper needed no changes. Behaviour is preserved, including
which section the re-pin is written back to, the lock: "skip" batching, and
carrying on past a failed lookup — lookups are now concurrent rather than
sequential, at the same request count.

`mops update` is cargo upgrade semantics, not cargo update: it rewrites the
manifest. Neither --help nor the doc page said so, which is the actual confusion
risk behind keeping the name. Both now say it, and list the exit codes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Kamirus Kamirus added the cli label Aug 12, 2026
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Cursor AI review

👍 APPROVE — looks safe to merge

Category Assessment Details
Summary Aligns mops update with mops outdated: exit 2 for missing config/unknown pkg, shared getAvailableGithubUpdates, and docs/help stating it rewrites mops.toml.
Code Quality Removes duplicated GitHub branch-head loop in update.ts in favor of getAvailableGithubUpdates in available-updates.ts; URL rebuild (org/name + branch + latest) matches the prior add(...) shape.
Consistency Exit 2 matches outdated.ts; --help/docs/skills/changelog updated together; tests mirror outdated.test.ts mocking style.
Security No auth/integrity changes; traced updateadd / checkIntegrity / getAvailableGithubUpdatesgetGithubCommit — same pin rewrite path, no widened trust.
Tests cli/tests/update-command.test.ts covers exit 2/0, registry add args (incl. pinned alias + --dev), GitHub re-pin/no-op/filter, and lookup/add failure continue-on-error.
Maintainability Single shared “outdated GitHub dep” rule prevents command drift; intentional leftover (GitHub lookup failure still exits 0 on update) is documented in the PR body.

Verdict

Decision: APPROVE
Risk: Low
Reason: Contained CLI consistency/docs fix with equivalence verified against the shared GitHub helper and solid unit coverage; exit-code correction is intentional and matches outdated.


Generated for commit 8319328

@automation-sa-sre automation-sa-sre left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval: the AI review verdict for 5141264 is APPROVE. See the "Cursor AI review" comment for details.

@automation-sa-sre automation-sa-sre left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval: the AI review verdict for 8319328 is APPROVE. See the "Cursor AI review" comment for details.

@Kamirus
Kamirus merged commit 19fa52f into v3 Aug 13, 2026
18 checks passed
@Kamirus
Kamirus deleted the kamil-claude/v3-cmd-consistency branch August 13, 2026 11:16
Kamirus added a commit that referenced this pull request Aug 13, 2026
Establishes the manual tracking convention for the install benchmark
from [#744](#744): the most
recent meaningful run lives in `perf/install-bench/RESULTS.md`, replaced
wholesale on each re-run, with a one-line history of prior headline
numbers. Deliberately not a CI gate — runs are only comparable within
one host and network, so a committed run is a point of reference.

## The run itself

v2.22.0 vs v3 at f8c619c — the first measurement with the whole
performance stack landed (#741 sorted lock, #742 update alignment, #743
resolve memo, #745 parallel installs, #746 in-flight re-check). Medians
of 3 against the live registry:

| scenario | v2 | v3 | v3 vs v2 |
| --- | --- | --- | --- |
| install-cold-nolock | 139.6s | 107.4s | 0.77x |
| install-cold-validlock | 106.6s | 61.1s | 0.57x |
| install-cold-stalelock | 128.0s | 95.7s | 0.75x |
| install-warm-nolock | 3.20s | 5.62s | 1.76x † |
| install-warm-validlock | 6.20s | 2.99s | 0.48x † |
| install-warm-stalelock | 3.31s | 2.45s | 0.74x |
| add-two | 4.00s | 3.84s | 0.96x |
| update-few | 8.02s | 5.42s | 0.68x |
| update-all | 14.9s | 2.87s | 0.19x |

† transient registry-latency window, not code: v2's own warm numbers
tripled against every prior run of the same released binary. A warm-only
re-check half an hour later returned to line — v3 warm-nolock 2.33s
(0.75x), warm-validlock 1.08s (0.42x) — and is recorded in RESULTS.md as
the representative warm numbers, with the main table kept unedited.

**v3 now beats released v2 in every scenario.** The cold no-lock install
— v3's one regression before #745 (1.23–1.25x in both pre-parallel
baselines) — is 0.77x, and CI-shaped installs (cold + committed lock)
are 43% faster.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants