docs: sync content against the ten upstream releases the watcher surfaced - #370
Conversation
…aced Closes the first batch of upstream-sync issues. Two of the ten needed real content changes; the rest were version strings or pin bumps. motoko-core v2.4.0 -> v2.6.1 deprecated every `Module.fromX` conversion that has a `toX` counterpart, and our Motoko examples used five of them across 20 call sites. Each replacement is the one named in the upstream @deprecated marker: Nat64.fromNat -> Nat.toNat64 Blob.fromArray -> Array.toBlob Nat8.fromNat -> Nat.toNat8 Float.fromInt -> Int.toFloat Text.fromChar -> Char.toText Imports were added where a replacement needs a module the block did not import. No import was removed: an unused one is harmless, a missing one does not compile, and the pre-existing imports are not this change's business. icp-cli v1.1.0 -> v1.3.0 removed nothing from docs/reference/cli.md (0 lines removed, 14 added for `icp canister link`), so no documented flag disappeared. Verifying every command against the reference did surface two that never existed, both against the installed v1.3.0: icp canister id <name> -> icp canister status <name> -i (-i prints ids only) icp identity whoami -> icp identity principal The four recipe releases are one additive change each, an optional `visibility` field on metadata entries, so the icp.yaml examples stay valid and only the version strings move. icp-js-core's major bump touches Agent.readState, Delegation permissions, effective subnet ID and URL paths, none of which our examples use: they import agent, agent/canister-env, principal, identity and candid only. cdk-rs 0.20.2 only makes entry points lenient about empty input. icp-js-canisters 3.6.0 adds NNS converter fields and snapshot visibility, and the stated minimum of 3.5.0 still holds. examples is bumped to 42c474d with all six snippet regions verified to resolve.
Running the first batch showed the examples check earning nothing. The only thing a bump can break is a snippet= path or a #region marker, and plugins/remark-snippet.mjs fails the build on either, verified by renaming a region and watching the build fail. A bump that breaks nothing needs no doc change, so an issue per upstream commit on an active repo is pure noise. It moves to the reference group with that reasoning recorded. The vendored group stays in the schema for a submodule that has no check of its own; it is empty today, since motoko and internetidentity have their own sync workflows.
Dropping the examples check entirely was the wrong call. The build catches a snippet= path or #region marker that stops resolving, but it cannot see the case that matters more: an example the docs quote gets corrected upstream, still resolves, and the docs keep showing the old code with a green build. The vendored check now compares the pinned gitlink against the branch head, asks the compare API which files moved, and intersects that with every file quoted by a snippet= in docs/. An unrelated commit on an active repo stays silent; a commit touching a quoted file opens an issue naming the files. Verified both ways against real history. Pinned at 01edb5d8, which precedes a fix to the send_http_get and send_http_post examples, it reports and names motoko/send_http_get/backend/main.mo and motoko/send_http_post/backend/main.mo. Pinned at b4fe175, where the 78 files in the range touch none of the four quoted files, it stays silent. The snippet path is <lang-dir>/<attribute>, where the directory comes from the fence language, so the language map from plugins/remark-snippet.mjs is mirrored here; that plugin cannot be imported because it pulls in remark dependencies the workflow does not install. An unmapped language throws rather than silently matching fewer files. If the comparison cannot be trusted, the API failing or truncating at its 300-file cap, the check reports instead of assuming nothing moved.
There was a problem hiding this comment.
Pull request overview
This PR syncs ICP Developer Docs content and upstream tracking metadata against the latest upstream releases surfaced by the watcher, including updating copied code snippets to avoid newly deprecated mo:core conversions and tightening the examples submodule drift signal to only report changes that affect quoted snippets.
Changes:
- Update Motoko code examples to replace deprecated
Module.fromXcalls (and related conversions) with the upstream-recommendedtoXAPIs. - Replace invalid
icpCLI invocations in docs (for example,icp canister id <name>→icp canister status <name> -i, andicp identity whoami→icp identity principal). - Bump watched upstream pins in
.sources/upstream.jsonand refine the upstream-check script to filter examples submodule alerts to only snippet-quoted files.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/check-upstream-releases.mjs | Adds snippet-quoted-file filtering for the vendored examples check and updates vendored checking behavior. |
| docs/references/application-canisters.md | Bumps asset-canister recipe version to the latest watched release. |
| docs/guides/security/data-integrity-and-authenticity.md | Updates Motoko snippet conversions to non-deprecated mo:core APIs (adds needed imports). |
| docs/guides/governance/testing.md | Replaces icp canister id usage with icp canister status -i for controller/CID extraction. |
| docs/guides/frontends/frameworks.md | Bumps asset-canister recipe versions across framework examples. |
| docs/guides/frontends/asset-canister.md | Bumps asset-canister and rust recipe versions in icp.yaml examples. |
| docs/guides/digital-assets/ledgers.mdx | Updates deprecated Motoko conversions and adds required imports. |
| docs/guides/digital-assets/chain-key-tokens.mdx | Updates deprecated Motoko conversions in snippets. |
| docs/guides/chain-fusion/exchange-rates.mdx | Updates deprecated float conversions and timestamp conversion in Motoko examples. |
| docs/guides/chain-fusion/ethereum.mdx | Updates deprecated Text.fromChar usage to Char.toText and bumps Motoko recipe version. |
| docs/guides/chain-fusion/chain-fusion-signer.md | Fixes icp-cli identity command to the correct subcommand. |
| docs/guides/chain-fusion/bitcoin.mdx | Updates deprecated Motoko conversions and adds required imports. |
| docs/guides/canister-management/reproducible-builds.md | Bumps prebuilt recipe version in an icp.yaml example. |
| docs/guides/canister-management/optimization.md | Bumps rust recipe version in an icp.yaml example. |
| docs/guides/canister-management/logs.md | Bumps rust recipe version in an icp.yaml example. |
| docs/guides/canister-management/large-wasm.md | Bumps rust recipe version in an icp.yaml example. |
| docs/guides/canister-calls/inter-canister-calls.mdx | Replaces icp canister id usage with icp canister status -i. |
| docs/guides/canister-calls/candid.mdx | Bumps Motoko and Rust recipe versions in icp.yaml examples. |
| docs/getting-started/project-structure.mdx | Bumps Motoko/Rust/asset-canister recipe versions in intro examples. |
| AGENTS.md | Updates upstream-check description for examples to reflect snippet-quoted-file filtering. |
| .sources/upstream.json | Bumps watched pins and adds pathFilter: "snippets" for the examples vendored entry. |
| .agents/upstream-tracking.md | Updates tracking procedure docs to reflect the new examples-reporting policy. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Addresses the Copilot review on #370. LANG_TO_DIR omitted the typescript and ts entries the plugin has, so a docs page using a ts snippet fence would have thrown 'unmapped language' even though the build resolves it. No page uses one today, which is why it was latent, and the comment above it already promised the two would be kept in step. They now match exactly. The header still said the vendored group was empty, written when it was, and not updated when the examples entry came back with pathFilter.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 23 changed files in this pull request and generated no new comments.
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
.agents/upstream-tracking.md:21
- The paragraph below the table contradicts the table: it says
examplesgets no issue, but the table statesexamplesgets a release issue when a quoted file moved. This makes the procedure ambiguous for maintainers.
`motoko` and `internetidentity` have their own weekly sync workflows that open
the bump PR directly. The `watched` repos are covered by the weekly **Upstream
release check**, which opens an issue. `examples` and the `reference` repos get
no issue.
scripts/check-upstream-releases.mjs:286
.sources/upstream.jsonincludes areferenceURL for the vendoredexamplesentry, but vendored issue bodies currently never show it (only watched repos include a "Published reference" row). Surfacing the reference for vendored entries would make the output consistent and avoid a seemingly-unused config field.
const body = [
`The \`${path}\` submodule is behind \`${repo}@${branch}\`.`,
'',
'| | |',
'|---|---|',
`| Pinned (gitlink) | \`${pinned}\` |`,
`| Branch head | \`${latest}\` |`,
`| Compare | https://github.com/${repo}/compare/${pinnedSha}...${headSha} |`,
'',
docs/guides/chain-fusion/exchange-rates.mdx:202
- This snippet now uses
Nat.toNat64(...), but the earlier Motoko example in this page does not importNat(it importsNat32/Nat64only). Readers copying the snippets into the same module will hit an unresolved identifier error unless they addimport Nat "mo:core/Nat";.
```motoko
let oneMinuteAgo : Nat64 = (Nat.toNat64(Int.abs(Time.now())) / 1_000_000_000) - 60;
The tracking doc's table said examples gets an issue when a quoted file moved while the paragraph below it said examples gets no issue; the paragraph was written before the path filter and never caught up. Vendored issue bodies dropped the entry's reference URL, so the field looked configured but unused. They now carry the same Published reference row watched bodies do. exchange-rates.mdx has a fragment that now calls Nat.toNat64 while the page's full example imported Nat32 and Nat64 but not Nat, so a reader assembling both into one module would hit an unresolved identifier. The example imports Nat.
|
The three suppressed comments in review 5043989084 are all correct and fixed in
Vendored issue bodies dropped the
That third one is worth calling out as a real gap in how I checked this: the import audit ran per code fence, and the page is the unit a reader actually copies from. All three earlier inline comments remain replied to and resolved. |
The AGENTS.md rule requiring a versioned cli.internetcomputer.org slug governs docs/ pages, which is where the validator enforces it. The reference field is the opposite case: an issue exists because a new release shipped, so a maintainer opening it wants that release's docs, not the pinned version's. A hardcoded slug would point at the version being replaced and would need bumping in every sync PR. Every other reference value already follows that convention, including two docs.rs/latest URLs. The exception is now stated in the schema comment so it is a decision rather than something to re-flag.
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
@deprecatedmarker, quoted below.icp canister status <name> -ireplacingicp canister id <name>. This is a real command substitution, verified against the installed CLI, not a rename.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.fromXconversion that has atoXcounterpart. 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 fromsrc/*.moat v2.6.1:@deprecatedtextNat64.fromNatNat.toNat64instead.Nat8.fromNatNat.toNat8instead.Blob.fromArrayArray.toBlobinstead.Float.fromIntInt.toFloatinstead.Text.fromCharChar.toTextinstead.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, droppingTextwherehex.chars()still needs it in scope for contextual dot, plusCyclesandPrincipal, which are unrelated. That pass was reverted.Two cases handled by hand: one
Nat64.fromNatappears 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.mdlost 0 lines between the two refs (14 added, all for the newicp canister link). No documented command or flag disappeared, so the bump itself is safe.Verifying every
icpinvocation indocs/against that reference then surfaced two commands that do not exist. Both confirmed against the installed v1.3.0, not just the reference:icp canister id <name>icp canister status <name> -i(-iis documented as "Only print the canister ids")icp identity whoamiicp identity principalThese predate the bump. They are exactly what the verification pass deferred in #354 was for.
The remaining eight
visibilityfield on metadata entries, so theicp.yamlexamples stay valid and only the 20 version strings move:asset-canisterv2.2.1→v2.3.0 (10 places),rustv3.3.0→v3.4.0 (6),motokov5.0.0→v5.1.0 (3),prebuiltv2.0.0→v2.1.0 (1).Agent.readState, delegation permissions, effective subnet ID and URL path handling. Our examples importagent,agent/canister-env,principal,identityandcandidonly, never construct aDelegation, and never callreadState.>= 3.5.0minimum still holds. Pin-only.42c474d, with all sixsnippet=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#regionmarker 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 asnippet=quotes, opening an issue only when they overlap, naming the files.Verified both ways against real history:
01edb5d8, before a fix to the twosend_http_*examplesmotoko/send_http_get/backend/main.moandmotoko/send_http_post/backend/main.mob4fe175, the pin this PR bumps fromThe 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, soLANG_TO_DIRis mirrored fromplugins/remark-snippet.mjsrather 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
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; our pin is already on the newest existing release tag, so there is nothing to sync until then. Tracked in #356.Known limits
icp 1.3.0locally and against the published reference, but not executed end to end against a live project.snippet=coverage depends onLANG_TO_DIRstaying 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.