Skip to content

docs: sync content against the ten upstream releases the watcher surfaced - #370

Merged
marc0olo merged 7 commits into
mainfrom
docs/upstream-sync-2026-08
Aug 27, 2026
Merged

docs: sync content against the ten upstream releases the watcher surfaced#370
marc0olo merged 7 commits into
mainfrom
docs/upstream-sync-2026-08

Conversation

@marc0olo

@marc0olo marc0olo commented Aug 27, 2026

Copy link
Copy Markdown
Member

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

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; 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.

…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.
@marc0olo
marc0olo requested a review from a team as a code owner August 27, 2026 17:15
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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 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.fromX calls (and related conversions) with the upstream-recommended toX APIs.
  • Replace invalid icp CLI invocations in docs (for example, icp canister id <name>icp canister status <name> -i, and icp identity whoamiicp identity principal).
  • Bump watched upstream pins in .sources/upstream.json and 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.

Comment thread scripts/check-upstream-releases.mjs
Comment thread docs/guides/chain-fusion/exchange-rates.mdx
Comment thread scripts/check-upstream-releases.mjs Outdated
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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 examples gets no issue, but the table states examples gets 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.json includes a reference URL for the vendored examples entry, 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 import Nat (it imports Nat32/Nat64 only). Readers copying the snippets into the same module will hit an unresolved identifier error unless they add import 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.
@marc0olo

Copy link
Copy Markdown
Member Author

The three suppressed comments in review 5043989084 are all correct and fixed in abb8f3c. They have no threads to reply in, so this covers them.

.agents/upstream-tracking.md: the paragraph contradicted the table. The table row says examples gets an issue only when a quoted file moved; the paragraph below still said examples and reference both get no issue. The paragraph predates the path filter and never caught up. It now states the actual behaviour: watched repos get an issue whenever they move, examples only when the range touched a file a snippet= quotes, reference repos are not checked.

Vendored issue bodies dropped the reference URL. Only checkOne emitted the "Published reference" row, so the field on the examples entry looked configured but was silently ignored. checkVendored now emits the same row. Verified by forcing a report:

| Compare | https://github.com/dfinity/examples/compare/01edb5d8...42c474dd |
| Published reference | https://github.com/dfinity/examples |

exchange-rates.mdx needed the Nat import. This is the sharpest of the three. The page's full example imported Cycles, Float, Int, Nat32 and Nat64, and the fragment further down now calls Nat.toNat64, so a reader assembling both into one module hits an unresolved identifier. My own PR body noted that fragment as "handled deliberately", which was true of the fragment in isolation and missed the page as a whole: the fragment is meant to go into that actor. The example now imports Nat.

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. npm run check:upstream exits 0, build passes, validate unchanged at 7 (the generated II spec).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread .sources/upstream.json
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.
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.

chore: submodule examples is behind dfinity/examples@master

3 participants