Skip to content

chore: merge main into v3 (2.24.0 release, MOPS_POCKET_IC_URL) - #768

Open
Kamirus wants to merge 8 commits into
v3from
kamil-claude/sync-v3-branch-main-505179
Open

chore: merge main into v3 (2.24.0 release, MOPS_POCKET_IC_URL)#768
Kamirus wants to merge 8 commits into
v3from
kamil-claude/sync-v3-branch-main-505179

Conversation

@Kamirus

@Kamirus Kamirus commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Brings main up to 2.24.0 into the v3 line: the MOPS_POCKET_IC_URL attach mode, the 2.21.0–2.23.0 docs backfill, the 2.x port of the v3 docs audit, and the 2.24.0 release/cli-releases artifacts.

Merge this with a merge commit, not squash — it is a mainv3 sync and must keep both parents.

MOPS_POCKET_IC_URL on v3

Every mops-managed PocketIC path (build --check-deploy, replica tests, mops bench, mops watch, the tests/benches mops publish runs) can now attach to an already-running PocketIC server instead of spawning the [toolchain] pocket-ic binary. The port is rewritten for v3 semantics — v3 has no dfx replica and no legacy pic-ic client, so the feature lands as: pin required as before, MOPS_POCKET_IC_URL is the one alternative source, and a pin is ignored with a warning when the URL is set.

Resolution choices a reviewer should check:

  • startPocketIc keeps v3's single-client shape (no client: "dfinity" overloads, no AnyPocketIc unions) and gains main's thunked options — in attached mode toolchain.bin("pocket-ic") is never resolved, so no binary is downloaded and no pin is needed.
  • v3 keeps pin validation in the toolchain layer (assertMinimumVersion at download, toolchain.bin erroring on a missing pin), so main's early-validation block in build.ts stays deleted; the attached-mode gate makes it moot there anyway. The --check-deploy requires a PocketIC pin test still asserts v3's error text.
  • mops test keeps no --replica flag; main's SIGINT bounded-teardown and settled-start error surfacing are ported (via cliErrorFrom), the dfx branches are not.
  • mops bench records no replicaVersion in attached mode (ported at the options default, since v3 has no replica-type dispatch).
  • Main's --check-deploy warns when MOPS_POCKET_IC_URL ignores a pin test moved into build-check-deploy.test.ts, which owns the build/check-deploy fixture on v3 (it does not exist on main); the two build/success-based URL tests stayed in build.test.ts.

What was deliberately not taken

  • The .mo-baseline fast-path fix (9de549d2) and its mo-baseline-em fixture: v3 rejects .mo check-stable baselines outright (#758), so there is no 3-step path to keep them on. The 2.24.0 changelog entry is kept as the historical record.
  • All dfx fallback code and copy (--replica, dfx-pocket-ic, deprecation warnings) — gone on v3, stays gone.

Docs, per the AGENTS.md merge rules

  • docs/versioned_docs/version-2.x/ is byte-identical to main (verified with git diff origin/main -- docs/versioned_docs/ → empty).
  • docs/docs/ keeps v3's pages; the only delta vs v3 is the new-feature copy rewritten in v3 terms (pin required unless MOPS_POCKET_IC_URL is set, no dfx mentions — main's "--replica dfx is unaffected" line is dropped from the env-vars page).
  • docs/docusaurus.config.js keeps lastVersion: '2.x'; release.yml keeps the docs deploy step.

Verified

tsc --noEmit clean, ESLint clean, and the merge-adjacent Jest suites pass locally (109 tests across pocket-ic-client, pocket-ic, check-stable, bench, build, build-check-deploy, cli, vendor-pic, test-reporter, publish-dry-run). CI runs the full matrix.

🤖 Generated with Claude Code

Kamirus and others added 7 commits August 14, 2026 10:04
…e` fold (#757)

2.23.0 scoped the moc 1.12.0+ folded upgrade check to canisters with
`[migrations]` and a **committed `.most`** baseline. The changelog,
[`mops check-stable`'s
docs](https://docs.mops.one/cli/dev/mops-check-stable) and
[#624](#624) all say `.mo`
baselines are unaffected. They are not: `runStableCheck` compiles a
`.mo` baseline to a scratch `.most`, then folds anyway.

The folded check is stricter — a field the initial actor requires that
no migration produces fails as `M0267` instead of warning `M0254` — so
anyone with `[migrations]`, a `.mo` baseline and moc 1.12.0+ can find a
green `mops check` red after upgrading to 2.23.0, with nothing in the
changelog to explain it.

## Before / After

An enhanced-migration canister whose chain never produces `d`,
`[check-stable] path = "deployed.mo"`, moc 1.12.0:

```console
$ # before
src/main.mo:9.7-9.8: type error [M0267], initial actor requires field `d` of type
  Int; not found in the previous version — write a migration that produces it
✗ Stable compatibility check failed for canister 'backend'
$ echo $?
1
```

```console
$ # after
✓ Stable compatibility check passed for canister 'backend'
$ echo $?
0
```

## Why it evaded the tests

Every moc 1.12.0 fixture pairs the fold's two preconditions the way the
feature intended. `check-stable/migrations-chain` has `[migrations]` and
a `.most` baseline; `check/deployed-compatible` has a `.mo` baseline but
no `[migrations]`, so `canUseStableBaselineCheck` is false and it never
reaches the second fold. Nothing pinned the one corner where the two
cross. `check-stable/mo-baseline-em` does now, and fails with `M0267` on
`main` without this change.

Worth noting the second fold could not have been fixed with a guard: `if
(isOldMostFile && canUseStableBaselineCheck(...))` is the exact
condition the earlier fast path already returns on, so the block is
unreachable once corrected. It is deleted rather than guarded, and
`runFoldedStableCheck` loses its `baselineIsMostFile` parameter —
"folded implies committed `.most`" now holds by construction instead of
by argument.

## What is unchanged

- Committed `.most` baselines keep the fold, the source locations and
the stricter `M0267`. That part of 2.23.0 was intended and stays.
- `mops check` already gated its own fold on
`configuredMost.endsWith(".most")`, so only the `runStableCheck` path it
delegates to was wrong.
- No docs change: the shipped prose describes this behavior correctly —
it is the code that drifted.

Also going onto `v3` as part of
[#756](#756), which is where
the bug was found, so the branches do not diverge.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
`mops build --check-deploy`, replica tests, and benches can talk to an
already-running PocketIC server instead of spawning the `[toolchain]
pocket-ic` binary. Platforms that keep PocketIC outside the sandbox
(gVisor memory) can set one env var; independent mops users are
unchanged.

Previously the only cleanup for a PocketIC run was killing the process
mops had spawned, which took every instance with it. That does not work
against a shared server, so mops now always `DELETE`s the instance it
created — including on SIGINT — and never stops the remote process.

## Before

```bash
mops build --check-deploy
# downloads and spawns [toolchain] pocket-ic, then kills that process
```

`--check-deploy` without a pin:

```text
PocketIC deployment check requires `pocket-ic` in `[toolchain]`. Run `mops toolchain use pocket-ic 15.0.0` to pin it.
```

## After

```bash
export MOPS_POCKET_IC_URL="http://127.0.0.1:8001"
mops build --check-deploy
# POST /instances on that server, install Wasm, DELETE the instance; server stays up
```

A pin is no longer required when the env var is set. If both are set,
the pin is ignored and mops warns once:

```text
`MOPS_POCKET_IC_URL` is set; the `pocket-ic` pin (15.0.0) in `[toolchain]` is ignored for this run.
Unset `MOPS_POCKET_IC_URL` to use the pinned binary.
```

Applies to every mops-managed PocketIC path (`build --check-deploy`,
`test --mode replica`, `bench`, `watch`). `--replica dfx` is unchanged.
The URL must be `http`/`https` and must speak the PocketIC control API,
not the IC HTTP gateway.

## What is unchanged

Auth, isolation, and spawning PocketIC itself stay with the caller (e.g.
a Caffeine proxy). Mops does not health-check or lazily start the
server; the first `POST /instances` is the request the proxy can key
off.


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Readers of the 2.x docs at the docs.mops.one site root never saw the
features shipped in CLI 2.21.0–2.23.0: `grep -rn "check-deploy"
docs/versioned_docs/version-2.x/` had zero hits even though `mops build
--check-deploy` shipped in 2.21.0. The versioned tree was treated as a
frozen snapshot while every feature doc landed only in `docs/docs/` —
per the amended "Keep docs in sync" rule, features shipping in a 2.x
release belong in both trees.

This replays the `docs/docs/` diffs of each 2.21.0–2.23.0 feature into
`docs/versioned_docs/version-2.x/`, wording identical:

- [#696](#696) — `mops self
update` major-version confirmation and `--major`
- [#644](#644) — `mops build
--check-wasm` / `--check-deploy`, `[build].check-wasm` / `check-deploy`,
and `wasmMemoryLimit` in the config reference
- [#713](#713) /
[#714](#714) — `mops.lock`
`graph` section and hash carry-over
- [#624](#624) —
check/check-stable/migrate diagnostics on moc 1.12.0+
- [#754](#754) — `pocket-ic
15.0.0` recommendation (6 pages)

After the replay, `diff -r docs/docs docs/versioned_docs/version-2.x` is
empty, so the sync state is trivially checkable. `docusaurus build`
passes (links and anchors resolve in both trees).

## What is unchanged

- `MOPS_POCKET_IC_URL` on the environment-variables page — already
mirrored by [#761](#761).
- 2.21.0–2.23.0 changelog entries with no `docs/docs/` counterpart (the
unzipper security fix, atomic lock writes, the ENOENT cache-state fixes,
the executable-bit and moc-wrapper fixes) — nothing to port; if any
deserve docs, that's a change to make in `docs/docs/` first.

## Follow-up worth flagging

The docs site deploys from the `v3` branch only, so this has no effect
on the live site until it is synced there. `v3`'s
`docs/versioned_docs/version-2.x/` is currently identical to
pre-backfill `main`, so the sync is exactly this patch — follow-up PR to
`v3` incoming.

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Release CLI v2.24.0.

Prepared by the [Prepare CLI
release](https://github.com/caffeinelabs/mops/actions/workflows/prepare-cli-release.yml)
workflow.

Approve this PR when CI is green — auto-merge is enabled.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Release artifacts generated by CI for CLI v2.24.0.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The 2.x CLI docs contradicted actual CLI behavior in nine places —
missing test/bench discovery rules, an undocumented test mode,
undocumented flags and environment variables, and stale toolchain
versions. Each defect was found by the v3 docs audit (branch
`kamil-claude/v3-sync-2x-docs`) and re-verified here against the 2.x
source (`cli/cli.ts`, `cli/commands/**`) before porting, since 2.x
behavior sometimes differs from v3.

## What was wrong

- **mops test**: the mode list omitted `replica` (the CLI accepts
`interpreter|wasi|replica`); the `// @testmode` block showed only `wasi`
and claimed the marker must be the first line — it is an exact full-line
match anywhere in the file (`lines.includes(...)` in `test/test.ts`);
"Make sure your actor doesn't have a name" contradicts the detection
regex `/^(persistent )?actor( class)?/`, which matches named actors too;
discovery was described as "test/*.test.mo" but is
`**/test?(s)/**/*.test.mo` with a `test/lib.mo` short-circuit and a
`[filter]` that widens the glob to `*<filter>*.mo`.
- **mops bench**: discovery is `**/bench?(mark)/**/*.bench.mo` with the
same filter widening — the page said only "bench/*.bench.mo".
- **mops owner / maintainer**: `--yes` undocumented.
- **mops user import**: `--no-encrypt` undocumented.
- **Environment variables**: `MOPS_ENV` (expands `{MOPS_ENV}` in path
dependencies, defaults to `local`) and `MOPS_CWD` (chdir before the
command runs, for npm scripts) undocumented.
- **mops docs generate**: the `-o` short alias undocumented.
- **mops toolchain info / update**: both accept `wasm-opt` (it is in
`TOOLCHAINS`), and `update <tool>` errors when the tool is not pinned in
`[toolchain]` — verified in `commands/toolchain/index.ts`. The pages
implied a four-tool list and unconditional updates.
- **mops build**: the "Each canister configuration supports" list
omitted `wasmMemoryLimit` (used in an example on the same page) and the
`migrations`/`check-stable` subtables.
- **Toolchain overview / use**: stale example versions `moc 0.10.3` /
`wasmtime 16.0.0` (and `pocket-ic 1.0.0` in `use`) → `1.0.0` / `41.0.0`
/ `15.0.0`, matching `09-mops.toml.md`.

## Deviations from the v3 wording

- The `replica` mode bullet is worded replica-neutrally — 2.x still has
the deprecated dfx path selected via `--replica`, so the v3 "PocketIC
replica" phrasing would be wrong here.
- The v3 `MOPS_ENV` note about lockfile staleness is not ported — it
describes v3-only lockfile behavior and links a v3-only anchor.
- The v3 missing-blank-line fix in mops-build does not apply — 2.x has
no `--locked` section on that page and the blank line is already
present.

## Tree sync

`docs/docs/` and `docs/versioned_docs/version-2.x/` must be
byte-identical (AGENTS.md). Besides applying every fix to both trees,
this also carries
[#761](#761
`MOPS_POCKET_IC_URL` wording into `versioned_docs` (`09-mops.toml.md`,
`cli/4-dev/03-mops-build.md`), where it had only landed in `docs/docs/`.
`diff -r docs/docs docs/versioned_docs/version-2.x` is now empty, and
`cd docs && npm run build` passes (Docusaurus validates links and
anchors).

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Cursor AI review

👍 APPROVE — looks safe to merge

Category Assessment Details
Summary Merges main’s 2.24.0 / MOPS_POCKET_IC_URL attach mode into v3 (thunked spawn, shared teardown, docs/changelog/skills/cli-releases), keeping v3’s no-dfx PocketIC shape.
Code Quality Shared attach/teardown lives in pocket-ic-startup.ts; callers (replica.ts, bench-replica.ts, check-deploy.ts) reuse startPocketIc thunks so toolchain.bin is skipped when attached.
Consistency Docs (docs/docs vs versioned_docs), ## Next + ## 2.24.0 changelog, and .agents/skills/mops-cli/SKILL.md match the feature; versioned tree retains dfx copy, /next does not.
Security Traced attach path in startPocketIc, stopPocketIc / trackAttachedPocketIc SIGINT teardown, and toolchain.installAll skip-download; opt-in http(s) URL only — no registry/auth/integrity changes.
Tests Unit coverage in pocket-ic-client.test.ts (URL parse, stop/SIGINT semantics); CLI coverage in build.test.ts, build-check-deploy.test.ts, bench.test.ts for no-pin attach, ignore-pin warning, malformed URL.
Maintainability Cleanup via finally in bench.ts / replica tests; signal teardown bounded; deliberate omission of main’s .mo-baseline fix matches v3 #758.

Verdict

Decision: APPROVE
Risk: Low
Reason: Opt-in attach mode is gated on MOPS_POCKET_IC_URL, reuses the existing PocketIC client paths without touching registry/install/auth, and is backed by focused unit plus CLI tests plus synced docs/changelog/skills.


Generated for commit 0834cb6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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 0834cb6 is APPROVE. See the "Cursor AI review" comment for details.

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