diff --git a/.claude/skills/new-revision/SKILL.md b/.claude/skills/new-revision/SKILL.md
new file mode 100644
index 000000000..da42f1843
--- /dev/null
+++ b/.claude/skills/new-revision/SKILL.md
@@ -0,0 +1,165 @@
+---
+name: new-revision
+description: Scaffold a new revision of an existing document by copying the latest version folder to a new version, setting the draft flag, and creating an appropriately-prefixed git branch for the review process.
+---
+
+# New Revision
+
+Scaffold a new revision of an existing document on the RMC documentation site. Copies the latest version folder to a new version directory, marks the document as draft, and creates a `docs/major/` or `docs/minor/` branch ready for the review workflow.
+
+**Arguments:** `$ARGUMENTS` — optional. If provided, use as hints for the prompts below (e.g., a document path or version number). Still confirm each value with the user before proceeding.
+
+## Step 1: Gather Information via Interactive Prompts
+
+Prompt the user for each value, one at a time. Show sensible defaults where possible. Do NOT proceed until all values are confirmed.
+
+### 1a — Document selection
+
+Ask: "Which existing document are you revising?"
+
+Read [static/versions/latestVersions.json](static/versions/latestVersions.json) and present the keys as a numbered list. The user picks one. The selected key is the `docBasePath` (e.g., `desktop-applications/lifesim/users-guide`).
+
+The corresponding value in the JSON is the `currentVersion` (e.g., `v1.0`).
+
+### 1b — Revision type
+
+Ask: "Is this a major revision or a minor revision?"
+
+- **Major revision** — substantial changes warranting a new major version. Branch prefix: `docs/major/`. Goes through Lane 2 (Peer → Lead Civil review).
+- **Minor revision** — smaller updates warranting a minor version bump. Branch prefix: `docs/minor/`. Goes through Lane 3 (Peer review only).
+
+### 1c — New version number
+
+Compute the default based on revision type:
+- Major: increment the major component, reset minor to 0 (e.g., `v1.0` → `v2.0`, `v1.5` → `v2.0`).
+- Minor: increment the minor component (e.g., `v1.0` → `v1.1`, `v1.5` → `v1.6`).
+
+Ask: "The new version will be `{newVersion}`. Is that correct, or would you like a different version number?"
+
+### 1d — Branch name
+
+Compute the default branch name as `docs/{major|minor}/{slug}-{newVersionWithoutV}` where `{slug}` is the last segment of the docBasePath (e.g., `users-guide`). Example: `docs/major/users-guide-v2.0`.
+
+Ask: "I'll use branch name `{branchName}`. Is that correct, or would you like a different name?"
+
+### 1e — Confirmation
+
+Display a summary:
+
+```
+Document: {docBasePath}
+Current version: {currentVersion}
+New version: {newVersion}
+Revision type: {major|minor}
+Branch: {branchName}
+Source folder: docs/{docBasePath}/{currentVersion}/
+Target folder: docs/{docBasePath}/{newVersion}/
+Figures source: static/figures/{docBasePath}/{currentVersion}/
+Figures target: static/figures/{docBasePath}/{newVersion}/
+Bibliography: static/bibliographies/{docBasePath}/{newVersion}/bib.json
+```
+
+Ask: "Does this look correct? (yes/no)"
+
+If no, ask which value to change and loop back.
+
+## Step 2: Create the git branch
+
+Create and check out the branch from the current `main` (not from the user's current branch — start clean):
+
+```bash
+git fetch origin main
+git checkout -b {branchName} origin/main
+```
+
+If the branch already exists, abort and report the conflict to the user.
+
+## Step 3: Copy the version folder
+
+Copy the entire current version directory to the new version directory:
+
+```bash
+cp -r docs/{docBasePath}/{currentVersion}/ docs/{docBasePath}/{newVersion}/
+```
+
+Then copy the figures folder:
+
+```bash
+cp -r static/figures/{docBasePath}/{currentVersion}/ static/figures/{docBasePath}/{newVersion}/
+```
+
+Then copy the bibliography folder:
+
+```bash
+cp -r static/bibliographies/{docBasePath}/{currentVersion}/ static/bibliographies/{docBasePath}/{newVersion}/
+```
+
+If any source folder doesn't exist, skip it and note in the final report.
+
+## Step 4: Update the version history file
+
+Read `docs/{docBasePath}/{newVersion}/00-version-history.mdx` and add a new placeholder row at the top of the `TableVersionHistory` props arrays:
+
+- `versions`: prepend the new version number without the `v` prefix (e.g., `'2.0'`)
+- `dates`: prepend the current month and year (e.g., `'April 2026'`)
+- `descriptions`: prepend `'Placeholder — describe the changes in this revision.'`
+- `modifiedBy`: prepend `'Enter author name'`
+- `reviewedBy`: prepend `'-'`
+- `approvedBy`: prepend `'-'`
+
+The author will fill in the actual values during the PR. The site admin will fill in `reviewedBy`/`approvedBy` at merge time.
+
+## Step 5: Set the draft flag
+
+Find the document's entry in the appropriate landing page JS file (search `src/pages/` for the `doc_location` matching `{docBasePath}`). Common locations:
+
+- Desktop apps: `src/pages/desktop-applications/{software}.js`
+- Toolboxes: `src/pages/toolboxes/{suite}.js`
+- Web apps: `src/pages/web-applications/{software}.js`
+- Dev: `src/pages/dev.js`
+
+In the matching entry, change `draft: false` to `draft: true`.
+
+> Note: this flips the draft flag on the *currently published* version too, since the flag is per-document, not per-version. The version-aware watermark logic in [src/theme/DocItem/index.js](src/theme/DocItem/index.js) ensures the watermark only appears on the *latest* version of a flagged document. Until this PR is merged, the latest version on the live site is still the previous version, which will not be watermarked. Once merged, the new version becomes latest and (briefly, until the site admin flips the flag back to `false`) the watermark will appear on it.
+
+## Step 6: Run generation scripts
+
+Run the build generation scripts to pick up the new version:
+
+```bash
+npm run sidebars && npm run counters && npm run versions
+```
+
+Verify no errors. If errors occur, diagnose and fix.
+
+## Step 7: Verify and report
+
+1. Glob to confirm the new version folder exists at `docs/{docBasePath}/{newVersion}/`
+2. Confirm the version history file has the new row
+3. Confirm the landing page JS has `draft: true`
+4. Confirm the branch is checked out (`git branch --show-current`)
+5. Report a summary to the user:
+
+```
+New revision scaffolded successfully!
+
+Document: {docBasePath}
+Old version: {currentVersion}
+New version: {newVersion}
+Branch: {branchName}
+
+Created:
+ - docs/{docBasePath}/{newVersion}/ (copied from {currentVersion})
+ - static/figures/{docBasePath}/{newVersion}/ (copied)
+ - static/bibliographies/{docBasePath}/{newVersion}/ (copied)
+
+Modified:
+ - docs/{docBasePath}/{newVersion}/00-version-history.mdx (new placeholder row)
+ - {landing page JS file} (draft: true)
+
+Next steps:
+ 1. Edit the new version's MDX files to make your changes
+ 2. Update 00-version-history.mdx with a real description and your name
+ 3. Run `npm start` to preview locally
+ 4. When ready, commit and open a PR (the workflow will detect the branch prefix and start {Lane 2: Peer → Lead Civil | Lane 3: Peer review} automatically)
+```
diff --git a/.claude/skills/pr/SKILL.md b/.claude/skills/pr/SKILL.md
index 8607174a2..4509f578f 100644
--- a/.claude/skills/pr/SKILL.md
+++ b/.claude/skills/pr/SKILL.md
@@ -68,28 +68,46 @@ Read `.claude/skills/git-conventions.md` for PR conventions.
- Derived from the **overall purpose** of all commits on the branch, not just the latest commit
- Example: "Redesign homepage with product tile grid layout"
-### Body
-Use this format — **Summary section only, no Test plan**:
+### Body — choose the format based on the branch prefix
-```markdown
-## Summary
-- {1-3 bullet points describing the changes and their purpose}
-```
+**If the current branch starts with `docs/`** → use the **Template Style** (Step 5a). The repo's PR template at `.github/pull_request_template.md` contains a checklist for document authors, including the Lane 1 "Technical edit comments addressed" checkbox that the stage-progression workflow watches for. Passing `--body` to `gh pr create` overrides the template entirely, so the skill must reproduce the template structure with the auto-generated content filled in.
-**Do NOT include:**
+**Otherwise (infrastructure, tooling, dependency, or any non-doc branch)** → use the **Summary Style** (Step 5b). These PRs are silently ignored by the review workflow and don't need the doc-author checklist.
+
+In both styles, the summary content should be based on **ALL** commits on the branch, not just the most recent one. Read through all the commit messages and the diff to understand the full scope. If `$ARGUMENTS` was provided, use it to focus the title and description.
+
+**Do NOT include in either style:**
- A "Test plan" section
- Any AI attribution, "Generated with Claude", or "Co-Authored-By" lines
-If `$ARGUMENTS` was provided, use it to focus the title and description.
+### Step 5a: Template Style (for `docs/` branches)
+
+1. Read [.github/pull_request_template.md](.github/pull_request_template.md). Use it as the structural skeleton.
+2. Compute the auto-generated summary: 1–3 bullets describing the changes.
+3. Compute the list of affected MDX documents: from `git diff --name-only main...HEAD`, keep entries matching `docs/**/*.mdx`. If the base is not `main`, use that instead.
+4. Build the PR body by transforming the template:
+ - Under `## Description`, replace the `` comment with the summary bullets.
+ - Under `## Affected documents`, replace the bare `- ` line with the list of affected MDX files. Format each as a markdown link relative to the repo root: `- [filename.mdx](docs/full/path/filename.mdx)`. If there are no changed MDX files, write `- _No MDX files changed in this PR._`
+ - Leave the `## Related issue(s)` section's comment placeholder unchanged so the author can fill it in.
+ - Leave **all checklist items unchecked**, including the Lane 1 Technical edit checkbox. The author checks them as they complete each item; the workflow specifically depends on the Technical edit checkbox being present and unchecked at PR open time.
+ - Leave the `## Notes for reviewers` comment placeholder unchanged.
+
+The result should be a complete copy of the template with the Description and Affected documents sections populated.
-The summary should be based on ALL commits on the branch, not just the most recent one. Read through all the commit messages and the diff to understand the full scope.
+### Step 5b: Summary Style (for non-`docs/` branches)
+
+Use this format — **Summary section only, no Test plan**:
+
+```markdown
+## Summary
+- {1-3 bullet points describing the changes and their purpose}
+```
## Step 6: Create the PR
```bash
gh pr create --title "{title}" --body "$(cat <<'EOF'
-## Summary
-{bullets}
+{body from Step 5a or Step 5b}
EOF
)"
```
diff --git a/.claude/skills/technical-edit/SKILL.md b/.claude/skills/technical-edit/SKILL.md
new file mode 100644
index 000000000..4178ecdfd
--- /dev/null
+++ b/.claude/skills/technical-edit/SKILL.md
@@ -0,0 +1,54 @@
+---
+name: technical-edit
+description: Run an AI-assisted technical edit on the current PR. Reads all changed MDX files, evaluates them against the RMC technical editing prompt, and posts inline review comments on the PR via the GitHub API.
+---
+
+# Technical Edit
+
+Run an AI-assisted technical edit on the current PR's documentation files.
+
+**Arguments:** `$ARGUMENTS` — optional PR number. If omitted, infer from the current branch.
+
+## Step 1: Identify the PR and changed files
+
+Determine the PR number from the current branch (use `gh pr view --json number`). List all changed `.mdx` files in the PR using `gh pr diff --name-only | grep '\.mdx$'`.
+
+## Step 2: Read the review prompt
+
+Read the standardized review prompt from `.github/ai-review/technical-editor-prompt.md`. This file contains the full set of review instructions including grammar rules, tense requirements, terminology conventions, Section 508 compliance checks, and style guidelines.
+
+## Step 3: Review each file
+
+For each changed MDX file:
+1. Read the file contents
+2. Apply the review prompt to the file
+3. For each finding, record: file path, line number or line range, severity (must-fix / should-fix / suggestion), the issue description, and a suggested fix if applicable
+
+## Step 4: Post the review on the PR
+
+Use the GitHub CLI to submit a bundled PR review with inline comments:
+
+```bash
+gh api repos/:owner/:repo/pulls/:pr/reviews \
+ --method POST \
+ -f body="AI technical edit complete. $(N) comments across $(M) files. Review prompt version: $(VERSION)." \
+ -f event="COMMENT" \
+ -f comments="[{\"path\": \"...\", \"line\": N, \"body\": \"...\"}]"
+```
+
+Each comment should be formatted as:
+```
+**[severity]** issue description
+
+> Suggested fix (if applicable)
+```
+
+Where severity is one of: 🔴 Must fix, 🟡 Should fix, 🔵 Suggestion.
+
+## Step 5: Report
+
+Tell the user:
+- How many comments were posted
+- How many files were reviewed
+- Which review prompt version was used
+- Remind the author to check the "Technical edit comments addressed" checkbox in the PR description when they're done addressing comments
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..ffb764b7f
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,13 @@
+/.github/ @usace-rmc/docs-admin
+/docusaurus.config.js @usace-rmc/docs-admin
+/tailwind.config.js @usace-rmc/docs-admin
+/package.json @usace-rmc/docs-admin
+/package-lock.json @usace-rmc/docs-admin
+/scripts/ @usace-rmc/docs-admin
+/src/theme/ @usace-rmc/docs-admin
+/src/pages/ @usace-rmc/docs-admin
+/src/components/ @usace-rmc/docs-admin
+/src/contexts/ @usace-rmc/docs-admin
+/src/clientModules/ @usace-rmc/docs-admin
+/src/css/ @usace-rmc/docs-admin
+/src/draftDocs.js @usace-rmc/docs-admin
diff --git a/.github/ai-review/technical-editor-prompt.md b/.github/ai-review/technical-editor-prompt.md
new file mode 100644
index 000000000..b27029a9e
--- /dev/null
+++ b/.github/ai-review/technical-editor-prompt.md
@@ -0,0 +1,59 @@
+# RMC Technical Editor Review Prompt
+
+You are a technical editor reviewing documentation for the U.S. Army Corps of Engineers Risk Management Center (USACE RMC). The documentation is written in MDX (Markdown with JSX) and covers dam safety, levee safety, and related risk analysis topics.
+
+## Audience
+
+Practicing dam and levee safety engineers within USACE. These are technical professionals who understand the domain — do not flag correct use of technical terminology as jargon.
+
+## Review criteria
+
+### Grammar and mechanics
+- Spelling, punctuation, and sentence structure
+- Subject-verb agreement
+- Correct use of hyphens, em dashes, and en dashes
+- Consistent serial comma usage
+
+### Tense and voice
+- Prefer third-person active voice for procedures and descriptions
+- Flag passive voice when active would be clearer
+- Flag inconsistent tense within a section
+
+### Clarity and concision
+- Flag wordy passages that could be shortened without losing meaning
+- Flag ambiguous pronouns or unclear referents
+- Flag sentences over 40 words that could be split
+- Flag buried leads — key information at the end of a long sentence
+
+### Terminology consistency
+- Flag inconsistent use of terms within the document (e.g., alternating between "embankment" and "dam" when referring to the same structure)
+- Do NOT flag correct domain terminology as errors
+
+### Section 508 accessibility compliance
+- Every image must have alt text (check for `alt=` attribute)
+- Heading hierarchy must not skip levels (e.g., h2 followed by h4 without h3)
+- Link text must be descriptive (flag "click here" or "link" as link text)
+- Tables must have header rows
+- Lists must use proper markdown list syntax, not manual numbering with plain text
+- Color must not be the sole means of conveying information
+
+### Style consistency
+- Figure and table captions must follow a consistent format
+- Citations must use the site's citation key format
+- Units should be consistent within each document (metric or imperial, not mixed)
+- Acronyms must be defined on first use within each chapter
+
+## Output format
+
+For each finding, produce:
+- The file path and line number(s)
+- A severity level: 🔴 Must fix (errors, accessibility violations), 🟡 Should fix (clarity, consistency issues), 🔵 Suggestion (stylistic improvements)
+- A clear description of the issue
+- A suggested fix where possible (use GitHub suggestion block format)
+
+## What NOT to flag
+- Correct use of technical terminology, even if uncommon
+- MDX component syntax (imports, JSX elements)
+- Frontmatter fields
+- Matters of technical judgment or domain accuracy (that is the peer reviewer's job)
+- Alternative phrasings that are equally acceptable
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 000000000..f7a9bcca7
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,26 @@
+## Description
+
+
+
+## Affected documents
+
+-
+
+## Related issue(s)
+
+
+
+## Pre-submission checklist
+
+- [ ] I have previewed these changes locally or via the PR preview URL
+- [ ] My branch name uses one of the expected prefixes: `docs/new/`, `docs/major/`, `docs/minor/`, or `docs/fix/`
+- [ ] I have updated `00-version-history.mdx` if this change warrants a version entry
+- [ ] I have assigned a specific peer reviewer via the Reviewers sidebar (if known)
+
+## Technical edit (Lane 1 only)
+
+- [ ] Technical edit comments addressed — ready for Director review
+
+## Notes for reviewers
+
+
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 000000000..63f869c3f
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,50 @@
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+ inputs:
+ ref:
+ description: 'Branch or ref to deploy (leave blank for main)'
+ required: false
+ type: string
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: false
+
+jobs:
+ build:
+ name: Build site
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.ref || github.ref }}
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+ - run: npm ci
+ - run: npm run build
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: ./build
+
+ deploy:
+ name: Deploy to production
+ needs: build
+ runs-on: ubuntu-latest
+ environment:
+ name: production
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/pr-preview-cleanup.yml b/.github/workflows/pr-preview-cleanup.yml
new file mode 100644
index 000000000..971084574
--- /dev/null
+++ b/.github/workflows/pr-preview-cleanup.yml
@@ -0,0 +1,31 @@
+name: PR Preview Cleanup
+
+on:
+ pull_request:
+ types: [closed]
+
+permissions:
+ contents: read
+
+jobs:
+ cleanup:
+ name: Delete preview directory
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ repository: usace-rmc/RMC-Software-Documentation-Previews
+ ref: gh-pages
+ ssh-key: ${{ secrets.PREVIEW_DEPLOY_KEY }}
+ - name: Remove PR preview directory
+ env:
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ if [ -d "pr-${PR_NUMBER}" ]; then
+ rm -rf "pr-${PR_NUMBER}"
+ git add -A
+ git commit -m "Clean up preview for PR #${PR_NUMBER}"
+ git push
+ fi
diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml
new file mode 100644
index 000000000..a10b14fd5
--- /dev/null
+++ b/.github/workflows/pr-preview.yml
@@ -0,0 +1,61 @@
+name: PR Preview Build
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+ paths:
+ - 'docs/**'
+ - 'src/**'
+ - 'static/**'
+ - 'docusaurus.config.js'
+ - 'tailwind.config.js'
+ - 'package.json'
+ - 'package-lock.json'
+ - 'scripts/**'
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ build-and-deploy:
+ name: Build and deploy preview
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+ - run: npm ci
+ - name: Build site with PR-specific baseUrl
+ env:
+ DOCUSAURUS_URL: https://usace-rmc.github.io
+ DOCUSAURUS_BASE_URL: /RMC-Software-Documentation-Previews/pr-${{ github.event.pull_request.number }}/
+ run: npm run build
+ - uses: peaceiris/actions-gh-pages@v4
+ with:
+ deploy_key: ${{ secrets.PREVIEW_DEPLOY_KEY }}
+ external_repository: usace-rmc/RMC-Software-Documentation-Previews
+ publish_branch: gh-pages
+ publish_dir: ./build
+ destination_dir: pr-${{ github.event.pull_request.number }}
+ keep_files: true
+ user_name: 'github-actions[bot]'
+ user_email: 'github-actions[bot]@users.noreply.github.com'
+ commit_message: 'Deploy preview for PR #${{ github.event.pull_request.number }}'
+ - name: Post or update preview URL comment
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const prNumber = context.issue.number;
+ const url = `https://usace-rmc.github.io/RMC-Software-Documentation-Previews/pr-${prNumber}/`;
+ const marker = '';
+ const body = `${marker}\n\n📄 **Preview deployed**\n\n${url}\n\n_This preview updates automatically when new commits are pushed. Deleted when the PR closes._`;
+ const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber });
+ const existing = comments.data.find(c => c.user.type === 'Bot' && c.body.includes(marker));
+ if (existing) {
+ await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body });
+ } else {
+ await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, body });
+ }
diff --git a/.github/workflows/stage-progression.yml b/.github/workflows/stage-progression.yml
new file mode 100644
index 000000000..72edaec11
--- /dev/null
+++ b/.github/workflows/stage-progression.yml
@@ -0,0 +1,144 @@
+name: Stage Progression
+
+on:
+ pull_request:
+ types: [opened, reopened, labeled, edited]
+ pull_request_review:
+ types: [submitted]
+
+permissions:
+ pull-requests: write
+ issues: write
+ contents: read
+
+jobs:
+ progress:
+ name: Manage review stage
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run stage progression logic
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const pr = context.payload.pull_request;
+ if (!pr) return;
+
+ const prNumber = pr.number;
+ const branch = pr.head.ref;
+ const labels = pr.labels.map(l => l.name);
+
+ const LANE_LABELS = ['lane:new-doc', 'lane:major-revision', 'lane:minor-revision', 'lane:editorial-fix'];
+ const STAGE_LABELS = ['stage:needs-lane', 'stage:peer-review', 'stage:lead-civil-review', 'stage:ai-editor-review', 'stage:director-review', 'stage:ready-to-merge'];
+
+ function detectLane(b) {
+ if (b.startsWith('docs/new/')) return 'lane:new-doc';
+ if (b.startsWith('docs/major/')) return 'lane:major-revision';
+ if (b.startsWith('docs/minor/')) return 'lane:minor-revision';
+ if (b.startsWith('docs/fix/')) return 'lane:editorial-fix';
+ return null;
+ }
+
+ async function addLabels(ls) { if (ls.length) await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, labels: ls }); }
+ async function removeLabel(l) { try { await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, name: l }); } catch(e) {} }
+ async function postComment(body) { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, body }); }
+
+ const existingLane = labels.find(l => LANE_LABELS.includes(l));
+ const existingStage = labels.find(l => STAGE_LABELS.includes(l));
+
+ // ── PR opened/reopened ──
+ if (context.eventName === 'pull_request' && ['opened', 'reopened'].includes(context.payload.action)) {
+ // Only auto-process branches under docs/. Non-doc PRs (infrastructure,
+ // tooling, etc.) are silently ignored on open. An admin can still opt
+ // any PR into the review process by manually applying a lane:* label,
+ // which is handled by the labeled-event branch below.
+ if (!branch.startsWith('docs/')) return;
+ const lane = existingLane || detectLane(branch);
+ if (!lane) {
+ await addLabels(['stage:needs-lane']);
+ await postComment(`⚠️ **Could not determine review lane**\n\nBranch \`${branch}\` starts with \`docs/\` but does not match an expected sub-prefix (\`docs/new/\`, \`docs/major/\`, \`docs/minor/\`, \`docs/fix/\`).\n\n@usace-rmc/docs-admin please apply the correct \`lane:*\` label.`);
+ return;
+ }
+ const toAdd = [lane];
+ let comment;
+ if (lane === 'lane:editorial-fix') {
+ toAdd.push('stage:ready-to-merge');
+ comment = `📋 **Lane: Editorial Fix**\n\nNo formal review required.\n\n@usace-rmc/docs-admin please review, merge, and approve the deploy.`;
+ } else {
+ toAdd.push('stage:peer-review');
+ const laneName = lane.replace('lane:', '').replace(/-/g, ' ');
+ const scope = lane === 'lane:new-doc' ? 'Peer → Lead Civil → Technical Edit → Director' : lane === 'lane:major-revision' ? 'Peer → Lead Civil' : 'Peer review only';
+ comment = `📋 **Lane: ${laneName}**\n\nReview scope: ${scope}.\n\nCurrently in **peer review**. If no peer reviewer has been assigned, @usace-rmc/docs-admin please assign one via the Reviewers sidebar.`;
+ }
+ await addLabels(toAdd);
+ await postComment(comment);
+ return;
+ }
+
+ // ── Label manually applied ──
+ if (context.eventName === 'pull_request' && context.payload.action === 'labeled') {
+ const added = context.payload.label.name;
+ if (LANE_LABELS.includes(added) && (!existingStage || existingStage === 'stage:needs-lane')) {
+ await removeLabel('stage:needs-lane');
+ if (added === 'lane:editorial-fix') {
+ await addLabels(['stage:ready-to-merge']);
+ await postComment(`📋 Lane set to **editorial fix**.\n\n@usace-rmc/docs-admin please review and merge.`);
+ } else {
+ await addLabels(['stage:peer-review']);
+ await postComment(`📋 Lane set to **${added.replace('lane:', '').replace(/-/g, ' ')}**. Moving to peer review.\n\n@usace-rmc/docs-admin please assign the peer reviewer.`);
+ }
+ }
+ return;
+ }
+
+ // ── PR description edited (check for technical edit checkbox) ──
+ if (context.eventName === 'pull_request' && context.payload.action === 'edited') {
+ if (existingStage === 'stage:ai-editor-review' && existingLane === 'lane:new-doc') {
+ const body = pr.body || '';
+ const checkboxChecked = body.includes('[x] Technical edit comments addressed');
+ if (checkboxChecked) {
+ await removeLabel('stage:ai-editor-review');
+ await addLabels(['stage:director-review']);
+ await postComment(`✅ **Technical edit marked complete** by the author.\n\nAdvancing to **Director review**.\n\n@usace-rmc/docs-admin please:\n1. If revisions were pushed during the technical edit, trigger a fresh checkpoint deploy of this branch\n2. Assign a member of @usace-rmc/docs-director via the Reviewers sidebar\n\nThe Director will review at the live URL.`);
+ }
+ }
+ return;
+ }
+
+ // ── Review approved ──
+ if (context.eventName === 'pull_request_review' && context.payload.review.state === 'approved') {
+ if (!existingLane || !existingStage) return;
+ const reviewer = context.payload.review.user.login;
+ let nextStage = null, comment = null;
+
+ if (existingLane === 'lane:new-doc') {
+ if (existingStage === 'stage:peer-review') {
+ nextStage = 'stage:lead-civil-review';
+ comment = `✅ **Peer review approved** by @${reviewer}.\n\nAdvancing to **RMC Lead Civil review**.\n\n@usace-rmc/docs-admin please assign the appropriate Lead Civil via the Reviewers sidebar. The Lead Civil reviews on the preview URL.`;
+ } else if (existingStage === 'stage:lead-civil-review') {
+ nextStage = 'stage:ai-editor-review';
+ comment = `✅ **Lead Civil review approved** by @${reviewer}.\n\nThe document is ready to be **deployed to the live site** (watermarked) for the technical edit and Director review phases.\n\n@usace-rmc/docs-admin next steps:\n1. Trigger a checkpoint deploy of branch \`${branch}\` via Actions → Deploy to GitHub Pages → Run workflow\n2. Approve the deploy at the production environment gate\n3. Post the live URL in a comment on this PR\n4. Run the \`/technical-edit\` Claude Code skill against this PR (or assign a human technical editor)\n\nAfter the author addresses the technical edit comments and checks the completion checkbox, the document will advance to Director review.`;
+ } else if (existingStage === 'stage:director-review') {
+ nextStage = 'stage:ready-to-merge';
+ comment = `✅ **Director review approved** by @${reviewer}.\n\nThis PR is **ready for final merge and publication**.\n\n@usace-rmc/docs-admin next steps:\n1. Check out this branch (locally or via github.dev)\n2. Flip the document's \`draft\` flag to \`false\`\n3. Update \`00-version-history.mdx\` with reviewer and approver names\n4. Commit and push\n5. Merge this PR to \`main\`\n6. Approve the final production deploy in the Actions tab`;
+ }
+ } else if (existingLane === 'lane:major-revision') {
+ if (existingStage === 'stage:peer-review') {
+ nextStage = 'stage:lead-civil-review';
+ comment = `✅ **Peer review approved** by @${reviewer}.\n\nAdvancing to **RMC Lead Civil review**.\n\n@usace-rmc/docs-admin please assign the appropriate Lead Civil via the Reviewers sidebar.`;
+ } else if (existingStage === 'stage:lead-civil-review') {
+ nextStage = 'stage:ready-to-merge';
+ comment = `✅ **Lead Civil review approved** by @${reviewer}.\n\nThis PR is **ready for final merge**.\n\n@usace-rmc/docs-admin next steps:\n1. Check out this branch\n2. Flip the document's \`draft\` flag to \`false\`\n3. Update \`00-version-history.mdx\`\n4. Commit and push\n5. Merge to \`main\`\n6. Approve the production deploy`;
+ }
+ } else if (existingLane === 'lane:minor-revision') {
+ if (existingStage === 'stage:peer-review') {
+ nextStage = 'stage:ready-to-merge';
+ comment = `✅ **Peer review approved** by @${reviewer}.\n\nThis PR is **ready for final merge**.\n\n@usace-rmc/docs-admin next steps:\n1. Check out this branch\n2. Flip the document's \`draft\` flag to \`false\`\n3. Update \`00-version-history.mdx\`\n4. Commit and push\n5. Merge to \`main\`\n6. Approve the production deploy`;
+ }
+ }
+
+ if (nextStage) {
+ await removeLabel(existingStage);
+ await addLabels([nextStage]);
+ await postComment(comment);
+ }
+ }
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 98e01cb6a..938aa44b9 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -47,8 +47,8 @@ export default {
title: 'RMC Software Documentation',
tagline: 'Documentation for RMC Software Packages',
onBrokenAnchors: 'warn',
- url: 'https://USACE-RMC.github.io', // Replace with your site's URL
- baseUrl: '/RMC-Software-Documentation/',
+ url: process.env.DOCUSAURUS_URL || 'https://USACE-RMC.github.io',
+ baseUrl: process.env.DOCUSAURUS_BASE_URL || '/RMC-Software-Documentation/',
favicon: 'img/USACE.png',
organizationName: 'USACE-RMC', // Your GitHub organization or username
projectName: 'RMC-Software-Documentation', // Your project name, make sure this matches your GitHub repo name
diff --git a/planning/01-repo-implementation.md b/planning/01-repo-implementation.md
new file mode 100644
index 000000000..737ca8b7c
--- /dev/null
+++ b/planning/01-repo-implementation.md
@@ -0,0 +1,641 @@
+# RMC Software Documentation — Review Process Implementation
+
+This document describes every structural change to the `usace-rmc/rmc-software-docs` repository for the new review and publishing workflow. Intended for a Claude Code agent or human developer with write access.
+
+## Review flow overview
+
+**Lane 1 — New document (two-phase, six-stage review):**
+
+1. Author opens PR with branch prefix `docs/new/`. Preview workflow publishes to unadvertised preview URL.
+2. Peer reviewer reviews on **preview URL**, approves.
+3. RMC Lead Civil reviews on **preview URL**, approves.
+4. Site admin triggers checkpoint deploy of PR branch to **production URL** (watermarked).
+5. AI technical edit: someone with Claude Code runs `/technical-edit`, which posts inline review comments on the PR. Author addresses comments, checks a checkbox in the PR description to confirm completion.
+6. Director reviews on **live URL**, approves with one click.
+7. Site admin flips draft flag to `false`, merges PR to `main`, approves final deploy (watermark removed).
+
+**Lane 2 — Major revision:**
+
+1. Author opens PR with `docs/major/`. Preview workflow publishes to preview URL.
+2. Peer reviewer reviews on preview URL, approves.
+3. RMC Lead Civil reviews on preview URL, approves.
+4. Site admin flips draft flag, merges to `main`, approves final deploy.
+
+**Lane 3 — Minor revision:** Peer review only on preview URL, then site admin merges and deploys.
+
+**Lane 4 — Editorial fix:** Site admin reviews on preview URL, merges and deploys. No formal review.
+
+**Key architectural notes:**
+- The deploy workflow supports deploying from arbitrary branches (not just `main`) for Lane 1 checkpoint deploys.
+- `main` does not always equal what's on the live site during Lane 1 reviews.
+- The AI technical edit stage advances when the author checks a task list checkbox in the PR description, not when a reviewer clicks approve.
+- The stage progression workflow only auto-processes PRs whose branch name starts with `docs/`. PRs from any other branch (infrastructure, tooling, dependency bumps, etc.) are silently ignored — no labels, no comments, no review-process noise. A site admin can still pull any PR into the review process by manually applying a `lane:*` label, which is the escape hatch for mis-named branches or one-off cases.
+- The PR preview workflow (`pr-preview.yml`) uses a broader path-based trigger and will build a preview for any PR that touches doc-relevant files, regardless of branch prefix. This is intentional: previews are useful for verifying non-doc changes (e.g., a config tweak) even when no formal review is required.
+
+## Scope
+
+This implementation adds:
+1. Version-aware draft watermark logic
+2. `.github/` directory: workflows, templates, CODEOWNERS
+3. `docusaurus.config.js` env-var update for preview builds
+4. Claude Code skills: `/new-revision` and `/technical-edit`
+
+Does **not** include: GitHub team creation, preview repo creation, branch protection, environment rules, or user-facing MDX documentation.
+
+---
+
+## Task 1: Update the draft watermark logic
+
+**File:** `src/theme/DocItem/index.js`
+
+Replace the entire file with:
+
+```js
+import React from "react";
+import DocItem from "@theme-original/DocItem";
+import { useLocation } from "@docusaurus/router";
+import { draftDocs } from "../../draftDocs";
+import latestVersions from "@site/static/versions/latestVersions.json";
+
+function getDocInfo(pathname) {
+ const stripped = pathname
+ .replace(/^\/RMC-Software-Documentation\/docs\//, "")
+ .replace(/^\/docs\//, "")
+ .replace(/^docs\//, "");
+ const match = stripped.match(/^(.+?)\/(v\d+\.\d+(?:\.\d+)?)(?:\/|$)/);
+ if (!match) return null;
+ return { docBasePath: match[1], version: match[2] };
+}
+
+function isDraftDoc(pathname) {
+ const info = getDocInfo(pathname);
+ if (!info) return false;
+ const isFlagged = draftDocs.some(
+ (base) => info.docBasePath === base || info.docBasePath.startsWith(base + "/")
+ );
+ if (!isFlagged) return false;
+ const latest = latestVersions[info.docBasePath];
+ if (!latest) return true;
+ return info.version === latest;
+}
+
+export default function DocItemWrapper(props) {
+ const location = useLocation();
+ const showWatermark = isDraftDoc(location.pathname);
+ return (
+ <>
+ {showWatermark && (
+
+ DRAFT
+
+ )}
+
+ >
+ );
+}
+```
+
+---
+
+## Task 2: Update `docusaurus.config.js`
+
+Replace the `url` and `baseUrl` lines:
+
+```js
+ url: process.env.DOCUSAURUS_URL || 'https://USACE-RMC.github.io',
+ baseUrl: process.env.DOCUSAURUS_BASE_URL || '/RMC-Software-Documentation/',
+```
+
+---
+
+## Task 3: Create `.github/` directory
+
+### 3.1 `.github/CODEOWNERS`
+
+```
+/.github/ @usace-rmc/docs-admin
+/docusaurus.config.js @usace-rmc/docs-admin
+/tailwind.config.js @usace-rmc/docs-admin
+/package.json @usace-rmc/docs-admin
+/package-lock.json @usace-rmc/docs-admin
+/scripts/ @usace-rmc/docs-admin
+/src/theme/ @usace-rmc/docs-admin
+/src/pages/ @usace-rmc/docs-admin
+/src/components/ @usace-rmc/docs-admin
+/src/contexts/ @usace-rmc/docs-admin
+/src/clientModules/ @usace-rmc/docs-admin
+/src/css/ @usace-rmc/docs-admin
+/src/draftDocs.js @usace-rmc/docs-admin
+```
+
+### 3.2 `.github/pull_request_template.md`
+
+```markdown
+## Description
+
+
+
+## Affected documents
+
+-
+
+## Related issue(s)
+
+
+
+## Pre-submission checklist
+
+- [ ] I have previewed these changes locally or via the PR preview URL
+- [ ] My branch name uses one of the expected prefixes: `docs/new/`, `docs/major/`, `docs/minor/`, or `docs/fix/`
+- [ ] I have updated `00-version-history.mdx` if this change warrants a version entry
+- [ ] I have assigned a specific peer reviewer via the Reviewers sidebar (if known)
+
+## Technical edit (Lane 1 only)
+
+- [ ] Technical edit comments addressed — ready for Director review
+
+## Notes for reviewers
+
+
+```
+
+### 3.3 `.github/workflows/deploy.yml`
+
+```yaml
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+ inputs:
+ ref:
+ description: 'Branch or ref to deploy (leave blank for main)'
+ required: false
+ type: string
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: false
+
+jobs:
+ build:
+ name: Build site
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.ref || github.ref }}
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+ - run: npm ci
+ - run: npm run build
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: ./build
+
+ deploy:
+ name: Deploy to production
+ needs: build
+ runs-on: ubuntu-latest
+ environment:
+ name: production
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
+```
+
+### 3.4 `.github/workflows/pr-preview.yml`
+
+```yaml
+name: PR Preview Build
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+ paths:
+ - 'docs/**'
+ - 'src/**'
+ - 'static/**'
+ - 'docusaurus.config.js'
+ - 'tailwind.config.js'
+ - 'package.json'
+ - 'package-lock.json'
+ - 'scripts/**'
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ build-and-deploy:
+ name: Build and deploy preview
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+ - run: npm ci
+ - name: Build site with PR-specific baseUrl
+ env:
+ DOCUSAURUS_URL: https://usace-rmc.github.io
+ DOCUSAURUS_BASE_URL: /RMC-Software-Documentation-Previews/pr-${{ github.event.pull_request.number }}/
+ run: npm run build
+ - uses: peaceiris/actions-gh-pages@v4
+ with:
+ deploy_key: ${{ secrets.PREVIEW_DEPLOY_KEY }}
+ external_repository: usace-rmc/RMC-Software-Documentation-Previews
+ publish_branch: gh-pages
+ publish_dir: ./build
+ destination_dir: pr-${{ github.event.pull_request.number }}
+ keep_files: true
+ user_name: 'github-actions[bot]'
+ user_email: 'github-actions[bot]@users.noreply.github.com'
+ commit_message: 'Deploy preview for PR #${{ github.event.pull_request.number }}'
+ - name: Post or update preview URL comment
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const prNumber = context.issue.number;
+ const url = `https://usace-rmc.github.io/RMC-Software-Documentation-Previews/pr-${prNumber}/`;
+ const marker = '';
+ const body = `${marker}\n\n📄 **Preview deployed**\n\n${url}\n\n_This preview updates automatically when new commits are pushed. Deleted when the PR closes._`;
+ const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber });
+ const existing = comments.data.find(c => c.user.type === 'Bot' && c.body.includes(marker));
+ if (existing) {
+ await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body });
+ } else {
+ await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, body });
+ }
+```
+
+### 3.5 `.github/workflows/pr-preview-cleanup.yml`
+
+```yaml
+name: PR Preview Cleanup
+
+on:
+ pull_request:
+ types: [closed]
+
+permissions:
+ contents: read
+
+jobs:
+ cleanup:
+ name: Delete preview directory
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ repository: usace-rmc/RMC-Software-Documentation-Previews
+ ref: gh-pages
+ ssh-key: ${{ secrets.PREVIEW_DEPLOY_KEY }}
+ - name: Remove PR preview directory
+ env:
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ if [ -d "pr-${PR_NUMBER}" ]; then
+ rm -rf "pr-${PR_NUMBER}"
+ git add -A
+ git commit -m "Clean up preview for PR #${PR_NUMBER}"
+ git push
+ fi
+```
+
+### 3.6 `.github/workflows/stage-progression.yml`
+
+```yaml
+name: Stage Progression
+
+on:
+ pull_request:
+ types: [opened, reopened, labeled, edited]
+ pull_request_review:
+ types: [submitted]
+
+permissions:
+ pull-requests: write
+ issues: write
+ contents: read
+
+jobs:
+ progress:
+ name: Manage review stage
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run stage progression logic
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const pr = context.payload.pull_request;
+ if (!pr) return;
+
+ const prNumber = pr.number;
+ const branch = pr.head.ref;
+ const labels = pr.labels.map(l => l.name);
+
+ const LANE_LABELS = ['lane:new-doc', 'lane:major-revision', 'lane:minor-revision', 'lane:editorial-fix'];
+ const STAGE_LABELS = ['stage:needs-lane', 'stage:peer-review', 'stage:lead-civil-review', 'stage:ai-editor-review', 'stage:director-review', 'stage:ready-to-merge'];
+
+ function detectLane(b) {
+ if (b.startsWith('docs/new/')) return 'lane:new-doc';
+ if (b.startsWith('docs/major/')) return 'lane:major-revision';
+ if (b.startsWith('docs/minor/')) return 'lane:minor-revision';
+ if (b.startsWith('docs/fix/')) return 'lane:editorial-fix';
+ return null;
+ }
+
+ async function addLabels(ls) { if (ls.length) await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, labels: ls }); }
+ async function removeLabel(l) { try { await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, name: l }); } catch(e) {} }
+ async function postComment(body) { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, body }); }
+
+ const existingLane = labels.find(l => LANE_LABELS.includes(l));
+ const existingStage = labels.find(l => STAGE_LABELS.includes(l));
+
+ // ── PR opened/reopened ──
+ if (context.eventName === 'pull_request' && ['opened', 'reopened'].includes(context.payload.action)) {
+ // Only auto-process branches under docs/. Non-doc PRs (infrastructure,
+ // tooling, etc.) are silently ignored on open. An admin can still opt
+ // any PR into the review process by manually applying a lane:* label,
+ // which is handled by the labeled-event branch below.
+ if (!branch.startsWith('docs/')) return;
+ const lane = existingLane || detectLane(branch);
+ if (!lane) {
+ await addLabels(['stage:needs-lane']);
+ await postComment(`⚠️ **Could not determine review lane**\n\nBranch \`${branch}\` starts with \`docs/\` but does not match an expected sub-prefix (\`docs/new/\`, \`docs/major/\`, \`docs/minor/\`, \`docs/fix/\`).\n\n@usace-rmc/docs-admin please apply the correct \`lane:*\` label.`);
+ return;
+ }
+ const toAdd = [lane];
+ let comment;
+ if (lane === 'lane:editorial-fix') {
+ toAdd.push('stage:ready-to-merge');
+ comment = `📋 **Lane: Editorial Fix**\n\nNo formal review required.\n\n@usace-rmc/docs-admin please review, merge, and approve the deploy.`;
+ } else {
+ toAdd.push('stage:peer-review');
+ const laneName = lane.replace('lane:', '').replace(/-/g, ' ');
+ const scope = lane === 'lane:new-doc' ? 'Peer → Lead Civil → Technical Edit → Director' : lane === 'lane:major-revision' ? 'Peer → Lead Civil' : 'Peer review only';
+ comment = `📋 **Lane: ${laneName}**\n\nReview scope: ${scope}.\n\nCurrently in **peer review**. If no peer reviewer has been assigned, @usace-rmc/docs-admin please assign one via the Reviewers sidebar.`;
+ }
+ await addLabels(toAdd);
+ await postComment(comment);
+ return;
+ }
+
+ // ── Label manually applied ──
+ if (context.eventName === 'pull_request' && context.payload.action === 'labeled') {
+ const added = context.payload.label.name;
+ if (LANE_LABELS.includes(added) && (!existingStage || existingStage === 'stage:needs-lane')) {
+ await removeLabel('stage:needs-lane');
+ if (added === 'lane:editorial-fix') {
+ await addLabels(['stage:ready-to-merge']);
+ await postComment(`📋 Lane set to **editorial fix**.\n\n@usace-rmc/docs-admin please review and merge.`);
+ } else {
+ await addLabels(['stage:peer-review']);
+ await postComment(`📋 Lane set to **${added.replace('lane:', '').replace(/-/g, ' ')}**. Moving to peer review.\n\n@usace-rmc/docs-admin please assign the peer reviewer.`);
+ }
+ }
+ return;
+ }
+
+ // ── PR description edited (check for technical edit checkbox) ──
+ if (context.eventName === 'pull_request' && context.payload.action === 'edited') {
+ if (existingStage === 'stage:ai-editor-review' && existingLane === 'lane:new-doc') {
+ const body = pr.body || '';
+ const checkboxChecked = body.includes('[x] Technical edit comments addressed');
+ if (checkboxChecked) {
+ await removeLabel('stage:ai-editor-review');
+ await addLabels(['stage:director-review']);
+ await postComment(`✅ **Technical edit marked complete** by the author.\n\nAdvancing to **Director review**.\n\n@usace-rmc/docs-admin please:\n1. If revisions were pushed during the technical edit, trigger a fresh checkpoint deploy of this branch\n2. Assign a member of @usace-rmc/docs-director via the Reviewers sidebar\n\nThe Director will review at the live URL.`);
+ }
+ }
+ return;
+ }
+
+ // ── Review approved ──
+ if (context.eventName === 'pull_request_review' && context.payload.review.state === 'approved') {
+ if (!existingLane || !existingStage) return;
+ const reviewer = context.payload.review.user.login;
+ let nextStage = null, comment = null;
+
+ if (existingLane === 'lane:new-doc') {
+ if (existingStage === 'stage:peer-review') {
+ nextStage = 'stage:lead-civil-review';
+ comment = `✅ **Peer review approved** by @${reviewer}.\n\nAdvancing to **RMC Lead Civil review**.\n\n@usace-rmc/docs-admin please assign the appropriate Lead Civil via the Reviewers sidebar. The Lead Civil reviews on the preview URL.`;
+ } else if (existingStage === 'stage:lead-civil-review') {
+ nextStage = 'stage:ai-editor-review';
+ comment = `✅ **Lead Civil review approved** by @${reviewer}.\n\nThe document is ready to be **deployed to the live site** (watermarked) for the technical edit and Director review phases.\n\n@usace-rmc/docs-admin next steps:\n1. Trigger a checkpoint deploy of branch \`${branch}\` via Actions → Deploy to GitHub Pages → Run workflow\n2. Approve the deploy at the production environment gate\n3. Post the live URL in a comment on this PR\n4. Run the \`/technical-edit\` Claude Code skill against this PR (or assign a human technical editor)\n\nAfter the author addresses the technical edit comments and checks the completion checkbox, the document will advance to Director review.`;
+ } else if (existingStage === 'stage:director-review') {
+ nextStage = 'stage:ready-to-merge';
+ comment = `✅ **Director review approved** by @${reviewer}.\n\nThis PR is **ready for final merge and publication**.\n\n@usace-rmc/docs-admin next steps:\n1. Check out this branch (locally or via github.dev)\n2. Flip the document's \`draft\` flag to \`false\`\n3. Update \`00-version-history.mdx\` with reviewer and approver names\n4. Commit and push\n5. Merge this PR to \`main\`\n6. Approve the final production deploy in the Actions tab`;
+ }
+ } else if (existingLane === 'lane:major-revision') {
+ if (existingStage === 'stage:peer-review') {
+ nextStage = 'stage:lead-civil-review';
+ comment = `✅ **Peer review approved** by @${reviewer}.\n\nAdvancing to **RMC Lead Civil review**.\n\n@usace-rmc/docs-admin please assign the appropriate Lead Civil via the Reviewers sidebar.`;
+ } else if (existingStage === 'stage:lead-civil-review') {
+ nextStage = 'stage:ready-to-merge';
+ comment = `✅ **Lead Civil review approved** by @${reviewer}.\n\nThis PR is **ready for final merge**.\n\n@usace-rmc/docs-admin next steps:\n1. Check out this branch\n2. Flip the document's \`draft\` flag to \`false\`\n3. Update \`00-version-history.mdx\`\n4. Commit and push\n5. Merge to \`main\`\n6. Approve the production deploy`;
+ }
+ } else if (existingLane === 'lane:minor-revision') {
+ if (existingStage === 'stage:peer-review') {
+ nextStage = 'stage:ready-to-merge';
+ comment = `✅ **Peer review approved** by @${reviewer}.\n\nThis PR is **ready for final merge**.\n\n@usace-rmc/docs-admin next steps:\n1. Check out this branch\n2. Flip the document's \`draft\` flag to \`false\`\n3. Update \`00-version-history.mdx\`\n4. Commit and push\n5. Merge to \`main\`\n6. Approve the production deploy`;
+ }
+ }
+
+ if (nextStage) {
+ await removeLabel(existingStage);
+ await addLabels([nextStage]);
+ await postComment(comment);
+ }
+ }
+```
+
+---
+
+## Task 4: Create labels
+
+| Label | Color | Description |
+|---|---|---|
+| `lane:new-doc` | `#0E8A16` | New document requiring full review |
+| `lane:major-revision` | `#1D76DB` | Major revision |
+| `lane:minor-revision` | `#5319E7` | Minor revision |
+| `lane:editorial-fix` | `#C5DEF5` | Editorial or grammatical fix |
+| `stage:needs-lane` | `#B60205` | Lane could not be determined |
+| `stage:peer-review` | `#FBCA04` | Awaiting peer review |
+| `stage:lead-civil-review` | `#FBCA04` | Awaiting RMC Lead Civil review |
+| `stage:ai-editor-review` | `#FBCA04` | Awaiting technical edit |
+| `stage:director-review` | `#FBCA04` | Awaiting Director review |
+| `stage:ready-to-merge` | `#0E8A16` | All reviews complete |
+
+---
+
+## Task 5: Create Claude Code skills
+
+### 5.1 `.claude/skills/new-revision/SKILL.md`
+
+Create the `/new-revision` skill. (Same content as previously specified — scaffolds a new version folder, sets draft flag, creates appropriately-prefixed branch.)
+
+### 5.2 `.claude/skills/technical-edit/SKILL.md`
+
+```markdown
+---
+name: technical-edit
+description: Run an AI-assisted technical edit on the current PR. Reads all changed MDX files, evaluates them against the RMC technical editing prompt, and posts inline review comments on the PR via the GitHub API.
+---
+
+# Technical Edit
+
+Run an AI-assisted technical edit on the current PR's documentation files.
+
+**Arguments:** `$ARGUMENTS` — optional PR number. If omitted, infer from the current branch.
+
+## Step 1: Identify the PR and changed files
+
+Determine the PR number from the current branch (use `gh pr view --json number`). List all changed `.mdx` files in the PR using `gh pr diff --name-only | grep '\.mdx$'`.
+
+## Step 2: Read the review prompt
+
+Read the standardized review prompt from `.github/ai-review/technical-editor-prompt.md`. This file contains the full set of review instructions including grammar rules, tense requirements, terminology conventions, Section 508 compliance checks, and style guidelines.
+
+## Step 3: Review each file
+
+For each changed MDX file:
+1. Read the file contents
+2. Apply the review prompt to the file
+3. For each finding, record: file path, line number or line range, severity (must-fix / should-fix / suggestion), the issue description, and a suggested fix if applicable
+
+## Step 4: Post the review on the PR
+
+Use the GitHub CLI to submit a bundled PR review with inline comments:
+
+```bash
+gh api repos/:owner/:repo/pulls/:pr/reviews \
+ --method POST \
+ -f body="AI technical edit complete. $(N) comments across $(M) files. Review prompt version: $(VERSION)." \
+ -f event="COMMENT" \
+ -f comments="[{\"path\": \"...\", \"line\": N, \"body\": \"...\"}]"
+```
+
+Each comment should be formatted as:
+```
+**[severity]** issue description
+
+> Suggested fix (if applicable)
+```
+
+Where severity is one of: 🔴 Must fix, 🟡 Should fix, 🔵 Suggestion.
+
+## Step 5: Report
+
+Tell the user:
+- How many comments were posted
+- How many files were reviewed
+- Which review prompt version was used
+- Remind the author to check the "Technical edit comments addressed" checkbox in the PR description when they're done addressing comments
+```
+
+### 5.3 `.github/ai-review/technical-editor-prompt.md`
+
+Create the standardized review prompt:
+
+```markdown
+# RMC Technical Editor Review Prompt
+
+You are a technical editor reviewing documentation for the U.S. Army Corps of Engineers Risk Management Center (USACE RMC). The documentation is written in MDX (Markdown with JSX) and covers dam safety, levee safety, and related risk analysis topics.
+
+## Audience
+
+Practicing dam and levee safety engineers within USACE. These are technical professionals who understand the domain — do not flag correct use of technical terminology as jargon.
+
+## Review criteria
+
+### Grammar and mechanics
+- Spelling, punctuation, and sentence structure
+- Subject-verb agreement
+- Correct use of hyphens, em dashes, and en dashes
+- Consistent serial comma usage
+
+### Tense and voice
+- Prefer third-person active voice for procedures and descriptions
+- Flag passive voice when active would be clearer
+- Flag inconsistent tense within a section
+
+### Clarity and concision
+- Flag wordy passages that could be shortened without losing meaning
+- Flag ambiguous pronouns or unclear referents
+- Flag sentences over 40 words that could be split
+- Flag buried leads — key information at the end of a long sentence
+
+### Terminology consistency
+- Flag inconsistent use of terms within the document (e.g., alternating between "embankment" and "dam" when referring to the same structure)
+- Do NOT flag correct domain terminology as errors
+
+### Section 508 accessibility compliance
+- Every image must have alt text (check for `alt=` attribute)
+- Heading hierarchy must not skip levels (e.g., h2 followed by h4 without h3)
+- Link text must be descriptive (flag "click here" or "link" as link text)
+- Tables must have header rows
+- Lists must use proper markdown list syntax, not manual numbering with plain text
+- Color must not be the sole means of conveying information
+
+### Style consistency
+- Figure and table captions must follow a consistent format
+- Citations must use the site's citation key format
+- Units should be consistent within each document (metric or imperial, not mixed)
+- Acronyms must be defined on first use within each chapter
+
+## Output format
+
+For each finding, produce:
+- The file path and line number(s)
+- A severity level: 🔴 Must fix (errors, accessibility violations), 🟡 Should fix (clarity, consistency issues), 🔵 Suggestion (stylistic improvements)
+- A clear description of the issue
+- A suggested fix where possible (use GitHub suggestion block format)
+
+## What NOT to flag
+- Correct use of technical terminology, even if uncommon
+- MDX component syntax (imports, JSX elements)
+- Frontmatter fields
+- Matters of technical judgment or domain accuracy (that is the peer reviewer's job)
+- Alternative phrasings that are equally acceptable
+```
+
+---
+
+## Task 6: Verify and open PR
+
+1. Run `npm run build` — must succeed.
+2. Validate all YAML files.
+3. Commit on branch `feature/review-workflow-infrastructure`.
+4. Open PR titled: `Add review workflow infrastructure`.
+
+## Summary checklist
+
+- [ ] `src/theme/DocItem/index.js` — version-aware watermark
+- [ ] `docusaurus.config.js` — env-driven URL/baseUrl
+- [ ] `.github/CODEOWNERS`
+- [ ] `.github/pull_request_template.md` — includes technical edit checkbox
+- [ ] `.github/workflows/deploy.yml` — with `workflow_dispatch` + `ref` input
+- [ ] `.github/workflows/pr-preview.yml`
+- [ ] `.github/workflows/pr-preview-cleanup.yml`
+- [ ] `.github/workflows/stage-progression.yml` — Lead Civil + AI editor + checkbox detection
+- [ ] `.github/ai-review/technical-editor-prompt.md`
+- [ ] `.claude/skills/new-revision/SKILL.md`
+- [ ] `.claude/skills/technical-edit/SKILL.md`
+- [ ] All 10 labels created
+- [ ] Build passes
diff --git a/planning/02-documentation-guide-implementation.md b/planning/02-documentation-guide-implementation.md
new file mode 100644
index 000000000..cb2b19d65
--- /dev/null
+++ b/planning/02-documentation-guide-implementation.md
@@ -0,0 +1,566 @@
+# Documentation Guide Content Implementation — Review and Approval Process
+
+Seven new chapters for `docs/dev/documentation-guide/` covering the complete review and approval process. Execute after `01-repo-implementation.md` is merged.
+
+## Task 1: Rename appendix files
+
+```bash
+cd docs/dev/documentation-guide
+git mv 09-appendix-a-source-code-structure.mdx 16-appendix-a-source-code-structure.mdx
+git mv 10-appendix-b-build-process-overview.mdx 17-appendix-b-build-process-overview.mdx
+git mv 11-appendix-c-search-configuration.mdx 18-appendix-c-search-configuration.mdx
+```
+
+URLs are unchanged because Docusaurus strips numeric prefixes.
+
+## Task 2: Update `scripts/generateSidebars.js`
+
+Replace `mainIds` and `appendixIds`:
+
+```js
+ const mainIds = [
+ '00-introduction',
+ '01-getting-started',
+ '02-versioning-system',
+ '03-project-structure',
+ '04-creating-new-document-walkthrough',
+ '05-docx-converter',
+ '06-creating-editing-pages',
+ '07-react-components',
+ '08-troubleshooting-faq',
+ '09-review-and-approval-overview',
+ '10-review-lanes',
+ '11-author-workflow',
+ '12-reviewer-workflow',
+ '13-technical-edit',
+ '14-director-workflow',
+ '15-site-admin-workflow',
+ ];
+ const appendixIds = [
+ '16-appendix-a-source-code-structure',
+ '17-appendix-b-build-process-overview',
+ '18-appendix-c-search-configuration',
+ ];
+```
+
+## Task 3: Create the seven chapter files
+
+All chapters follow existing conventions: `title:` frontmatter only, `NavContainer` import, standard markdown.
+
+---
+
+### 3.1 `09-review-and-approval-overview.mdx`
+
+```mdx
+---
+title: Review and Approval Process Overview
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Review and Approval Process Overview
+
+This chapter and the six that follow describe the review and approval process for all documentation published on the RMC Software Documentation website.
+
+## Who participates
+
+**Author.** Writes or revises the document. The only role assumed to have local development tooling.
+
+**Peer reviewer.** Subject-matter expert assigned ad-hoc to review technical accuracy. Works entirely in the GitHub web interface.
+
+**RMC Lead Civil.** Provides technical oversight and quality assurance. Assigned ad-hoc per document. Works in the GitHub web interface.
+
+**Technical edit (AI-assisted).** An AI-powered editorial review that checks grammar, clarity, tense, terminology, and Section 508 accessibility compliance. A team member triggers the review using a Claude Code skill; the AI posts comments directly on the pull request. A human technical editor can be substituted at the site admin's discretion.
+
+**Director.** The RMC Director provides final approval for new documents only. Reviews the document on the live site and clicks approve — no file editing required.
+
+**Site administrator.** Manages reviewer assignments, checkpoint deploys, merge preparation, and final deploys. The only role with access to protected parts of the repository.
+
+## The four review lanes
+
+Every change falls into one of four lanes based on its scope:
+
+**Lane 1: New document.** Peer review → Lead Civil review → Technical edit → Director approval. The document is deployed to the live site (watermarked) after Lead Civil approval so the technical edit and Director review happen at the document's final URL.
+
+**Lane 2: Major revision.** Peer review → Lead Civil review. Entire review happens on the preview site. Site admin deploys the final version after Lead Civil approval.
+
+**Lane 3: Minor revision.** Peer review only on the preview site.
+
+**Lane 4: Editorial fix.** Site admin reviews and deploys directly. No formal review.
+
+## The draft watermark
+
+Documents flagged as drafts display a large diagonal "DRAFT" watermark. For Lane 1, the watermark appears on the live site during the technical edit and Director review phases, signaling to any reader that the content is not yet authoritative. The watermark is removed when the site admin flips the draft flag after Director approval.
+
+For Lanes 2 and 3, the document under revision only exists on the preview site during review. The currently-published version on the live site is never watermarked.
+
+## Where to go next
+
+- Authoring a document: read **Review Lanes**, then **Author Workflow**
+- Asked to review: read **Reviewer Workflow**
+- Running a technical edit: read **Technical Edit**
+- Director reviewing a new document: read **Director Workflow**
+- Site administrator: read **Site Admin Workflow**
+```
+
+---
+
+### 3.2 `10-review-lanes.mdx`
+
+```mdx
+---
+title: Review Lanes
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Review Lanes
+
+Every change follows one of four review lanes, determined by the branch name prefix.
+
+| Branch prefix | Lane |
+|---|---|
+| `docs/new/` | New document |
+| `docs/major/` | Major revision |
+| `docs/minor/` | Minor revision |
+| `docs/fix/` | Editorial fix |
+
+**The branch prefix is what tells the workflow that a PR is part of the review process.** Pull requests from branches that don't start with `docs/` are ignored by the review workflow entirely — no labels, no bot comments, no required reviews. This is intentional: infrastructure changes, tooling updates, dependency bumps, and other non-document work should not be routed through the document review process.
+
+If a branch starts with `docs/` but doesn't match one of the four sub-prefixes above (for example, a typo like `docs/newfoo/` or an old-style name like `docs/update`), the workflow applies `stage:needs-lane` and tags a site admin to assign the correct lane manually.
+
+If a document revision was accidentally pushed to a branch that doesn't start with `docs/`, a site admin can pull it into the review process by manually applying a `lane:*` label to the PR. The workflow treats a manually-applied lane label as the start signal and proceeds normally from there.
+
+## Lane 1: New document
+
+**When to use.** Any completely new document being added to the site.
+
+**Required reviews.** Peer review → RMC Lead Civil review → Technical edit (AI-assisted) → Director approval.
+
+**What happens.** The document is first visible only on the unadvertised PR preview URL, where peer review and Lead Civil review happen. After Lead Civil approval, the site admin deploys the PR branch to the live production site with the DRAFT watermark. The technical edit and Director review both happen on the live URL. After Director approval, the site admin flips the draft flag, merges the PR, and deploys the final version — removing the watermark.
+
+**Example branches:** `docs/new/totalrisk-applications-guide`, `docs/new/lifesim-validation-oroville`
+
+## Lane 2: Major revision
+
+**When to use.** Substantial changes to an existing document warranting a new major version (e.g., v1.0 → v2.0).
+
+**Required reviews.** Peer review → RMC Lead Civil review.
+
+**What happens.** The entire review happens on the preview URL. The old version stays live and unwatermarked. After Lead Civil approval, the site admin flips the flag, merges, and deploys. The new version becomes the default; the old version is accessible via the version selector.
+
+**Example branches:** `docs/major/bep-progression-v2.0`
+
+## Lane 3: Minor revision
+
+**When to use.** Smaller updates warranting a minor version bump (e.g., v1.0 → v1.1).
+
+**Required reviews.** Peer review only.
+
+**What happens.** Same as Lane 2 but without Lead Civil review.
+
+**Example branches:** `docs/minor/bep-progression-v1.1`
+
+## Lane 4: Editorial fix
+
+**When to use.** Typos, broken links, grammatical corrections that don't change technical meaning.
+
+**Required reviews.** None. Site admin reviews and merges directly.
+
+**No version change, no watermark.**
+
+**Example branches:** `docs/fix/bep-progression-typos`
+
+## Choosing the right lane
+
+When in doubt, choose the more conservative lane. A site admin can reassign lanes by swapping `lane:*` labels.
+```
+
+---
+
+### 3.3 `11-author-workflow.mdx`
+
+```mdx
+---
+title: Author Workflow
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Author Workflow
+
+What the author does from start to publication, across all four lanes.
+
+## Starting work
+
+### With Claude Code skills
+
+- **New document (Lane 1):** Run `/new-doc`. Creates branch, scaffolds files, sets draft flag.
+- **Revision (Lanes 2/3):** Run `/new-revision`. Copies the latest version to a new version folder, sets draft flag, creates branch.
+- **Editorial fix (Lane 4):** Create a `docs/fix/` branch manually and edit files directly.
+
+### Without Claude Code
+
+All steps can be done manually in any IDE, via `git` on the command line, or entirely in the browser using github.dev (press `.` on any GitHub repo page to open a browser-based VS Code).
+
+**For a new document:** Create a `docs/new/` branch, create the directory structure under `docs/` with a `v1.0/` folder, add boilerplate MDX files, add a landing page JS entry with `draft: true`.
+
+**For a revision:** Create a `docs/major/-` or `docs/minor/-` branch, copy the current version folder to the new version, set `draft: true` on the landing page entry, add a placeholder version history row.
+
+## Opening the pull request
+
+Open a PR via Claude Code (`/pr`) or the GitHub web interface. The PR template prefills a description structure — fill in the sections. Assign your peer reviewer in the Reviewers sidebar if you know who it should be.
+
+Within minutes, two bot comments appear: a preview URL and a stage progression comment identifying your lane.
+
+## Responding to review comments
+
+Reviewers post comments on specific lines in the Files changed tab. For each comment: make the fix, push a commit, reply explaining what you did. The reviewer resolves the thread when satisfied.
+
+For suggested changes (pre-filled code blocks), you can click "Commit suggestion" to apply the fix in one click.
+
+**All comment threads must be resolved before the PR can merge.**
+
+## The technical edit (Lane 1)
+
+After Lead Civil approval and the checkpoint deploy, the technical edit stage begins. A team member runs the `/technical-edit` Claude Code skill, which posts inline review comments on the PR. These comments cover grammar, tense, clarity, terminology, and Section 508 compliance.
+
+Address each comment the same way you address human reviewer comments — push fixes, reply, and the site admin or you can resolve threads as they're addressed.
+
+**When you've addressed all technical edit comments,** check the checkbox in the PR description:
+
+`- [x] Technical edit comments addressed — ready for Director review`
+
+Checking this box is what advances the document to Director review. Don't check it until you've addressed all comments.
+
+## Where reviewers read your document
+
+For Lane 1: peer review and Lead Civil review happen on the **preview URL**. After Lead Civil approval, the site admin deploys the document to the **live production site** (watermarked). The technical edit and Director review happen at the live URL. If you push revisions during these phases, the site admin re-deploys so the live URL stays current.
+
+For Lanes 2, 3, and 4: all review happens on the preview URL only.
+
+## When the review is complete
+
+The site admin prepares the merge: flips the draft flag, updates version history, merges the PR, and approves the final deploy. You'll see email notifications as this happens. Once the deploy completes, your document is live.
+```
+
+---
+
+### 3.4 `12-reviewer-workflow.mdx`
+
+```mdx
+---
+title: Reviewer Workflow
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Reviewer Workflow
+
+What peer reviewers and RMC Lead Civils do when assigned to review a documentation pull request. Written for someone with little GitHub experience. Everything can be done from a web browser.
+
+## Prerequisites
+
+You need a GitHub account and membership in the `usace-rmc` organization. A site administrator will send you an invitation — click the link to accept.
+
+## Receiving a review request
+
+GitHub emails you with subject "You were requested to review [title]." Click the link to open the PR.
+
+## Where to read the document
+
+**Both peer reviewers and Lead Civils review on the preview URL.** In the PR's comment thread, look for a bot comment that says "Preview deployed" with a URL. Click it. This opens the rendered document on an unadvertised preview site with a DRAFT watermark.
+
+Read the document as you would any web page. This is where your review happens — you are reading, not editing.
+
+**Peer reviewers:** Focus on technical accuracy. Are claims correct? Equations right? Procedures complete?
+
+**Lead Civils:** Focus on technical quality and oversight. Does the document meet RMC standards? Is the scope appropriate? Are conclusions defensible?
+
+## Leaving feedback
+
+Click the **Files changed** tab on the PR. Hover over a line to see the blue "+" icon. Click it to open a comment box.
+
+**Plain comment:** Type your feedback and click "Start a review" (first comment) or "Add review comment" (subsequent).
+
+**Suggested change:** Click the "±" icon in the comment toolbar. Edit the pre-filled code block to your proposed wording. The author can accept your suggestion with one click.
+
+## Submitting your review
+
+Click **Finish your review** (upper right of Files changed). Choose:
+
+- **Approve** — ready to advance
+- **Request changes** — author needs to fix issues first
+- **Comment** — notes only, no approval or rejection
+
+Click **Submit review.**
+
+## After you approve
+
+The stage progression workflow advances the PR automatically. You don't need to do anything further unless someone tags you with a follow-up question.
+
+## Stale approvals
+
+If the author pushes new commits after you approve, GitHub automatically dismisses your approval. You'll be asked to re-review. Check the changes and re-approve if they look good.
+```
+
+---
+
+### 3.5 `13-technical-edit.mdx`
+
+```mdx
+---
+title: Technical Edit
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Technical Edit
+
+The technical edit is an AI-assisted editorial review that checks the document for grammar, clarity, tense consistency, terminology, and Section 508 accessibility compliance. It is the default editorial review method for new documents (Lane 1). A human technical editor can be substituted at the site admin's discretion.
+
+## When it happens
+
+The technical edit occurs after the RMC Lead Civil approves a Lane 1 PR and after the site admin has deployed the document to the live site (watermarked). At this point, the document has already been reviewed for technical accuracy by the peer reviewer and for technical quality by the Lead Civil. The technical edit focuses exclusively on editorial quality and accessibility compliance.
+
+## How it works
+
+1. A team member with Claude Code access checks out the PR branch and runs `/technical-edit`.
+2. Claude reads all changed MDX files and applies a standardized review prompt committed to the repository at `.github/ai-review/technical-editor-prompt.md`.
+3. Claude posts inline review comments directly on the PR — on specific lines, with severity levels and suggested fixes — exactly like a human reviewer would.
+4. The author addresses each comment: pushes fixes, replies to threads, and resolves conversations as they're addressed.
+5. When all comments are addressed, the author checks the checkbox in the PR description: `Technical edit comments addressed — ready for Director review`.
+6. The stage progression workflow detects the checkbox and advances the PR to Director review.
+
+## What it reviews
+
+**Grammar and mechanics.** Spelling, punctuation, sentence structure, subject-verb agreement, hyphenation, serial comma usage.
+
+**Tense and voice.** Third-person active voice consistency. Flags passive voice when active would be clearer. Flags inconsistent tense within sections.
+
+**Clarity and concision.** Wordy passages, ambiguous pronouns, sentences over 40 words, buried leads.
+
+**Terminology.** Inconsistent use of terms within the document (e.g., alternating "embankment" and "dam" for the same structure). Does not flag correct domain terminology.
+
+**Section 508 accessibility.** Image alt text, heading hierarchy (no skipped levels), descriptive link text, table header rows, proper list syntax, color not as sole information channel.
+
+**Style consistency.** Figure/table caption format, citation key format, unit consistency, acronym definitions on first use.
+
+## What it does NOT review
+
+Technical accuracy — that is the peer reviewer's job. Domain conclusions. MDX syntax. Frontmatter fields.
+
+## The review prompt
+
+The review prompt is a versioned file in the repository at `.github/ai-review/technical-editor-prompt.md`. It can be updated over time as the team learns what the AI catches well and what it misses. Each AI review comment includes the prompt version used, so comments can be traced back to the exact instructions that generated them.
+
+## Fallback to a human editor
+
+A site admin can route any document to a human technical editor instead of (or in addition to) the AI review. The human editor follows the same workflow as peer reviewers and Lead Civils: they're assigned to the PR, review the document (on the live URL for Lane 1), post comments, and submit their review. The author addresses comments the same way. The only difference is that advancement to Director review requires the human editor to click Approve rather than the author checking the checkbox.
+
+## Who can run the skill
+
+Anyone with Claude Code access (a personal Claude subscription) can run `/technical-edit`. The output — the PR review comments — is visible to everyone on GitHub regardless of their subscription status. Only the trigger requires Claude access.
+
+If nobody with Claude access is available, use the human editor fallback.
+```
+
+---
+
+### 3.6 `14-director-workflow.mdx`
+
+```mdx
+---
+title: Director Workflow
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Director Workflow
+
+What the RMC Director does when reviewing a new document. The Director's role is intentionally simple: read the document, approve it, move on. The Director only reviews **new documents** (Lane 1).
+
+## Prerequisites
+
+1. A GitHub account (sign up at `github.com` if needed).
+2. Membership in `@usace-rmc/docs-director` (a site admin adds you; accept the email invitation).
+
+One-time setup.
+
+## What you will be asked to do
+
+When a new document has passed peer review, Lead Civil review, and the technical edit, a site administrator assigns you as a reviewer. GitHub emails you.
+
+Click the link in the email. On the pull request page, scroll through comments to find one from a **site administrator** containing a URL starting with `https://usace-rmc.github.io/RMC-Software-Documentation/`. This is the **live production site** — the same URL readers will use.
+
+Click it. The document displays with a DRAFT watermark that will be removed after your approval.
+
+> **Important:** Use the live URL posted by the site administrator, not the automatic "Preview deployed" bot comment from earlier in the thread.
+
+Read the document. It has already been reviewed for technical accuracy (peer reviewer), technical quality (Lead Civil), and editorial quality (technical edit). Your review is a final verification that the document meets RMC standards.
+
+## Approving
+
+1. Back on the PR, click the **Files changed** tab
+2. Click **Review changes** (upper right)
+3. Select **Approve**
+4. Optionally type a note
+5. Click **Submit review**
+
+Done. The site administrator handles everything from here.
+
+## If something needs fixing
+
+Select **Request changes** instead of Approve and describe the issue. The author will fix it, and you'll be asked to re-review.
+
+For minor suggestions you don't want to block on, select Approve and include a note — the site admin will coordinate the follow-up.
+```
+
+---
+
+### 3.7 `15-site-admin-workflow.mdx`
+
+```mdx
+---
+title: Site Admin Workflow
+---
+
+import NavContainer from '@site/src/components/NavContainer';
+
+
+
+# Site Admin Workflow
+
+Responsibilities and procedures for site administrators.
+
+## Responsibilities
+
+1. Assigning reviewers (peer, Lead Civil, Director) at each stage transition
+2. Running checkpoint deploys for Lane 1 PRs
+3. Running or coordinating the technical edit
+4. Preparing final merge commits (flipping draft flag, updating version history)
+5. Merging PRs and approving production deploys
+6. Handling Lane 4 editorial fix PRs as sole reviewer
+7. Resolving edge cases
+
+## Daily routine
+
+Check for PRs needing your attention. The stage progression workflow tags `@usace-rmc/docs-admin` at every transition. Filter: `is:open label:"stage:ready-to-merge"` or `is:open review-requested:@me`.
+
+## Assigning reviewers
+
+Reviewers are assigned ad-hoc per PR via the Reviewers sidebar (gear icon → type username → select). There are no standing review teams for peer reviewers or Lead Civils. The workflow's transition comment tells you which role to assign next.
+
+For Lane 1, you assign up to three people across the lifecycle: the peer reviewer (if the author didn't), the Lead Civil after peer approval, and the Director after the technical edit.
+
+## Running a checkpoint deploy (Lane 1)
+
+After Lead Civil approval, deploy the PR branch to the live site (watermarked):
+
+1. Repo → **Actions** tab → click **Deploy to GitHub Pages** in the sidebar
+2. Click **Run workflow** dropdown (upper right)
+3. Enter the PR branch name in the **ref** field
+4. Click **Run workflow**
+5. When the build completes, click **Review deployments** → check `production` → **Approve and deploy**
+6. Verify the document on the live URL with the watermark
+7. Post a comment on the PR with the live URL so the technical editor and Director know where to read
+
+Re-deploy whenever the author pushes revisions during the technical edit or Director review. Post a comment noting the update.
+
+## Running the technical edit
+
+After the checkpoint deploy, run `/technical-edit` from Claude Code while on the PR branch. If you don't have Claude Code access, coordinate with a team member who does.
+
+The AI posts inline review comments. The author addresses them and checks the PR description checkbox to advance.
+
+## Preparing the final merge
+
+When a PR reaches `stage:ready-to-merge`:
+
+1. Check out the PR branch (locally or via github.dev)
+2. In the landing page JS file, change `draft: true` to `draft: false`
+3. Update `00-version-history.mdx` with reviewer/approver names
+4. Commit and push
+5. Merge the PR
+6. Approve the final production deploy in Actions
+
+For Lane 1: `reviewedBy` includes the peer reviewer and Lead Civil; `approvedBy` is the Director.
+For Lanes 2/3: `reviewedBy` is the peer reviewer (and Lead Civil for Lane 2); `approvedBy` is `-`.
+Lane 4: no version history update needed.
+
+## Approving deploys
+
+Every deploy pauses at the production environment gate. You receive an email. Navigate to Actions → the workflow run → Review deployments → check `production` → Approve and deploy.
+
+A Lane 1 document may involve multiple deploys: one checkpoint after Lead Civil approval, re-deploys during technical edit/Director review, and one final deploy after merge.
+
+## Handling Lane 4 PRs
+
+Lane 4 PRs skip formal review. You are the reviewer, approver, and merger:
+
+1. Click the preview URL to see the change
+2. Review the Files changed tab
+3. Approve, merge, approve the deploy
+
+## Edge cases
+
+**Wrong lane:** Remove the current `lane:*` label, apply the correct one. The workflow re-initializes.
+
+**Branch starts with `docs/` but doesn't match a sub-prefix:** The workflow applies `stage:needs-lane` and tags you. Apply the correct `lane:*` label.
+
+**Document revision pushed to a non-`docs/` branch:** The workflow ignored the PR at open time because the branch prefix didn't match. Apply the correct `lane:*` label manually — the workflow will detect the label event and start the review process. Optionally ask the author to rename the branch for next time.
+
+**Non-document PR getting bot noise:** Should not happen under the current configuration — only branches starting with `docs/` are auto-processed. If you see this, check the workflow trigger and the script's branch-prefix guard.
+
+**Unresponsive reviewer:** Ping them on the PR, or reassign.
+
+**Stale checkpoint deploy:** If the live URL shows outdated content, re-run the checkpoint deploy and post a comment.
+
+**Build fails on checkpoint deploy:** Coordinate with the author to fix the branch.
+
+**Build fails after merge to main:** Push a hotfix to `main` or revert the merge. Re-run the deploy.
+
+## Onboarding new site admins
+
+1. Clone the repo, confirm local build works
+2. Read these Documentation Guide chapters
+3. Shadow an existing admin through one full PR lifecycle
+4. Practice on a Lane 4 editorial fix PR
+```
+
+---
+
+## Task 4: Verify
+
+1. Run `npm run sidebars` to regenerate sidebar
+2. Run `npm run build` — must succeed
+3. Run `npm start` and verify all seven new chapters appear in order
+4. Confirm renamed appendices still appear at the bottom
+
+## Task 5: Open the PR
+
+Branch: `docs/new/documentation-guide-review-chapters`
+
+PR title: `Add review and approval process chapters to Documentation Guide`
+
+## Checklist
+
+- [ ] Three appendix files renamed
+- [ ] `scripts/generateSidebars.js` updated
+- [ ] Seven new chapter MDX files created
+- [ ] `npm run sidebars` run
+- [ ] Build passes
+- [ ] Visual check passes
+- [ ] PR opened
diff --git a/src/theme/DocItem/index.js b/src/theme/DocItem/index.js
index ed4a2943b..162334e68 100644
--- a/src/theme/DocItem/index.js
+++ b/src/theme/DocItem/index.js
@@ -2,23 +2,37 @@ import React from "react";
import DocItem from "@theme-original/DocItem";
import { useLocation } from "@docusaurus/router";
import { draftDocs } from "../../draftDocs";
+import latestVersions from "@site/static/versions/latestVersions.json";
+
+function getDocInfo(pathname) {
+ const stripped = pathname
+ .replace(/^\/RMC-Software-Documentation\/docs\//, "")
+ .replace(/^\/docs\//, "")
+ .replace(/^docs\//, "");
+ const match = stripped.match(/^(.+?)\/(v\d+\.\d+(?:\.\d+)?)(?:\/|$)/);
+ if (!match) return null;
+ return { docBasePath: match[1], version: match[2] };
+}
function isDraftDoc(pathname) {
- // Remove site base URL and /docs/ prefix
- const docPath = pathname
- .replace(/^\/RMC-Software-Documentation\/docs\//, "") // Remove base URL and /docs/
- .replace(/^docs\//, ""); // Fallback if base URL is not present
- return draftDocs.some((base) => docPath.startsWith(base));
+ const info = getDocInfo(pathname);
+ if (!info) return false;
+ const isFlagged = draftDocs.some(
+ (base) => info.docBasePath === base || info.docBasePath.startsWith(base + "/")
+ );
+ if (!isFlagged) return false;
+ const latest = latestVersions[info.docBasePath];
+ if (!latest) return true;
+ return info.version === latest;
}
export default function DocItemWrapper(props) {
const location = useLocation();
const showWatermark = isDraftDoc(location.pathname);
-
return (
<>
{showWatermark && (
-