Skip to content

fix(release): extract frozen docs snapshots from the release ref only - #8154

Open
bokelley wants to merge 2 commits into
mainfrom
fix/release-docs-exact-snapshot
Open

bokelley wants to merge 2 commits into
mainfrom
fix/release-docs-exact-snapshot

Conversation

@bokelley

@bokelley bokelley commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

The frozen docs snapshot for 3.2.4 (bot PR #8150) failed its checks because the release-docs workflow leaks main-only pages into it. This fixes the extraction. It does not touch any existing dist/docs/<semver> snapshot.

Root cause

release-docs.yml runs in a checkout of main and did git archive "$SOURCE_REF" -- docs | tar -x -C "dist/docs/$VERSION" --strip-components=1 || { …fallback… }. The target directory does not exist yet, so tar -C always fails and the fallback always runs: it extracts the tag over main's own docs/ tree and mv docs/*s the merged result into the snapshot. Every page that exists only on main lands in the "frozen" snapshot. Reproduced locally: 393 files for v3.2.4, whose tag has 388.

Effects found:

  • chore: snapshot docs for v3.2.4 #8150 (dist/docs/3.2.4) carries 5 pages not in the tag: reference/trust-json (the actual broken-links/nav-coverage failure), runbooks/training-agent-gcs-reporting.md, and the three 3.3 preview pages.
  • The merged 3.2.3 snapshot carries 4 such pages.
  • The merged 3.1.27 snapshot (chore: snapshot docs for v3.1.27 #8026) carries about 50 pages that are not in the v3.1.27 tag (3.2 and 3.3 pages). It is immutable and not changed here; whether and how to treat it is a maintainer decision.

The other #8150 failures ("Missing runtime schema snapshot 3.2.4" in the production docs index smoke and the dependent server tests) are fixed by the 3.2.4 forward merge, #8153, not by this PR.

Change

  • scripts/extract-release-docs-snapshot.sh extracts git archive <ref> -- docs into an empty directory, leaves the checkout's docs/ untouched, and fails closed unless the snapshot's file list equals the ref's.
  • One explicit exception, carried over from current behavior: the stable 3.2 navigation (parity-locked with 3.2.x since chore(docs): sync 3.2.3 maintenance snapshot navigation #8000) links a "3.3 preview" group (reference/whats-new-in-3-3, reference/3-3-beta, reference/migration/3-2-to-3-3). A stable 3.2.x snapshot carries exactly those three from the checkout, logged, with their development-only warnings, until that nav group is removed. Nothing else leaks. Removing the group and this list is a docs-owner decision I did not make here.
  • The script also refuses (before any mutation) to run when dist/docs/<version> is already tracked in the checkout's HEAD tree or index, so a rerun can never rewrite a published snapshot. Only untracked scratch output from an interrupted run is replaced. A regression commits a published snapshot, reruns extraction (same and different ref), expects failure, and verifies the bytes and git status are unchanged.
  • release-docs.yml calls the script; tests/extract-release-docs-snapshot.test.cjs covers exactness, tag-wins-over-main, other lines carry nothing, checkout untouched, stale-snapshot replacement, fail-closed cases, and that the workflow no longer has the overlay fallback. Wired into npm test.

Evidence

  • Scratch simulation on current main: exact-tag extraction + the existing link rewrite + update-release-docs-nav.mjs 3.2.4 3.2 gives 391 files (388 + the 3 preview pages), and docs-nav-validation passes 49/49 (trust-json is reported as awaiting the next snapshot, as designed). The result matches chore: snapshot docs for v3.2.4 #8150's tree except it drops trust-json and the runbook, and the two preview pages are newer because main moved; docs.json, .dockerignore, llms-current.md and schema-tools.ts match chore: snapshot docs for v3.2.4 #8150 exactly.
  • Independent Sonnet code review: no defects; two fail-closed fragilities (non-ASCII names, symlinks) were addressed.
  • Local pre-commit hook passed (1,106 root tests, full server unit suite, typecheck).

No changeset: the files are not protocol-scoped (check-changeset-protocol-scope passes).

Follow-ups (not in this PR)

  1. This is release tooling and release-docs.yml is identical on 3.2.x; the release: published event runs the tag's workflow copy, so cherry-pick to 3.2.x after this lands for the next 3.2.x snapshot.
  2. Regeneration of chore: snapshot docs for v3.2.4 #8150: after chore(release): forward-merge 3.2.4 release records into main #8153 and this PR are merged, dispatch release-docs.yml for 3.2.4 on main. It reuses the branch auto/docs-v3.2.4, so the existing bot PR is updated rather than replaced.

🤖 Generated with Claude Code

The release-docs workflow runs in a checkout of main and extracted the
release tag with `tar -x -C dist/docs/<version>` into a directory that did
not exist yet. That always failed and fell through to an unconditional
fallback that extracted the tag over main's own docs/ tree, then moved the
merged result into the snapshot. Every page that exists only on main ended up
in the frozen "<version>" snapshot: the 3.2.4 snapshot PR carried five
(reference/trust-json, the training-agent GCS runbook and three 3.3 story
pages) and the merged 3.1.27 snapshot carries about fifty 3.2 and 3.3 pages.

Extract through scripts/extract-release-docs-snapshot.sh instead. It
extracts `git archive <ref> -- docs` into an empty directory, leaves the
checkout's docs/ untouched, and fails closed unless the snapshot's file list
equals the ref's. The only exception is the three 3.3 preview story pages
that the stable 3.2 navigation already links; a stable 3.2.x snapshot carries
exactly those, loudly and covered by tests, until the preview group is
removed from the navigation.

Existing dist/docs snapshots are not changed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ladon verdict: Escalate to human review

Escalate — gated path requires human/CODEOWNERS approval.

This PR modifies .github/workflows/release-docs.yml, which matches the deterministic hard approval gate (gated_paths: true). review_decision is REVIEW_REQUIRED, not APPROVED, so the gate is NOT satisfied and the outcome must be escalate per decision table row 2.

Escalation reasons

  • .github/workflows/release-docs.yml is under a hard approval gate (.github/workflows/**); human/CODEOWNERS review is required before merge.

The change itself looks clean: it replaces broken inline release-docs extraction with scripts/extract-release-docs-snapshot.sh, which extracts a git archive of the ref into an empty dir and fails closed unless the file list matches the tag. Exactness checks cover files and symlinks with matching collation and core.quotepath=off; the 3.3-preview exception is gated, logged, and fail-closed; tests cover exactness, tag-wins-over-main, checkout-untouched, stale replacement, and fail-closed paths. No Critical/High/Medium findings, no changeset required (not protocol-scoped). Once a human/CODEOWNERS approval lands, this is approvable.

Why human review

  • .github/workflows/release-docs.yml is under a hard approval gate (.github/workflows/**) and review_decision is REVIEW_REQUIRED — human/CODEOWNERS approval required before merge.
  • This PR touches a path under a hard, non-overridable approval gate (.github/workflows/release-docs.yml (modified) matches .github/workflows/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

@aao-secretariat aao-secretariat Bot added the ladon/needs-human-review Ladon has escalated this PR for human review. label Oct 12, 2026
…mmitted

A rerun of the release-docs workflow on a version whose dist/docs snapshot is
already tracked in the checkout would delete and rewrite a published, immutable
release record. The extraction script now fails before touching it when the
snapshot exists in the HEAD tree or the index. Only untracked output left by an
interrupted run is replaced.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ladon verdict: Escalate to human review

Escalate — gated path requires human/CODEOWNERS approval.

This PR modifies .github/workflows/release-docs.yml, which matches the hard, path-based approval gate .github/workflows/** (gated_paths: true). The current GitHub review_decision is REVIEW_REQUIRED, not APPROVED, so the gate is not satisfied and Ladon cannot auto-approve regardless of how clean the diff is.

The change itself is sound: the reviewer found no blocking issues. The delta adds a fail-closed immutability guard to scripts/extract-release-docs-snapshot.sh (checks both HEAD tree and index for dist/docs/<version> before any mutation, so published snapshots can never be rewritten and rm -rf only reaches untracked scratch), plus two well-constructed tests (committed, staged, different-ref rerun; bytes and git status asserted unchanged). This aligns with the immutable-released-artifacts floor. No critical/high/medium findings surfaced.

Escalation reasons

  • .github/workflows/release-docs.yml (modified) is under a hard approval gate (.github/workflows/**) and review_decision is REVIEW_REQUIRED, not APPROVED. A human/CODEOWNERS approval must be recorded before this can merge.

Once a human/CODEOWNERS approval lands, this PR should fall through to approve on its next run — the diff is clean with no actionable findings.

Why human review

  • .github/workflows/release-docs.yml is under a hard approval gate (.github/workflows/**) and review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval is required before merge.
  • This PR touches a path under a hard, non-overridable approval gate (.github/workflows/release-docs.yml (modified) matches .github/workflows/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ladon/needs-human-review Ladon has escalated this PR for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant