diff --git a/.claude/skills/release-docs/SKILL.md b/.claude/skills/release-docs/SKILL.md index 315e7a2c200..73c1561a198 100644 --- a/.claude/skills/release-docs/SKILL.md +++ b/.claude/skills/release-docs/SKILL.md @@ -48,9 +48,14 @@ paste the key into the conversation or onto a command line. `BB` once provisioned). In the cut that is the release tag's. - **The cut runs in its own worktree** (`$CUT`), created from the destination commit; it moves the cut's pin to the Labs tag. The destination checkout is not touched until Step 17, - and its pin never moves: the destination's dev docs keep following their own pin, a v6 - nightly until the docs carry a separate v7 line (`docs/CLAUDE.md`). A v6.x cut pins its - tag on aztec-node's `v6` branch (Step 12). + and its pins never move: the destination's dev docs keep following their own + (`docs/CLAUDE.md`, "Two dev lines: change both"). +- **A line cut.** A release whose major has a dev line (`docs/lines/v/`: a v6.x + release while `docs/lines/v6/` exists) is cut from that line, on its tag on aztec-node's + `v` branch. Step 2c promotes the line into the cut's main paths + (`docs/scripts/promote_line.sh`), so every later step reads the line's pages and pin + there; its examples stay in `docs/lines/v/examples/` (`$EXAMPLES`), which its pages + quote. Any other release is cut from main's pages. - **Release inputs**, recorded in the commit that lands the cut (Step 17): | Input | Source | @@ -62,15 +67,17 @@ paste the key into the conversation or onto a command line. | Destination | the branch and commit the cut started from | - **Snippet links.** Snippets under `labs/` link to aztec-node at the pinned commit; snippets - from `docs/examples/` link to this repository at `DOCS_COMMIT`, which a release build - requires (`include_code.js` refuses to preprocess a `RELEASE_TYPE` other than `nightly` - without it). The cut never changes `docs/examples/`, so those links show the lines the + from the examples (`$EXAMPLES`: `docs/examples/`, or a line cut's + `docs/lines//examples/`) link to this repository at `DOCS_COMMIT`, which a release + build requires (`include_code.js` refuses to preprocess a `RELEASE_TYPE` other than + `nightly` without it). The cut never changes them, so those links show the lines the snapshot quotes. - **Examples build from the pin.** `docs/examples/bootstrap.sh` builds them with the pin's published toolchain against the default checkout, `docs/.aztec-node/tree`, which their Nargo.toml path dependencies name; it ignores `AZTEC_NODE_DIR`. In the cut that is a second checkout of the tag's commit, so the examples the snapshot quotes build and run - at the tag (Step 15). + at the tag (Step 15). A line cut builds the line's examples in a staged copy instead + (`examples/bootstrap.sh --line `). - **State** lives in `~/.cache/aztec-docs-cut//`: `env.sh` (sourced by every command block from Step 2 on, since shell state does not carry over between commands), the worktree, the CLI's home, the local network and logs. `` is `v`; @@ -166,16 +173,23 @@ grep -rlE '#if\((devnet|testnet|mainnet|nightly)\)' docs/docs-developers/ docs/d Then set each other type's `` in `docs_env` (2b) to the version its network reports in Step 1, and run Step 11b's `update_docs_versions.sh` once per type. +A version both networks read serves its API reference from `mainnet/`, but Step 6 and +`#api_ref_version` use the rendered type's folder, so a shared snapshot rendered as testnet +fails Step 13's agent readiness check. Until that is supported, offer the owner a mainnet +rendering only. + ### Step 2: Prepare the Cut Worktree #### 2a. The Labs tag must exist ```bash -git ls-remote --exit-code --tags https://github.com/aztec-labs-eng/aztec-node.git refs/tags/v +git ls-remote --exit-code --tags https://github.com/aztec-labs-eng/aztec-node.git \ + "refs/tags/v" "refs/tags/v^{}" ``` **Abort if it exits non-zero**: the release has not been tagged. Ask aztec-node's remote, -never this repository, whose `v6…` tags are unrelated. +never this repository, whose `v6…` tags are unrelated. A release tag prints its commit; an +annotated tag (nightlies are) prints the tag object and, on its `^{}` line, the commit. #### 2b. Record the destination @@ -188,9 +202,16 @@ git diff --quiet --ignore-submodules=all && git diff --cached --quiet --ignore-s || { echo "commit or discard the changes first" >&2; exit 1; } git fetch origin next DOCS_COMMIT=$(git merge-base HEAD origin/next) -git diff --quiet "$DOCS_COMMIT" HEAD -- docs/examples \ - || { echo "docs/examples differs from origin/next: land those changes on next first" >&2; exit 1; } LABS_TAG=v +major=${LABS_TAG#v} major=${major%%.*} +LINE= EXAMPLES=docs/examples PINFILE=docs/aztec-node.json +if [ -f "docs/lines/v$major/aztec-node.json" ]; then + LINE=v$major EXAMPLES=docs/lines/v$major/examples PINFILE=docs/lines/v$major/aztec-node.json +fi +node -p "require('./$PINFILE').ref" | grep -q "^v$major\." \ + || { echo "no dev docs follow v$major: neither main's pin nor a line (docs/lines/v$major/)" >&2; exit 1; } +git diff --quiet "$DOCS_COMMIT" HEAD -- "$EXAMPLES" \ + || { echo "$EXAMPLES differs from origin/next: land those changes on next first" >&2; exit 1; } CUT_ID= STATE=$HOME/.cache/aztec-docs-cut/$CUT_ID ! git show-ref --verify -q "refs/heads/docs-cut/$CUT_ID" && mkdir -p "${STATE%/*}" && mkdir "$STATE" \ @@ -207,7 +228,9 @@ CLI_HOME=$CLI_HOME DEST_ROOT=$(pwd) DEST=$(git rev-parse HEAD) DEST_BRANCH=$(printf %q "$(git branch --show-current)") -DEST_PIN_REF=$(node -p 'require("./docs/aztec-node.json").ref') +LINE=$LINE +EXAMPLES=$EXAMPLES +DEST_PIN_REF=$(node -p "require('./$PINFILE').ref") DOCS_COMMIT=$DOCS_COMMIT export AZTEC_NODE_DIR=$STATE/aztec-node CLI_PATH=$CUT/docs/.aztec-node/cli/node_modules/.bin:$CUT/docs/.aztec-node/bin:$STATE/aztec-node/aztec-up/bin/0.0.1 @@ -219,8 +242,9 @@ docs_env() { } aztec_cli() { [ -x $CUT/docs/.aztec-node/cli/node_modules/.bin/aztec ] || { echo "no release CLI: run Step 3" >&2; return 1; } - env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u NARGO_HOME -u AZTEC_HOME \\ - -u ANVIL_BIN -u FORGE_BIN -u CAST_BIN HOME=$CLI_HOME PATH=\$CLI_PATH:\$PATH "\$@" + env -u ANVIL_BIN -u FORGE_BIN -u CAST_BIN HOME=$CLI_HOME NARGO_HOME=$CLI_HOME/.nargo AZTEC_HOME=$CLI_HOME/.aztec \\ + XDG_CONFIG_HOME=$CLI_HOME/.config XDG_DATA_HOME=$CLI_HOME/.local/share XDG_CACHE_HOME=$CLI_HOME/.cache \\ + PATH=\$CLI_PATH:\$PATH "\$@" } EOF ``` @@ -235,8 +259,10 @@ own home, and `CLI_PATH` first on `PATH`; Step 15 sets `CLI_PATH=$INSTALLER_PATH the installer's layout instead. `COMMIT_TAG` keeps its `v`: `#include_aztec_version` emits it as a git ref, and `#include_version_without_prefix` falls back to `latest` when it lacks one. -`DOCS_COMMIT` is the destination's base on `origin/next`, and the check above proves the -destination's `docs/examples/` equals it, so links to it resolve and show the snapshot's +`LINE` names the dev line a line cut promotes, and is empty for a cut of main's pages; +`DEST_PIN_REF` is the pin of the pages the cut starts from. `DOCS_COMMIT` is the +destination's base on `origin/next`, and the check above proves the destination's examples +(`$EXAMPLES`) equal it, so links to it resolve and show the snapshot's lines. `AZTEC_NODE_DIR` puts the cut's checkout outside the worktree: nargo run anywhere under `docs/` takes `docs/Nargo.toml` as its workspace, and nothing run in the checkout (2d, Step 6) may see it. @@ -249,6 +275,26 @@ git -C "$DEST_ROOT" worktree add -b "docs-cut/$CUT_ID" "$CUT" "$DEST" cd "$CUT/docs" && node scripts/aztec_node.mts pin "$LABS_TAG" ``` +**A line cut** (`$LINE` set) promotes the line instead of running that `pin`: + +```bash +. ~/.cache/aztec-docs-cut//env.sh && cd "$CUT/docs" +CUT=$CUT scripts/promote_line.sh "$LINE" "$LABS_TAG" && + git -C "$CUT" add -- docs && git -C "$CUT" commit -q -m "docs: promote the $LINE line at $LABS_TAG" && + node scripts/aztec_node.mts fetch +``` + +`promote_line.sh` refuses, before writing anything, unless it runs in `$CUT`, `docs/` is +clean, and the tag has the line's major. Then it pins the line to the tag +(`aztec_node.mts --line $LINE pin`, which also installs the line's l1-artifacts), and +refuses, restoring the line's pin, unless the pinned commit is on aztec-node's `$LINE` branch. +Only then does it replace `docs-developers/`, `docs-operate/` and both sidebars with the +line's, and copy the line's pin over `docs/aztec-node.json`. That promotion commit is +release-only (Step 17). `fetch` then checks main's checkout out at that pin and reports the +same drift as `pin` below. The promotion commit already carries the pin, so the pin commit +below has something to commit only when l1-artifacts drifted; otherwise `PINNED` is the +promotion commit. + `pin` checks the tag's commit out into `$AZTEC_NODE_DIR` (a shallow clone without aztec-node's own `docs/`), writes the commit and the tag's `BB_VERSION` and `NOIR_VERSION` into `docs/aztec-node.json`, then prints every remaining drift with its fix and exits 1 @@ -269,7 +315,8 @@ node -e ' yarn install node scripts/aztec_node.mts provision nargo bb node scripts/aztec_node.mts check -git add aztec-node.json package.json yarn.lock && git commit -m "docs: pin aztec-node $LABS_TAG" +git add aztec-node.json package.json yarn.lock && + { git diff --cached --quiet || git commit -m "docs: pin aztec-node $LABS_TAG"; } echo "PINNED=$(git rev-parse HEAD)" >>"$STATE/env.sh" ``` @@ -323,7 +370,7 @@ yet run by a cut): `cd "$AZTEC_NODE_DIR" && env -u root -u ci3 AZTEC_TOOLCHAIN_F node scripts/aztec_node.mts check && echo "pin: ok" docs_env sh -c 'echo "$AZTEC_NODE_REF $AZTEC_NODE_COMMIT DOCS_COMMIT=$DOCS_COMMIT"; "$NARGO" --version; "$BB" --version' node -p 'require("./node_modules/@aztec-foundation/l1-artifacts/package.json").version' -git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- docs/examples && echo "examples: ok" +git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- "$EXAMPLES" && echo "examples: ok" ``` All of these must hold; stop at the first that does not: @@ -332,10 +379,10 @@ All of these must hold; stop at the first that does not: file, the pin's bb and noir equal the tag's `BB_VERSION` and `NOIR_VERSION`, and `docs/package.json`'s l1-artifacts equals `BB_VERSION`. - `AZTEC_NODE_REF` is `v` and `AZTEC_NODE_COMMIT` is the commit 2a's - `ls-remote` printed. `NARGO` and `BB` are set (`env` exports them only once provisioned at + `ls-remote` printed (its `^{}` line for an annotated tag). `NARGO` and `BB` are set (`env` exports them only once provisioned at the pinned versions) and print `nargo version = $NOIR_VERSION` and `$BB_VERSION`. - The installed l1-artifacts version equals `BB_VERSION`. -- `examples: ok`: the cut's `docs/examples/` is `DOCS_COMMIT`'s. +- `examples: ok`: the cut's examples (`$EXAMPLES`) are `DOCS_COMMIT`'s. ### Unversioned root pages @@ -578,16 +625,17 @@ aztec-node marks breaking changes only with the conventional-commit `!`, never a body of port commits (`chore: port … from monorepo`), which list the breaking commits they carry: read those bodies too. -**2. Locate candidate usages.** For each triple, grep the cut's source docs: +**2. Locate candidate usages.** For each triple, grep the cut's source docs and the examples +its pages quote (`$EXAMPLES`): ```bash -cd ~/.cache/aztec-docs-cut//worktree/docs -grep -rn "" docs-developers/ docs-operate/ docs-participate/ docs/ examples/ +. ~/.cache/aztec-docs-cut//env.sh && cd "$CUT/docs" +grep -rn "" docs-developers/ docs-operate/ docs-participate/ docs/ "${EXAMPLES#docs/}/" ``` Prioritize surfaces with no compiler gate: hand-written code blocks (most of them in `docs-developers/docs/aztec-nr/` and `docs-operate/`), prose that names functions or flags, -and install or CLI commands. A hit in an `#include_code` target or `docs/examples/` usually +and install or CLI commands. A hit in an `#include_code` target or the examples usually means the build already fails; treat those as cross-checks. **3. Adjudicate every candidate; do not fix from grep hits alone.** A symbol grep is noisy @@ -800,21 +848,24 @@ of a major the page usually lands after the tag. . ~/.cache/aztec-docs-cut//env.sh major=$({ jq -r '."."' "$AZTEC_NODE_DIR/.version-manifest.json" 2>/dev/null || jq -r '."."' "$AZTEC_NODE_DIR/.release-please-manifest.json"; } | cut -d. -f1) -git -C "$DEST_ROOT" show "$DEST:docs/docs-operate/operators/reference/changelog/v$major.md" >/dev/null \ +src=docs${LINE:+/lines/$LINE} +git -C "$DEST_ROOT" show "$DEST:$src/docs-operate/operators/reference/changelog/v$major.md" >/dev/null \ && echo "page present" || echo "MISSING: v$major.md" -git -C "$DEST_ROOT" show "$DEST:docs/docs-operate/operators/reference/changelog/index.md" | grep -n '^### ' | head -3 -git -C "$DEST_ROOT" show "$DEST:docs/sidebars-operate.js" | grep -n "changelog/v$major" +git -C "$DEST_ROOT" show "$DEST:$src/docs-operate/operators/reference/changelog/index.md" | grep -n '^### ' | head -3 +git -C "$DEST_ROOT" show "$DEST:$src/sidebars-operate.js" | grep -n "changelog/v$major" ``` The major is the Labs version, read from the manifest in the checkout; the root manifest versions the Foundation. aztec-node renamed that file, so the command reads whichever name the -pinned commit carries. +pinned commit carries. A line cut checks the line's copy (`$src`), which it promoted. All three must hold: 1. The page exists (a major with several releases may use a minor-qualified name such as `v5.2.md`; check that name). 2. `index.md` has a `### ` entry for this release's major (and minor, once the series has - more than one); an rc or patch is covered by its minor's entry. + more than one); an rc or patch is covered by its minor's entry, and a nightly by its + major's page. A minor release such as `6.1.0` needs its `### [v6.1.x]` entry landed + first. 3. `docs/sidebars-operate.js` lists the page; an unlisted page is published but has no nav entry. @@ -829,7 +880,7 @@ only into the cut. `docs:version` snapshots `processed-docs/` (the resolved tree the docs plugins serve), not the raw `docs-*` source, so preprocess first with every release variable. Snippets under `labs/` resolve against the cut's checkout (the tag) and the rest against the cut's -`docs/examples/` (`DOCS_COMMIT`'s). A snippet whose file or marker the tag lacks fails +examples (`$EXAMPLES`, `DOCS_COMMIT`'s). A snippet whose file or marker the tag lacks fails preprocessing: its page quotes code newer than the release. Edit that page in the cut for the release (a release-only change, Step 17), or stop and ask the owner when it documents a feature the release lacks. @@ -857,7 +908,7 @@ grep -rhoE 'github\.com/AztecProtocol/aztec-packages(/(blob|tree)/[^/)"]+(/[^/)" version (as at `v6.0.0-rc.1`), yet this repository's tag of that name holds no Labs code. - Under `noir-projects/` or `yarn-project/`: Labs code, so in the snapshot it names aztec-node (`https://github.com/aztec-labs-eng/aztec-node`) at the tag. - - Under `docs/examples`: this repository's examples, which the snapshot quotes at + - Under `docs/examples` (a line cut's `docs/lines//examples`): this repository's examples, which the snapshot quotes at `DOCS_COMMIT`. Clone steps are the usual hit: the source clones aztec-packages `next`, and the snapshot's clone must check out `DOCS_COMMIT` after cloning (fix the snapshot after 11b, not the source). @@ -875,11 +926,12 @@ grep -rhoE 'github\.com/AztecProtocol/aztec-packages(/(blob|tree)/[^/)"]+(/[^/)" . ~/.cache/aztec-docs-cut//env.sh && cd "$CUT/docs" docs_env sh -c 'echo "aztec-node: $AZTEC_NODE_COMMIT aztec-packages: $DOCS_COMMIT"' grep -rhoE 'github\.com/aztec-labs-eng/aztec-node/blob/[^/)"]+' processed-docs/ | sort | uniq -c -grep -rhoE 'github\.com/AztecProtocol/aztec-packages/blob/[^/)"]+/docs/examples' processed-docs/ | sort | uniq -c +grep -rhoE 'github\.com/AztecProtocol/aztec-packages/blob/[^/)"]+/docs/(lines/[^/]+/)?examples' processed-docs/ | sort | uniq -c ``` -Every aztec-node link must name `AZTEC_NODE_COMMIT` and every `docs/examples` link -`DOCS_COMMIT`. `include_code.js` writes snippet links with exactly those commits, so any +Every aztec-node link must name `AZTEC_NODE_COMMIT` and every examples link +`DOCS_COMMIT`; in a line cut, the promoted pages' example links name +`docs/lines/$LINE/examples`. `include_code.js` writes snippet links with exactly those commits, so any other ref is a hand-written link: give a moving ref (`main`, `next`) the tag in the snapshot after 11b. @@ -981,12 +1033,9 @@ git -C "$AZTEC_NODE_HISTORY" log --oneline --left-right --cherry-pick --name-onl Skip this step when the two refs name the same commit. `--cherry-pick` drops commits that reached both sides as patch-equivalent ports. A hand backport adapted to its line is not -patch-equivalent and shows on both sides: judge it against `$AZTEC_NODE_DIR`, the tag. A -destination pinned to a v7 nightly would list every v7 commit since `v6` left `main` as -`>`, and once `docs/examples/` use v7-only APIs Step 15 fails for a v6.x cut and stops: no -snapshot edit can fix the examples. That is why the dev pin stays on a v6 nightly -(`docs/CLAUDE.md`); if the destination's pin is a v7 tag, stop and report before cutting. -The history goes into a checkout of its own, fetched afresh +patch-equivalent and shows on both sides: judge it against `$AZTEC_NODE_DIR`, the tag. +`DEST_PIN_REF` is the pin of the pages the cut started from, the line's in a line cut, so +both refs are on one aztec-node branch. The history goes into a checkout of its own, fetched afresh down to the refs' merge base, which GitHub names without local history; fetching it into `$AZTEC_NODE_DIR` instead keeps that checkout's earlier shallow boundaries (the merge base goes missing) and shortens the history Step 8 fetched. The check compares the merge base @@ -1075,8 +1124,16 @@ the Aztec.js examples, which are source-only. Long-running and install-heavy. . ~/.cache/aztec-docs-cut//env.sh && cd "$CUT" pin=$(node docs/scripts/aztec_node.mts env) || exit 1 eval "$pin" - env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u NARGO_HOME -u NARGO -u AZTEC_HOME \ - HOME="$CLI_HOME" NON_INTERACTIVE=1 bash <(curl -fsSL "https://install.aztec.network/$AZTEC_VERSION") + need=$(curl -fsSL "https://install.aztec.network/$AZTEC_VERSION/versions" | sed -n 's/^node: //p') + NODE_BIN= + have=$("$NODE_BIN/node" --version | cut -c2-) + [ -n "$need" ] && [ "$(printf '%s\n' "$need" "$have" | sort -V | head -n1)" = "$need" ] \ + || { echo "the installer needs Node ${need:-?}; $NODE_BIN has $have" >&2; exit 1; } + printf 'NODE_BIN=%q\nINSTALLER_PATH=$INSTALLER_PATH:$NODE_BIN\n' "$NODE_BIN" >>"$STATE/env.sh" + INSTALLER_PATH=$INSTALLER_PATH:$NODE_BIN + env -u NARGO HOME="$CLI_HOME" NARGO_HOME="$CLI_HOME/.nargo" AZTEC_HOME="$CLI_HOME/.aztec" \ + XDG_CONFIG_HOME="$CLI_HOME/.config" XDG_DATA_HOME="$CLI_HOME/.local/share" XDG_CACHE_HOME="$CLI_HOME/.cache" \ + PATH="$NODE_BIN:$PATH" NON_INTERACTIVE=1 bash <(curl -fsSL "https://install.aztec.network/$AZTEC_VERSION") CLI_PATH=$INSTALLER_PATH aztec_cli aztec --version foundry=$(sed -n 's/^ENV FOUNDRY_VERSION=v//p' "$AZTEC_NODE_DIR/build-images/src/Dockerfile") for tool in anvil forge cast; do @@ -1087,11 +1144,21 @@ the Aztec.js examples, which are source-only. Long-running and install-heavy. . "$STATE/network.env" ``` + The installer requires the Node its `versions` file names (`node: 26.12.0` for v6.1 + nightlies; check, never assume). `NODE_BIN` is any directory holding at least that Node, + such as an nvm version's `bin`. It goes first on `PATH` for the installer and, through + `INSTALLER_PATH` (appended to `env.sh`), for every release command of this step, so the + machine's default Node stays as it is: never run `nvm alias default`. The installer + cannot change it either: it looks for nvm under `$HOME`, which is `$CLI_HOME`, and + without a new enough Node it stops with `Minimum Node.js version … not found`. + The CLI must report `AZTEC_VERSION`. The installer runs with `HOME` set to `$CLI_HOME`, - so its node, foundry, nargo and shell-profile edits stay out of the real home. Clearing - `NARGO_HOME` and `AZTEC_HOME` keeps noirup and the toolchain under that home too (with - `NARGO_HOME` set, noirup lands in the real home and the install fails), and clearing - `NARGO` stops the installer from copying that binary in as the release's nargo. + so its node, foundry, nargo and shell-profile edits stay out of the real home. It also + gets `NARGO_HOME`, `AZTEC_HOME` and the XDG directories inside `$CLI_HOME`, set rather + than inherited: noirup's own installer writes to `$NARGO_HOME`, and the release + installer then runs `$HOME/.nargo/bin/noirup`, so a `NARGO_HOME` from the real shell + rewrites the real home's noirup and fails the install. Clearing `NARGO` stops the + installer from copying that binary in as the release's nargo. `NON_INTERACTIVE=1` skips the prompt and the closing `exec $SHELL`. foundryup refuses to install while any `anvil` runs on the host (`'anvil' is currently running`): wait for it to exit, and never stop another run's anvil. The release's L1 deployment needs the @@ -1125,6 +1192,27 @@ the Aztec.js examples, which are source-only. Long-running and install-heavy. `$AZTEC_NODE_URL` in place of its `localhost` URLs. Record drift: renamed commands, changed flags, stale addresses, different output. + - **On the release's publication day**, a fresh project that `yarn init` gives Yarn 4 + refuses the release's packages for their first day (`All versions satisfying … are + quarantined`). Record that against every page that hits it without the + publication-day tip `token_bridge.md` carries. Then, in that walk project only, add + the tip's scoped pre-approval, limited to the tag's own packages, to its `.yarnrc.yml`: + + ```yaml + npmPreapprovedPackages: + - "@aztec-labs/*@" + ``` + + Yarn matches each entry as a package glob plus a version range, so this admits + nothing else. Never turn the gate off (`npmMinimalAgeGate: 0`, + `YARN_NPM_MINIMAL_AGE_GATE`), and never edit the repository's `.yarnrc.yml`. + - **A line cut's tutorials whose project is the line's examples** (they clone this + repository and build under `docs/lines//examples/`) may not build there: nargo + takes `docs/Nargo.toml` as the workspace, as `examples/bootstrap.sh --line` notes. + Walk each one as written first, and record every failure with its doc line. Only then + run its commands in a copy of the `DOCS_LINE_STAGE` stage of item 4, to check the code + itself; a pass there never clears the as-written failure. + 4. **Build and run the Aztec.js examples at the tag**, in the cut, against the local network: ```bash @@ -1133,19 +1221,36 @@ the Aztec.js examples, which are source-only. Long-running and install-heavy. examples/bootstrap.sh compile PATH="$CLI_HOME/.aztec/current/internal-bin:$PATH" examples/bootstrap.sh compile-solidity TXE_PORT= examples/bootstrap.sh test-contracts - docs_env examples/ts/aztecjs_runner/run.sh + PATH="$NODE_BIN:$PATH" docs_env examples/ts/aztecjs_runner/run.sh ``` `examples/bootstrap.sh` provisions the tag's nargo, bb and CLI and fetches its commit into `$CUT/docs/.aztec-node/tree` (Release model), so the circuit and contracts compile and the TXE tests run at the tag (`recursive_verification` reads the circuit's artifact); `compile-solidity` builds the artifacts `example_swap` imports, with the forge item 1 - checked. `run.sh` installs the tag's packages into each example and runs it - against `$AZTEC_NODE_URL`. The examples are the destination's: a failure here means the + checked. `run.sh` installs the tag's packages into each example and runs it, on the + installer's Node, against `$AZTEC_NODE_URL`. The examples are the destination's: a failure here means the snapshot quotes code that does not work at the release. Report it with the example and the error. Never edit `docs/examples/` in the cut (Step 17 refuses it): a fix that also holds at the destination's pin lands on `next` first, and the cut restarts. + **A line cut** builds and runs the line's examples instead, in a staged copy that + `DOCS_LINE_STAGE` keeps across the commands (`examples/bootstrap.sh --line` stages one + outside the repository, since nargo would take `docs/Nargo.toml` as the workspace): + + ```bash + . ~/.cache/aztec-docs-cut//env.sh && . "$STATE/network.env" && cd "$CUT/docs" + export DOCS_LINE_STAGE=$STATE/line-examples + examples/bootstrap.sh --line "$LINE" compile-circuits + examples/bootstrap.sh --line "$LINE" compile + PATH="$CLI_HOME/.aztec/current/internal-bin:$PATH" examples/bootstrap.sh --line "$LINE" compile-solidity + TXE_PORT= examples/bootstrap.sh --line "$LINE" test-contracts + PATH="$NODE_BIN:$PATH" docs_env "$DOCS_LINE_STAGE/examples/ts/aztecjs_runner/run.sh" + ``` + + The line's pin is the tag (Step 2c), so these run at the tag like main's. Never edit + `docs/lines/$LINE/examples/` in the cut either: its fixes land on `next` first. + 5. **Stop the network**, which kills only its process group and releases its ports: ```bash @@ -1254,19 +1359,22 @@ Repeat it for `operate` and ``. ### Step 17: Carry the Results Back to the Destination First check that the destination's `docs/` has not moved since Step 2b, then record the -cut on its branch, check that it left `docs/examples/` as `DOCS_COMMIT` has it (the -snapshot's example links name that commit), and list every change the cut made after its -pin commit (Step 2c): +cut on its branch, check that it left the examples (`$EXAMPLES`) as `DOCS_COMMIT` has them +(the snapshot's example links name that commit), and list every change the cut made after +its pin commit (Step 2c): ```bash . ~/.cache/aztec-docs-cut//env.sh git -C "$DEST_ROOT" diff --quiet "$DEST" -- docs || { echo "destination docs/ moved: restart the cut" >&2; exit 1; } cd "$CUT" && git add -- docs && git commit -m "docs: cut $LABS_TAG" -git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- docs/examples \ - || { echo "the cut changed docs/examples: land the change on next and restart the cut" >&2; exit 1; } +git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- "$EXAMPLES" \ + || { echo "the cut changed $EXAMPLES: land the change on next and restart the cut" >&2; exit 1; } git -C "$CUT" diff --name-status "$PINNED" HEAD -- docs ``` +A line cut's promotion commit precedes `$PINNED`, so the list never shows it: it stays in +the cut. + Sort every listed path into exactly one class: 1. **Release results**, copied per named path. Directories are synced with @@ -1305,8 +1413,23 @@ Sort every listed path into exactly one class: Read the patch before applying it. Never copy a source directory wholesale: the cut's copy carries release-only edits. -3. **Release-only changes** stay in the cut: the pin commit (`docs/aztec-node.json`, - `docs/package.json`, `docs/yarn.lock`), generated source pages (`aztec_js_reference.md`, + In a line cut the cut's `docs-developers/`, `docs-operate/` and sidebars are the line's + pages, so their repairs belong to the destination's `docs/lines/$LINE/`. Write their + patch relative to `docs/` and apply it under the line: + + ```bash + git -C "$CUT" diff --relative=docs "$PINNED" HEAD -- ... >"$STATE/line-repairs.patch" + git -C "$DEST_ROOT" apply -3 --directory="docs/lines/$LINE" "$STATE/line-repairs.patch" + ``` + + A release's migration-notes and operator-changelog entries (Steps 8 and 10b) also go into + main's copies, since readers of the next major upgrade from this release + (`docs/CLAUDE.md`): apply the same hunks to `docs/docs-developers/` and + `docs/docs-operate/`, resolving by hand where main's copy differs. Other repairs reach + main's pages only when the code they describe is the same at main's pin (the same rule). + +3. **Release-only changes** stay in the cut: the promotion and pin commits + (`docs/aztec-node.json`, `docs/package.json`, `docs/yarn.lock`, a line's pin), generated source pages (`aztec_js_reference.md`, the CLI references, `node-api-reference.md`), and source edits that only the release needs (Steps 8b, 11 and 12). The destination keeps its own pin and the pages generated from it. diff --git a/.claude/skills/release-docs/local_network.sh b/.claude/skills/release-docs/local_network.sh index b16833ecc53..86314d5731a 100755 --- a/.claude/skills/release-docs/local_network.sh +++ b/.claude/skills/release-docs/local_network.sh @@ -6,9 +6,10 @@ # local_network.sh start # local_network.sh stop # -# CLI_HOME is the HOME the network runs with, so nothing is written under the real home; CLI_PATH -# (prepended to PATH) holds the release's aztec CLI and the tools it runs. start waits up to READY_TIMEOUT seconds (default 600) for the node to -# report , then writes /network.env (AZTEC_NODE_URL, ETHEREUM_HOST, the ports) +# CLI_HOME is the HOME the network runs with, and holds its NARGO_HOME, AZTEC_HOME and XDG +# directories, so nothing is written under the real home; CLI_PATH (prepended to PATH) holds the +# release's aztec CLI and the Node and tools it runs. start waits up to READY_TIMEOUT seconds +# (default 600) for the node to report , then writes /network.env (AZTEC_NODE_URL, ETHEREUM_HOST, the ports) # for later commands to source; the log is /network.log. set -euo pipefail @@ -119,9 +120,10 @@ function cmd_start { open STDOUT, ">>", $log or die "$log: $!"; open STDERR, ">&", \*STDOUT; exec @ARGV or die "exec: $!"; - ' "$state/network.log" env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u NARGO_HOME -u AZTEC_HOME \ - -u ANVIL_BIN -u FORGE_BIN -u CAST_BIN \ - HOME="$CLI_HOME" PATH="$CLI_PATH:$PATH" \ + ' "$state/network.log" env -u ANVIL_BIN -u FORGE_BIN -u CAST_BIN \ + HOME="$CLI_HOME" NARGO_HOME="$CLI_HOME/.nargo" AZTEC_HOME="$CLI_HOME/.aztec" \ + XDG_CONFIG_HOME="$CLI_HOME/.config" XDG_DATA_HOME="$CLI_HOME/.local/share" XDG_CACHE_HOME="$CLI_HOME/.cache" \ + PATH="$CLI_PATH:$PATH" \ ANVIL_PORT="${ports[2]}" DATA_DIRECTORY="$state/network-data" P2P_ENABLED=false \ aztec start --local-network --port "${ports[0]}" --admin-port "${ports[1]}") with_registry repoint_rows "$run" "$pgid" diff --git a/.claude/skills/release-network-docs/SKILL.md b/.claude/skills/release-network-docs/SKILL.md index dc958c42d8d..38cdb2296f0 100644 --- a/.claude/skills/release-network-docs/SKILL.md +++ b/.claude/skills/release-network-docs/SKILL.md @@ -63,9 +63,14 @@ The rules of `/release-docs` (its "Release model" section) apply unchanged: same name are unrelated Foundation commits. - Toolchain and package versions come from the pin (`node docs/scripts/aztec_node.mts env`). - The cut runs in its own worktree (`$CUT`) created from the destination commit and moves - the cut's pin to the Labs tag; the destination, and its pin, are not touched until Step 10. -- A release build links `docs/examples/` snippets to this repository at `DOCS_COMMIT`, the - destination's base on `origin/next`, and the cut never changes `docs/examples/`. + the cut's pin to the Labs tag; the destination, and its pins, are not touched until Step 10. +- A release whose major has a dev line (`docs/lines/v/`: a v6.x release while + `docs/lines/v6/` exists) is a **line cut**: Step 2c promotes the line into the cut's main + paths (`docs/scripts/promote_line.sh`), and every later step reads the line's operator + pages and pin there (`docs/CLAUDE.md`, "Two dev lines: change both"). +- A release build links example snippets (`$EXAMPLES`: `docs/examples/`, or a line cut's + `docs/lines//examples/`) to this repository at `DOCS_COMMIT`, the destination's base + on `origin/next`, and the cut never changes them. - State lives in `~/.cache/aztec-docs-cut//`, whose `env.sh` every command block from Step 2 on sources. `` is `network-v`, or another name (`dryrun-network-v`) for a rehearsal or a second cut of the same @@ -147,9 +152,16 @@ git diff --quiet --ignore-submodules=all && git diff --cached --quiet --ignore-s || { echo "commit or discard the changes first" >&2; exit 1; } git fetch origin next DOCS_COMMIT=$(git merge-base HEAD origin/next) -git diff --quiet "$DOCS_COMMIT" HEAD -- docs/examples \ - || { echo "docs/examples differs from origin/next: land those changes on next first" >&2; exit 1; } LABS_TAG=v +major=${LABS_TAG#v} major=${major%%.*} +LINE= EXAMPLES=docs/examples PINFILE=docs/aztec-node.json +if [ -f "docs/lines/v$major/aztec-node.json" ]; then + LINE=v$major EXAMPLES=docs/lines/v$major/examples PINFILE=docs/lines/v$major/aztec-node.json +fi +node -p "require('./$PINFILE').ref" | grep -q "^v$major\." \ + || { echo "no dev docs follow v$major: neither main's pin nor a line (docs/lines/v$major/)" >&2; exit 1; } +git diff --quiet "$DOCS_COMMIT" HEAD -- "$EXAMPLES" \ + || { echo "$EXAMPLES differs from origin/next: land those changes on next first" >&2; exit 1; } CUT_ID= STATE=$HOME/.cache/aztec-docs-cut/$CUT_ID ! git show-ref --verify -q "refs/heads/docs-cut/$CUT_ID" && mkdir -p "${STATE%/*}" && mkdir "$STATE" \ @@ -166,29 +178,37 @@ CLI_HOME=$CLI_HOME DEST_ROOT=$(pwd) DEST=$(git rev-parse HEAD) DEST_BRANCH=$(printf %q "$(git branch --show-current)") -DEST_PIN_REF=$(node -p 'require("./docs/aztec-node.json").ref') +LINE=$LINE +EXAMPLES=$EXAMPLES +DEST_PIN_REF=$(node -p "require('./$PINFILE').ref") DOCS_COMMIT=$DOCS_COMMIT export AZTEC_NODE_DIR=$STATE/aztec-node CLI_PATH=$CUT/docs/.aztec-node/cli/node_modules/.bin:$CUT/docs/.aztec-node/bin:$STATE/aztec-node/aztec-up/bin/0.0.1 docs_env() { local pin; pin=\$(node "$CUT/docs/scripts/aztec_node.mts" env) || return 1 eval "\$pin" - COMMIT_TAG=$LABS_TAG RELEASE_TYPE= = DOCS_COMMIT=$DOCS_COMMIT "\$@" + COMMIT_TAG=$LABS_TAG RELEASE_TYPE= = DOCS_COMMIT=$DOCS_COMMIT \\ + KEEP_DEVELOPER_VERSIONS=1 "\$@" } aztec_cli() { [ -x $CUT/docs/.aztec-node/cli/node_modules/.bin/aztec ] || { echo "no release CLI: run Step 5b" >&2; return 1; } - env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u NARGO_HOME -u AZTEC_HOME \\ - -u ANVIL_BIN -u FORGE_BIN -u CAST_BIN HOME=$CLI_HOME PATH=\$CLI_PATH:\$PATH "\$@" + env -u ANVIL_BIN -u FORGE_BIN -u CAST_BIN HOME=$CLI_HOME NARGO_HOME=$CLI_HOME/.nargo AZTEC_HOME=$CLI_HOME/.aztec \\ + XDG_CONFIG_HOME=$CLI_HOME/.config XDG_DATA_HOME=$CLI_HOME/.local/share XDG_CACHE_HOME=$CLI_HOME/.cache \\ + PATH=\$CLI_PATH:\$PATH "\$@" } EOF ``` `` is `MAINNET_TAG` or `TESTNET_TAG`, and its value has no `v`; `` sets the other type's tag to the version its network runs, or is empty. `COMMIT_TAG` -keeps its `v` (the preprocessor emits it as a git ref). `docs_env` checks the cut's pin +keeps its `v` (the preprocessor emits it as a git ref). `KEEP_DEVELOPER_VERSIONS=1` is +required: this cut leaves the developer docs' versions alone, so their API reference links +must name the folders the build serves now. Without it the dev pages can link a folder this +build does not serve, and agent readiness fails the build. `docs_env` checks the cut's pin and checkout and exports the pin's versions before running a docs command; it fails when they disagree. `AZTEC_NODE_DIR` keeps the cut's checkout outside the worktree, as -`/release-docs` Step 2b explains. +`/release-docs` Step 2b explains. `LINE` names the line a line cut promotes (empty +otherwise), and `DEST_PIN_REF` is the pin of the pages the cut starts from. #### 2c. Create the worktree and move its pin to the tag @@ -198,6 +218,16 @@ git -C "$DEST_ROOT" worktree add -b "docs-cut/$CUT_ID" "$CUT" "$DEST" cd "$CUT/docs" && node scripts/aztec_node.mts pin "$LABS_TAG" ``` +**A line cut** (`$LINE` set) promotes the line instead of running that `pin`, as +`/release-docs` Step 2c explains: + +```bash +. ~/.cache/aztec-docs-cut//env.sh && cd "$CUT/docs" +CUT=$CUT scripts/promote_line.sh "$LINE" "$LABS_TAG" && + git -C "$CUT" add -- docs && git -C "$CUT" commit -q -m "docs: promote the $LINE line at $LABS_TAG" && + node scripts/aztec_node.mts fetch +``` + `pin` checks the tag out into `$AZTEC_NODE_DIR`, writes its commit and toolchain into `docs/aztec-node.json`, and prints every remaining drift with its fix. It needs `gh` logged in (tested with 2.85.0): it records the sha256 of each noir archive that `gh attestation @@ -215,14 +245,17 @@ node -e ' ' yarn install node scripts/aztec_node.mts check && echo "pin: ok" -git add aztec-node.json package.json yarn.lock && git commit -m "docs: pin aztec-node $LABS_TAG" +git add aztec-node.json package.json yarn.lock && + { git diff --cached --quiet || git commit -m "docs: pin aztec-node $LABS_TAG"; } echo "PINNED=$(git rev-parse HEAD)" >>"$STATE/env.sh" -git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- docs/examples && echo "examples: ok" +git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- "$EXAMPLES" && echo "examples: ok" ``` `check` must print `pin: ok` (the checkout is the tag's commit and clean, and the pin's bb and `docs/package.json`'s l1-artifacts equal the tag's `BB_VERSION`), and `examples: ok` -must follow. Never initialize `labs/` in the cut and run no root `make` target there. The +must follow. A line cut's promotion commit already carries the pin, so the pin commit has +something to commit only when l1-artifacts drifted; otherwise `PINNED` is the promotion +commit. Never initialize `labs/` in the cut and run no root `make` target there. The release inputs (`docs/docs-operate/`, `docs/sidebars-operate.js`) are the destination's content; `docs/docs/networks.md` and the existing snapshots are the destination's live copies, which Step 10 copies back. @@ -378,16 +411,19 @@ page usually lands after the tag, so check the destination commit: . ~/.cache/aztec-docs-cut//env.sh major=$({ jq -r '."."' "$AZTEC_NODE_DIR/.version-manifest.json" 2>/dev/null || jq -r '."."' "$AZTEC_NODE_DIR/.release-please-manifest.json"; } | cut -d. -f1) -git -C "$DEST_ROOT" show "$DEST:docs/docs-operate/operators/reference/changelog/v$major.md" >/dev/null \ +src=docs${LINE:+/lines/$LINE} +git -C "$DEST_ROOT" show "$DEST:$src/docs-operate/operators/reference/changelog/v$major.md" >/dev/null \ && echo "page present" || echo "MISSING: v$major.md" -git -C "$DEST_ROOT" show "$DEST:docs/docs-operate/operators/reference/changelog/index.md" | grep -n '^### ' | head -3 -git -C "$DEST_ROOT" show "$DEST:docs/sidebars-operate.js" | grep -n "changelog/v$major" +git -C "$DEST_ROOT" show "$DEST:$src/docs-operate/operators/reference/changelog/index.md" | grep -n '^### ' | head -3 +git -C "$DEST_ROOT" show "$DEST:$src/sidebars-operate.js" | grep -n "changelog/v$major" ``` The page exists (or its minor-qualified name, such as `v5.2.md`), `index.md` has a `### ` -entry for this release's major (and minor, once the series has more than one), and the -sidebar lists the page. The cut started from the destination, so its copy is the -destination's. +entry for this release's major (and minor, once the series has more than one; a nightly is +covered by its major's page, and a minor release such as `6.1.0` needs its `### [v6.1.x]` +entry landed first), and the sidebar lists the page. The cut started from the destination, +so its copy is the destination's; a line cut checks the line's copy (`$src`), which it +promoted. **Owner approval required.** If any check fails, stop and report which: the page lands on the destination first (`/updating-changelog`), through a PR the owner opens and merges, @@ -423,7 +459,8 @@ grep -rhoE 'github\.com/AztecProtocol/aztec-packages(/(blob|tree)/[^/)"]+(/[^/)" gets the tag in the snapshot. - Classify every hit of the last command by path, as `/release-docs` Step 11 does: Labs code (`noir-projects/`, `yarn-project/`) names aztec-node at the tag in the snapshot, - `docs/examples` names `DOCS_COMMIT`, Foundation code (`l1-contracts/`, `barretenberg/`) + the examples (`docs/examples`, or a line cut's `docs/lines//examples`) name + `DOCS_COMMIT`, Foundation code (`l1-contracts/`, `barretenberg/`) takes `#include_foundation_version`, and anything else `v` or `next`. @@ -481,7 +518,8 @@ git -C "$AZTEC_NODE_HISTORY" log --oneline --left-right --cherry-pick --name-onl Never fetch with `--shallow-exclude=`: the merge base is usually reachable from it, so it is cut off and the range lists both sides back to the boundary (v6.0.0 against `v6.0.0-rc.3`: 166/166 commits instead of 57/2). This fetch needs no previous -release, so it also works when that is not a Labs tag. The separate history checkout and +release, so it also works when that is not a Labs tag. In a line cut `DEST_PIN_REF` is the +line's pin, so both refs are on one aztec-node branch. The separate history checkout and a failed count check work as in `/release-docs` Step 12. So do hand backports: one adapted to its line (`v6`) is not patch-equivalent, so `--cherry-pick` keeps it on both sides; judge it against `$AZTEC_NODE_DIR`, the tag. @@ -572,11 +610,14 @@ fixed goes to the owner. . ~/.cache/aztec-docs-cut//env.sh git -C "$DEST_ROOT" diff --quiet "$DEST" -- docs || { echo "destination docs/ moved: restart the cut" >&2; exit 1; } cd "$CUT" && git add -- docs && git commit -m "docs: cut $LABS_TAG network docs" -git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- docs/examples \ - || { echo "the cut changed docs/examples: land the change on next and restart the cut" >&2; exit 1; } +git -C "$CUT" diff --quiet "$DOCS_COMMIT" HEAD -- "$EXAMPLES" \ + || { echo "the cut changed $EXAMPLES: land the change on next and restart the cut" >&2; exit 1; } git -C "$CUT" diff --name-status "$PINNED" HEAD -- docs ``` +A line cut's promotion commit precedes `$PINNED`, so the list never shows it: it stays in +the cut. + Sort every listed path into exactly one class: 1. **Release results**, copied per named path, with the Step 8 deletions run explicitly: @@ -605,8 +646,22 @@ Sort every listed path into exactly one class: git -C "$DEST_ROOT" apply -3 "$STATE/shared-repairs.patch" ``` -3. **Release-only changes** stay in the cut: the pin commit (`docs/aztec-node.json`, - `docs/package.json`, `docs/yarn.lock`), the regenerated `node-api-reference.md` and + In a line cut the cut's `docs-operate/` and `sidebars-operate.js` are the line's, so + their repairs belong to the destination's `docs/lines/$LINE/`: + + ```bash + git -C "$CUT" diff --relative=docs "$PINNED" HEAD -- ... >"$STATE/line-repairs.patch" + git -C "$DEST_ROOT" apply -3 --directory="docs/lines/$LINE" "$STATE/line-repairs.patch" + ``` + + An operator-changelog entry for the release also goes into main's copy + (`docs/docs-operate/`), since operators of the next major upgrade from it + (`docs/CLAUDE.md`): apply the same hunks there and resolve by hand where main's copy + differs. Other repairs reach main's pages only when the behaviour they describe is the same + at main's pin. + +3. **Release-only changes** stay in the cut: the promotion and pin commits + (`docs/aztec-node.json`, `docs/package.json`, `docs/yarn.lock`, a line's pin), the regenerated `node-api-reference.md` and `cli-reference.md` sources, and source edits only the release needs (Steps 6 and 7a). A destination commit cherry-picked into the cut also shows in this list: it is already on diff --git a/.claude/skills/update-doc-references/SKILL.md b/.claude/skills/update-doc-references/SKILL.md index 80dc08ea5ac..a08351cfca1 100644 --- a/.claude/skills/update-doc-references/SKILL.md +++ b/.claude/skills/update-doc-references/SKILL.md @@ -8,19 +8,24 @@ description: Analyze source-file changes referenced by documentation, update aff When source files referenced by documentation change, analyze the changes and update the affected documentation if needed. -The docs live in this repository's `docs/`. Most of the code they document is aztec-node's, -at the commit `docs/aztec-node.json` pins, read through a checkout of it -(`docs/.aztec-node/tree`, or `$AZTEC_NODE_DIR`) that `node docs/scripts/aztec_node.mts -fetch` keeps. A page's frontmatter `references` names paths from this repository's root: -`labs/` for Labs code, where the `labs/` prefix names that checkout and -never the `labs/` submodule, and plain paths for this repository's own files -(`docs/examples/...`). A reference ending in `/*` covers every file under that directory. +The docs live in this repository's `docs/`, in two lines that each have their own copy of +every developer and operator page (`docs/CLAUDE.md`, "Two dev lines: change both"). Most of +the code they document is aztec-node's: main's pages describe aztec-node `main` at the commit +`docs/aztec-node.json` pins, read through a checkout of it (`docs/.aztec-node/tree`, or +`$AZTEC_NODE_DIR`), and the v6 line's pages (`docs/lines/v6/`) describe aztec-node `v6` at +the commit `docs/lines/v6/aztec-node.json` pins, read through `docs/lines/v6/.aztec-node/tree`. +`node docs/scripts/aztec_node.mts fetch` keeps both. A page's frontmatter `references` names +paths from this repository's root: `labs/` for Labs code, where the +`labs/` prefix names the checkout of the page's line and never the `labs/` submodule, and +plain paths for this repository's own files (`docs/examples/...`, `docs/lines/v6/examples/...`). +A reference ending in `/*` covers every file under that directory. ## Workflow ### Step 1: Parse the Prompt -Extract from the dispatch prompt: +The dispatcher is offline, so the skill runs by hand: it needs only the PR number and its +repository, and Step 3 finds the pages the PR's files reach. A dispatch prompt gives: - the PR number and its repository: `aztec-labs-eng/aztec-node` for Labs code (the usual case), `AztecProtocol/aztec-packages` for this repository's own files @@ -40,31 +45,34 @@ gh pr diff --repo An aztec-node PR names paths from aztec-node's root: prefix them with `labs/` to compare them with `references`. -The source docs follow the pin's line, aztec-node `v6` until the docs carry a separate v7 -line (`docs/CLAUDE.md`). An aztec-node PR into `main` (`baseRefName` `main`, v7) changes -code the pin may never get. Test its merge commit against the pin (an unmerged PR is not -in it): +Each line's pages describe the code at that line's pin. The PR's base branch +(`baseRefName`: `main` or `v6`) says which line to start with, not which lines it reaches: +test its merge commit against every pin (an unmerged PR is in none): ```bash cd "$(git rev-parse --show-toplevel)" merge=$(gh pr view --repo aztec-labs-eng/aztec-node --json mergeCommit -q .mergeCommit.oid) -pin=$(node -p 'require("./docs/aztec-node.json").commit') -gh api "repos/aztec-labs-eng/aztec-node/compare/$merge...$pin" --jq .status +for pinfile in docs/aztec-node.json docs/lines/*/aztec-node.json; do + echo "$pinfile: $(gh api "repos/aztec-labs-eng/aztec-node/compare/$merge...$(node -p "require('./$pinfile').commit")" --jq .status)" +done ``` -`ahead` or `identical` means the pin has it: continue as for any PR. Otherwise edit no -source docs, since they describe v6. Still run Steps 3 and 4, and report what v7 docs -would need. +`ahead` or `identical` means that line's pin has the change, so its pages may need it. A line +whose pin lacks it gets no edit that quotes the new code: report what its pages will need +when its pin moves. Then compare the symbol or behaviour the pages document in both +checkouts, and edit each copy whose checkout has it (Step 5): a `main` PR can fix behaviour v6 +shares, and a page that is wrong about code both lines have is wrong in both copies. -When the change is a move of the docs' pin rather than a PR (`node -docs/scripts/aztec_node.mts pin `), take it from the two pin commits, fetched into the -checkout. A two-commit diff needs no history between them: +When the change is a move of a pin rather than a PR (`node docs/scripts/aztec_node.mts +[--line ] pin `), take it from the two pin commits, fetched into that line's +checkout. A two-commit diff needs no history between them. For main: ```bash cd "$(git rev-parse --show-toplevel)" -old=$(git show "$(git merge-base origin/next HEAD):docs/aztec-node.json" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).commit') -new=$(node -p 'require("./docs/aztec-node.json").commit') -node docs/scripts/aztec_node.mts fetch && pin=$(node docs/scripts/aztec_node.mts env) || exit 1 +pinfile=docs/aztec-node.json lineopt= # the v6 line's: pinfile=docs/lines/v6/aztec-node.json lineopt="--line v6" +old=$(git show "$(git merge-base origin/next HEAD):$pinfile" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).commit') +new=$(node -p "require('./$pinfile').commit") +node docs/scripts/aztec_node.mts $lineopt fetch && pin=$(node docs/scripts/aztec_node.mts $lineopt env) || exit 1 eval "$pin" git -C "$AZTEC_NODE_DIR" fetch --depth 1 --no-tags origin "$old" "$new" git -C "$AZTEC_NODE_DIR" diff --name-only "$old" "$new" | sed 's|^|labs/|' @@ -77,21 +85,23 @@ the report, since the examples and the Solidity snippets follow them. ### Step 3: Identify Affected Documentation The prompt lists which source files changed and which docs reference them. Confirm the -mapping from the docs' frontmatter, from the repository root (the library scans -`docs/docs-developers`, `docs/docs-operate`, `docs/docs-participate` and `docs/docs`, -never the versioned snapshots): +mapping from the docs' frontmatter, from the repository root, once per line (the library +scans a line's `docs-developers`, `docs-operate`, `docs-participate` and `docs`, never the +versioned snapshots): ```bash cd "$(git rev-parse --show-toplevel)" source docs/scripts/lib/extract_doc_references.sh map=$(mktemp) changed=$(mktemp) -extract_references_mapping docs "$map" gh pr view --repo aztec-labs-eng/aztec-node --json files -q '.files[].path' | sed 's|^|labs/|' >"$changed" -awk -F'|' 'NR == FNR {changed[$0]; next} - {ref = $1; dir = sub(/\/\*$/, "/", ref) - for (f in changed) if (dir ? index(f, ref) == 1 : f == ref) print f " -> " $2}' \ - "$changed" "$map" | sort -u +for root in docs docs/lines/*; do + extract_references_mapping "$root" "$map" + awk -F'|' 'NR == FNR {changed[$0]; next} + {ref = $1; dir = sub(/\/\*$/, "/", ref) + for (f in changed) if (dir ? index(f, ref) == 1 : f == ref) print f " -> " $2}' \ + "$changed" "$map" | sort -u +done ``` For a PR of this repository drop the `sed`; for a pin move write Step 2's `--name-only` @@ -125,8 +135,9 @@ Changes that typically do NOT require doc updates: ### Step 5: Make Updates -If documentation updates are needed, edit this repository's source docs (`docs/docs-*` and -`docs/docs/`), never a versioned snapshot, the checkout or `labs/`: +If documentation updates are needed, edit this repository's source docs (`docs/docs-*`, +`docs/docs/` and each line's `docs/lines//docs-*`, per Step 2), never a versioned +snapshot, a checkout or `labs/`: 1. Make precise, minimal changes with the Edit tool. 2. Only modify content directly affected by the code changes. @@ -134,13 +145,17 @@ If documentation updates are needed, edit this repository's source docs (`docs/d 4. Do not make cosmetic changes unrelated to the code changes. 5. Do not add or remove sections unless required by the code change. 6. Update code examples if the API changed; a path in `#include_code` or `references` keeps - its `labs/` prefix. `docs/examples/` builds with the pin's published toolchain, so after a - pin move run `docs/examples/bootstrap.sh` to compile and type-check them at the new pin. + its `labs/` prefix, and a v6 page's paths into its examples keep `docs/lines/v6/`. Each + line's examples build with its pin's published toolchain, so after a pin move run + `docs/examples/bootstrap.sh` (main) or `docs/examples/bootstrap.sh --line v6` to compile and + type-check them at the new pin. 7. Correct explanations if behavior changed. -Then run `docs/scripts/check_doc_references.sh`, which checks `labs/` references in the -pinned checkout (run `node docs/scripts/aztec_node.mts fetch` first; it must print `All -referenced paths exist.`), and, from `docs/`, `yarn spellcheck`. An aztec-node PR newer +Then run `docs/scripts/check_doc_references.sh` and, for the v6 line, +`docs/scripts/check_doc_references.sh docs/lines/v6`, which check `labs/` references in each +line's checkout (run `node docs/scripts/aztec_node.mts fetch` first; each must print `All +referenced paths exist.`), and, from `docs/`, `yarn preprocess && yarn spellcheck` (a v6 +page is spellchecked through its preprocessed copy). An aztec-node PR newer than the pin is not in the checkout yet, so an edit that quotes its code (a new `#include_code` marker, a moved file in `references`) fails until the pin includes it: make such edits together with the pin move, or report them, rather than editing them to diff --git a/.claude/skills/updating-changelog/SKILL.md b/.claude/skills/updating-changelog/SKILL.md index 499e0dfcf2d..1a8d10af3f5 100644 --- a/.claude/skills/updating-changelog/SKILL.md +++ b/.claude/skills/updating-changelog/SKILL.md @@ -5,11 +5,15 @@ description: Updates changelog documentation for contract developers and node op # Updating Changelog -The docs live in this repository's `docs/`. The code they describe is mostly aztec-node's, -at the commit `docs/aztec-node.json` pins, read through a checkout of it that -`node docs/scripts/aztec_node.mts fetch` keeps (`$AZTEC_NODE_DIR`, default -`docs/.aztec-node/tree`; its version and its changes are read there, never in the `labs/` -submodule), plus this repository's own code (`l1-contracts/`, `barretenberg/`, …). +The docs live in this repository's `docs/`, in two lines that each have their own copy of +every developer and operator page (`docs/CLAUDE.md`, "Two dev lines: change both"). The code +they describe is mostly aztec-node's: main's pages follow aztec-node `main` at the commit +`docs/aztec-node.json` pins, and the v6 line's (`docs/lines/v6/`) follow aztec-node `v6` at the +commit `docs/lines/v6/aztec-node.json` pins. Each is read through its line's checkout, which +`node docs/scripts/aztec_node.mts fetch` keeps (main's is `$AZTEC_NODE_DIR`, default +`docs/.aztec-node/tree`; v6's is `docs/lines/v6/.aztec-node/tree`); versions and changes are +read there, never in the `labs/` submodule. This repository's own code (`l1-contracts/`, +`barretenberg/`, …) is the rest. aztec-node records operator-facing changes as they land, in `CHANGELOG-OPERATORS.md` at its root. It keeps one copy per release line, on that line's branch, so the checkout holds the copy @@ -21,11 +25,13 @@ The diff is still read, as the check on what the file missed. ### 1. Determine Target Files -The version is the Labs release the docs' pin names, read from the checkout: +The version is the Labs release the line's pin names, read from its checkout. For main +(for the v6 line, `lineopt="--line v6"`): ```bash cd "$(git rev-parse --show-toplevel)" -node docs/scripts/aztec_node.mts fetch && pin=$(node docs/scripts/aztec_node.mts env) || exit 1 +lineopt= +node docs/scripts/aztec_node.mts $lineopt fetch && pin=$(node docs/scripts/aztec_node.mts $lineopt env) || exit 1 eval "$pin" jq -r '."."' "$AZTEC_NODE_DIR/.version-manifest.json" 2>/dev/null || jq -r '."."' "$AZTEC_NODE_DIR/.release-please-manifest.json" @@ -39,16 +45,21 @@ root versions the Foundation tree instead, whose numbers are unrelated to Labs': the version from it. Documenting one aztec-node PR (source 3 below) takes the major from the PR's line instead, -since the pin can lag it or sit on the other line: `baseRefName` `main` is the major `main` carries (v7 from +since a pin can lag it: `baseRefName` `main` is the major `main` carries (v7 from 2026-11-04), `v6` is v6. -**Target files:** +**Which lines get the entry.** A v6.x entry goes into both lines, since v7 readers upgrade +from the latest v6. A v7 entry goes into main only. Released entries are history in either +line: never edit them. + +**Target files**, in each line that gets the entry (main's paths below; the v6 line's are the +same under `docs/lines/v6/`): - Aztec contract developers: `docs/docs-developers/docs/resources/migration_notes.md` - Node operators and Ethereum contract developers: `docs/docs-operate/operators/reference/changelog/v{major}.md` -When that file is new (the first entry of a major), two more files must be updated or -the page ships unreachable: +When that file is new (the first entry of a major), two more files of the same line must +be updated or the page ships unreachable: - `docs/docs-operate/operators/reference/changelog/index.md`: add a `### [](./.md)` entry at the top of `## Version history`. The heading @@ -76,15 +87,17 @@ lives: git diff origin/next...HEAD -- . ':!labs' ``` -2. **Labs code, when this branch moves the docs' pin** (`docs/aztec-node.json`, moved with - `node docs/scripts/aztec_node.mts pin `). Read the range in the checkout; both - commits must be in it, and a two-commit diff needs no history between them: +2. **Labs code, when this branch moves a line's pin** (`docs/aztec-node.json` or + `docs/lines//aztec-node.json`, moved with `node docs/scripts/aztec_node.mts [--line + ] pin `). Read the range in that line's checkout; both commits must be in it, + and a two-commit diff needs no history between them. For main: ```bash cd "$(git rev-parse --show-toplevel)" - old=$(git show "$(git merge-base origin/next HEAD):docs/aztec-node.json" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).commit') - new=$(node -p 'require("./docs/aztec-node.json").commit') - node docs/scripts/aztec_node.mts fetch && pin=$(node docs/scripts/aztec_node.mts env) || exit 1 + pinfile=docs/aztec-node.json lineopt= # the v6 line's: pinfile=docs/lines/v6/aztec-node.json lineopt="--line v6" + old=$(git show "$(git merge-base origin/next HEAD):$pinfile" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).commit') + new=$(node -p "require('./$pinfile').commit") + node docs/scripts/aztec_node.mts $lineopt fetch && pin=$(node docs/scripts/aztec_node.mts $lineopt env) || exit 1 eval "$pin" git -C "$AZTEC_NODE_DIR" fetch --depth 1 --no-tags origin "$old" "$new" git -C "$AZTEC_NODE_DIR" diff "$old" "$new" -- CHANGELOG-OPERATORS.md @@ -158,8 +171,8 @@ that no one will notice have drifted apart. ### 4. Edit Documentation -After approval, add entries to the appropriate files in this repository's `docs/` (never -in the checkout or under `labs/`, and never a versioned snapshot). +After approval, add entries to the appropriate files of each line that gets them, in this +repository's `docs/` (never in a checkout or under `labs/`, and never a versioned snapshot). ## Migration Notes Format diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index cd6fbac658a..415ed57ac69 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -2,6 +2,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +## Two dev lines: change both + +The dev docs follow two aztec-node lines, and each developer and operator page has a copy per line. The root pages (`docs/docs/`), `docs-participate/`, the versioned snapshots and `static/` are shared. + +| Line | Follows | Pages and examples | Pin | +| --- | --- | --- | --- | +| main | aztec-node `main` | `docs-developers/`, `docs-operate/`, `sidebars-*.js`, `examples/` | `aztec-node.json` | +| v6 | aztec-node `v6` | `lines/v6/docs-developers/`, `lines/v6/docs-operate/`, `lines/v6/sidebars-*.js`, `lines/v6/examples/` | `lines/v6/aztec-node.json` | + +- **A change goes into both lines.** Change one line only when the change is specific to it. +- **Decide that from the code, not the PR.** Grep the symbol or behaviour you document in each line's checkout: `.aztec-node/tree` for main, `lines/v6/.aztec-node/tree` for v6. If it is the same in both, change both copies. If it differs or is missing in one, change only the line that has it, the way that line has it. + - A Labs PR's base branch (`main` or `v6`) only says which checkout to start with. A `main` PR can fix behaviour v6 shares, and a backport to `v6` still needs this check. + - A fix to wording, structure or a mistake that both copies share is never line-specific. +- **Port with the line's paths.** The counterpart of `docs-developers/` is `lines/v6/docs-developers/`. In a v6 page, `#include_code` and `references:` paths into `docs/examples/` start with `docs/lines/v6/examples/`, and paths into `docs/node_modules/@aztec-foundation/l1-artifacts/` start with `docs/lines/v6/.aztec-node/l1-artifacts/`. `labs/` paths are the same in both and read each line's own checkout. +- **Check both lines** with `yarn build` (a preview also serves v6 at `/developers-v6/` and `/operate-v6/`), `./bootstrap.sh check`, `examples/bootstrap.sh` and `examples/bootstrap.sh --line v6`. +- **Migration notes and the operator changelog exist in both lines.** A v6.x entry goes into both, since v7 readers upgrade from the latest v6. A v7 entry goes into main only. Released entries are history in either line: never edit them. + ## Overview You are working with the **Aztec Protocol Documentation** - a comprehensive documentation site built with Docusaurus 3 for Aztec, the decentralized Ethereum L2 for building unstoppable private apps. Your role includes both technical development tasks and ensuring all documentation meets quality standards for accuracy, clarity, and usability. @@ -19,7 +36,7 @@ This project uses Yarn 4.13.0 as specified in the `packageManager` field of pack - `yarn build` - Build production site with full validation (includes clean, preprocess, spellcheck, and move steps) - It ends with the search index check: renaming or moving a page a search probe expects (`PROBES` in `scripts/check_search_index.mts`) fails the build until the probe lists the new path - `yarn serve` - Serve the built static site -- `yarn spellcheck` - Run spell checking with cspell on markdown files +- `yarn spellcheck` - Run spell checking with cspell on markdown files. A line's pages are checked only through their preprocessed copies, so run `yarn preprocess` first after editing one - `yarn clean` - Clean build artifacts and processed docs ### API Documentation Generation @@ -63,8 +80,9 @@ The aztec-node (Labs) code the docs quote is the commit `aztec-node.json` pins, - Move the pin with `node scripts/aztec_node.mts pin ` (a release or nightly tag), never by hand; then set `@aztec-foundation/l1-artifacts` to the version `check` names, run `yarn install`, and commit `aztec-node.json` with `package.json` and `yarn.lock`. - `pin` needs `gh` logged in: it records the sha256 of each noir release archive in `noirArchives` once `gh attestation verify` proves noir's publish workflow built it, and `provision` refuses a nargo archive whose sha256 differs. Never edit `noirArchives` to get past a mismatch: it means the release archive changed after the pin. - Tools that need nargo, bb or the aztec CLI use the pinned published ones: `node scripts/aztec_node.mts provision nargo bb cli`, then `eval "$(node scripts/aztec_node.mts env)"` exports `NARGO`, `BB`, `AZTEC` and the versions. Never run nargo inside `docs/` or the checkout: it takes `docs/Nargo.toml` as its workspace. -- The dev docs stay on aztec-node's v6 line until they carry a separate v7 line: move their pin to the newest `v6.*` nightly, never to a v7 tag (`main` carries v7 from 2026-11-04). A v6.x release is cut from the dev docs' pages and examples, so it works only while they are v6 content. Then check that the recorded commit is on `v6`: `gh api "repos/aztec-labs-eng/aztec-node/compare/v6...$(node -p 'require("./aztec-node.json").commit')" --jq .status` prints `behind` or `identical`. -- A release cut moves the pin to the release tag in its own worktree only (`/release-docs`, `/release-network-docs`); v6.x releases are cut from their tags on aztec-node's `v6` branch. The dev docs keep their pin. +- Each line's pin follows its own aztec-node branch (see "Two dev lines: change both"): `aztec-node.json` follows `main` (v7 from 2026-11-04), and `lines//aztec-node.json` follows ``. Move a line's pin with `node scripts/aztec_node.mts --line pin `: it installs the line's l1-artifacts into `lines//.aztec-node/`, so `package.json` does not change. A line's `pin` and `check` refuse a tag of another major. After moving any pin, check that the recorded commit is on its branch: `gh api "repos/aztec-labs-eng/aztec-node/compare/..." --jq .status` prints `behind` or `identical`. +- A release cut moves the pins in its own worktree only (`/release-docs`, `/release-network-docs`); the dev docs keep theirs. A cut of a line's major (a v6.x release, from its tag on aztec-node's `v6` branch) first promotes the line into the main paths with `scripts/promote_line.sh`. +- Retire a line with `git rm -r docs/lines/` after its last release, or once no network runs its major: from then on, preprocessing fails on the line's API reference links. ### Preprocessing Environment Variables @@ -79,6 +97,7 @@ The preprocessing system uses these environment variables: | `TESTNET_TAG` | Version for testnet builds | from `developer_version_config.json` | | `MAINNET_TAG` | Version for mainnet builds | from `developer_version_config.json` | | `COMMIT_TAG` | Legacy variable, used as fallback for `NIGHTLY_TAG` | `ref` in `aztec-node.json` | +| `KEEP_DEVELOPER_VERSIONS` | `1` when the release leaves the developer docs' versions alone (a network-only cut, `/release-network-docs`): `#api_ref_version` then names the folder `developer_version_config.json` serves now, not the one it serves once `RELEASE_TYPE` reads the version being built | unset | ### Preprocessing Macros @@ -186,6 +205,8 @@ The `examples/` directory contains runnable code examples that are included in d **Validation (type-checking)**: `examples/bootstrap.sh` compiles Noir circuits, Noir contracts, Solidity, and type-checks TypeScript examples. This runs on every PR. +`examples/bootstrap.sh --line ` builds a line's examples the same way, in a copy staged outside the repository (nargo would take `docs/Nargo.toml` as the workspace). Run it whole: the stage is new every run, so a single step such as `validate-ts` finds no compiled contracts, unless `DOCS_LINE_STAGE=` keeps one stage across runs (a release cut does). A line's examples run against a network only at its release cut, never in CI. + The Solidity examples compile against the l1-contracts sources shipped in the `@aztec-foundation/l1-artifacts` devDependency (see `examples/solidity/foundry.toml`). Its version in `package.json` must equal `toolchain.l1Artifacts` in `aztec-node.json` (the pinned aztec-node's `BB_VERSION`); `node scripts/aztec_node.mts check` fails until both move together. The examples build with the pin's published toolchain, the same code the snippets quote: `examples/bootstrap.sh` provisions nargo, bb and the aztec CLI (`@aztec-labs/aztec`) at the pinned versions, the contracts' Nargo path dependencies point into the default checkout (`.aztec-node/tree`; an `AZTEC_NODE_DIR` override never applies to them), and the TS examples install `@aztec-labs/*` at `AZTEC_VERSION` and `@aztec-foundation/*` at `BB_VERSION` from npm. @@ -400,5 +421,5 @@ Approved external documentation sources: - Suggest improvements even if they go beyond pure editing - When making changes to documentation processes or tooling, remember to check and update READMEs, project documentation (like this file), and code comments -Last updated: 2026-11-02 -Version: 1.11 +Last updated: 2026-11-05 +Version: 1.12 diff --git a/docs/README.md b/docs/README.md index d4a25015371..392a0d8c373 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,6 +4,23 @@ Documentation for the Aztec Network, built with Docusaurus You can view the latest successful build here: https://docs.aztec.network +## Two dev lines + +The dev docs follow two aztec-node branches at once: `main` (v7) and `v6`, which keeps shipping v6.x releases. So each developer and operator page exists twice. The landing pages (`docs/`), `docs-participate/`, the versioned snapshots and `static/` are shared. + +| Line | Follows | Pages and examples | Pin | +| --- | --- | --- | --- | +| main | aztec-node `main` | `docs-developers/`, `docs-operate/`, `sidebars-*.js`, `examples/` | `aztec-node.json` | +| v6 | aztec-node `v6` | `lines/v6/docs-developers/`, `lines/v6/docs-operate/`, `lines/v6/sidebars-*.js`, `lines/v6/examples/` | `lines/v6/aztec-node.json` | + +- Make each change in both lines, unless it is specific to one. Decide from the code: look the symbol or behaviour up in each line's checkout (`.aztec-node/tree` and `lines/v6/.aztec-node/tree`). If it is the same in both, change both pages; if not, change the line that has it. A fix to wording or to a mistake both copies share always goes into both. +- In a v6 page, snippet and `references:` paths name the line's own files: `docs/lines/v6/examples/...` and `docs/lines/v6/.aztec-node/l1-artifacts/...`. `labs/` paths are the same in both lines and read each line's checkout. While the two pins differ, preprocessing refuses a page that quotes the other line's files. +- Deploy previews serve the v6 line at `/developers-v6/` and `/operate-v6/`, marked noindex and left out of search, `llms.txt` and the sitemap. Production never builds it. +- `./bootstrap.sh` checks each line's references and builds its examples (`examples/bootstrap.sh --line v6`). A line's examples run against a network only at its release cut. +- Migration notes and the operator changelog exist in both lines. A v6.x entry goes into both, since v7 readers upgrade from the latest v6; a v7 entry goes into main only. +- A v6.x release cut promotes the v6 line into the main paths with `scripts/promote_line.sh` (see the release skills). +- Retire a line with `git rm -r docs/lines/` after its last release, or once no network runs its major. + ## Docusaurus This website is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator. @@ -221,14 +238,16 @@ node scripts/aztec_node.mts check # fail on any drift between the pin node scripts/aztec_node.mts pin # move the pin to an aztec-node release or nightly tag (needs gh) node scripts/aztec_node.mts provision nargo bb cli # install the pinned nargo, bb and aztec CLI into .aztec-node/ eval "$(node scripts/aztec_node.mts env)" # export AZTEC_NODE_DIR, the versions, NARGO, BB and AZTEC +node scripts/aztec_node.mts --line v6 # the same for a line, with its own pin and lines/v6/.aztec-node/ +node scripts/aztec_node.mts lines # list the lines (none in production) ``` - `yarn build`, `yarn start` and `./bootstrap.sh` fetch first, so a fresh clone needs nothing else. The checkout is a shallow clone without aztec-node's own `docs/`; `AZTEC_NODE_DIR` moves it elsewhere. - `#include_code` and `references:` paths keep their `labs/` prefix, which names the checkout: `labs/yarn-project/...` reads `.aztec-node/tree/yarn-project/...`, and source links name aztec-node at the pinned commit (a tag can move; a commit cannot). - **Moving the pin:** run `pin `, then do what `check` asks (usually: set `@aztec-foundation/l1-artifacts` in `package.json` to the pinned `BB_VERSION` and run `yarn install`), and commit `aztec-node.json`, `package.json` and `yarn.lock` together. Snippets whose markers moved fail the build until the pages follow. - **Verified nargo:** `pin` needs the GitHub CLI, logged in. It downloads noir's release archive for each platform, has `gh attestation verify` check that noir's `publish-nargo.yml` workflow built it, and records its sha256 in `noirArchives`. `provision nargo` needs no `gh`: it refuses an archive whose sha256 differs from the pin, and a platform the pin has no sha256 for. Never edit `noirArchives` by hand; a mismatch means the release archive changed after the pin. -- **Which tag:** the dev docs stay on aztec-node's v6 line until they carry a separate v7 line. Move their pin to the newest `v6.*` nightly, never to a v7 tag (`main` carries v7 from 2026-11-04): a v6.x release is cut from the dev docs' pages and examples, so it works only while they are v6 content. Then check that the recorded commit is on `v6` (from `docs/`): `gh api "repos/aztec-labs-eng/aztec-node/compare/v6...$(node -p 'require("./aztec-node.json").commit')" --jq .status` prints `behind` or `identical`. -- **Release cuts** move the pin to the release tag inside their own worktree, and the snapshot is generated from that; the dev docs keep their pin. v6.x releases are cut from their tags on aztec-node's `v6` branch. See the `release-docs` and `release-network-docs` skills under `.claude/skills/`. +- **Which tag:** each line's pin follows its own aztec-node branch: `aztec-node.json` follows `main` (v7 from 2026-11-04), and `lines//aztec-node.json` follows ``. A line's `pin` installs its l1-artifacts into `lines//.aztec-node/`, so `package.json` stays as it is, and its `pin` and `check` refuse a tag of another major. After moving a pin, check that the recorded commit is on its branch (from `docs/`): `gh api "repos/aztec-labs-eng/aztec-node/compare/..." --jq .status` prints `behind` or `identical`. +- **Release cuts** move the pins inside their own worktree, and the snapshot is generated from that; the dev docs keep their pins. A v6.x release is cut from its tag on aztec-node's `v6` branch, after `scripts/promote_line.sh` moves the v6 line into the main paths. See the `release-docs` and `release-network-docs` skills under `.claude/skills/`. - **Examples** build with the pinned published toolchain against the default checkout, which their Nargo.toml path dependencies name (`../../../.aztec-node/tree/...`), so `AZTEC_NODE_DIR` does not apply to them. The TS examples install `@aztec-labs/*` at the pinned `AZTEC_VERSION` and `@aztec-foundation/*` at `BB_VERSION`. - Never run nargo inside `docs/` or the checkout: nargo takes `docs/Nargo.toml` as its workspace. diff --git a/docs/bootstrap.sh b/docs/bootstrap.sh index 84fba747683..409774a9642 100755 --- a/docs/bootstrap.sh +++ b/docs/bootstrap.sh @@ -12,11 +12,13 @@ hash=$( $(find docs docs-developers docs-operate docs-participate developer_versioned_docs network_versioned_docs $([ -d lines ] && echo lines) -type f -name "*.md*" -exec grep '^#include_code' {} \; | \ awk '{ gsub("^/", "", $3); if ($3 !~ /^labs\//) print "^" $3 }' | sort -u) ) -# A release build renders its own versions and links this repository's files at DOCS_COMMIT, so it -# never shares a cache entry with a dev build. +# Production serves neither the dev docs nor the lines, and a release build renders its own versions +# and links this repository's files at DOCS_COMMIT: every variable that changes the output keys it. # cache_content_hash hashes blob ids without their names, so the docs tree id keys renamed pages. hash=$(hash_str "$hash" "$(git -C "$repo_root" rev-parse HEAD:docs)" \ - "${COMMIT_TAG:-}" "${RELEASE_TYPE:-}" "${DOCS_COMMIT:-}") + "CONTEXT=${CONTEXT:-}" "COMMIT_TAG=${COMMIT_TAG:-}" "RELEASE_TYPE=${RELEASE_TYPE:-}" "DOCS_COMMIT=${DOCS_COMMIT:-}" \ + "NIGHTLY_TAG=${NIGHTLY_TAG:-}" "DEVNET_TAG=${DEVNET_TAG:-}" "TESTNET_TAG=${TESTNET_TAG:-}" \ + "MAINNET_TAG=${MAINNET_TAG:-}" "KEEP_DEVELOPER_VERSIONS=${KEEP_DEVELOPER_VERSIONS:-}") # Every function that reads aztec-node code fetches and checks the pinned checkout first, on a cache # hit too, since later steps read it (scripts/aztec_node.mts; a no-op without network when current). diff --git a/docs/examples/bootstrap.sh b/docs/examples/bootstrap.sh index b8bdb84e5aa..539ac5ac9ba 100755 --- a/docs/examples/bootstrap.sh +++ b/docs/examples/bootstrap.sh @@ -40,15 +40,22 @@ if [ "$cmd" = --line ]; then exit 1 fi aztec_node+=(--line "$DOCS_LINE") - # On disk rather than in /tmp: the contract artifacts are large. - mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}" - STAGE=$(mktemp -d "${XDG_CACHE_HOME:-$HOME/.cache}/aztec-docs-$DOCS_LINE.XXXXXX") - cp -R "$line_root/Nargo.toml" "$line_root/examples" "$REPO_ROOT/docs/.yarnrc.yml" "$STAGE/" + # On disk rather than in /tmp: the contract artifacts are large. A release cut runs a line's + # examples one step at a time, so DOCS_LINE_STAGE names a stage it keeps across runs (and removes + # itself): later steps find what earlier ones compiled. + if [ -n "${DOCS_LINE_STAGE:-}" ]; then + stage=$DOCS_LINE_STAGE + else + mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}" + STAGE=$(mktemp -d "${XDG_CACHE_HOME:-$HOME/.cache}/aztec-docs-$DOCS_LINE.XXXXXX") + stage=$STAGE + fi + mkdir -p "$stage/node_modules/@aztec-foundation" + cp -R "$line_root/Nargo.toml" "$line_root/examples" "$REPO_ROOT/docs/.yarnrc.yml" "$stage/" # The links may dangle until pin_toolchain fetches the line. - mkdir -p "$STAGE/node_modules/@aztec-foundation" - ln -s "$line_root/.aztec-node" "$STAGE/.aztec-node" - ln -s "$line_root/.aztec-node/l1-artifacts" "$STAGE/node_modules/@aztec-foundation/l1-artifacts" - export DOCS_ROOT=$STAGE + ln -sfn "$line_root/.aztec-node" "$stage/.aztec-node" + ln -sfn "$line_root/.aztec-node/l1-artifacts" "$stage/node_modules/@aztec-foundation/l1-artifacts" + export DOCS_ROOT=$stage else export DOCS_PATH=docs DOCS_ROOT=$REPO_ROOT/docs fi diff --git a/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/aave_bridge.md b/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/aave_bridge.md index 13a0aabd17c..67a5a912ac7 100644 --- a/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/aave_bridge.md +++ b/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/aave_bridge.md @@ -115,8 +115,11 @@ This template is a community-maintained starter. If the repository is unavailabl ```bash git clone https://github.com/critesjosh/hardhat-aztec-example cd hardhat-aztec-example +git checkout 3be1b31f8054cd4a81817b6940171849950b8dfb ``` +The `git checkout` pins the starter to a commit we reviewed, so the tutorial always uses reviewed code. + Before adding dependencies, make the starter install with yarn 4: create the `.yarnrc.yml`, swap `@aztec/l1-contracts` for `@aztec-foundation/l1-artifacts`, point the `postinstall` remappings at the new package, and add the root `remappings.txt`. These are the first three steps of the [Token Bridge tutorial's project setup](./token_bridge.md#project-setup); without them `yarn add` fails on the starter's git dependencies and `npx hardhat compile` cannot resolve the `@aztec/*` imports. When complete, your project will have this structure: diff --git a/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/token_bridge.md b/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/token_bridge.md index 6785a52fa01..7e86bd7e5f4 100644 --- a/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/token_bridge.md +++ b/docs/lines/v6/docs-developers/docs/tutorials/js_tutorials/token_bridge.md @@ -28,13 +28,15 @@ Let's start simple. Since this is an Ethereum project, it's easier to just start ```bash git clone https://github.com/critesjosh/hardhat-aztec-example +cd hardhat-aztec-example +git checkout 3be1b31f8054cd4a81817b6940171849950b8dfb ``` -You're cloning a repo here to make it easier for Aztec's `l1-contracts` to be mapped correctly. You should now have a `hardhat-aztec-example` folder with Hardhat's default starter, with a few changes in `package.json`. +You're cloning a repo here to make it easier for Aztec's `l1-contracts` to be mapped correctly. You should now have a `hardhat-aztec-example` folder with Hardhat's default starter, with a few changes in `package.json`. The `git checkout` pins the starter to a commit we reviewed, so the tutorial always uses reviewed code. We want to add a few more dependencies now before we start. The starter needs four changes before it installs with yarn 4. -First, from the `hardhat-aztec-example` directory (`cd hardhat-aztec-example`), tell yarn to install into `node_modules` (the starter's scripts and Hardhat expect a real `node_modules` tree) and allow the starter's one git dependency, `forge-std`. Create `.yarnrc.yml`: +First, from the `hardhat-aztec-example` directory, tell yarn to install into `node_modules` (the starter's scripts and Hardhat expect a real `node_modules` tree) and allow the starter's one git dependency, `forge-std`. Create `.yarnrc.yml`: ```yaml nodeLinker: node-modules diff --git a/docs/scripts/__tests__/promote_line.test.mts b/docs/scripts/__tests__/promote_line.test.mts new file mode 100644 index 00000000000..38b51a8515b --- /dev/null +++ b/docs/scripts/__tests__/promote_line.test.mts @@ -0,0 +1,111 @@ +import assert from "node:assert/strict"; +import { execFileSync, spawnSync } from "node:child_process"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { after, before, beforeEach, test } from "node:test"; + +const git = (cwd: string, ...args: string[]) => + execFileSync("git", ["-C", cwd, "-c", "commit.gpgsign=false", "-c", "user.name=t", "-c", "user.email=t@t", ...args], { encoding: "utf8" }).trim(); + +function write(file: string, text: string) { + fs.mkdirSync(path.dirname(file), { recursive: true }); + fs.writeFileSync(file, text); +} + +const MAIN_PATHS = ["docs-developers", "docs-operate", "sidebars-developer.js", "sidebars-operate.js", "aztec-node.json"]; +const PINNED = "b".repeat(40); +const pinFile = (ref: string, commit: string, repository = "https://github.com/aztec-labs-eng/aztec-node") => + JSON.stringify({ repository, ref, commit }, null, 2) + "\n"; + +// A cut worktree: main's paths and a v6 line holding different pages, whose pin names a fork. The pin +// tool is a stand-in (the real one is tested in aztec_node.test.mts) that pins the line to PINNED in +// the canonical repository like `pin` does, or writes the pin and fails like a failed check. `gh` +// answers only the compare of the v6 branch with PINNED in the canonical repository, so comparing +// the tag or the fork fails. +let root: string, docs: string, bin: string; +before(() => { + root = fs.mkdtempSync(path.join(os.tmpdir(), "promote-line-")); + docs = path.join(root, "docs"); + bin = path.join(root, "bin"); + write(path.join(docs, "scripts/promote_line.sh"), fs.readFileSync(path.resolve(import.meta.dirname, "../promote_line.sh"), "utf8")); + write( + path.join(docs, "scripts/aztec_node.mts"), + `import fs from "node:fs"; +const [flag, line, cmd, tag] = process.argv.slice(2); +if (flag !== "--line" || cmd !== "pin") process.exit(2); +fs.writeFileSync(new URL(\`../lines/\${line}/aztec-node.json\`, import.meta.url), ${JSON.stringify(pinFile("TAG", PINNED))}.replace("TAG", tag)); +process.exit(process.env.PIN_FAIL ? 1 : 0); +`, + ); + write( + path.join(bin, "gh"), + `#!/usr/bin/env bash\n[ "$2" = repos/aztec-labs-eng/aztec-node/compare/v6...${PINNED} ] && echo "\${COMPARE_STATUS:-behind}" || exit 1\n`, + ); + fs.chmodSync(path.join(bin, "gh"), 0o755); + for (const [dir, who] of [[docs, "main"], [path.join(docs, "lines/v6"), "line"]]) { + write(path.join(dir, "docs-developers/docs/a.md"), `${who} a\n`); + write(path.join(dir, "docs-operate/operators/b.md"), `${who} b\n`); + write(path.join(dir, "sidebars-developer.js"), `// ${who}\n`); + write(path.join(dir, "sidebars-operate.js"), `// ${who}\n`); + } + write(path.join(docs, "docs-developers/docs/main-only.md"), "v7 only\n"); + write(path.join(docs, "aztec-node.json"), pinFile("v7.0.0-nightly.1", "a".repeat(40))); + write(path.join(docs, "lines/v6/aztec-node.json"), pinFile("v6.1.0-nightly.1", "c".repeat(40), "https://github.com/a-fork/aztec-node")); + git(root, "init", "-q"); + git(root, "add", "-A"); + git(root, "commit", "-q", "-m", "cut"); +}); +after(() => fs.rmSync(root, { recursive: true, force: true })); +beforeEach(() => { + git(root, "reset", "-q", "--hard"); + git(root, "clean", "-qfd"); +}); + +const promote = (tag: string, env: Record = {}) => + spawnSync("bash", [path.join(docs, "scripts/promote_line.sh"), "v6", tag], { + encoding: "utf8", + env: { ...process.env, PATH: `${bin}:${process.env.PATH}`, CUT: root, COMPARE_STATUS: undefined, PIN_FAIL: undefined, ...env }, + }); + +const snapshot = (dir: string) => + Object.fromEntries( + MAIN_PATHS.flatMap((p) => { + const full = path.join(dir, p); + if (!fs.existsSync(full)) return [[p, null]]; + if (fs.statSync(full).isFile()) return [[p, fs.readFileSync(full, "utf8")]]; + return (fs.readdirSync(full, { recursive: true }) as string[]) + .filter((f) => fs.statSync(path.join(full, f)).isFile()) + .sort() + .map((f) => [`${p}/${f}`, fs.readFileSync(path.join(full, f), "utf8")]); + }), + ); + +test("a line cut serves the line's pages and its tag's pin from the main paths", () => { + const r = promote("v6.0.1"); + assert.equal(r.status, 0, r.stderr); + assert.deepEqual(snapshot(docs), snapshot(path.join(docs, "lines/v6"))); + assert.equal(JSON.parse(fs.readFileSync(path.join(docs, "aztec-node.json"), "utf8")).ref, "v6.0.1"); +}); + +test("a wrong worktree, a dirty docs/, another major, a pinned commit off the branch and a failed pin leave the main paths and the line untouched", () => { + const before = snapshot(docs); + const cases: [string, () => ReturnType, RegExp][] = [ + ["no cut", () => promote("v6.0.1", { CUT: undefined }), /not the cut worktree/], + ["another worktree", () => promote("v6.0.1", { CUT: os.tmpdir() }), /not the cut worktree/], + ["dirty docs/", () => (write(path.join(docs, "docs-developers/docs/wip.md"), "wip\n"), promote("v6.0.1")), /uncommitted changes/], + ["another major", () => promote("v7.0.0"), /v7\.0\.0 is not a v6 release/], + ["off the branch", () => promote("v6.0.1", { COMPARE_STATUS: "diverged" }), new RegExp(`${PINNED}\\) is not on aztec-labs-eng/aztec-node's v6 branch .*diverged`)], + ["failed pin", () => promote("v6.0.1", { PIN_FAIL: "1" }), /pinning line v6 to v6\.0\.1 failed/], + ]; + for (const [name, run, message] of cases) { + git(root, "reset", "-q", "--hard"); + git(root, "clean", "-qfd"); + const r = run(); + assert.notEqual(r.status, 0, name); + assert.match(r.stderr, message, name); + fs.rmSync(path.join(docs, "docs-developers/docs/wip.md"), { force: true }); + assert.deepEqual(snapshot(docs), before, name); + assert.equal(git(root, "status", "--porcelain"), "", name); + } +}); diff --git a/docs/scripts/promote_line.sh b/docs/scripts/promote_line.sh new file mode 100755 index 00000000000..1b63c4618c4 --- /dev/null +++ b/docs/scripts/promote_line.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Promotes a dev line (docs/lines//) into a release cut's main paths, pinned to the release tag. +# Only a cut's worktree ($CUT, from its env.sh) may run it: it rewrites main's pages. The promoted +# pages keep quoting docs/lines// snippets, which include_code allows while both pins name one +# commit. +# +# CUT= docs/scripts/promote_line.sh +set -euo pipefail + +fail() { + echo "promote_line: $*" >&2 + exit 1 +} +unpin() { + git -C "$root" checkout -q -- "docs/lines/$line/aztec-node.json" + fail "$@" +} +[ $# -eq 2 ] || { echo "usage: CUT= $0 " >&2; exit 2; } +line=$1 tag=$2 +docs=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P) +root=$(dirname "$docs") + +[[ "$line" =~ ^v([0-9]+)$ ]] || fail "$line is not a line name (v)" +major=${BASH_REMATCH[1]} +line_root=$docs/lines/$line +[ -f "$line_root/aztec-node.json" ] || fail "no line $line: docs/lines/$line/aztec-node.json is missing" +[ -n "${CUT:-}" ] && [ "$(cd "$CUT" 2>/dev/null && pwd -P)" = "$root" ] || + fail "this is $root, not the cut worktree: run it from the cut, with the cut's env.sh sourced (\$CUT)" +[ -z "$(git -C "$root" status --porcelain -- docs)" ] || fail "docs/ has uncommitted changes: commit or discard them first" +[[ "$tag" =~ ^v${major}\. ]] || fail "$tag is not a v$major release, and line $line takes only v$major tags" + +node "$docs/scripts/aztec_node.mts" --line "$line" pin "$tag" || unpin "pinning line $line to $tag failed; the main paths are untouched" +# The commit the pin recorded, not the tag, which can move after the pin resolves it; and the +# repository the pin enforces, not the one the line named before. +read -r repo commit < <(node -p 'const p = require(process.argv[1]); new URL(p.repository).pathname.slice(1) + " " + p.commit' "$line_root/aztec-node.json") +status=$(gh api "repos/$repo/compare/$line...$commit" --jq .status) || unpin "cannot compare $tag ($commit) with $repo's $line branch" +case "$status" in + behind | identical) ;; + *) unpin "$tag ($commit) is not on $repo's $line branch (compare $line...$commit: $status)" ;; +esac + +for tree in docs-developers docs-operate; do + rm -rf "${docs:?}/$tree" + cp -R "$line_root/$tree" "$docs/$tree" +done +cp "$line_root/sidebars-developer.js" "$line_root/sidebars-operate.js" "$docs/" +cp "$line_root/aztec-node.json" "$docs/aztec-node.json" +echo "promoted line $line at $tag into docs/: commit it as the promotion commit" diff --git a/docs/src/__tests__/network_docs.test.js b/docs/src/__tests__/network_docs.test.js index 0e3bf38f24b..ebccf37200b 100644 --- a/docs/src/__tests__/network_docs.test.js +++ b/docs/src/__tests__/network_docs.test.js @@ -10,6 +10,7 @@ const { lineApiFolder, lineInstances, llmsRoutes, + networkApiFolder, networkSection, startHere, startHereLinks, @@ -96,6 +97,12 @@ describe("Aztec.nr API folders", () => { }); }); + it("give each network the folder of its version, shared when the networks share one", () => { + const folders = (config) => ["mainnet", "testnet", "devnet"].map((type) => networkApiFolder(config, type)); + assert.deepStrictEqual(folders(shared), ["mainnet", "mainnet", undefined]); + assert.deepStrictEqual(folders(split), ["mainnet", "testnet", undefined]); + }); + it("send the API page of every released version to a folder that exists, whatever its label", () => { const config = require("../../developer_version_config.json"); const [developer] = docsInstances(config, config, true); diff --git a/docs/src/network_docs.js b/docs/src/network_docs.js index 7b1af099c82..f708f67dda3 100644 --- a/docs/src/network_docs.js +++ b/docs/src/network_docs.js @@ -139,6 +139,19 @@ function lineApiFolders(developerConfig, lines) { ); } +/** + * The API reference folder a network's docs link: the one `apiReferenceDirs` serves for the version + * that network reads, so networks on one version share it. + * + * @param {Record} developerConfig release type → version + * @param {string} network a release type + * @returns {string | undefined} undefined for a release type no network maps (nightly, devnet) + */ +function networkApiFolder(developerConfig, network) { + const version = NETWORKS.includes(network) && developerConfig[network]; + return version ? aztecNrApiFolders(docsInstances(developerConfig, {}, true)[0])[version] : undefined; +} + /** * The API reference folders of each docs version a network reads, one per kind, in the folder * aztecNrApiFolders names (the TypeScript reference is published per network the same way). @@ -363,6 +376,7 @@ module.exports = { lineApiFolders, lineInstances, llmsRoutes, + networkApiFolder, networkSection, scopedApiIndexes, startHere, diff --git a/docs/src/preprocess/__tests__/include_code.test.js b/docs/src/preprocess/__tests__/include_code.test.js index eac35153b20..e57d416d4f6 100644 --- a/docs/src/preprocess/__tests__/include_code.test.js +++ b/docs/src/preprocess/__tests__/include_code.test.js @@ -140,6 +140,17 @@ describe("include_code", () => { await assert.rejects(preprocessIncludeCode(include("docs/lines/v1/examples/a.ts"), "page.md", root.rootDir), /is line v1's, but this page is main's/); }); + it("lets main's pages quote a line's files while both pin one commit, as a promoted line cut does", async () => { + const line = path.join(root.rootDir, "docs/lines/v1"); + write(path.join(line, "aztec-node.json"), fs.readFileSync(path.join(root.rootDir, "docs/aztec-node.json"))); + write(path.join(line, "examples/a.ts"), "// docs:start:x\nconst promoted = 1;\n// docs:end:x\n"); + process.env.DOCS_COMMIT = "def456"; + + const { content } = await preprocessIncludeCode("#include_code x /docs/lines/v1/examples/a.ts typescript\n", "page.md", root.rootDir); + assert.match(content, /const promoted = 1/); + assert.ok(content.includes("aztec-packages/blob/def456/docs/lines/v1/examples/a.ts#L1-L3")); + }); + it("checks a line's checkout even after main's check passed on the same directory", async () => { const line = path.join(root.rootDir, "docs/lines/v1"); const tree = path.join(line, ".aztec-node/tree"); diff --git a/docs/src/preprocess/__tests__/include_version.test.js b/docs/src/preprocess/__tests__/include_version.test.js index f5c0d6a0e87..071c637750f 100644 --- a/docs/src/preprocess/__tests__/include_version.test.js +++ b/docs/src/preprocess/__tests__/include_version.test.js @@ -187,20 +187,48 @@ describe("preprocessIncludeVersion", () => { describe("#api_ref_version macro", () => { // Only testnet and mainnet API references are published; other builds use the generated next/. + // A network links the folder the build serves for its version, which it shares with any network + // on the same version. + const { apiReferenceDirs, docsInstances } = require("../../network_docs"); + const config = require("../../../developer_version_config.json"); + const served = (network) => + apiReferenceDirs(docsInstances(config, {}, true)[0]).find((d) => d.networks.includes(network)).folder; const testCases = [ ["nightly", "next"], ["devnet", "next"], - ["testnet", "testnet"], - ["mainnet", "mainnet"], + ["testnet", served("testnet")], + ["mainnet", served("mainnet")], ]; + const TAGS = ["NIGHTLY_TAG", "DEVNET_TAG", "TESTNET_TAG", "MAINNET_TAG", "KEEP_DEVELOPER_VERSIONS"]; + const apiRefVersion = async (vars) => { + for (const v of TAGS) delete process.env[v]; + setEnv(vars); + return (await preprocessIncludeVersion("#api_ref_version", "test.md")).content; + }; + testCases.forEach(([releaseType, expected]) => { it(`resolves to ${expected} for ${releaseType}`, async () => { - setEnv({ RELEASE_TYPE: releaseType }); - const { content } = await preprocessIncludeVersion("#api_ref_version", "test.md"); - assert.strictEqual(content, expected); + assert.strictEqual(await apiRefVersion({ RELEASE_TYPE: releaseType }), expected); }); }); + + // A release cut freezes these links into its snapshot before it maps the new version, so they + // name the folder the build serves once the release type reads the version being built. + it("names testnet's own folder for a testnet release on a version mainnet does not run", async () => { + assert.strictEqual(await apiRefVersion({ RELEASE_TYPE: "testnet", TESTNET_TAG: "999.0.0" }), "testnet"); + }); + + it("names mainnet's folder for a testnet release on mainnet's version", async () => { + assert.strictEqual(await apiRefVersion({ RELEASE_TYPE: "testnet", TESTNET_TAG: config.mainnet }), "mainnet"); + }); + + it("keeps the folder the developer versions serve now when the release does not change them", async () => { + assert.strictEqual( + await apiRefVersion({ RELEASE_TYPE: "testnet", TESTNET_TAG: "999.0.0", KEEP_DEVELOPER_VERSIONS: "1" }), + served("testnet"), + ); + }); }); describe("on a line page", () => { diff --git a/docs/src/preprocess/include_code.js b/docs/src/preprocess/include_code.js index 0d03fb402cd..9d6ce88f569 100644 --- a/docs/src/preprocess/include_code.js +++ b/docs/src/preprocess/include_code.js @@ -74,6 +74,9 @@ function checkSnippetLine(relativeCodeFilePath, rootDir, line) { const owner = lineOf(relativeCodeFilePath, rootDir); if (!owner && !MAIN_ONLY.test(relativeCodeFilePath)) return; if (owner?.name === line?.name) return; + // Pins naming one commit quote the same code: a line cut (scripts/promote_line.sh) serves the + // line's pages from main's paths under the line's pin, and they keep quoting the line's files. + if (readPin(rootDir, owner).commit === readPin(rootDir, line).commit) return; const whose = (l) => (l ? `line ${l.name}'s` : "main's"); throw new Error(`${relativeCodeFilePath} is ${whose(owner)}, but this page is ${whose(line)}: quote the page's own copy`); } diff --git a/docs/src/preprocess/include_version.js b/docs/src/preprocess/include_version.js index 109df9568de..a3f06f600fe 100644 --- a/docs/src/preprocess/include_version.js +++ b/docs/src/preprocess/include_version.js @@ -2,7 +2,7 @@ const fs = require("fs"); const path = require("path"); const { processConditionalBlocks } = require("./conditional_content"); const { releaseNameFor, versionLabel } = require("../release_names"); -const { lineApiFolders } = require("../network_docs"); +const { lineApiFolders, networkApiFolder } = require("../network_docs"); const { lineOf, readPin } = require("./line"); // Load version defaults from config file (source of truth for version→type mapping) @@ -128,10 +128,15 @@ async function preprocessIncludeVersion(markdownContent, filePath = "unknown", r ); const releaseNetwork = getReleaseNetwork(releaseType); - // API ref paths - const apiRefVersion = releaseType === "testnet" ? "testnet" - : releaseType === "mainnet" ? "mainnet" - : "next"; + // The folder the build serves once this release type reads the version being built: a release + // cut freezes these links into its snapshot before it maps that version. A testnet on mainnet's + // version has no folder of its own. A release that leaves the developer docs alone (a network-only + // cut) keeps their versions, so its build links folders it serves. + const developerVersions = process.env.KEEP_DEVELOPER_VERSIONS === "1" + ? developerVersionConfig + : { ...developerVersionConfig, [releaseType]: `v${stripV(releaseVersion)}` }; + const apiRefVersion = networkApiFolder(developerVersions, releaseType) + ?? (releaseType === "testnet" || releaseType === "mainnet" ? releaseType : "next"); // Step 1: Process conditional blocks FIRST (before version substitution) // This allows conditionals to contain version macros