docs: bump icp-cli docs links to the 1.3 version slug - #354
Merged
Conversation
All 16 distinct URLs and all 7 anchors verified live at /1.3/.
marc0olo
force-pushed
the
docs/cli-docs-1-3
branch
from
August 26, 2026 10:19
2627ee0 to
95c674f
Compare
This was referenced Aug 26, 2026
infra: reduce .sources/ submodules to what the site actually needs, watch releases for the rest
#355
Closed
raymondk
approved these changes
Aug 27, 2026
marc0olo
added a commit
that referenced
this pull request
Aug 27, 2026
…358) Closes #355. `.sources/` held 16 submodules. Three are opened by the build; the rest were vendored so an agent could check a fact, or to supply skills through a symlink chain. Both have cheaper answers. **Result: 3 submodules, 10 watched entries across 6 upstreams, 7 verified on demand, skills mirrored from the registry.** ## Kept, because the build opens them | Submodule | Resolved by | |---|---| | `motoko` | synced pages, plus 52 `<motokoExamples>` includes | | `internetidentity` | `sync-ii-spec.mjs`, which generates two reference pages | | `examples` | `remark-snippet.mjs`, which extracts `snippet=` code | Thirteen go: eleven that existed only so an agent could check a fact, plus `icskills` and `dotskills`, which fed the skills symlink chain. The eleven appeared only in the `AGENTS.md` source table and `.agents/submodule-bumping.md`, and CI initializes just `examples` and `motoko`, so nothing in the build referenced any of them. ## What is worth watching, and what is not Watching everything meant a weekly check on repos the docs barely draw on. Measured footprint in `docs/` decided each one: | Watched | Pages | Hits | Also | |---|---|---|---| | `icp-cli` | 51 | 461 | the docs-site link slug | | `motoko-core` | 63 | 328 | | | `cdk-rs` | 47 | 336 | pinned versions in prose | | `icp-js-core` | 15 | 47 | | | `icp-cli-recipes` | 11 | 26 | every hit is a pinned recipe version in prose; one entry per recipe | | `icp-js-canisters` | 4 | 8 | a stated minimum version | The other six became a `reference` group: `icp-cli-templates` (linked, not restated), `candid` (a rarely moving spec), `response-verification` (two pages, both linking to docs.rs), `chain-fusion-signer` (7 mentions), `papi` (1 page), `ic-pub-key` (3 pages). They keep their entry and verify path so an agent knows where to look, but carry no pin and produce no issue: verify against the **latest** release on demand, since the surface is small enough that the next edit to those pages catches drift. Each entry records the footprint that decided it, so promotion back to `watched` is a judgment someone can re-make. ## Every upstream is now checked exactly once | Upstream | Checked by | Produces | |---|---|---| | `motoko`, `internetidentity` | their existing sync workflows, unchanged | a bump PR | | `examples` | `upstream-releases.yml`, `vendored` | an issue when the gitlink falls behind `master` | | 10 watched entries | `upstream-releases.yml`, `watched` | an issue when a newer release exists | | 7 reference repos | nothing | nothing; verified against the latest release on demand | | 29 IC skills | `.claude/sync-ic-skills.sh` on session start | nothing; not committed | `examples` previously had **no** drift notification of any kind: it tracks a branch, and the only two workflows that could have noticed belong to the other two submodules. Issues carry `upstream-sync` plus a per-upstream label, and a run whose title already matches an open issue does nothing, so a repo that stays behind produces no weekly noise. ## Watching `.sources/upstream.json` records per repo: the ref the docs are verified against, where its releases appear, which file's diff is the review payload, and what to re-check. `scripts/check-upstream-releases.mjs` writes an issue body per repo that moved (no token needed). `npm run check:upstream` runs it locally. Agents verify against the **pinned** ref, so a review is reproducible and a page cannot document a flag from a release whose links have not been adapted: ```bash curl -sL https://raw.githubusercontent.com/dfinity/icp-cli/<pinned>/docs/reference/cli.md ``` `raw.githubusercontent.com` rather than `gh api .../contents/...`: the API returns base64 truncated at ~2.3 KB against 71 KB for the full file, and a truncated flag reference looks complete. ### Where releases appear differs per repo, and getting it wrong fails silently | `track` | Latest from | Repos | |---|---|---| | `release` | git tags matching an anchored pattern | `icp-cli`, `motoko-core`, `icp-js-core`, and one entry per `icp-cli-recipes` recipe | | `crate` | crates.io | `cdk-rs` | | `npm` | npm registry | `icp-js-canisters` | Seven defects found and fixed: three while building this, one from Copilot, three from review: 1. **Lexicographic sorting reported downgrades.** These repos tag in four shapes; as strings `0.9.4` beats `0.20.1`. Sorting is numeric-run aware. 2. **`cdk-rs` was pinned to `0.20.1`, which is not a tag** but the published crate version, with the newest tag two minors behind. Against tags that pin could never be overtaken, so the repo governing every Rust code block would have reported "current" for ever. A `release` pin that is not among the matched tags is now a **loud failure**; every pin was audited. 3. **`icp-js-sdk-docs` was the wrong repo entirely.** It is the js.icp.build delivery site, so a commit meant the docs site rebuilt. Replaced by `icp-js-core` (tags match npm) and `icp-js-canisters` (tags lag npm by two majors, so npm is the signal). Sibling repos, different correct answers. 4. **`icp-cli-recipes` monitoring was a no-op for four of five recipes.** Refs compare by numeric run, so `rust-` against `static-site-` compares textually and only the alphabetically-last prefix could ever be reported, while the entry read as watched. Each recipe now has its own entry, pin, issue and label, which immediately surfaces four releases the docs are behind. 5. **The pin guard covered only the `release` track.** A `crate` or `npm` pin in the wrong shape (`v0.20.1` for a crate that publishes `0.20.1`) compared as older for ever. Registry pins are now checked against the published version list, and crates.io reads `max_stable_version` so a prerelease is not reported as the latest release. 6. **`summarizeChange` counted by set membership**, so an added line that already appeared elsewhere in the file read as unchanged. It now counts occurrences: `cli.md` v1.1.0 to v1.3.0 reports 14 added rather than 11. 7. **The `commit` track ordered short SHAs** with the version comparator, so an update whose SHA happened to sort lower read as "current". Demonstrated with pin `ef03698` against head `9f1e819`. SHAs have no order, so it is now a prefix match, with the full SHA in links. `commit` is currently used by nothing: it exists for a repo with no releases at all, and after the reduction below no watched repo is in that state. ### First run: 9 of 11 have drifted `icp-cli` v1.1.0→v1.3.0, `motoko-core` v2.4.0→v2.6.1, `cdk-rs` 0.20.1→0.20.2, `icp-js-core` v5.4.0→v6.1.0, `icp-js-canisters` 3.5.0→3.6.0, and four recipes: `asset-canister` v2.2.1→v2.3.0, `rust` v3.3.0→v3.4.0, `motoko` v5.0.0→v5.1.0, `prebuilt` v2.0.0→v2.1.0. The `static-site` recipe and `examples` are current. Three carry real content risk: `motoko-core` (two minors of `mo:core`), `icp-js-core` (a major bump, `Agent.readState` revamped), `cdk-rs`. Where a changelog exists it is the review payload, because "check every API signature" is unbounded while a changelog names the symbols to grep for. `icp-cli` is pinned at v1.1.0 deliberately: #354 moved the doc *links* to the 1.3 slug, but the commands were last verified against v1.1.0, so the first watch issue carries that pass rather than hiding it. ## Skills `.claude/sync-ic-skills.sh` on `SessionStart`, byte-identical to the script `dfinity/examples` runs, replaces two submodules and a double symlink chain. Coverage rises 16 → 29 and corrects two table entries pointing at skills that no longer exist upstream: `asset-canister` → `static-site` (which covers the legacy recipe and the migration) and `vetkd` → `vetkeys`. No symlinks, in either direction: Claude finds a skill whether it is a directory or a link, no other harness auto-discovers any path, and for the synced 29 a symlink is actively wrong because the sync consumes anything at a name the registry publishes (verified in a sandbox). AGENTS.md states the non-Claude path instead: fetch the registry index by URL, explicitly **not** `.claude/skills/`, which is gitignored and empty in a fresh clone. `icp-brand-design`, `icp-brand-voice`, and `technical-documentation` stay committed. The last is not on the registry and changed once since our pin, only to relicense `AGPL-3.0-only` → MIT. That license is why it was a submodule; MIT still requires the notice to travel, so its text sits in the skill directory and a new root `NOTICE` records the attribution. ## Instructions updated `AGENTS.md` (source material, CLI verification, the `1.3` slug no longer derived from a submodule pin, skills, key directories), `.agents/upstream-tracking.md` replacing `submodule-bumping.md`, and `CONTRIBUTING.md`. ## Worth challenging - **The workflow itself has never run.** The script is exercised locally; the Actions job (app token, label creation, supersede logic) is not. - **`examples` costs 265 MB** for one page today (6 snippets, 2 examples). Keeping it bets on `<CodeExample>` spreading. - **`ic-cdk-timers` and `ic-cdk-executor` version separately** from `ic-cdk` and are not tracked individually; the `affects` note tells a reviewer to check them. - **`setup.sh` now prunes stale `.sources/` directories.** An existing clone keeps them after a submodule is removed, and a frozen `.sources/icp-cli/` looks authoritative while being exactly what the verify-at-the-pinned-ref rule exists to prevent. Only untracked directories are touched. - **The `reference` group trades a prompt for less noise.** If nobody edits those pages, drift sits there unreported. That is the deliberate bet: six weekly checks on repos with a 1-to-3 page footprint cost more attention than they return. - **The three committed skills are watched by nothing.** - **The non-Claude skill path is an instruction, not a mechanism.** Claude gets skills regardless; every other harness only by compliance. ## Found along the way, not fixed here `ic-cdk` is pinned to four different versions across the docs: `0.19` in 8 places, plus `0.20`, `0.17`, and `0.17.1`. The published crate is 0.20.2. That is a content bug rather than infrastructure, so it belongs with the `cdk-rs` watch issue rather than in this PR. ## Follow-up #279 is unblocked: of the 11 repos its "keep as-is" bucket names, only `examples` is still a submodule, and `affects` now carries the upstream-to-pages mapping. After merge: trigger the workflow once so the drifts land as issues, batch the pin-only bumps, then handle `icp-cli` and `motoko-core` as their own PRs. ## Merge order These three are independent in intent but share one file, so they have a preferred order: **#354, then #357, then #358.** | | PR | Why here | |---|---|---| | 1 | #354 CLI docs links to the 1.3 slug | Content only, no dependencies, and the smallest diff. | | 2 | #357 clear the hand-written `validate --all` violations | Touches `scripts/validate.js`, `data-persistence.mdx`, `chain-key-tokens.mdx`; no overlap with the other two. Merging it here drops `validate --all` on `main` from 11 errors to 7. | | 3 | #358 `.sources/` reduction | Largest diff, and it shares `docs/guides/canister-management/lifecycle.mdx` with #354 (different lines: a CLI link there, a stale `.sources/` pointer here). Last means at most one rebase, on a cleaner validate baseline. | The remaining 7 errors after #357 are all in `docs/references/internet-identity-spec.md`, which is generated by `sync-ii-spec.mjs`. They clear when [dfinity/internet-identity#4284](dfinity/internet-identity#4284) merges and the next spec sync runs; that PR is independent of the order here.
marc0olo
added a commit
that referenced
this pull request
Aug 27, 2026
…aced (#370) Closes #360, #361, #362, #363, #364, #365, #366, #367, #368, #369. The first batch from the upstream watcher added in #358, plus one fix to the watcher itself that running the batch exposed. **23 files, 18 of them docs pages.** Two of the ten issues needed real content changes; the other eight were version strings or pin bumps. Every claim below was checked against the upstream at the new ref. Where a replacement is named, it is upstream's own wording, not an inference. ## What a reviewer should scrutinise 1. **The 20 Motoko call-site replacements** are the only changes that alter code a reader copies. Each one is named in upstream's `@deprecated` marker, quoted below. 2. **`icp canister status <name> -i`** replacing `icp canister id <name>`. This is a real command substitution, verified against the installed CLI, not a rename. 3. **The examples path filter** decides whether a whole class of issue fires. Its two-way verification is in the table below. Everything else is a version string or a pin. ## motoko-core v2.4.0 → v2.6.1: 20 deprecated call sites (#362) v2.6.0 deprecated every `Module.fromX` conversion that has a `toX` counterpart. Our examples used five of them, so left alone each one emits a compiler warning for anyone who copies the code. The replacements are read from `src/*.mo` at v2.6.1: | Deprecated | Upstream's `@deprecated` text | Sites | |---|---|---| | `Nat64.fromNat` | Use `Nat.toNat64` instead. | 7 | | `Nat8.fromNat` | Use `Nat.toNat8` instead. | 5 | | `Blob.fromArray` | Use `Array.toBlob` instead. | 5 | | `Float.fromInt` | Use `Int.toFloat` instead. | 2 | | `Text.fromChar` | Use `Char.toText` instead. | 1 | **Import policy: four added, zero removed.** A replacement can need a module the block did not import (`Nat`, `Char`), so those are added. Nothing is removed, deliberately: an unused import is harmless, a missing one does not compile, and pre-existing imports are not this change's business. A first attempt did prune them and got it wrong three ways, dropping `Text` where `hex.chars()` still needs it in scope for contextual dot, plus `Cycles` and `Principal`, which are unrelated. That pass was reverted. Two cases handled by hand: one `Nat64.fromNat` appears in prose rather than a fence (`ledgers.mdx`), and one fence is a fragment with no import block of its own, so it gets the call change without an import. ## icp-cli v1.1.0 → v1.3.0: nothing lost, two commands that never existed (#361) The decisive check is that **`docs/reference/cli.md` lost 0 lines** between the two refs (14 added, all for the new `icp canister link`). No documented command or flag disappeared, so the bump itself is safe. Verifying every `icp` invocation in `docs/` against that reference then surfaced two commands that do not exist. Both confirmed against the installed v1.3.0, not just the reference: | In the docs | Actual | Sites | |---|---|---| | `icp canister id <name>` | `icp canister status <name> -i` (`-i` is documented as "Only print the canister ids") | 4 | | `icp identity whoami` | `icp identity principal` | 1 | These predate the bump. They are exactly what the verification pass deferred in #354 was for. ## The remaining eight - **Four recipes** (#366, #367, #368, #369) each shipped **one identical additive change**, an optional `visibility` field on metadata entries, so the `icp.yaml` examples stay valid and only the 20 version strings move: `asset-canister` v2.2.1→v2.3.0 (10 places), `rust` v3.3.0→v3.4.0 (6), `motoko` v5.0.0→v5.1.0 (3), `prebuilt` v2.0.0→v2.1.0 (1). - **icp-js-core v5.4.0 → v6.1.0** (#364) is a major bump, and still pin-only for us. It changes `Agent.readState`, delegation permissions, effective subnet ID and URL path handling. Our examples import `agent`, `agent/canister-env`, `principal`, `identity` and `candid` only, never construct a `Delegation`, and never call `readState`. - **cdk-rs 0.20.2** (#363) only makes entry points lenient about an empty input vector. Pin-only. - **icp-js-canisters 3.6.0** (#365) adds NNS converter fields and snapshot visibility; the stated `>= 3.5.0` minimum still holds. Pin-only. - **examples** (#360) bumped to `42c474d`, with all six `snippet=` regions verified to resolve. ## Watcher fix: report an examples bump only when it touches a quoted file Running the batch showed #360 was noise, and the first attempt at fixing that was wrong in an instructive way. I dropped the check entirely, reasoning that the build already fails when a `snippet=` path or `#region` marker stops resolving. It does, but that only covers **breakage**. It cannot see an example being **corrected upstream while still resolving**, which leaves the docs quoting old code with a green build. That is the more valuable signal, and dropping the check would have lost it. So the check stays and gets precise. The entry carries `pathFilter: "snippets"`, and the check intersects the files changed between the pinned gitlink and the branch head with every file a `snippet=` quotes, opening an issue only when they overlap, naming the files. Verified both ways against real history: | Pin | Range | Result | |---|---|---| | `01edb5d8`, before a fix to the two `send_http_*` examples | 5 commits, 80 files | **reports**, naming `motoko/send_http_get/backend/main.mo` and `motoko/send_http_post/backend/main.mo` | | `b4fe175`, the pin this PR bumps from | 4 commits, 78 files, none quoted | **silent** | The second row is the point: #360 fired for a range touching nothing the docs quote, and would not fire now. Two implementation details worth a look. The snippet path is `<lang-dir>/<attribute>`, where the directory comes from the **fence language**, so `LANG_TO_DIR` is mirrored from `plugins/remark-snippet.mjs` rather than imported, because that plugin pulls in remark dependencies and the workflow installs none. The two must be kept in step, and an unmapped language throws rather than silently matching fewer files. Separately, when the comparison cannot be trusted, the API failing or truncating at its 300-file cap, the check reports instead of assuming nothing moved. The per-recipe split from #358 is unchanged. A batch release produces one issue per recipe, four here for a single upstream change. That is the cost of tracking them independently, and it is what made four stale version strings visible. ## Verification ``` npm run check:upstream # every entry current, exits 0 npm run build # passes npm run validate # 7 errors, unchanged from main ``` The 7 are all in `docs/references/internet-identity-spec.md`, which is generated. They clear when Internet Identity cuts its next dated release containing [dfinity/internet-identity#4284](dfinity/internet-identity#4284); our pin is already on the newest existing release tag, so there is nothing to sync until then. Tracked in #356. ## Known limits - The two CLI command fixes are verified against `icp 1.3.0` locally and against the published reference, but not executed end to end against a live project. - `snippet=` coverage depends on `LANG_TO_DIR` staying in step with the plugin. The two now match key for key, verified by parsing both maps rather than reading them, and an unmapped language fails loudly, which is the safe direction. It is still a duplicated constant: the plugin cannot be imported here because it pulls in remark dependencies the workflow does not install.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cli.internetcomputer.orglinks from the1.1slug to1.3(14 files)/1.3/Verification
All 16 distinct URLs return 200 at
/1.3/, and all 7 deep-link anchors were confirmed present in the live 1.3 pages (icp-canister-logs,icp-canister-settings-update,icp-cycles,icp-token-allowance,icp-token-approve,canister-ids,networks).npm run buildpasses.Follow-ups
The
AGENTS.mdlinking rule still names1.1as the current slug and derives it from the pinned icp-cli release. That rule change, and the.sources/icp-clipin itself (still v1.1.0), are covered by #355.Merge order
These three are independent in intent but share one file, so they have a preferred order: #354, then #357, then #358.
validate --allviolationsscripts/validate.js,data-persistence.mdx,chain-key-tokens.mdx; no overlap with the other two. Merging it here dropsvalidate --allonmainfrom 11 errors to 7..sources/reductiondocs/guides/canister-management/lifecycle.mdxwith #354 (different lines: a CLI link there, a stale.sources/pointer here). Last means at most one rebase, on a cleaner validate baseline.The remaining 7 errors after #357 are all in
docs/references/internet-identity-spec.md, which is generated bysync-ii-spec.mjs. They clear when dfinity/internet-identity#4284 merges and the next spec sync runs; that PR is independent of the order here.