diff --git a/.githooks/README.md b/.githooks/README.md
index 7c77879b5..3e5d8424d 100644
--- a/.githooks/README.md
+++ b/.githooks/README.md
@@ -27,9 +27,16 @@ Owned concerns:
- fast staged local/offline checks
- structure + style + staged static test validations
+- scoped basic test lane only; repo-wide governance/unit suites stay out of pre-commit
- staged generator sync for managed artifacts
+- reuses cached pass results when the staged snapshot and hook/test inputs are unchanged
- runtime budget enforcement (default: `<= 60s`)
+Install behavior:
+
+- configures worktree-local `core.hooksPath=.githooks`
+- runs hooks directly from tracked repo files instead of copying stale hook files into `.git/hooks`
+
Out-of-scope concerns:
- browser sweeps
diff --git a/.githooks/install.sh b/.githooks/install.sh
index aafb17d65..1130429d8 100755
--- a/.githooks/install.sh
+++ b/.githooks/install.sh
@@ -3,54 +3,63 @@
# @category utility
# @purpose tooling:dev-tools
# @scope .githooks
-# @owner docs
+# @domain docs
# @needs E-C6, F-C1
-# @purpose-statement Installs git hooks by setting core.hooksPath to .githooks/
+# @purpose-statement Installs git hooks by routing this worktree to .githooks via worktree-local core.hooksPath
# @pipeline manual — developer tool
# @usage bash .githooks/install.sh [flags]
# Install git hooks
-# Support both regular repos and worktrees
-GIT_COMMON_DIR=$(git rev-parse --git-common-dir 2>/dev/null)
-if [ -z "$GIT_COMMON_DIR" ] || [ "$GIT_COMMON_DIR" = "--git-common-dir" ]; then
- GIT_COMMON_DIR=".git"
-fi
-HOOKS_DIR="$GIT_COMMON_DIR/hooks"
-SOURCE_DIR=".githooks"
+set -euo pipefail
+
+REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
+SOURCE_DIR="$REPO_ROOT/.githooks"
+
+cd "$REPO_ROOT"
-if [ ! -d "$HOOKS_DIR" ]; then
- echo "Error: hooks directory not found at $HOOKS_DIR"
+if ! git rev-parse --git-dir >/dev/null 2>&1; then
+ echo "Error: this command must run inside a git worktree."
exit 1
fi
if [ ! -d "$SOURCE_DIR" ]; then
- echo "Error: .githooks directory not found. Are you in the repository root?"
+ echo "Error: .githooks directory not found at $SOURCE_DIR"
+ exit 1
+fi
+
+if [ ! -f "$SOURCE_DIR/pre-commit" ] || [ ! -f "$SOURCE_DIR/pre-push" ]; then
+ echo "Error: required hook entrypoints are missing from $SOURCE_DIR"
exit 1
fi
-echo "Installing git hooks..."
+echo "Installing git hooks for this worktree..."
-# Install pre-commit hook
-if [ -f "$SOURCE_DIR/pre-commit" ]; then
- cp "$SOURCE_DIR/pre-commit" "$HOOKS_DIR/pre-commit"
- chmod +x "$HOOKS_DIR/pre-commit"
- echo "✓ Installed pre-commit hook"
-else
- echo "✗ pre-commit hook not found in $SOURCE_DIR"
+git config extensions.worktreeConfig true
+
+SHARED_HOOKS_PATH=$(git config --local --get-all core.hooksPath 2>/dev/null || true)
+if [ -n "$SHARED_HOOKS_PATH" ]; then
+ git config --local --unset-all core.hooksPath || true
+ echo "✓ Cleared shared core.hooksPath override"
fi
-# Install pre-push hook
-if [ -f "$SOURCE_DIR/pre-push" ]; then
- cp "$SOURCE_DIR/pre-push" "$HOOKS_DIR/pre-push"
- chmod +x "$HOOKS_DIR/pre-push"
- echo "✓ Installed pre-push hook"
-else
- echo "✗ pre-push hook not found in $SOURCE_DIR"
+git config --worktree core.hooksPath .githooks
+chmod +x "$SOURCE_DIR/pre-commit" "$SOURCE_DIR/pre-push"
+
+RESOLVED_HOOKS_PATH=$(git config --worktree --path --get core.hooksPath 2>/dev/null || true)
+if [ -z "$RESOLVED_HOOKS_PATH" ]; then
+ echo "Error: failed to resolve worktree-local core.hooksPath"
+ exit 1
fi
+if [[ "$RESOLVED_HOOKS_PATH" != /* ]]; then
+ RESOLVED_HOOKS_PATH="$REPO_ROOT/$RESOLVED_HOOKS_PATH"
+fi
+
+echo "✓ Using worktree-local core.hooksPath: $RESOLVED_HOOKS_PATH"
+echo "✓ Hook entrypoints are executable"
echo ""
echo "Git hooks installed successfully!"
echo ""
-echo "The pre-commit hook will now check for style guide violations."
-echo "The pre-push hook will enforce codex task contracts on codex/* branches."
+echo "The pre-commit hook now runs directly from .githooks/pre-commit."
+echo "The pre-push hook now runs directly from .githooks/pre-push."
echo "See .githooks/README.md for details."
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
index b5f49b5e6..a0afcb920 100755
--- a/.githooks/pre-commit
+++ b/.githooks/pre-commit
@@ -3,7 +3,7 @@
# @category orchestrator
# @purpose infrastructure:pipeline-orchestration
# @scope .githooks
-# @owner docs
+# @domain docs
# @needs R-R29
# @purpose-statement Pre-commit hook orchestrator — runs structural checks, unit tests, codex validation, and docs-index freshness check before allowing commit
# @pipeline P1 (commit, hook entry point)
@@ -12,14 +12,15 @@
# Checks for common violations before allowing commits
#
# To install this hook, run:
-# cp .githooks/pre-commit .git/hooks/pre-commit
-# chmod +x .git/hooks/pre-commit
+# bash .githooks/install.sh
+# # or: lpd hooks install
#
# Bypass flags (use sparingly):
# SKIP_STRUCTURE_CHECK=1 - Skip root directory and snippets structure checks
# SKIP_STYLE_CHECK=1 - Skip style guide compliance checks
# SKIP_VERIFICATION=1 - Skip verification scripts
# SKIP_TESTS=1 - Skip test suite
+# DISABLE_PRECOMMIT_STAGED_CACHE=1 - Force rerun of the expensive staged validation suite
# SKIP_ALL=1 - Skip all checks (use with extreme caution)
#
# Human-only override flags:
@@ -43,6 +44,7 @@ SKIP_STRUCTURE_CHECK=${SKIP_STRUCTURE_CHECK:-0}
SKIP_STYLE_CHECK=${SKIP_STYLE_CHECK:-0}
SKIP_VERIFICATION=${SKIP_VERIFICATION:-0}
SKIP_TESTS=${SKIP_TESTS:-0}
+DISABLE_PRECOMMIT_STAGED_CACHE=${DISABLE_PRECOMMIT_STAGED_CACHE:-0}
SKIP_ALL=${SKIP_ALL:-0}
ALLOW_DELETIONS=${ALLOW_DELETIONS:-0}
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
@@ -64,6 +66,78 @@ get_staged_docs_pages() {
STAGED_DOCS_PAGES=$(get_staged_docs_pages)
+PRECOMMIT_STAGED_CACHE_HIT=0
+PRECOMMIT_STAGED_CACHE_KEY=""
+PRECOMMIT_STAGED_CACHE_INDEX_TREE=""
+PRECOMMIT_STAGED_CACHE_FILE=""
+PRECOMMIT_STAGED_CACHE_CREATED_AT=""
+
+can_use_precommit_staged_cache() {
+ if [ "$DISABLE_PRECOMMIT_STAGED_CACHE" = "1" ]; then
+ return 1
+ fi
+
+ if [ "$SKIP_VERIFICATION" = "1" ] || [ "$SKIP_TESTS" = "1" ]; then
+ return 1
+ fi
+
+ if ! command -v node &>/dev/null || [ ! -f "tools/lib/precommit-staged-cache.js" ]; then
+ return 1
+ fi
+
+ return 0
+}
+
+read_precommit_staged_cache() {
+ if ! can_use_precommit_staged_cache; then
+ return 1
+ fi
+
+ local output=""
+ output=$(node - "$PWD" <<'NODE'
+const cache = require('./tools/lib/precommit-staged-cache');
+const repoRoot = process.argv[2];
+
+try {
+ const result = cache.readCache({ repoRoot });
+ process.stdout.write([
+ result.hit ? '1' : '0',
+ result.key || '',
+ result.indexTree || '',
+ result.cacheFilePath || '',
+ result.entry?.createdAt || ''
+ ].join('\t'));
+} catch (error) {
+ process.stderr.write(`${error.message}\n`);
+ process.exit(1);
+}
+NODE
+ ) || return 1
+
+ IFS=$'\t' read -r PRECOMMIT_STAGED_CACHE_HIT PRECOMMIT_STAGED_CACHE_KEY PRECOMMIT_STAGED_CACHE_INDEX_TREE PRECOMMIT_STAGED_CACHE_FILE PRECOMMIT_STAGED_CACHE_CREATED_AT <<< "$output"
+ [ "$PRECOMMIT_STAGED_CACHE_HIT" = "1" ]
+}
+
+write_precommit_staged_cache() {
+ if ! can_use_precommit_staged_cache; then
+ return 1
+ fi
+
+ node - "$PWD" "$CURRENT_BRANCH" <<'NODE'
+const cache = require('./tools/lib/precommit-staged-cache');
+const repoRoot = process.argv[2];
+const branch = process.argv[3];
+
+cache.writeCache({
+ repoRoot,
+ metadata: {
+ branch,
+ source: 'pre-commit'
+ }
+});
+NODE
+}
+
get_forbidden_staged_generated_outputs() {
if ! command -v node &>/dev/null || [ ! -f "tools/lib/generated-artifacts.js" ]; then
return 0
@@ -823,35 +897,6 @@ else
fi
fi
-# Run verification scripts (legacy path disabled for faster staged-only hooks)
-if [ "$SKIP_VERIFICATION" = "1" ]; then
- echo -e "${YELLOW}⚠️ Verification scripts bypassed (SKIP_VERIFICATION=1)${NC}"
-else
- echo ""
- echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
- echo -e "${YELLOW}Skipping legacy verify.sh in pre-commit (staged-only fast mode).${NC}"
- echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
- FORBIDDEN_GENERATED_OUTPUTS=$(get_forbidden_staged_generated_outputs)
- if [ -n "$FORBIDDEN_GENERATED_OUTPUTS" ]; then
- echo -e "${RED}Forbidden staged ephemeral generated outputs detected:${NC}"
- while IFS= read -r path; do
- [ -z "$path" ] && continue
- echo " - $path"
- WARNINGS+=("❌ Forbidden staged ephemeral generated output: $path")
- VIOLATIONS=$((VIOLATIONS + 1))
- done <<< "$FORBIDDEN_GENERATED_OUTPUTS"
- echo "Move local-only reports to an ignored scratch path instead of committing them."
- exit 1
- fi
- echo "Checking generated file banners..."
- if node tools/scripts/enforce-generated-file-banners.js --check --staged; then
- echo -e "${GREEN}✓ Generated file banner check passed${NC}"
- else
- echo "Generated file banners missing or incorrect. Run: node tools/scripts/enforce-generated-file-banners.js --write"
- exit 1
- fi
-fi
-
run_node_check() {
local label="$1"
local failure_message="$2"
@@ -954,7 +999,7 @@ const tags = [
'@category',
'@purpose',
'@scope',
- '@owner',
+ '@domain',
'@needs',
'@purpose-statement',
'@pipeline',
@@ -999,7 +1044,7 @@ const tags = [
'@category',
'@purpose',
'@scope',
- '@owner',
+ '@domain',
'@needs',
'@purpose-statement',
'@pipeline',
@@ -1077,13 +1122,12 @@ NODE
print_governance_dependency_error() {
echo ""
- echo "✗ Governance auto-repair is unavailable in this checkout."
+ echo "✗ Governance auto-repair tooling is unavailable or outdated in this checkout."
echo ""
- echo " REPAIR-00a is not merged here yet."
echo " Expected tools/scripts/validators/governance/audit-script-inventory.js"
- echo " to support --staged-only and --quiet."
+ echo " with --staged-only and --quiet support, plus the matching governance helpers."
echo ""
- echo " Update from docs-v2 after REPAIR-00a merges, then retry."
+ echo " Sync the checkout to the current governance baseline and ensure repo dependencies are installed."
echo " Run 'cd tools && npm run repair:governance -- --dry-run' for more detail."
echo " To skip: SKIP_VERIFICATION=1 git commit -m 'message'"
echo ""
@@ -1295,170 +1339,228 @@ run_governance_auto_repair() {
)
}
-# Component governance checks
-if [ "$SKIP_TESTS" != "1" ]; then
- STAGED_COMPONENTS=$(git diff --cached --name-only --diff-filter=ACM -- snippets/components | grep -E '\.jsx$' | grep -v '/_archive/' || true)
- if [ -n "$STAGED_COMPONENTS" ]; then
- run_node_check \
- "Running component JSDoc validation (staged)..." \
- "❌ Component JSDoc validation failed" \
- tools/scripts/validators/components/check-component-docs.js --staged
-
- run_node_check \
- "Running component styling validation (staged)..." \
- "❌ Component styling validation failed" \
- tools/scripts/validators/components/check-component-css.js --staged
-
- if [ $VIOLATIONS -eq 0 ]; then
- echo -e "${YELLOW}Repairing derived component metadata...${NC}"
- if node tools/scripts/remediators/components/repair-component-metadata.js --staged --fix 2>&1; then
- echo "$STAGED_COMPONENTS" | xargs git add 2>/dev/null
- echo -e "${GREEN}✓ Component metadata repaired${NC}"
- else
- VIOLATIONS=$((VIOLATIONS + 1))
- WARNINGS+=("❌ Component metadata has NEEDS_HUMAN errors - inspect repair-component-metadata output")
- echo -e "${RED}❌ Component metadata repair found issues requiring human attention${NC}"
- fi
- fi
-
- if [ $VIOLATIONS -eq 0 ]; then
- echo -e "${YELLOW}Regenerating component registry...${NC}"
- if node tools/scripts/generate-component-registry.js 2>&1; then
- git add docs-guide/component-registry.json docs-guide/component-registry-schema.json 2>/dev/null
- echo -e "${GREEN}✓ Component registry regenerated${NC}"
- else
- VIOLATIONS=$((VIOLATIONS + 1))
- WARNINGS+=("❌ Component registry generation failed")
- echo -e "${RED}❌ Component registry generation failed${NC}"
- fi
- fi
-
- if [ $VIOLATIONS -eq 0 ]; then
- echo -e "${YELLOW}Regenerating component usage map...${NC}"
- if node tools/scripts/scan-component-imports.js 2>&1; then
- git add docs-guide/component-usage-map.json 2>/dev/null
- echo -e "${GREEN}✓ Component usage map regenerated${NC}"
- else
- VIOLATIONS=$((VIOLATIONS + 1))
- WARNINGS+=("❌ Component usage map generation failed")
- echo -e "${RED}❌ Component usage map generation failed${NC}"
- fi
- fi
+RUN_PRECOMMIT_EXPENSIVE_SUITE=1
- if [ $VIOLATIONS -eq 0 ] && [ -f "tools/scripts/generate-docs-guide-components-index.js" ]; then
- echo -e "${YELLOW}Regenerating components catalog...${NC}"
- if node tools/scripts/generate-docs-guide-components-index.js --fix 2>&1; then
- git add docs-guide/catalog/components-catalog.mdx 2>/dev/null
- echo -e "${GREEN}✓ Components catalog regenerated${NC}"
- else
- VIOLATIONS=$((VIOLATIONS + 1))
- WARNINGS+=("❌ Components catalog generation failed")
- echo -e "${RED}❌ Components catalog generation failed${NC}"
- fi
- fi
+if [ $VIOLATIONS -gt 0 ]; then
+ echo ""
+ echo -e "${YELLOW}Skipping expensive staged validation because blocking pre-check violations already exist.${NC}"
+ RUN_PRECOMMIT_EXPENSIVE_SUITE=0
+elif read_precommit_staged_cache; then
+ echo ""
+ echo -e "${GREEN}✓ Reusing cached staged validation for unchanged staged content${NC}"
+ if [ -n "$PRECOMMIT_STAGED_CACHE_CREATED_AT" ]; then
+ echo " Cached at: $PRECOMMIT_STAGED_CACHE_CREATED_AT"
fi
+ RUN_PRECOMMIT_EXPENSIVE_SUITE=0
fi
-# Run test suite (fast mode for pre-commit)
-if [ "$SKIP_TESTS" = "1" ]; then
- echo -e "${YELLOW}⚠️ Test suite bypassed (SKIP_TESTS=1)${NC}"
-else
- echo ""
- echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
- echo -e "${YELLOW}Running test suite (staged files only)...${NC}"
- if [ -f "tests/run-all.js" ] && command -v node &>/dev/null; then
- if [ -d "tools/node_modules" ]; then
- export NODE_PATH="$(pwd)/tools/node_modules:${NODE_PATH:-}"
- elif [ -d "tests/node_modules" ]; then
- export NODE_PATH="$(pwd)/tests/node_modules:${NODE_PATH:-}"
- else
- echo -e "${YELLOW}⚠️ Dependencies not installed. Run 'cd tools && npm install' or 'cd tests && npm install' to enable tests${NC}"
+if [ "$RUN_PRECOMMIT_EXPENSIVE_SUITE" = "1" ]; then
+ # Run verification scripts (legacy path disabled for faster staged-only hooks)
+ if [ "$SKIP_VERIFICATION" = "1" ]; then
+ echo -e "${YELLOW}⚠️ Verification scripts bypassed (SKIP_VERIFICATION=1)${NC}"
+ else
+ echo ""
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
+ echo -e "${YELLOW}Skipping legacy verify.sh in pre-commit (staged-only fast mode).${NC}"
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
+ FORBIDDEN_GENERATED_OUTPUTS=$(get_forbidden_staged_generated_outputs)
+ if [ -n "$FORBIDDEN_GENERATED_OUTPUTS" ]; then
+ echo -e "${RED}Forbidden staged ephemeral generated outputs detected:${NC}"
+ while IFS= read -r path; do
+ [ -z "$path" ] && continue
+ echo " - $path"
+ WARNINGS+=("❌ Forbidden staged ephemeral generated output: $path")
+ VIOLATIONS=$((VIOLATIONS + 1))
+ done <<< "$FORBIDDEN_GENERATED_OUTPUTS"
+ echo "Move local-only reports to an ignored scratch path instead of committing them."
+ exit 1
fi
-
- if [ "$SKIP_VERIFICATION" != "1" ] && [ $VIOLATIONS -eq 0 ]; then
- if ! run_governance_auto_repair; then
- exit 1
- fi
+ echo "Checking generated file banners..."
+ if node tools/scripts/enforce-generated-file-banners.js --check --staged; then
+ echo -e "${GREEN}✓ Generated file banner check passed${NC}"
+ else
+ echo "Generated file banners missing or incorrect. Run: node tools/scripts/enforce-generated-file-banners.js --write"
+ exit 1
fi
+ fi
- if [ -f "tools/scripts/generate-pages-index.js" ]; then
+ # Component governance checks
+ if [ "$SKIP_TESTS" != "1" ]; then
+ STAGED_COMPONENTS=$(git diff --cached --name-only --diff-filter=ACM -- snippets/components | grep -E '\.jsx$' | grep -v '/_archive/' || true)
+ if [ -n "$STAGED_COMPONENTS" ]; then
run_node_check \
- "Running v2/pages index generation (staged changes)..." \
- "❌ v2/pages index generation failed - fix index sync issues" \
- tools/scripts/generate-pages-index.js --staged --write --stage
- fi
+ "Running component JSDoc validation (staged)..." \
+ "❌ Component JSDoc validation failed" \
+ tools/scripts/validators/components/check-component-docs.js --staged
- if [ -f "tools/scripts/remediators/content/repair-mdx-safe-markdown.js" ]; then
run_node_check \
- "Running staged MDX-safe markdown auto-repair..." \
- "❌ MDX-safe markdown auto-repair failed - inspect repair-mdx-safe-markdown output" \
- tools/scripts/remediators/content/repair-mdx-safe-markdown.js --write --staged --stage
- fi
+ "Running component styling validation (staged)..." \
+ "❌ Component styling validation failed" \
+ tools/scripts/validators/components/check-component-css.js --staged
+
+ if [ $VIOLATIONS -eq 0 ]; then
+ echo -e "${YELLOW}Repairing derived component metadata...${NC}"
+ if node tools/scripts/remediators/components/repair-component-metadata.js --staged --fix 2>&1; then
+ echo "$STAGED_COMPONENTS" | xargs git add 2>/dev/null
+ echo -e "${GREEN}✓ Component metadata repaired${NC}"
+ else
+ VIOLATIONS=$((VIOLATIONS + 1))
+ WARNINGS+=("❌ Component metadata has NEEDS_HUMAN errors - inspect repair-component-metadata output")
+ echo -e "${RED}❌ Component metadata repair found issues requiring human attention${NC}"
+ fi
+ fi
- if [ -f "tools/scripts/validators/content/check-mdx-safe-markdown.js" ]; then
- run_node_check \
- "Running staged MDX-safe markdown validation..." \
- "❌ MDX-safe markdown validation failed - inspect check-mdx-safe-markdown output" \
- tools/scripts/validators/content/check-mdx-safe-markdown.js --staged
- fi
+ if [ $VIOLATIONS -eq 0 ]; then
+ echo -e "${YELLOW}Regenerating component registry...${NC}"
+ if node tools/scripts/generate-component-registry.js 2>&1; then
+ git add docs-guide/component-registry.json docs-guide/component-registry-schema.json 2>/dev/null
+ echo -e "${GREEN}✓ Component registry regenerated${NC}"
+ else
+ VIOLATIONS=$((VIOLATIONS + 1))
+ WARNINGS+=("❌ Component registry generation failed")
+ echo -e "${RED}❌ Component registry generation failed${NC}"
+ fi
+ fi
- if [ -f "tools/scripts/generate-docs-index.js" ]; then
- if should_check_generated_artifact "docs-index.json"; then
- echo -e "${YELLOW}Checking generated artifact freshness...${NC}"
- GENERATED_ARTIFACT_SUMMARY=$(format_generated_artifact_message "docs-index.json" "summary")
- DOCS_INDEX_ARGS="--staged"
- if echo "$STAGED_FILES_SNAPSHOT_ALL" | grep -Eq '^docs\.json$'; then
- DOCS_INDEX_ARGS=""
+ if [ $VIOLATIONS -eq 0 ]; then
+ echo -e "${YELLOW}Regenerating component usage map...${NC}"
+ if node tools/scripts/scan-component-imports.js 2>&1; then
+ git add docs-guide/component-usage-map.json 2>/dev/null
+ echo -e "${GREEN}✓ Component usage map regenerated${NC}"
+ else
+ VIOLATIONS=$((VIOLATIONS + 1))
+ WARNINGS+=("❌ Component usage map generation failed")
+ echo -e "${RED}❌ Component usage map generation failed${NC}"
fi
- if node tools/scripts/generate-docs-index.js --check $DOCS_INDEX_ARGS >/dev/null 2>&1; then
- echo -e "${GREEN}✓ ${GENERATED_ARTIFACT_SUMMARY} is up to date${NC}"
+ fi
+
+ if [ $VIOLATIONS -eq 0 ] && [ -f "tools/scripts/generate-docs-guide-components-index.js" ]; then
+ echo -e "${YELLOW}Regenerating components catalog...${NC}"
+ if node tools/scripts/generate-docs-guide-components-index.js --fix 2>&1; then
+ git add docs-guide/catalog/components-catalog.mdx 2>/dev/null
+ echo -e "${GREEN}✓ Components catalog regenerated${NC}"
else
VIOLATIONS=$((VIOLATIONS + 1))
- GENERATED_ARTIFACT_GENERATOR=$(format_generated_artifact_message "docs-index.json" "generator")
- WARNINGS+=("❌ Generated artifact freshness issue: docs-index.json is stale. Run: ${GENERATED_ARTIFACT_GENERATOR}")
- echo -e "${RED}❌ ${GENERATED_ARTIFACT_SUMMARY} is stale${NC}"
- echo " Source files changed within its declared manifest scope."
- echo " Remediation: ${GENERATED_ARTIFACT_GENERATOR}"
- exit 1
+ WARNINGS+=("❌ Components catalog generation failed")
+ echo -e "${RED}❌ Components catalog generation failed${NC}"
fi
- else
- echo -e "${GREEN}✓ No manifest-declared docs-index sources staged, skipping docs-index freshness check${NC}"
fi
fi
+ fi
- if [ -f "tools/scripts/remediators/content/sync-docs-paths.js" ]; then
- run_node_check \
- "Running staged docs path sync..." \
- "❌ Docs path sync failed - inspect sync-docs-paths output" \
- tools/scripts/remediators/content/sync-docs-paths.js --write --staged --stage
- fi
+ # Run test suite (fast mode for pre-commit)
+ if [ "$SKIP_TESTS" = "1" ]; then
+ echo -e "${YELLOW}⚠️ Test suite bypassed (SKIP_TESTS=1)${NC}"
+ else
+ echo ""
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
+ echo -e "${YELLOW}Running test suite (staged files only)...${NC}"
+ if [ -f "tests/run-all.js" ] && command -v node &>/dev/null; then
+ if [ -d "tools/node_modules" ]; then
+ export NODE_PATH="$(pwd)/tools/node_modules:${NODE_PATH:-}"
+ elif [ -d "tests/node_modules" ]; then
+ export NODE_PATH="$(pwd)/tests/node_modules:${NODE_PATH:-}"
+ else
+ echo -e "${YELLOW}⚠️ Dependencies not installed. Run 'cd tools && npm install' or 'cd tests && npm install' to enable tests${NC}"
+ fi
+
+ if [ "$SKIP_VERIFICATION" != "1" ] && [ $VIOLATIONS -eq 0 ]; then
+ if ! run_governance_auto_repair; then
+ exit 1
+ fi
+ fi
+
+ if [ -f "tools/scripts/generate-pages-index.js" ]; then
+ run_node_check \
+ "Running v2/pages index generation (staged changes)..." \
+ "❌ v2/pages index generation failed - fix index sync issues" \
+ tools/scripts/generate-pages-index.js --staged --write --stage
+ fi
- run_node_check \
- "Running core staged test suite..." \
- "❌ Core staged test suite failed - see output above" \
- tests/run-all.js --staged --skip-browser
+ if [ -f "tools/scripts/remediators/content/repair-mdx-safe-markdown.js" ]; then
+ run_node_check \
+ "Running staged MDX-safe markdown auto-repair..." \
+ "❌ MDX-safe markdown auto-repair failed - inspect repair-mdx-safe-markdown output" \
+ tools/scripts/remediators/content/repair-mdx-safe-markdown.js --write --staged --stage
+ fi
- if [ -n "$STAGED_DOCS_PAGES" ]; then
- if [ -f "tests/integration/v2-link-audit.js" ]; then
+ if [ -f "tools/scripts/validators/content/check-mdx-safe-markdown.js" ]; then
run_node_check \
- "Running staged V2 link audit..." \
- "❌ Staged V2 link audit failed - see /tmp/livepeer-link-audit-precommit.md" \
- tests/integration/v2-link-audit.js --staged --strict --report /tmp/livepeer-link-audit-precommit.md
+ "Running staged MDX-safe markdown validation..." \
+ "❌ MDX-safe markdown validation failed - inspect check-mdx-safe-markdown output" \
+ tools/scripts/validators/content/check-mdx-safe-markdown.js --staged
+ fi
+
+ if [ -f "tools/scripts/generate-docs-index.js" ]; then
+ if should_check_generated_artifact "docs-index.json"; then
+ echo -e "${YELLOW}Checking generated artifact freshness...${NC}"
+ GENERATED_ARTIFACT_SUMMARY=$(format_generated_artifact_message "docs-index.json" "summary")
+ DOCS_INDEX_ARGS="--staged"
+ if echo "$STAGED_FILES_SNAPSHOT_ALL" | grep -Eq '^docs\.json$'; then
+ DOCS_INDEX_ARGS=""
+ fi
+ if node tools/scripts/generate-docs-index.js --check $DOCS_INDEX_ARGS >/dev/null 2>&1; then
+ echo -e "${GREEN}✓ ${GENERATED_ARTIFACT_SUMMARY} is up to date${NC}"
+ else
+ VIOLATIONS=$((VIOLATIONS + 1))
+ GENERATED_ARTIFACT_GENERATOR=$(format_generated_artifact_message "docs-index.json" "generator")
+ WARNINGS+=("❌ Generated artifact freshness issue: docs-index.json is stale. Run: ${GENERATED_ARTIFACT_GENERATOR}")
+ echo -e "${RED}❌ ${GENERATED_ARTIFACT_SUMMARY} is stale${NC}"
+ echo " Source files changed within its declared manifest scope."
+ echo " Remediation: ${GENERATED_ARTIFACT_GENERATOR}"
+ exit 1
+ fi
+ else
+ echo -e "${GREEN}✓ No manifest-declared docs-index sources staged, skipping docs-index freshness check${NC}"
+ fi
fi
- if [ -f "tests/integration/v2-wcag-audit.js" ]; then
+ if [ -f "tools/scripts/remediators/content/sync-docs-paths.js" ]; then
run_node_check \
- "Running staged V2 WCAG accessibility audit..." \
- "❌ Staged V2 WCAG accessibility audit failed - see /tmp/livepeer-wcag-audit-precommit.md" \
- tests/integration/v2-wcag-audit.js --staged --fix --stage --max-pages 10 --fail-impact serious --report /tmp/livepeer-wcag-audit-precommit.md --report-json /tmp/livepeer-wcag-audit-precommit.json
+ "Running staged docs path sync..." \
+ "❌ Docs path sync failed - inspect sync-docs-paths output" \
+ tools/scripts/remediators/content/sync-docs-paths.js --write --staged --stage
+ fi
+
+ run_all_args=(tests/run-all.js --staged --skip-browser --precommit-basic)
+ if [ "$SKIP_VERIFICATION" != "1" ]; then
+ run_all_args+=(--skip-mdx-safe-markdown-check --skip-pages-index --skip-script-docs)
+ fi
+ run_node_check \
+ "Running basic staged test suite..." \
+ "❌ Basic staged test suite failed - see output above" \
+ "${run_all_args[@]}"
+
+ if [ -n "$STAGED_DOCS_PAGES" ]; then
+ if [ -f "tests/integration/v2-link-audit.js" ]; then
+ run_node_check \
+ "Running staged V2 link audit..." \
+ "❌ Staged V2 link audit failed - see /tmp/livepeer-link-audit-precommit.md" \
+ tests/integration/v2-link-audit.js --staged --strict --report /tmp/livepeer-link-audit-precommit.md
+ fi
+
+ if [ -f "tests/integration/v2-wcag-audit.js" ]; then
+ run_node_check \
+ "Running staged V2 WCAG accessibility audit..." \
+ "❌ Staged V2 WCAG accessibility audit failed - see /tmp/livepeer-wcag-audit-precommit.md" \
+ tests/integration/v2-wcag-audit.js --staged --fix --stage --max-pages 10 --fail-impact serious --report /tmp/livepeer-wcag-audit-precommit.md --report-json /tmp/livepeer-wcag-audit-precommit.json
+ fi
+ else
+ echo -e "${GREEN}✓ No staged docs pages, skipping link audit and WCAG audit${NC}"
fi
else
- echo -e "${GREEN}✓ No staged docs pages, skipping link audit and WCAG audit${NC}"
+ echo -e "${YELLOW}⚠️ Test suite not available, skipping...${NC}"
+ fi
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
+ fi
+
+ if [ $VIOLATIONS -eq 0 ]; then
+ if write_precommit_staged_cache >/dev/null 2>&1; then
+ echo -e "${GREEN}✓ Cached staged validation results for reuse${NC}"
+ else
+ echo -e "${YELLOW}⚠️ Could not persist staged validation cache; future commits will rerun the expensive suite${NC}"
fi
- else
- echo -e "${YELLOW}⚠️ Test suite not available, skipping...${NC}"
fi
- echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
fi
# Report results
diff --git a/.githooks/script-index.md b/.githooks/script-index.md
index 70513d29c..930481146 100644
--- a/.githooks/script-index.md
+++ b/.githooks/script-index.md
@@ -5,7 +5,7 @@
| Script | Summary | Usage | Domain |
|---|---|---|---|
-| `.githooks/install.sh` | Installs git hooks by setting core.hooksPath to .githooks/ | `bash .githooks/install.sh [flags]` | docs |
+| `.githooks/install.sh` | Installs git hooks by routing this worktree to .githooks via worktree-local core.hooksPath | `bash .githooks/install.sh [flags]` | docs |
| `.githooks/pre-commit` | Pre-commit hook orchestrator — runs structural checks, unit tests, codex validation, and docs-index freshness check before allowing commit | `bash .githooks/pre-commit [flags]` | docs |
| `.githooks/pre-commit-no-deletions` | Variant pre-commit hook that blocks file deletions (safety net for content preservation) | `bash .githooks/pre-commit-no-deletions [flags]` | docs |
| `.githooks/pre-push` | Pre-push hook — blocks push if AI stash files present, codex locks stale, or task contract invalid | `bash .githooks/pre-push [flags]` | docs |
diff --git a/ai-tools/ai-skills/page-authoring/SKILL.md b/ai-tools/ai-skills/page-authoring/SKILL.md
index eaeddf8e1..b6d63198a 100644
--- a/ai-tools/ai-skills/page-authoring/SKILL.md
+++ b/ai-tools/ai-skills/page-authoring/SKILL.md
@@ -104,7 +104,7 @@ Do not hardcode your own enum list in local docs or prompts.
- Prefer governed snippets/components before inventing new presentation patterns
- Use cards for navigation, tables for exact comparisons, steps for sequential task completion, and accordions for optional depth
- If styling pressure is high, solve it in a component primitive rather than in page-level MDX
-- **Never stack consecutive tables.** Two StyledTables back-to-back is a layout failure. Use tabs, accordions, cards, bordered boxes, or prose to break up tabular content. The component library has over 100 components - use them.
+- **Maximum 1-2 tables per page.** Tables support prose - they do not replace it. A page with more tables than paragraphs is a spreadsheet, not documentation. If information feels tabular, consider whether cards, accordions, or bordered boxes communicate it better. Never stack consecutive tables.
### Terminology and context
diff --git a/contribute/CONTRIBUTING/GIT-HOOKS.md b/contribute/CONTRIBUTING/GIT-HOOKS.md
index f84856425..c2c1bd043 100644
--- a/contribute/CONTRIBUTING/GIT-HOOKS.md
+++ b/contribute/CONTRIBUTING/GIT-HOOKS.md
@@ -22,6 +22,8 @@ lpd hooks status
- fast staged local/offline checks only
- structure/style/static checks + staged generator sync
+- fail-fast when cheap blocking violations already exist
+- reuses the expensive staged validation result when staged content and hook inputs are unchanged
- enforces pre-commit runtime budget (default `<= 60s`)
### Pre-push (`.githooks/pre-push`)
diff --git a/docs-guide/catalog/scripts-catalog.mdx b/docs-guide/catalog/scripts-catalog.mdx
index e6c3cfc9d..7ecefca8a 100644
--- a/docs-guide/catalog/scripts-catalog.mdx
+++ b/docs-guide/catalog/scripts-catalog.mdx
@@ -24,7 +24,7 @@ Run command: node tests/unit/script-docs.test.js --write --rebuild-indexes
| Script | Summary | Usage | Domain |
|---|---|---|---|
-| `.githooks/install.sh` | Installs git hooks by setting core.hooksPath to .githooks/ | `bash .githooks/install.sh [flags]` | docs |
+| `.githooks/install.sh` | Installs git hooks by routing this worktree to .githooks via worktree-local core.hooksPath | `bash .githooks/install.sh [flags]` | docs |
| `.githooks/pre-commit` | Pre-commit hook orchestrator — runs structural checks, unit tests, codex validation, and docs-index freshness check before allowing commit | `bash .githooks/pre-commit [flags]` | docs |
| `.githooks/pre-commit-no-deletions` | Variant pre-commit hook that blocks file deletions (safety net for content preservation) | `bash .githooks/pre-commit-no-deletions [flags]` | docs |
| `.githooks/pre-push` | Pre-push hook — blocks push if AI stash files present, codex locks stale, or task contract invalid | `bash .githooks/pre-push [flags]` | docs |
@@ -96,6 +96,7 @@ Run command: node tests/unit/script-docs.test.js --write --rebuild-indexes
| `tests/unit/openapi-rolling-issue.test.js` | Tests OpenAPI rolling issue tracker — validates issue creation and dedup logic | `node tests/unit/openapi-rolling-issue.test.js [flags]` | docs |
| `tests/unit/orchestrator-guides-research-review.test.js` | Tests orchestrator-guides-research-review.js — validates live Orchestrators Guides tranche extraction, report summary helpers, and registry-drift detection for the research packet generator. | `node tests/unit/orchestrator-guides-research-review.test.js` | docs |
| `tests/unit/ownerless-governance.test.js` | Validates the ownerless governance manifest, primary gate-layer contract, and forbidden human-owner dependency in governed policy and GitHub surfaces. | `node tests/unit/ownerless-governance.test.js [--staged|--files a,b]` | docs |
+| `tests/unit/precommit-staged-cache.test.js` | Tests precommit-staged-cache.js — validates staged-tree cache hits, invalidation, and pruning | `node tests/unit/precommit-staged-cache.test.js` | docs |
| `tests/unit/quality.test.js` | Content quality checks — validates frontmatter completeness, thin content detection, placeholder flagging | `node tests/unit/quality.test.js [flags]` | docs |
| `tests/unit/repair-governance.test.js` | Tests repair-governance.js for safe dry-run, fix, rollback, strict exit handling, and workflow contract coverage. | `node tests/unit/repair-governance.test.js` | docs |
| `tests/unit/repair-spelling.test.js` | Unit tests for repair-spelling.js — validates deterministic spelling fixes and exclusion ranges | `node tests/unit/repair-spelling.test.js [flags]` | docs |
@@ -295,6 +296,7 @@ Run command: node tests/unit/script-docs.test.js --write --rebuild-indexes
| `tools/lib/load-js-yaml.js` | YAML loader utility — resolves js-yaml from repo-local installs and falls back to a minimal parser for task-contract style files in bare worktrees | `node -e "require('./tools/lib/load-js-yaml')"` | docs |
| `tools/lib/load-minimatch.js` | Glob matcher loader — resolves minimatch from repo-local installs and falls back to a simple glob matcher for bare worktrees | `node -e "require('./tools/lib/load-minimatch')"` | docs |
| `tools/lib/mdx-safe-markdown.js` | Shared MDX-safe markdown helpers that collect first-party markdown files, detect unsafe patterns, and apply deterministic repairs. | `node tools/lib/mdx-safe-markdown.js [flags]` | docs |
+| `tools/lib/precommit-staged-cache.js` | Shared pre-commit staged-cache helpers — fingerprint staged content plus hook inputs and persist reusable pass markers | `const cache = require('./precommit-staged-cache');` | docs |
| `tools/lib/script-governance-config.js` | Shared governance constants for script discovery, indexing, classification, and pipeline normalisation across the repo. | `const config = require('../lib/script-governance-config');` | docs |
| `tools/lib/script-header-utils.js` | Shared helpers for extracting and reading top-of-file script governance headers without scanning into executable source. | `const { extractLeadingScriptHeader } = require('../lib/script-header-utils');` | docs |
diff --git a/docs.json b/docs.json
index 646342647..83be66b2b 100644
--- a/docs.json
+++ b/docs.json
@@ -2096,10 +2096,7 @@
{
"group": "Home",
"icon": "house-heart",
- "pages": [
- "v2/home/mission-control",
- "v2/home/primer"
- ]
+ "pages": ["v2/home/mission-control", "v2/home/primer"]
},
{
"group": "Livepeer",
@@ -2126,16 +2123,12 @@
{
"anchor": "Resource HUB",
"icon": "books",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
"icon": "horizontal-rule",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -2197,16 +2190,12 @@
{
"anchor": "Resource HUB",
"icon": "books",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
"icon": "horizontal-rule",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -2230,16 +2219,12 @@
{
"group": "Daydream",
"icon": "camera-movie",
- "pages": [
- "v2/solutions/daydream/overview"
- ]
+ "pages": ["v2/solutions/daydream/overview"]
},
{
"group": "Livepeer Studio",
"icon": "film-canister",
- "pages": [
- "v2/solutions/livepeer-studio/overview"
- ]
+ "pages": ["v2/solutions/livepeer-studio/overview"]
},
{
"group": "Stream.place",
@@ -2261,16 +2246,12 @@
{
"group": "Embody Avatars",
"icon": "user-robot",
- "pages": [
- "v2/solutions/embody/overview"
- ]
+ "pages": ["v2/solutions/embody/overview"]
},
{
"group": "Frameworks",
"icon": "clapperboard-play",
- "pages": [
- "v2/solutions/frameworks/overview"
- ]
+ "pages": ["v2/solutions/frameworks/overview"]
}
]
},
@@ -2330,9 +2311,7 @@
},
{
"group": "Player & embed",
- "pages": [
- "v2/solutions/livepeer-studio/player"
- ]
+ "pages": ["v2/solutions/livepeer-studio/player"]
},
{
"group": "Reference",
@@ -2471,16 +2450,12 @@
{
"anchor": "Resource HUB",
"icon": "books",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
"icon": "horizontal-rule",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -2570,16 +2545,12 @@
{
"anchor": "Resource HUB",
"icon": "books",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
"icon": "horizontal-rule",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -2588,7 +2559,7 @@
"icon": "torii-gate",
"anchors": [
{
- "anchor": "Gateways",
+ "anchor": "Gateways NEW",
"icon": "torii-gate",
"groups": [
{
@@ -2703,7 +2674,7 @@
]
},
{
- "group": "AI & Job Pipelines",
+ "group": "AI and Job Pipelines",
"pages": [
"v2/gateways/guides/node-pipelines/guide",
"v2/gateways/guides/node-pipelines/video-pipelines",
@@ -2713,7 +2684,7 @@
]
},
{
- "group": "Payments & Pricing",
+ "group": "Payments and Pricing",
"pages": [
"v2/gateways/guides/payments-and-pricing/payment-guide",
"v2/gateways/guides/payments-and-pricing/funding-guide",
@@ -2837,178 +2808,170 @@
]
}
]
+ }
+ ]
+ },
+ {
+ "tab": "Orchestrators",
+ "icon": "microchip",
+ "groups": [
+ {
+ "group": "Start Here",
+ "icon": "microchip",
+ "pages": [
+ "v2/orchestrators/portal",
+ "v2/orchestrators/navigator"
+ ]
},
{
- "anchor": "Resource HUB",
- "icon": "books",
+ "group": "Concepts",
+ "icon": "book-open",
"pages": [
- "v2/resources/redirect"
+ "v2/orchestrators/concepts/role",
+ "v2/orchestrators/concepts/capabilities",
+ "v2/orchestrators/concepts/architecture",
+ "v2/orchestrators/concepts/incentive-model"
]
},
{
- "anchor": " ",
- "icon": "horizontal-rule",
+ "group": "Quickstart",
+ "icon": "bolt",
"pages": [
- " "
+ "v2/orchestrators/quickstart/guide",
+ "v2/orchestrators/quickstart/video-transcoding",
+ "v2/orchestrators/quickstart/tutorial",
+ "v2/orchestrators/quickstart/ai-prompt-start"
]
- }
- ]
- },
- {
- "tab": "Orchestrators",
- "icon": "microchip",
- "anchors": [
+ },
{
- "anchor": "Orchestrators",
- "icon": "microchip",
- "groups": [
+ "group": "Setup",
+ "icon": "gear",
+ "pages": [
+ "v2/orchestrators/setup/guide",
+ "v2/orchestrators/setup/rcs-requirements",
+ "v2/orchestrators/setup/rs-install",
+ "v2/orchestrators/setup/configure",
+ "v2/orchestrators/setup/connect-and-activate",
+ "v2/orchestrators/setup/test",
+ "v2/orchestrators/setup/r-monitor"
+ ]
+ },
+ {
+ "group": "Guides",
+ "icon": "chart-line",
+ "pages": [
{
- "group": "Start Here",
- "icon": "microchip",
+ "group": "Operator Considerations",
"pages": [
- "v2/orchestrators/portal",
- "v2/orchestrators/navigator"
+ "v2/orchestrators/guides/operator-considerations/operator-rationale",
+ "v2/orchestrators/guides/operator-considerations/business-case",
+ "v2/orchestrators/guides/operator-considerations/operator-impact",
+ "v2/orchestrators/guides/operator-considerations/requirements"
]
},
{
- "group": "Concepts",
- "icon": "book-open",
+ "group": "Deployment Details",
"pages": [
- "v2/orchestrators/concepts/role",
- "v2/orchestrators/concepts/capabilities",
- "v2/orchestrators/concepts/architecture",
- "v2/orchestrators/concepts/incentive-model"
+ "v2/orchestrators/guides/deployment-details/setup-options",
+ "v2/orchestrators/guides/deployment-details/draft1-setup-options",
+ "v2/orchestrators/guides/deployment-details/x-deprecated/dep-3-setup-options",
+ "v2/orchestrators/guides/deployment-details/siphon-setup",
+ "v2/orchestrators/guides/deployment-details/dual-mode-configuration",
+ "v2/orchestrators/guides/deployment-details/orchestrator-transcoder-setup",
+ "v2/orchestrators/guides/deployment-details/join-a-pool",
+ "v2/orchestrators/guides/deployment-details/new-join-a-pool"
]
},
{
- "group": "Quickstart",
- "icon": "bolt",
+ "group": "Workloads and AI",
"pages": [
- "v2/orchestrators/quickstart/guide",
- "v2/orchestrators/quickstart/video-transcoding"
+ "v2/orchestrators/guides/ai-and-job-workloads/workload-options",
+ "v2/orchestrators/guides/ai-and-job-workloads/video-transcoding-operations",
+ "v2/orchestrators/guides/ai-and-job-workloads/ai-inference-operations",
+ "v2/orchestrators/guides/ai-and-job-workloads/diffusion-pipeline-setup",
+ "v2/orchestrators/guides/ai-and-job-workloads/llm-pipeline-setup",
+ "v2/orchestrators/guides/ai-and-job-workloads/realtime-ai-setup",
+ "v2/orchestrators/guides/ai-and-job-workloads/audio-and-vision-pipelines",
+ "v2/orchestrators/guides/ai-and-job-workloads/model-demand-reference",
+ "v2/orchestrators/guides/ai-and-job-workloads/model-hosting"
]
},
{
- "group": "Setup",
- "icon": "gear",
+ "group": "Staking and Earning",
"pages": [
- "v2/orchestrators/setup/guide",
- "v2/orchestrators/setup/rcs-requirements",
- "v2/orchestrators/setup/rs-install",
- "v2/orchestrators/setup/r-configure",
- "v2/orchestrators/setup/sc-connect",
- "v2/orchestrators/setup/activate",
- "v2/orchestrators/setup/test",
- "v2/orchestrators/setup/r-monitor"
+ "v2/orchestrators/guides/staking-and-rewards/earning-model",
+ "v2/orchestrators/guides/staking-and-rewards/reward-mechanics",
+ "v2/orchestrators/guides/payments-and-pricing/payment-receipts",
+ "v2/orchestrators/guides/payments-and-pricing/payments",
+ "v2/orchestrators/guides/staking-and-rewards/delegate-operations",
+ "v2/orchestrators/guides/staking-and-rewards/network-participation"
]
},
{
- "group": "Guides",
- "icon": "chart-line",
+ "group": "Config and Optimisation",
"pages": [
- {
- "group": "Feasibility & Hardware",
- "pages": [
- "v2/orchestrators/guides/feasibility-and-hardware/feasibility-economics",
- "v2/orchestrators/guides/feasibility-and-hardware/hardware-reference",
- "v2/orchestrators/guides/feasibility-and-hardware/benchmarking",
- "v2/orchestrators/guides/feasibility-and-hardware/session-limits"
- ]
- },
- {
- "group": "Setup Paths",
- "pages": [
- "v2/orchestrators/guides/setup-paths/setup-navigator",
- "v2/orchestrators/guides/setup-paths/find-your-path",
- "v2/orchestrators/guides/setup-paths/join-a-pool",
- "v2/orchestrators/guides/setup-paths/siphon-setup"
- ]
- },
- {
- "group": "Staking & Rewards",
- "pages": [
- "v2/orchestrators/guides/staking-and-rewards/earnings",
- "v2/orchestrators/guides/staking-and-rewards/rewards-and-fees",
- "v2/orchestrators/guides/staking-and-rewards/attracting-delegates",
- "v2/orchestrators/guides/staking-and-rewards/payments",
- "v2/orchestrators/guides/staking-and-rewards/governance"
- ]
- },
- {
- "group": "Workloads & AI",
- "pages": [
- "v2/orchestrators/guides/workloads-and-ai/job-types",
- "v2/orchestrators/guides/workloads-and-ai/video-transcoding",
- "v2/orchestrators/guides/workloads-and-ai/ai-workloads-guide",
- "v2/orchestrators/guides/workloads-and-ai/batch-ai-setup",
- "v2/orchestrators/guides/workloads-and-ai/realtime-ai-setup",
- "v2/orchestrators/guides/workloads-and-ai/model-vram-reference"
- ]
- },
- {
- "group": "Monitoring & Troubleshooting",
- "pages": [
- "v2/orchestrators/guides/monitoring-and-troubleshooting/tools",
- "v2/orchestrators/guides/monitoring-and-troubleshooting/explorer-guide",
- "v2/orchestrators/guides/monitoring-and-troubleshooting/metrics-monitoring",
- "v2/orchestrators/guides/monitoring-and-troubleshooting/troubleshooting"
- ]
- },
- {
- "group": "Advanced Operations",
- "pages": [
- "v2/orchestrators/guides/advanced-operations/run-a-pool",
- "v2/orchestrators/guides/advanced-operations/gateways-orchestrators",
- "v2/orchestrators/guides/advanced-operations/large-scale-operations",
- "v2/orchestrators/guides/advanced-operations/orchestrator-transcoder-setup"
- ]
- }
+ "v2/orchestrators/guides/config-and-optimisation/pricing-strategy",
+ "v2/orchestrators/guides/config-and-optimisation/capacity-planning",
+ "v2/orchestrators/guides/config-and-optimisation/ai-model-management",
+ "v2/orchestrators/guides/config-and-optimisation/reward-call-tuning"
]
},
{
- "group": "Resources",
- "icon": "books",
+ "group": "Monitoring and Tools",
"pages": [
- "v2/orchestrators/resources/faq",
- "v2/orchestrators/resources/community-guides",
- "v2/orchestrators/resources/community-pools",
- {
- "group": "Technical Reference",
- "pages": [
- "v2/orchestrators/resources/technical/cli-flags",
- "v2/orchestrators/resources/technical/x-contract-addresses",
- "v2/orchestrators/resources/gpu-support",
- "v2/orchestrators/resources/arbitrum-rpc",
- "v2/orchestrators/resources/arbitrum-exchanges",
- "v2/orchestrators/resources/technical/x-troubleshooting",
- "v2/orchestrators/resources/technical/x-changelog",
- "v2/orchestrators/resources/technical/x-support-status"
- ]
- },
- {
- "group": "Guides Index [Review]",
- "pages": [
- "v2/orchestrators/resources/x-guides",
- "v2/orchestrators/resources/x-help",
- "v2/orchestrators/resources/x-payments"
- ]
- }
+ "v2/orchestrators/guides/monitoring-and-tooling/operator-toolbox",
+ "v2/orchestrators/guides/monitoring-and-tooling/explorer-operations",
+ "v2/orchestrators/guides/monitoring-and-tooling/metrics-and-alerting",
+ "v2/orchestrators/guides/monitoring-and-tooling/troubleshooting"
+ ]
+ },
+ {
+ "group": "Advanced Operations",
+ "pages": [
+ "v2/orchestrators/guides/advanced-operations/gateway-relationships",
+ "v2/orchestrators/guides/advanced-operations/gateway-orchestrator-interface",
+ "v2/orchestrators/guides/advanced-operations/pool-operators",
+ "v2/orchestrators/guides/advanced-operations/scale-operations"
+ ]
+ },
+ {
+ "group": "Roadmap and Funding",
+ "pages": [
+ "v2/orchestrators/guides/roadmap-and-funding/funding-and-support",
+ "v2/orchestrators/guides/roadmap-and-funding/orchestrator-profiles"
+ ]
+ },
+ {
+ "group": "Tutorials",
+ "pages": [
+ "v2/orchestrators/guides/tutorials/byoc-cpu-smoke-test",
+ "v2/orchestrators/guides/tutorials/zero-to-first-reward",
+ "v2/orchestrators/guides/tutorials/ai-earning-quickstart",
+ "v2/orchestrators/guides/tutorials/add-ai-to-video-node",
+ "v2/orchestrators/guides/tutorials/full-ai-pipeline-tutorial",
+ "v2/orchestrators/guides/tutorials/realtime-ai-tutorial"
]
}
]
},
{
- "anchor": "Resource HUB",
+ "group": "Resources",
"icon": "books",
"pages": [
- "v2/resources/redirect"
- ]
- },
- {
- "anchor": " ",
- "icon": "horizontal-rule",
- "pages": [
- " "
+ "v2/orchestrators/resources/faq",
+ "v2/orchestrators/resources/glossary",
+ "v2/orchestrators/resources/community-guides",
+ "v2/orchestrators/resources/community-pools",
+ {
+ "group": "Technical Reference",
+ "pages": [
+ "v2/orchestrators/resources/technical/cli-flags",
+ "v2/orchestrators/resources/technical/x-contract-addresses",
+ "v2/orchestrators/resources/gpu-support",
+ "v2/orchestrators/resources/arbitrum-rpc",
+ "v2/orchestrators/resources/arbitrum-exchanges"
+ ]
+ }
]
}
]
@@ -3074,16 +3037,12 @@
{
"anchor": "Resource HUB",
"icon": "books",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
"icon": "horizontal-rule",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -3137,25 +3096,19 @@
{
"group": "Help Center",
"icon": "comments-question-check",
- "pages": [
- "v2/community/faq"
- ]
+ "pages": ["v2/community/faq"]
}
]
},
{
"anchor": "Resource HUB",
"icon": "books",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
"icon": "horizontal-rule",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -3172,7 +3125,6 @@
"group": "Resources",
"icon": "books",
"pages": [
- "v2/resources/redirect",
"v2/resources/resources-portal",
"contribute/CONTRIBUTING"
]
@@ -3216,9 +3168,7 @@
{
"group": "Developer References",
"icon": "book",
- "pages": [
- "v2/resources/livepeer-glossary"
- ]
+ "pages": ["v2/resources/livepeer-glossary"]
},
{
"group": "Gateway References",
@@ -3230,37 +3180,27 @@
{
"group": "Orchestrator References",
"icon": "microchip",
- "pages": [
- "v2/resources/livepeer-glossary"
- ]
+ "pages": ["v2/resources/livepeer-glossary"]
},
{
"group": "LPT & Delegator References",
"icon": "hand-holding-dollar",
- "pages": [
- "v2/resources/livepeer-glossary"
- ]
+ "pages": ["v2/resources/livepeer-glossary"]
},
{
"group": "Community Resources",
"icon": "",
- "pages": [
- "v2/resources/livepeer-glossary"
- ]
+ "pages": ["v2/resources/livepeer-glossary"]
},
{
"group": "Partner Resources",
"icon": "handshake",
- "pages": [
- "v2/resources/livepeer-glossary"
- ]
+ "pages": ["v2/resources/livepeer-glossary"]
},
{
"group": "Help Center",
"icon": "comments-question-check",
- "pages": [
- "v2/resources/livepeer-glossary"
- ]
+ "pages": ["v2/resources/livepeer-glossary"]
},
{
"group": "Technical References",
@@ -3268,9 +3208,7 @@
"pages": [
{
"group": "Protocol References",
- "pages": [
- " "
- ]
+ "pages": [" "]
}
]
},
@@ -3287,9 +3225,7 @@
{
"anchor": "Help Center",
"icon": "comments-question-check",
- "pages": [
- "v2/resources/redirect"
- ]
+ "pages": ["v2/resources/redirect"]
},
{
"anchor": " ",
@@ -3455,6 +3391,192 @@
]
}
]
+ },
+ {
+ "language": "es",
+ "tabs": [
+ {
+ "tab": "About",
+ "icon": "camera-movie",
+ "anchors": [
+ {
+ "anchor": "About Livepeer",
+ "icon": "play",
+ "groups": [
+ {
+ "group": "About Livepeer",
+ "icon": "graduation-cap",
+ "pages": [
+ "v2/es/about/portal",
+ "v2/es/about/livepeer-overview",
+ "v2/es/about/core-concepts",
+ "v2/es/about/mental-model"
+ ]
+ },
+ {
+ "group": "Livepeer Protocol",
+ "icon": "cube",
+ "pages": [
+ "v2/es/about/livepeer-protocol/overview",
+ "v2/es/about/livepeer-protocol/core-mechanisms",
+ "v2/es/about/livepeer-protocol/livepeer-token",
+ "v2/es/about/livepeer-protocol/governance-model",
+ "v2/es/about/livepeer-protocol/treasury",
+ "v2/es/about/livepeer-protocol/economics",
+ "v2/es/about/livepeer-protocol/technical-architecture"
+ ]
+ },
+ {
+ "group": "Livepeer Network",
+ "icon": "circle-nodes",
+ "pages": [
+ "v2/es/about/livepeer-network/overview",
+ "v2/es/about/livepeer-network/actors",
+ "v2/es/about/livepeer-network/job-lifecycle",
+ "v2/es/about/livepeer-network/marketplace",
+ "v2/es/about/livepeer-network/technical-architecture",
+ "v2/es/about/livepeer-network/interfaces"
+ ]
+ },
+ {
+ "group": "Resources",
+ "icon": "books",
+ "pages": [
+ "v2/es/about/resources/livepeer-whitepaper",
+ "v2/es/about/resources/livepeer-glossary",
+ "v2/es/about/resources/blockchain-contracts",
+ "v2/es/about/resources/technical-roadmap"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "language": "fr",
+ "tabs": [
+ {
+ "tab": "About",
+ "icon": "camera-movie",
+ "anchors": [
+ {
+ "anchor": "About Livepeer",
+ "icon": "play",
+ "groups": [
+ {
+ "group": "About Livepeer",
+ "icon": "graduation-cap",
+ "pages": [
+ "v2/fr/about/portal",
+ "v2/fr/about/livepeer-overview",
+ "v2/fr/about/core-concepts",
+ "v2/fr/about/mental-model"
+ ]
+ },
+ {
+ "group": "Livepeer Protocol",
+ "icon": "cube",
+ "pages": [
+ "v2/fr/about/livepeer-protocol/overview",
+ "v2/fr/about/livepeer-protocol/core-mechanisms",
+ "v2/fr/about/livepeer-protocol/livepeer-token",
+ "v2/fr/about/livepeer-protocol/governance-model",
+ "v2/fr/about/livepeer-protocol/treasury",
+ "v2/fr/about/livepeer-protocol/economics",
+ "v2/fr/about/livepeer-protocol/technical-architecture"
+ ]
+ },
+ {
+ "group": "Livepeer Network",
+ "icon": "circle-nodes",
+ "pages": [
+ "v2/fr/about/livepeer-network/overview",
+ "v2/fr/about/livepeer-network/actors",
+ "v2/fr/about/livepeer-network/job-lifecycle",
+ "v2/fr/about/livepeer-network/marketplace",
+ "v2/fr/about/livepeer-network/technical-architecture",
+ "v2/fr/about/livepeer-network/interfaces"
+ ]
+ },
+ {
+ "group": "Resources",
+ "icon": "books",
+ "pages": [
+ "v2/fr/about/resources/livepeer-whitepaper",
+ "v2/fr/about/resources/livepeer-glossary",
+ "v2/fr/about/resources/blockchain-contracts",
+ "v2/fr/about/resources/technical-roadmap"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "language": "cn",
+ "tabs": [
+ {
+ "tab": "About",
+ "icon": "camera-movie",
+ "anchors": [
+ {
+ "anchor": "About Livepeer",
+ "icon": "play",
+ "groups": [
+ {
+ "group": "About Livepeer",
+ "icon": "graduation-cap",
+ "pages": [
+ "v2/cn/about/portal",
+ "v2/cn/about/livepeer-overview",
+ "v2/cn/about/core-concepts",
+ "v2/cn/about/mental-model"
+ ]
+ },
+ {
+ "group": "Livepeer Protocol",
+ "icon": "cube",
+ "pages": [
+ "v2/cn/about/livepeer-protocol/overview",
+ "v2/cn/about/livepeer-protocol/core-mechanisms",
+ "v2/cn/about/livepeer-protocol/livepeer-token",
+ "v2/cn/about/livepeer-protocol/governance-model",
+ "v2/cn/about/livepeer-protocol/treasury",
+ "v2/cn/about/livepeer-protocol/economics",
+ "v2/cn/about/livepeer-protocol/technical-architecture"
+ ]
+ },
+ {
+ "group": "Livepeer Network",
+ "icon": "circle-nodes",
+ "pages": [
+ "v2/cn/about/livepeer-network/overview",
+ "v2/cn/about/livepeer-network/actors",
+ "v2/cn/about/livepeer-network/job-lifecycle",
+ "v2/cn/about/livepeer-network/marketplace",
+ "v2/cn/about/livepeer-network/technical-architecture",
+ "v2/cn/about/livepeer-network/interfaces"
+ ]
+ },
+ {
+ "group": "Resources",
+ "icon": "books",
+ "pages": [
+ "v2/cn/about/resources/livepeer-whitepaper",
+ "v2/cn/about/resources/livepeer-glossary",
+ "v2/cn/about/resources/blockchain-contracts",
+ "v2/cn/about/resources/technical-roadmap"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
}
]
}
diff --git a/lpd b/lpd
index cb5566cdb..22b3e3c19 100755
--- a/lpd
+++ b/lpd
@@ -613,32 +613,32 @@ run_cli_step() {
}
hook_status_check() {
- local source_hook="$REPO_ROOT/.githooks/pre-commit"
- # Support both regular repos and worktrees
- local git_common_dir
- git_common_dir=$(cd "$REPO_ROOT" && git rev-parse --git-common-dir 2>/dev/null)
- if [ -z "$git_common_dir" ] || [ "$git_common_dir" = "--git-common-dir" ]; then
- git_common_dir="$REPO_ROOT/.git"
- fi
- local target_hook="$git_common_dir/hooks/pre-commit"
+ local source_dir="$REPO_ROOT/.githooks"
+ local source_hook="$source_dir/pre-commit"
+ local source_pre_push="$source_dir/pre-push"
+ local hooks_path
if [ ! -f "$source_hook" ]; then
echo "missing-source"
return 1
fi
- if [ ! -f "$target_hook" ]; then
+ hooks_path="$(cd "$REPO_ROOT" && git config --path --get core.hooksPath 2>/dev/null || true)"
+ if [ -z "$hooks_path" ]; then
echo "not-installed"
return 1
fi
+ if [[ "$hooks_path" != /* ]]; then
+ hooks_path="$REPO_ROOT/$hooks_path"
+ fi
- if [ ! -x "$target_hook" ]; then
- echo "not-executable"
+ if [ "$hooks_path" != "$source_dir" ]; then
+ echo "wrong-path:$hooks_path"
return 1
fi
- if ! cmp -s "$source_hook" "$target_hook"; then
- echo "out-of-date"
+ if [ ! -x "$source_hook" ] || [ ! -x "$source_pre_push" ]; then
+ echo "not-executable"
return 1
fi
@@ -667,16 +667,16 @@ cmd_hooks() {
status="$(hook_status_check)" || true
case "$status" in
installed)
- finish 0 "hooks status" "Hooks are installed and up to date."
+ finish 0 "hooks status" "Hooks are installed via worktree-local core.hooksPath."
;;
not-installed)
finish 1 "hooks status" "Hooks are not installed."
;;
- out-of-date)
- finish 1 "hooks status" "Installed hooks are out of date."
+ wrong-path:*)
+ finish 1 "hooks status" "Hooks are routed to the wrong path: ${status#wrong-path:}"
;;
not-executable)
- finish 1 "hooks status" "Hook exists but is not executable."
+ finish 1 "hooks status" "Hook entrypoints exist but are not executable."
;;
*)
finish 1 "hooks status" "Hook status check failed: $status"
@@ -696,10 +696,10 @@ cmd_hooks() {
Usage:
lpd hooks install
- - info: Install/update `.git/hooks/pre-commit` from `.githooks/pre-commit`.
+ - info: Configure this worktree to execute hooks directly from `.githooks/`.
lpd hooks status
- - info: Check whether the installed pre-commit hook exists, is executable, and matches source.
+ - info: Check whether this worktree routes hooks to `.githooks/` and whether entrypoints are executable.
lpd hooks verify
- info: Run hook verification checks from `.githooks/verify.sh`.
@@ -720,6 +720,7 @@ Bypass Flags (pre-commit; use sparingly):
- `SKIP_STYLE_CHECK=1` : skip style-guide compliance checks.
- `SKIP_VERIFICATION=1` : skip verification script checks.
- `SKIP_TESTS=1` : skip staged test suite checks.
+ - `DISABLE_PRECOMMIT_STAGED_CACHE=1` : rerun the expensive staged suite even if the staged snapshot already passed.
- `SKIP_ALL=1` : skip all pre-commit checks.
Human-Only Overrides:
diff --git a/tasks/reports/navigation-links/navigation-report.json b/tasks/reports/navigation-links/navigation-report.json
index 81f45adab..3d8fe530b 100644
--- a/tasks/reports/navigation-links/navigation-report.json
+++ b/tasks/reports/navigation-links/navigation-report.json
@@ -1,13 +1,13 @@
{
- "generatedAt": "2026-03-09T04:18:18.404Z",
- "totalEntries": 1181,
+ "generatedAt": "2026-03-16T20:55:39.113Z",
+ "totalEntries": 1329,
"syntaxErrors": [],
"missingRoutes": [
{
"file": "docs.json",
"rule": "Missing route",
- "value": "v2/gateways/guides-and-tools/gateway-job-pipelines/overview",
- "normalized": "v2/gateways/guides-and-tools/gateway-job-pipelines/overview",
+ "value": "v2/gateways/guides-and-resources/gateway-job-pipelines/overview",
+ "normalized": "v2/gateways/guides-and-resources/gateway-job-pipelines/overview",
"pointer": "navigation.versions[1].languages[0].tabs[8].anchors[0].groups[4].pages[0]",
"suggestions": [
{
diff --git a/tasks/reports/navigation-links/navigation-report.md b/tasks/reports/navigation-links/navigation-report.md
index ed25aaf4b..b427a106b 100644
--- a/tasks/reports/navigation-links/navigation-report.md
+++ b/tasks/reports/navigation-links/navigation-report.md
@@ -1,7 +1,7 @@
# Docs Navigation Route Report
-- Generated at (UTC): 2026-03-09T04:18:18.404Z
-- Entries scanned: 1181
+- Generated at (UTC): 2026-03-16T20:55:39.113Z
+- Entries scanned: 1329
- Syntax errors: 0
- Missing routes: 1
- Missing routes with suggestions: 1
@@ -12,7 +12,7 @@
## Missing Routes
-- `v2/gateways/guides-and-tools/gateway-job-pipelines/overview` (normalized: `v2/gateways/guides-and-tools/gateway-job-pipelines/overview`)
+- `v2/gateways/guides-and-resources/gateway-job-pipelines/overview` (normalized: `v2/gateways/guides-and-resources/gateway-job-pipelines/overview`)
- Pointer: `navigation.versions[1].languages[0].tabs[8].anchors[0].groups[4].pages[0]`
- Suggested remaps:
- `v1/ai/api-reference/overview` (same leaf segment match [score=0.65])
diff --git a/tasks/reports/script-classifications.json b/tasks/reports/script-classifications.json
index 98a0e9006..a126a66b6 100644
--- a/tasks/reports/script-classifications.json
+++ b/tasks/reports/script-classifications.json
@@ -665,6 +665,16 @@
"purpose_statement": "Validates the ownerless governance manifest, primary gate-layer contract, and forbidden human-owner dependency in governed policy and GitHub surfaces.",
"pipeline": "P1, P3"
},
+ {
+ "path": "tests/unit/precommit-staged-cache.test.js",
+ "script": "precommit-staged-cache.test",
+ "category": "validator",
+ "purpose": "qa:repo-health",
+ "scope": "tests/unit, tools/lib/precommit-staged-cache.js",
+ "needs": "R-R14, R-R29",
+ "purpose_statement": "Tests precommit-staged-cache.js — validates staged-tree cache hits, invalidation, and pruning",
+ "pipeline": "P1, manual"
+ },
{
"path": "tests/unit/quality.test.js",
"script": "quality.test",
@@ -1212,6 +1222,16 @@
"purpose_statement": "Shared MDX-safe markdown helpers that collect first-party markdown files, detect unsafe patterns, and apply deterministic repairs.",
"pipeline": "indirect -- library module"
},
+ {
+ "path": "tools/lib/precommit-staged-cache.js",
+ "script": "precommit-staged-cache",
+ "category": "orchestrator",
+ "purpose": "infrastructure:pipeline-orchestration",
+ "scope": ".githooks, tests, tools/lib, tools/scripts",
+ "needs": "R-R29",
+ "purpose_statement": "Shared pre-commit staged-cache helpers — fingerprint staged content plus hook inputs and persist reusable pass markers",
+ "pipeline": "indirect -- library module"
+ },
{
"path": "tools/lib/script-governance-config.js",
"script": "script-governance-config",
diff --git a/tests/README.md b/tests/README.md
index d1662f332..49ec9ed35 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -189,6 +189,8 @@ npm --prefix tests run test:pages-index
npm --prefix tests run test:pages-index:write
npm --prefix tests run test:pages-index:rebuild
npm --prefix tests run test:generated-banners
+npm --prefix tests run test:precommit
+npm --prefix tests run test:precommit-cache
npm --prefix tests run test:browser
npm --prefix tests run test:openapi:audit
npm --prefix tests run test:openapi:issue
@@ -239,21 +241,21 @@ Use those pages for workflow scope, commands, readiness, outputs, and source-of-
- Full matrix: `tests/PR-CI-TESTS-AND-SCRIPT-RUN-MATRIX.md`
## Pre-commit Interaction
-- Pre-commit runs `tests/run-all.js --staged --skip-browser` in fast mode.
+- Pre-commit runs `tests/run-all.js --staged --skip-browser --precommit-basic --skip-mdx-safe-markdown-check --skip-pages-index --skip-script-docs` in fast mode after those checks already ran earlier in the hook.
- Docs navigation checks in this flow are check-only and do not rewrite `tasks/reports/navigation-links/navigation-report.*`.
-- Pre-commit also runs domain audit on staged docs pages:
- `node tests/integration/domain-pages-audit.js --staged --base-url https://docs.livepeer.org --version "$DOMAIN_AUDIT_VERSION"`
- Pre-commit runs staged WCAG accessibility audit (conservative autofix enabled by default, blocks on remaining `serious`/`critical` issues):
`node tests/integration/v2-wcag-audit.js --staged --fix --stage --max-pages 10 --fail-impact serious --report /tmp/livepeer-wcag-audit-precommit.md --report-json /tmp/livepeer-wcag-audit-precommit.json`
- Pre-commit runs staged V2 link audit (strict internal validation, external classify-only):
`node tests/integration/v2-link-audit.js --staged --strict --report /tmp/livepeer-link-audit-precommit.md`
-- Set `DOMAIN_AUDIT_VERSION=v1|v2|both` to control scope in pre-commit.
- Pre-commit enforces script header docs for newly added scripts and auto-updates script indexes:
`node tests/unit/script-docs.test.js --staged --write --stage --autofill`
Missing headers are auto-inserted, then commit remains blocked until placeholder values are filled.
- Pre-commit also synchronizes `v2/pages` index files:
`node tools/scripts/generate-pages-index.js --staged --write --stage`
This regenerates top-level section `index.mdx` files, updates root `v2/pages/index.mdx`, marks missing `docs.json` pages with `⚠️`, and removes nested `index.mdx`/`index.md` files.
+- The hook lane intentionally stops at staged syntax/style/content basics. Repo-wide governance/unit suites stay in full `node tests/run-all.js` runs and CI.
+- Pre-commit fails fast on cheap blockers and skips the expensive staged suite until those are fixed.
+- After the expensive staged suite passes once, repeat commits with unchanged staged content reuse a cache marker. Set `DISABLE_PRECOMMIT_STAGED_CACHE=1` to force a rerun.
## Script Header Template (Required for New Scripts)
Newly added scripts must include these tags near the top of the file:
diff --git a/tests/WHEN-TESTS-RUN.md b/tests/WHEN-TESTS-RUN.md
index c0c580312..2779f0648 100644
--- a/tests/WHEN-TESTS-RUN.md
+++ b/tests/WHEN-TESTS-RUN.md
@@ -21,8 +21,10 @@
- Pages index sync (`tools/scripts/generate-pages-index.js --staged --write --stage`)
- Staged WCAG accessibility audit with conservative autofix (`tests/integration/v2-wcag-audit.js --staged --fix --stage --max-pages 10 --fail-impact serious ...`)
- Staged strict V2 link audit (`tests/integration/v2-link-audit.js --staged --strict ...`)
-- Staged domain audit (`tests/integration/domain-pages-audit.js --staged ...`)
- Staged selection will eventually exclude governed V2 non-publishable lanes through `.mintignore`; legacy buckets such as `_contextData`, `_plans-and-research`, `x-resources`, and nested `review.md` remain in inventory until move waves complete.
+- Expensive staged validation runs only after cheap pre-checks pass.
+- The hook test runner uses a `--precommit-basic` lane with staged syntax/style/content checks only; repo-wide governance/unit suites are deferred to full runs and CI.
+- Repeat commits with unchanged staged content reuse the cached expensive-suite result unless `DISABLE_PRECOMMIT_STAGED_CACHE=1` is set.
**Speed:** Fast (~10-30 seconds) for most commits, depends on staged scope
diff --git a/tests/package.json b/tests/package.json
index 4c8a0dd4b..af45707c6 100644
--- a/tests/package.json
+++ b/tests/package.json
@@ -26,7 +26,9 @@
"test:pages-index:write": "node ../tools/scripts/generate-pages-index.js --write",
"test:pages-index:rebuild": "node ../tools/scripts/generate-pages-index.js --write --rebuild-indexes",
"test:generated-banners": "node ../tools/scripts/enforce-generated-file-banners.js --check",
+ "test:precommit": "node run-all.js --staged --skip-browser --precommit-basic",
"test:scripts": "node unit/script-docs.test.js",
+ "test:precommit-cache": "node unit/precommit-staged-cache.test.js",
"test:components:governance": "node unit/component-governance-utils.test.js && node unit/component-governance-generators.test.js",
"test:browser": "node integration/browser.test.js",
"test:openapi:audit": "node integration/openapi-reference-audit.js --full --strict",
diff --git a/tests/run-all.js b/tests/run-all.js
index bd02e9f76..685243a4a 100644
--- a/tests/run-all.js
+++ b/tests/run-all.js
@@ -4,7 +4,7 @@
* @category orchestrator
* @purpose infrastructure:pipeline-orchestration
* @scope tests
- * @owner docs
+ * @domain docs
* @needs R-R29
* @purpose-statement Test orchestrator — dispatches all unit test suites. Called by pre-commit hook and npm test.
* @pipeline P1, P2, P3
@@ -37,6 +37,7 @@ const checkAgentDocsFreshnessTests = require('./unit/check-agent-docs-freshness.
const rootAllowlistFormatTests = require('./unit/root-allowlist-format.test');
const exportPortableSkillsTests = require('./unit/export-portable-skills.test');
const docsGuideSotTests = require('./unit/docs-guide-sot.test');
+const precommitStagedCacheTests = require('./unit/precommit-staged-cache.test');
const uiTemplateGeneratorTests = require('./unit/ui-template-generator.test');
const componentGovernanceUtilsTests = require('./unit/component-governance-utils.test');
const componentGovernanceGeneratorTests = require('./unit/component-governance-generators.test');
@@ -54,6 +55,10 @@ const skipBrowser = args.includes('--skip-browser');
const watch = args.includes('--watch');
const runWcag = args.includes('--wcag');
const wcagNoFix = args.includes('--wcag-no-fix');
+const precommitBasic = args.includes('--precommit-basic');
+const skipMdxSafeMarkdownCheck = args.includes('--skip-mdx-safe-markdown-check');
+const skipPagesIndex = args.includes('--skip-pages-index');
+const skipScriptDocs = args.includes('--skip-script-docs');
let totalErrors = 0;
let totalWarnings = 0;
@@ -132,6 +137,10 @@ function hasStagedUiTemplateChanges() {
);
}
+function logPrecommitBasicSkip(summary) {
+ console.log(` skipped in --precommit-basic lane (${summary})`);
+}
+
/**
* Run all tests
*/
@@ -194,51 +203,60 @@ async function runAllTests() {
// Repo-wide MDX-safe Markdown Validation
console.log('\n🧱 Running Repo-wide MDX-safe Markdown Validation...');
- const mdxSafeMarkdownResult = normalizeSuiteResult(mdxSafeMarkdownValidator.run({
- args: {
- stagedOnly,
- files: [],
- json: false
- }
- }));
- totalErrors += mdxSafeMarkdownResult.errors.length;
- totalWarnings += mdxSafeMarkdownResult.warnings.length;
- console.log(` ${mdxSafeMarkdownResult.errors.length} errors, ${mdxSafeMarkdownResult.warnings.length} warnings`);
-
- // MDX Guardrails
- console.log('\n🛡️ Running MDX Guardrail Tests...');
- const mdxGuardsResult = normalizeSuiteResult(mdxGuardsTests.runTests());
- totalErrors += mdxGuardsResult.errors.length;
- totalWarnings += mdxGuardsResult.warnings.length;
- console.log(` ${mdxGuardsResult.errors.length} errors, ${mdxGuardsResult.warnings.length} warnings`);
-
- // MDX-safe Markdown Unit Tests
- console.log('\n🧪 Running MDX-safe Markdown Unit Tests...');
- const mdxSafeMarkdownUnitResult = normalizeSuiteResult(mdxSafeMarkdownUnitTests.runTests());
- totalErrors += mdxSafeMarkdownUnitResult.errors.length;
- totalWarnings += mdxSafeMarkdownUnitResult.warnings.length;
- console.log(` ${mdxSafeMarkdownUnitResult.errors.length} errors, ${mdxSafeMarkdownUnitResult.warnings.length} warnings`);
-
- // Docs Page Scope Tests
- console.log('\n🗂️ Running Docs Page Scope Tests...');
- const docsPageScopeResult = normalizeSuiteResult(docsPageScopeTests.runTests());
- totalErrors += docsPageScopeResult.errors.length;
- totalWarnings += docsPageScopeResult.warnings.length;
- console.log(` ${docsPageScopeResult.errors.length} errors, ${docsPageScopeResult.warnings.length} warnings`);
-
- // Docs Authoring Rules Tests
- console.log('\n🧭 Running Docs Authoring Rules Tests...');
- const docsAuthoringRulesResult = normalizeSuiteResult(docsAuthoringRulesTests.runTests());
- totalErrors += docsAuthoringRulesResult.errors.length;
- totalWarnings += docsAuthoringRulesResult.warnings.length;
- console.log(` ${docsAuthoringRulesResult.errors.length} errors, ${docsAuthoringRulesResult.warnings.length} warnings`);
-
- // Frontmatter Taxonomy Tests
- console.log('\n🧾 Running Frontmatter Taxonomy Tests...');
- const frontmatterTaxonomyResult = normalizeSuiteResult(frontmatterTaxonomyTests.runTests());
- totalErrors += frontmatterTaxonomyResult.errors.length;
- totalWarnings += frontmatterTaxonomyResult.warnings.length;
- console.log(` ${frontmatterTaxonomyResult.errors.length} errors, ${frontmatterTaxonomyResult.warnings.length} warnings`);
+ if (skipMdxSafeMarkdownCheck) {
+ console.log(' skipped (handled earlier in pre-commit)');
+ } else {
+ const mdxSafeMarkdownResult = normalizeSuiteResult(mdxSafeMarkdownValidator.run({
+ args: {
+ stagedOnly,
+ files: [],
+ json: false
+ }
+ }));
+ totalErrors += mdxSafeMarkdownResult.errors.length;
+ totalWarnings += mdxSafeMarkdownResult.warnings.length;
+ console.log(` ${mdxSafeMarkdownResult.errors.length} errors, ${mdxSafeMarkdownResult.warnings.length} warnings`);
+ }
+
+ if (precommitBasic) {
+ console.log('\n🧪 Running Repo-wide Governance Unit Suites...');
+ logPrecommitBasicSkip('hook lane is limited to staged syntax/style/content basics');
+ } else {
+ // MDX Guardrails
+ console.log('\n🛡️ Running MDX Guardrail Tests...');
+ const mdxGuardsResult = normalizeSuiteResult(mdxGuardsTests.runTests());
+ totalErrors += mdxGuardsResult.errors.length;
+ totalWarnings += mdxGuardsResult.warnings.length;
+ console.log(` ${mdxGuardsResult.errors.length} errors, ${mdxGuardsResult.warnings.length} warnings`);
+
+ // MDX-safe Markdown Unit Tests
+ console.log('\n🧪 Running MDX-safe Markdown Unit Tests...');
+ const mdxSafeMarkdownUnitResult = normalizeSuiteResult(mdxSafeMarkdownUnitTests.runTests());
+ totalErrors += mdxSafeMarkdownUnitResult.errors.length;
+ totalWarnings += mdxSafeMarkdownUnitResult.warnings.length;
+ console.log(` ${mdxSafeMarkdownUnitResult.errors.length} errors, ${mdxSafeMarkdownUnitResult.warnings.length} warnings`);
+
+ // Docs Page Scope Tests
+ console.log('\n🗂️ Running Docs Page Scope Tests...');
+ const docsPageScopeResult = normalizeSuiteResult(docsPageScopeTests.runTests());
+ totalErrors += docsPageScopeResult.errors.length;
+ totalWarnings += docsPageScopeResult.warnings.length;
+ console.log(` ${docsPageScopeResult.errors.length} errors, ${docsPageScopeResult.warnings.length} warnings`);
+
+ // Docs Authoring Rules Tests
+ console.log('\n🧭 Running Docs Authoring Rules Tests...');
+ const docsAuthoringRulesResult = normalizeSuiteResult(docsAuthoringRulesTests.runTests());
+ totalErrors += docsAuthoringRulesResult.errors.length;
+ totalWarnings += docsAuthoringRulesResult.warnings.length;
+ console.log(` ${docsAuthoringRulesResult.errors.length} errors, ${docsAuthoringRulesResult.warnings.length} warnings`);
+
+ // Frontmatter Taxonomy Tests
+ console.log('\n🧾 Running Frontmatter Taxonomy Tests...');
+ const frontmatterTaxonomyResult = normalizeSuiteResult(frontmatterTaxonomyTests.runTests());
+ totalErrors += frontmatterTaxonomyResult.errors.length;
+ totalWarnings += frontmatterTaxonomyResult.warnings.length;
+ console.log(` ${frontmatterTaxonomyResult.errors.length} errors, ${frontmatterTaxonomyResult.warnings.length} warnings`);
+ }
// Spelling Tests
console.log('\n🔤 Running Spelling Tests...');
@@ -261,150 +279,172 @@ async function runAllTests() {
totalWarnings += linksResult.warnings.length;
console.log(` ${linksResult.errors.length} errors, ${linksResult.warnings.length} warnings`);
- // Docs Navigation Validation
- console.log('\n🧭 Running Docs Navigation Validation...');
- const docsNavigationResult = normalizeSuiteResult(docsNavigationTests.runTests({ writeReport: false }));
- totalErrors += docsNavigationResult.errors.length;
- totalWarnings += docsNavigationResult.warnings.length;
- console.log(` ${docsNavigationResult.errors.length} errors, ${docsNavigationResult.warnings.length} warnings`);
-
- // Docs Path Sync Validation
- console.log('\n🛤️ Running Docs Path Sync Validation...');
- const docsPathSyncResult = normalizeSuiteResult(docsPathSyncTests.runTests());
- totalErrors += docsPathSyncResult.errors.length;
- totalWarnings += docsPathSyncResult.warnings.length;
- console.log(` ${docsPathSyncResult.errors.length} errors, ${docsPathSyncResult.warnings.length} warnings`);
-
- // Script Docs Enforcement
- console.log('\n🧾 Running Script Documentation Enforcement...');
- const scriptDocsResult = normalizeSuiteResult(scriptDocsTests.runTests({ stagedOnly }));
- totalErrors += scriptDocsResult.errors.length;
- totalWarnings += scriptDocsResult.warnings.length;
- console.log(` ${scriptDocsResult.errors.length} errors, ${scriptDocsResult.warnings.length} warnings`);
-
- // Skill Docs Enforcement
- console.log('\n📘 Running Skill Documentation Enforcement...');
- const skillDocsResult = normalizeSuiteResult(skillDocsTests.runTests({ stagedOnly }));
- totalErrors += skillDocsResult.errors.length;
- totalWarnings += skillDocsResult.warnings.length;
- console.log(` ${skillDocsResult.errors.length} errors, ${skillDocsResult.warnings.length} warnings`);
-
- // AI-tools Registry Governance
- console.log('\n🗂️ Running AI-tools Registry Checks...');
- const aiToolsRegistryResult = normalizeSuiteResult(aiToolsRegistryTests.runTests({ stagedOnly }));
- totalErrors += aiToolsRegistryResult.errors.length;
- totalWarnings += aiToolsRegistryResult.warnings.length;
- if (aiToolsRegistryResult.skipped) {
- console.log(' skipped (no staged AI-tools governance changes)');
+ if (precommitBasic) {
+ console.log('\n🧭 Running Extended Governance and Repo-wide Suites...');
+ logPrecommitBasicSkip('run full test lane or CI for repo-wide governance and unit coverage');
} else {
+ // Docs Navigation Validation
+ console.log('\n🧭 Running Docs Navigation Validation...');
+ const docsNavigationResult = normalizeSuiteResult(docsNavigationTests.runTests({ writeReport: false }));
+ totalErrors += docsNavigationResult.errors.length;
+ totalWarnings += docsNavigationResult.warnings.length;
+ console.log(` ${docsNavigationResult.errors.length} errors, ${docsNavigationResult.warnings.length} warnings`);
+
+ // Docs Path Sync Validation
+ console.log('\n🛤️ Running Docs Path Sync Validation...');
+ const docsPathSyncResult = normalizeSuiteResult(docsPathSyncTests.runTests());
+ totalErrors += docsPathSyncResult.errors.length;
+ totalWarnings += docsPathSyncResult.warnings.length;
+ console.log(` ${docsPathSyncResult.errors.length} errors, ${docsPathSyncResult.warnings.length} warnings`);
+
+ // Script Docs Enforcement
+ console.log('\n🧾 Running Script Documentation Enforcement...');
+ if (skipScriptDocs) {
+ console.log(' skipped (handled earlier in pre-commit)');
+ } else {
+ const scriptDocsResult = normalizeSuiteResult(scriptDocsTests.runTests({ stagedOnly }));
+ totalErrors += scriptDocsResult.errors.length;
+ totalWarnings += scriptDocsResult.warnings.length;
+ console.log(` ${scriptDocsResult.errors.length} errors, ${scriptDocsResult.warnings.length} warnings`);
+ }
+
+ // Skill Docs Enforcement
+ console.log('\n📘 Running Skill Documentation Enforcement...');
+ const skillDocsResult = normalizeSuiteResult(skillDocsTests.runTests({ stagedOnly }));
+ totalErrors += skillDocsResult.errors.length;
+ totalWarnings += skillDocsResult.warnings.length;
+ console.log(` ${skillDocsResult.errors.length} errors, ${skillDocsResult.warnings.length} warnings`);
+
+ // AI-tools Registry Governance
+ console.log('\n🗂️ Running AI-tools Registry Checks...');
+ const aiToolsRegistryResult = normalizeSuiteResult(aiToolsRegistryTests.runTests({ stagedOnly }));
+ totalErrors += aiToolsRegistryResult.errors.length;
+ totalWarnings += aiToolsRegistryResult.warnings.length;
+ if (aiToolsRegistryResult.skipped) {
+ console.log(' skipped (no staged AI-tools governance changes)');
+ } else {
+ console.log(
+ ` ${aiToolsRegistryResult.errors.length} errors, ${aiToolsRegistryResult.warnings.length} warnings`
+ );
+ }
+
+ // Ownerless Governance
+ console.log('\n🧭 Running Ownerless Governance Checks...');
+ const ownerlessGovernanceResult = normalizeSuiteResult(ownerlessGovernanceTests.runTests({ stagedOnly }));
+ totalErrors += ownerlessGovernanceResult.errors.length;
+ totalWarnings += ownerlessGovernanceResult.warnings.length;
+ console.log(` ${ownerlessGovernanceResult.errors.length} errors, ${ownerlessGovernanceResult.warnings.length} warnings`);
+
+ // Agent Docs Freshness
+ console.log('\n🤖 Running Agent Docs Freshness Checks...');
+ const agentDocsFreshnessResult = normalizeSuiteResult(checkAgentDocsFreshnessTests.runTests());
+ totalErrors += agentDocsFreshnessResult.errors.length;
+ totalWarnings += agentDocsFreshnessResult.warnings.length;
+ console.log(` ${agentDocsFreshnessResult.errors.length} errors, ${agentDocsFreshnessResult.warnings.length} warnings`);
+
+ // Root Allowlist Format
+ console.log('\n🧱 Running Root Allowlist Format Checks...');
+ const rootAllowlistFormatResult = normalizeSuiteResult(rootAllowlistFormatTests.runTests());
+ totalErrors += rootAllowlistFormatResult.errors.length;
+ totalWarnings += rootAllowlistFormatResult.warnings.length;
+ console.log(` ${rootAllowlistFormatResult.errors.length} errors, ${rootAllowlistFormatResult.warnings.length} warnings`);
+
+ // Portable Skill Export
+ console.log('\n📦 Running Portable Skill Export Checks...');
+ const exportPortableSkillsResult = normalizeSuiteResult(await exportPortableSkillsTests.runTests());
+ totalErrors += exportPortableSkillsResult.errors.length;
+ totalWarnings += exportPortableSkillsResult.warnings.length;
+ console.log(` ${exportPortableSkillsResult.errors.length} errors, ${exportPortableSkillsResult.warnings.length} warnings`);
+
+ // Docs-guide Source of Truth
+ console.log('\n📚 Running Docs-guide Source-of-Truth Checks...');
+ if (hasStagedDocsGuideSotChanges()) {
+ const docsGuideSotResult = normalizeSuiteResult(docsGuideSotTests.runTests({ stagedOnly }));
+ totalErrors += docsGuideSotResult.errors.length;
+ totalWarnings += docsGuideSotResult.warnings.length;
+ console.log(` ${docsGuideSotResult.errors.length} errors, ${docsGuideSotResult.warnings.length} warnings`);
+ } else {
+ console.log(' skipped (no staged docs-guide source-of-truth changes)');
+ }
+
+ // Pre-commit Cache Unit Tests
+ console.log('\n🧮 Running Pre-commit Cache Unit Tests...');
+ const precommitStagedCacheResult = normalizeSuiteResult(await precommitStagedCacheTests.runTests());
+ totalErrors += precommitStagedCacheResult.errors.length;
+ totalWarnings += precommitStagedCacheResult.warnings.length;
console.log(
- ` ${aiToolsRegistryResult.errors.length} errors, ${aiToolsRegistryResult.warnings.length} warnings`
+ ` ${precommitStagedCacheResult.errors.length} errors, ${precommitStagedCacheResult.warnings.length} warnings`
);
- }
- // Ownerless Governance
- console.log('\n🧭 Running Ownerless Governance Checks...');
- const ownerlessGovernanceResult = normalizeSuiteResult(ownerlessGovernanceTests.runTests({ stagedOnly }));
- totalErrors += ownerlessGovernanceResult.errors.length;
- totalWarnings += ownerlessGovernanceResult.warnings.length;
- console.log(` ${ownerlessGovernanceResult.errors.length} errors, ${ownerlessGovernanceResult.warnings.length} warnings`);
-
- // Agent Docs Freshness
- console.log('\n🤖 Running Agent Docs Freshness Checks...');
- const agentDocsFreshnessResult = normalizeSuiteResult(checkAgentDocsFreshnessTests.runTests());
- totalErrors += agentDocsFreshnessResult.errors.length;
- totalWarnings += agentDocsFreshnessResult.warnings.length;
- console.log(` ${agentDocsFreshnessResult.errors.length} errors, ${agentDocsFreshnessResult.warnings.length} warnings`);
-
- // Root Allowlist Format
- console.log('\n🧱 Running Root Allowlist Format Checks...');
- const rootAllowlistFormatResult = normalizeSuiteResult(rootAllowlistFormatTests.runTests());
- totalErrors += rootAllowlistFormatResult.errors.length;
- totalWarnings += rootAllowlistFormatResult.warnings.length;
- console.log(` ${rootAllowlistFormatResult.errors.length} errors, ${rootAllowlistFormatResult.warnings.length} warnings`);
-
- // Portable Skill Export
- console.log('\n📦 Running Portable Skill Export Checks...');
- const exportPortableSkillsResult = normalizeSuiteResult(await exportPortableSkillsTests.runTests());
- totalErrors += exportPortableSkillsResult.errors.length;
- totalWarnings += exportPortableSkillsResult.warnings.length;
- console.log(` ${exportPortableSkillsResult.errors.length} errors, ${exportPortableSkillsResult.warnings.length} warnings`);
-
- // Docs-guide Source of Truth
- console.log('\n📚 Running Docs-guide Source-of-Truth Checks...');
- if (hasStagedDocsGuideSotChanges()) {
- const docsGuideSotResult = normalizeSuiteResult(docsGuideSotTests.runTests({ stagedOnly }));
- totalErrors += docsGuideSotResult.errors.length;
- totalWarnings += docsGuideSotResult.warnings.length;
- console.log(` ${docsGuideSotResult.errors.length} errors, ${docsGuideSotResult.warnings.length} warnings`);
- } else {
- console.log(' skipped (no staged docs-guide source-of-truth changes)');
- }
+ // UI Template Generator
+ console.log('\n🧱 Running UI Template Generator Checks...');
+ if (hasStagedUiTemplateChanges()) {
+ const uiTemplateGeneratorResult = normalizeSuiteResult(uiTemplateGeneratorTests.runTests());
+ totalErrors += uiTemplateGeneratorResult.errors.length;
+ totalWarnings += uiTemplateGeneratorResult.warnings.length;
+ console.log(` ${uiTemplateGeneratorResult.errors.length} errors, ${uiTemplateGeneratorResult.warnings.length} warnings`);
+ } else {
+ console.log(' skipped (no staged UI template changes)');
+ }
- // UI Template Generator
- console.log('\n🧱 Running UI Template Generator Checks...');
- if (hasStagedUiTemplateChanges()) {
- const uiTemplateGeneratorResult = normalizeSuiteResult(uiTemplateGeneratorTests.runTests());
- totalErrors += uiTemplateGeneratorResult.errors.length;
- totalWarnings += uiTemplateGeneratorResult.warnings.length;
- console.log(` ${uiTemplateGeneratorResult.errors.length} errors, ${uiTemplateGeneratorResult.warnings.length} warnings`);
- } else {
- console.log(' skipped (no staged UI template changes)');
- }
+ // Component Governance Utility Tests
+ console.log('\n🧩 Running Component Governance Utility Tests...');
+ const componentGovernanceUtilsResult = normalizeSuiteResult(componentGovernanceUtilsTests.runTests());
+ totalErrors += componentGovernanceUtilsResult.errors.length;
+ totalWarnings += componentGovernanceUtilsResult.warnings.length;
+ console.log(
+ ` ${componentGovernanceUtilsResult.errors.length} errors, ${componentGovernanceUtilsResult.warnings.length} warnings`
+ );
- // Component Governance Utility Tests
- console.log('\n🧩 Running Component Governance Utility Tests...');
- const componentGovernanceUtilsResult = normalizeSuiteResult(componentGovernanceUtilsTests.runTests());
- totalErrors += componentGovernanceUtilsResult.errors.length;
- totalWarnings += componentGovernanceUtilsResult.warnings.length;
- console.log(
- ` ${componentGovernanceUtilsResult.errors.length} errors, ${componentGovernanceUtilsResult.warnings.length} warnings`
- );
+ // Component Governance Generator Tests
+ console.log('\n🗂️ Running Component Governance Generator Tests...');
+ if (hasStagedComponentGovernanceChanges()) {
+ const componentGovernanceGeneratorResult = normalizeSuiteResult(componentGovernanceGeneratorTests.runTests());
+ totalErrors += componentGovernanceGeneratorResult.errors.length;
+ totalWarnings += componentGovernanceGeneratorResult.warnings.length;
+ console.log(
+ ` ${componentGovernanceGeneratorResult.errors.length} errors, ${componentGovernanceGeneratorResult.warnings.length} warnings`
+ );
+ } else {
+ console.log(' skipped (no staged component governance changes)');
+ }
- // Component Governance Generator Tests
- console.log('\n🗂️ Running Component Governance Generator Tests...');
- if (hasStagedComponentGovernanceChanges()) {
- const componentGovernanceGeneratorResult = normalizeSuiteResult(componentGovernanceGeneratorTests.runTests());
- totalErrors += componentGovernanceGeneratorResult.errors.length;
- totalWarnings += componentGovernanceGeneratorResult.warnings.length;
- console.log(
- ` ${componentGovernanceGeneratorResult.errors.length} errors, ${componentGovernanceGeneratorResult.warnings.length} warnings`
+ // Usefulness Unit Tests
+ console.log('\n📈 Running Usefulness Unit Tests...');
+ const usefulnessRubricCheck = spawnSync(
+ 'node',
+ ['tests/unit/usefulness-rubric.test.js'],
+ { cwd: REPO_ROOT, encoding: 'utf8' }
);
- } else {
- console.log(' skipped (no staged component governance changes)');
- }
+ if (usefulnessRubricCheck.stdout) process.stdout.write(usefulnessRubricCheck.stdout);
+ if (usefulnessRubricCheck.stderr) process.stderr.write(usefulnessRubricCheck.stderr);
+ if (usefulnessRubricCheck.status !== 0) totalErrors += 1;
- // Usefulness Unit Tests
- console.log('\n📈 Running Usefulness Unit Tests...');
- const usefulnessRubricCheck = spawnSync(
- 'node',
- ['tests/unit/usefulness-rubric.test.js'],
- { cwd: REPO_ROOT, encoding: 'utf8' }
- );
- if (usefulnessRubricCheck.stdout) process.stdout.write(usefulnessRubricCheck.stdout);
- if (usefulnessRubricCheck.stderr) process.stderr.write(usefulnessRubricCheck.stderr);
- if (usefulnessRubricCheck.status !== 0) totalErrors += 1;
-
- const usefulnessJourneyCheck = spawnSync(
- 'node',
- ['tests/unit/usefulness-journey.test.js'],
- { cwd: REPO_ROOT, encoding: 'utf8' }
- );
- if (usefulnessJourneyCheck.stdout) process.stdout.write(usefulnessJourneyCheck.stdout);
- if (usefulnessJourneyCheck.stderr) process.stderr.write(usefulnessJourneyCheck.stderr);
- if (usefulnessJourneyCheck.status !== 0) totalErrors += 1;
- const usefulnessFailures = (usefulnessRubricCheck.status === 0 ? 0 : 1) + (usefulnessJourneyCheck.status === 0 ? 0 : 1);
- console.log(` ${usefulnessFailures} errors, 0 warnings`);
+ const usefulnessJourneyCheck = spawnSync(
+ 'node',
+ ['tests/unit/usefulness-journey.test.js'],
+ { cwd: REPO_ROOT, encoding: 'utf8' }
+ );
+ if (usefulnessJourneyCheck.stdout) process.stdout.write(usefulnessJourneyCheck.stdout);
+ if (usefulnessJourneyCheck.stderr) process.stderr.write(usefulnessJourneyCheck.stderr);
+ if (usefulnessJourneyCheck.status !== 0) totalErrors += 1;
+ const usefulnessFailures = (usefulnessRubricCheck.status === 0 ? 0 : 1) + (usefulnessJourneyCheck.status === 0 ? 0 : 1);
+ console.log(` ${usefulnessFailures} errors, 0 warnings`);
+ }
// Pages Index Sync Validation
console.log('\n🗂️ Running Pages Index Sync Validation...');
- const pagesIndexResult = normalizeSuiteResult(pagesIndexGenerator.run({ stagedOnly }));
- totalErrors += pagesIndexResult.errors.length;
- totalWarnings += pagesIndexResult.warnings.length;
- if (pagesIndexResult.skipped) {
- console.log(' skipped (no staged v2/pages changes)');
+ if (skipPagesIndex) {
+ console.log(' skipped (handled earlier in pre-commit)');
} else {
- console.log(` ${pagesIndexResult.errors.length} errors, ${pagesIndexResult.warnings.length} warnings`);
+ const pagesIndexResult = normalizeSuiteResult(pagesIndexGenerator.run({ stagedOnly }));
+ totalErrors += pagesIndexResult.errors.length;
+ totalWarnings += pagesIndexResult.warnings.length;
+ if (pagesIndexResult.skipped) {
+ console.log(' skipped (no staged v2/pages changes)');
+ } else {
+ console.log(` ${pagesIndexResult.errors.length} errors, ${pagesIndexResult.warnings.length} warnings`);
+ }
}
// Generated Banner Enforcement
diff --git a/tests/script-index.md b/tests/script-index.md
index b3eeca92a..9ac75f8cb 100644
--- a/tests/script-index.md
+++ b/tests/script-index.md
@@ -56,6 +56,7 @@
| `tests/unit/openapi-rolling-issue.test.js` | Tests OpenAPI rolling issue tracker — validates issue creation and dedup logic | `node tests/unit/openapi-rolling-issue.test.js [flags]` | docs |
| `tests/unit/orchestrator-guides-research-review.test.js` | Tests orchestrator-guides-research-review.js — validates live Orchestrators Guides tranche extraction, report summary helpers, and registry-drift detection for the research packet generator. | `node tests/unit/orchestrator-guides-research-review.test.js` | docs |
| `tests/unit/ownerless-governance.test.js` | Validates the ownerless governance manifest, primary gate-layer contract, and forbidden human-owner dependency in governed policy and GitHub surfaces. | `node tests/unit/ownerless-governance.test.js [--staged\|--files a,b]` | docs |
+| `tests/unit/precommit-staged-cache.test.js` | Tests precommit-staged-cache.js — validates staged-tree cache hits, invalidation, and pruning | `node tests/unit/precommit-staged-cache.test.js` | docs |
| `tests/unit/quality.test.js` | Content quality checks — validates frontmatter completeness, thin content detection, placeholder flagging | `node tests/unit/quality.test.js [flags]` | docs |
| `tests/unit/repair-governance.test.js` | Tests repair-governance.js for safe dry-run, fix, rollback, strict exit handling, and workflow contract coverage. | `node tests/unit/repair-governance.test.js` | docs |
| `tests/unit/repair-spelling.test.js` | Unit tests for repair-spelling.js — validates deterministic spelling fixes and exclusion ranges | `node tests/unit/repair-spelling.test.js [flags]` | docs |
diff --git a/tests/unit/precommit-staged-cache.test.js b/tests/unit/precommit-staged-cache.test.js
new file mode 100644
index 000000000..8399aabb2
--- /dev/null
+++ b/tests/unit/precommit-staged-cache.test.js
@@ -0,0 +1,208 @@
+#!/usr/bin/env node
+/**
+ * @script precommit-staged-cache.test
+ * @category validator
+ * @purpose qa:repo-health
+ * @scope tests/unit, tools/lib/precommit-staged-cache.js
+ * @domain docs
+ * @needs R-R14, R-R29
+ * @purpose-statement Tests precommit-staged-cache.js — validates staged-tree cache hits, invalidation, and pruning
+ * @pipeline P1, manual
+ * @usage node tests/unit/precommit-staged-cache.test.js
+ */
+
+const assert = require('assert');
+const fs = require('fs');
+const os = require('os');
+const path = require('path');
+const { spawnSync } = require('child_process');
+
+const {
+ getCacheDir,
+ readCache,
+ writeCache
+} = require('../../tools/lib/precommit-staged-cache');
+
+function mkTmpDir(prefix) {
+ return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
+}
+
+function writeFile(absolutePath, content) {
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
+ fs.writeFileSync(absolutePath, content, 'utf8');
+}
+
+function buildGitEnv() {
+ const env = { ...process.env };
+ Object.keys(env).forEach((key) => {
+ if (key.startsWith('GIT_')) {
+ delete env[key];
+ }
+ });
+ return env;
+}
+
+function runGit(repoRoot, args) {
+ const result = spawnSync('git', args, {
+ cwd: repoRoot,
+ encoding: 'utf8',
+ env: buildGitEnv()
+ });
+
+ if (result.status !== 0) {
+ throw new Error((result.stderr || result.stdout || `git ${args.join(' ')}`).trim());
+ }
+
+ return String(result.stdout || '').trim();
+}
+
+function initRepo() {
+ const repoRoot = mkTmpDir('precommit-staged-cache-');
+ const hooksDir = path.join(repoRoot, '.git-hooks-disabled');
+
+ runGit(repoRoot, ['init']);
+ runGit(repoRoot, ['config', 'user.name', 'Codex Test']);
+ runGit(repoRoot, ['config', 'user.email', 'codex@example.com']);
+ fs.mkdirSync(hooksDir, { recursive: true });
+ runGit(repoRoot, ['config', 'core.hooksPath', hooksDir]);
+
+ writeFile(path.join(repoRoot, '.githooks/pre-commit'), '#!/bin/bash\necho precommit\n');
+ writeFile(path.join(repoRoot, 'tests/run-all.js'), 'module.exports = {};\n');
+ writeFile(path.join(repoRoot, 'tests/unit/precommit-staged-cache.test.js'), '// fixture\n');
+ writeFile(path.join(repoRoot, 'tools/lib/precommit-staged-cache.js'), 'module.exports = {};\n');
+ writeFile(path.join(repoRoot, 'docs/example.mdx'), '# Example\n');
+
+ runGit(repoRoot, ['add', '.']);
+ runGit(repoRoot, ['commit', '-m', 'test fixture']);
+
+ return repoRoot;
+}
+
+async function runTests() {
+ const errors = [];
+ const watchedFiles = [
+ '.githooks/pre-commit',
+ 'tests/run-all.js',
+ 'tools/lib/precommit-staged-cache.js'
+ ];
+
+ try {
+ const repoRoot = initRepo();
+ writeFile(path.join(repoRoot, 'docs/example.mdx'), '# Example\n\nUpdated.\n');
+ runGit(repoRoot, ['add', 'docs/example.mdx']);
+
+ const gitEnv = buildGitEnv();
+ const initial = readCache({ repoRoot, watchedFiles, namespace: 'test-precommit-cache', gitEnv });
+ assert.strictEqual(initial.hit, false, 'cache should miss before first write');
+
+ const written = writeCache({
+ repoRoot,
+ watchedFiles,
+ namespace: 'test-precommit-cache',
+ metadata: { branch: 'docs-v2-dev' },
+ gitEnv
+ });
+ assert.ok(fs.existsSync(written.cacheFilePath), 'cache file should be written');
+
+ const reread = readCache({ repoRoot, watchedFiles, namespace: 'test-precommit-cache', gitEnv });
+ assert.strictEqual(reread.hit, true, 'cache should hit after write for unchanged staged tree');
+ assert.strictEqual(reread.entry.metadata.branch, 'docs-v2-dev');
+ console.log(' ✓ cache hits after recording an unchanged staged tree');
+ } catch (error) {
+ errors.push({ message: `cache hit after write: ${error.message}` });
+ }
+
+ try {
+ const repoRoot = initRepo();
+ const gitEnv = buildGitEnv();
+ writeFile(path.join(repoRoot, 'docs/example.mdx'), '# Example\n\nUpdated.\n');
+ runGit(repoRoot, ['add', 'docs/example.mdx']);
+ writeCache({ repoRoot, watchedFiles, namespace: 'test-precommit-cache', gitEnv });
+
+ writeFile(path.join(repoRoot, 'docs/example.mdx'), '# Example\n\nUpdated twice.\n');
+ runGit(repoRoot, ['add', 'docs/example.mdx']);
+
+ const changedTree = readCache({ repoRoot, watchedFiles, namespace: 'test-precommit-cache', gitEnv });
+ assert.strictEqual(changedTree.hit, false, 'cache should miss when staged content changes');
+ console.log(' ✓ cache invalidates when the staged tree changes');
+ } catch (error) {
+ errors.push({ message: `staged tree invalidation: ${error.message}` });
+ }
+
+ try {
+ const repoRoot = initRepo();
+ const gitEnv = buildGitEnv();
+ writeFile(path.join(repoRoot, 'docs/example.mdx'), '# Example\n\nUpdated.\n');
+ runGit(repoRoot, ['add', 'docs/example.mdx']);
+ writeCache({ repoRoot, watchedFiles, namespace: 'test-precommit-cache', gitEnv });
+
+ writeFile(path.join(repoRoot, 'tests/run-all.js'), 'module.exports = { changed: true };\n');
+
+ const changedWatcher = readCache({ repoRoot, watchedFiles, namespace: 'test-precommit-cache', gitEnv });
+ assert.strictEqual(changedWatcher.hit, false, 'cache should miss when a watched hook file changes');
+ console.log(' ✓ cache invalidates when watched hook files change');
+ } catch (error) {
+ errors.push({ message: `watched file invalidation: ${error.message}` });
+ }
+
+ try {
+ const repoRoot = initRepo();
+ const gitEnv = buildGitEnv();
+ writeFile(path.join(repoRoot, 'docs/example.mdx'), '# Example\n\nUpdated.\n');
+ runGit(repoRoot, ['add', 'docs/example.mdx']);
+
+ writeCache({
+ repoRoot,
+ watchedFiles,
+ namespace: 'test-precommit-cache',
+ metadata: { id: 1 },
+ maxEntries: 1,
+ gitEnv
+ });
+
+ writeFile(path.join(repoRoot, 'docs/example-2.mdx'), '# Another\n');
+ runGit(repoRoot, ['add', 'docs/example-2.mdx']);
+ writeCache({
+ repoRoot,
+ watchedFiles,
+ namespace: 'test-precommit-cache',
+ metadata: { id: 2 },
+ maxEntries: 1,
+ gitEnv
+ });
+
+ const cacheDir = getCacheDir({ repoRoot, namespace: 'test-precommit-cache', gitEnv });
+ const entries = fs.readdirSync(cacheDir).filter((entry) => entry.endsWith('.json'));
+ assert.strictEqual(entries.length, 1, 'cache pruning should keep only the requested number of entries');
+ console.log(' ✓ cache pruning removes stale entries');
+ } catch (error) {
+ errors.push({ message: `cache pruning: ${error.message}` });
+ }
+
+ return {
+ passed: errors.length === 0,
+ errors,
+ warnings: [],
+ total: 4
+ };
+}
+
+if (require.main === module) {
+ runTests()
+ .then((result) => {
+ if (result.passed) {
+ console.log(`\n✅ precommit-staged-cache tests passed (${result.total} cases)`);
+ process.exit(0);
+ }
+
+ console.error(`\n❌ ${result.errors.length} precommit-staged-cache test failure(s)`);
+ result.errors.forEach((entry) => console.error(` - ${entry.message}`));
+ process.exit(1);
+ })
+ .catch((error) => {
+ console.error(`\n❌ precommit-staged-cache tests crashed: ${error.message}`);
+ process.exit(1);
+ });
+}
+
+module.exports = { runTests };
diff --git a/tools/lib/precommit-staged-cache.js b/tools/lib/precommit-staged-cache.js
new file mode 100644
index 000000000..6cb1df2df
--- /dev/null
+++ b/tools/lib/precommit-staged-cache.js
@@ -0,0 +1,234 @@
+/**
+ * @script precommit-staged-cache
+ * @category orchestrator
+ * @purpose infrastructure:pipeline-orchestration
+ * @scope .githooks, tests, tools/lib, tools/scripts
+ * @domain docs
+ * @needs R-R29
+ * @purpose-statement Shared pre-commit staged-cache helpers — fingerprint staged content plus hook inputs and persist reusable pass markers
+ * @pipeline indirect -- library module
+ * @usage const cache = require('./precommit-staged-cache');
+ */
+const crypto = require('crypto');
+const fs = require('fs');
+const path = require('path');
+const { spawnSync } = require('child_process');
+
+const DEFAULT_NAMESPACE = 'pre-commit-expensive-suite';
+const DEFAULT_MAX_ENTRIES = 25;
+const DEFAULT_WATCHED_FILES = Object.freeze([
+ '.githooks/pre-commit',
+ 'tests/run-all.js',
+ 'tests/integration/v2-link-audit.js',
+ 'tests/integration/v2-wcag-audit.js',
+ 'tests/unit/ai-tools-registry.test.js',
+ 'tests/unit/check-agent-docs-freshness.test.js',
+ 'tests/unit/component-governance-generators.test.js',
+ 'tests/unit/component-governance-utils.test.js',
+ 'tests/unit/copy-lint.test.js',
+ 'tests/unit/docs-authoring-rules.test.js',
+ 'tests/unit/docs-guide-sot.test.js',
+ 'tests/unit/docs-navigation.test.js',
+ 'tests/unit/docs-page-scope.test.js',
+ 'tests/unit/docs-path-sync.test.js',
+ 'tests/unit/export-portable-skills.test.js',
+ 'tests/unit/frontmatter-taxonomy.test.js',
+ 'tests/unit/links-imports.test.js',
+ 'tests/unit/mdx-guards.test.js',
+ 'tests/unit/mdx-safe-markdown.test.js',
+ 'tests/unit/mdx.test.js',
+ 'tests/unit/ownerless-governance.test.js',
+ 'tests/unit/precommit-staged-cache.test.js',
+ 'tests/unit/quality.test.js',
+ 'tests/unit/root-allowlist-format.test.js',
+ 'tests/unit/script-docs.test.js',
+ 'tests/unit/skill-docs.test.js',
+ 'tests/unit/spelling.test.js',
+ 'tests/unit/style-guide.test.js',
+ 'tests/unit/ui-template-generator.test.js',
+ 'tests/unit/usefulness-journey.test.js',
+ 'tests/unit/usefulness-rubric.test.js',
+ 'tools/lib/generated-artifacts.js',
+ 'tools/lib/precommit-staged-cache.js',
+ 'tools/lib/script-governance-config.js',
+ 'tools/scripts/enforce-generated-file-banners.js',
+ 'tools/scripts/generate-component-registry.js',
+ 'tools/scripts/generate-docs-guide-components-index.js',
+ 'tools/scripts/generate-docs-index.js',
+ 'tools/scripts/generate-pages-index.js',
+ 'tools/scripts/remediators/components/repair-component-metadata.js',
+ 'tools/scripts/remediators/content/repair-mdx-safe-markdown.js',
+ 'tools/scripts/remediators/content/sync-docs-paths.js',
+ 'tools/scripts/scan-component-imports.js',
+ 'tools/scripts/sync-codex-skills.js',
+ 'tools/scripts/validators/components/check-component-css.js',
+ 'tools/scripts/validators/components/check-component-docs.js',
+ 'tools/scripts/validators/components/check-naming-conventions.js',
+ 'tools/scripts/validators/content/check-mdx-safe-markdown.js',
+ 'tools/scripts/validators/governance/audit-script-inventory.js'
+]);
+
+function normalizeRepoPath(filePath) {
+ return String(filePath || '').split(path.sep).join('/');
+}
+
+function runGit(repoRoot, args, options = {}) {
+ const result = spawnSync('git', args, {
+ cwd: repoRoot,
+ encoding: 'utf8',
+ env: options.gitEnv || process.env
+ });
+
+ if (result.status !== 0) {
+ throw new Error((result.stderr || result.stdout || `git ${args.join(' ')}`).trim());
+ }
+
+ return String(result.stdout || '').trim();
+}
+
+function resolveGitDir(repoRoot, options = {}) {
+ return path.resolve(repoRoot, runGit(repoRoot, ['rev-parse', '--git-dir'], options));
+}
+
+function getIndexTree(repoRoot, options = {}) {
+ return runGit(repoRoot, ['write-tree'], options);
+}
+
+function hashFileContent(repoRoot, relativePath) {
+ const normalizedPath = normalizeRepoPath(relativePath);
+ const absolutePath = path.join(repoRoot, normalizedPath);
+ if (!fs.existsSync(absolutePath)) return `missing:${normalizedPath}`;
+
+ const hash = crypto.createHash('sha256');
+ hash.update(fs.readFileSync(absolutePath));
+ return hash.digest('hex');
+}
+
+function normalizeWatchedFiles(watchedFiles = DEFAULT_WATCHED_FILES) {
+ return [...new Set((watchedFiles || []).map(normalizeRepoPath).filter(Boolean))].sort();
+}
+
+function getCacheDir({ repoRoot, namespace = DEFAULT_NAMESPACE, gitEnv }) {
+ return path.join(resolveGitDir(repoRoot, { gitEnv }), 'lpd-hook-cache', namespace);
+}
+
+function computeCacheKey({ repoRoot, namespace = DEFAULT_NAMESPACE, watchedFiles = DEFAULT_WATCHED_FILES, gitEnv }) {
+ const normalizedFiles = normalizeWatchedFiles(watchedFiles);
+ const indexTree = getIndexTree(repoRoot, { gitEnv });
+ const digest = crypto.createHash('sha256');
+
+ digest.update(`${namespace}\n${indexTree}\n`);
+ normalizedFiles.forEach((relativePath) => {
+ digest.update(`${relativePath}\0${hashFileContent(repoRoot, relativePath)}\n`);
+ });
+
+ return {
+ namespace,
+ indexTree,
+ watchedFiles: normalizedFiles,
+ key: digest.digest('hex')
+ };
+}
+
+function getCacheFilePath({ repoRoot, namespace = DEFAULT_NAMESPACE, key, gitEnv }) {
+ return path.join(getCacheDir({ repoRoot, namespace, gitEnv }), `${key}.json`);
+}
+
+function pruneCacheDir(cacheDir, maxEntries = DEFAULT_MAX_ENTRIES) {
+ if (!fs.existsSync(cacheDir)) return;
+
+ const entries = fs.readdirSync(cacheDir)
+ .filter((entry) => entry.endsWith('.json'))
+ .map((entry) => {
+ const absolutePath = path.join(cacheDir, entry);
+ const stats = fs.statSync(absolutePath);
+ return {
+ absolutePath,
+ mtimeMs: stats.mtimeMs
+ };
+ })
+ .sort((left, right) => right.mtimeMs - left.mtimeMs);
+
+ entries.slice(Math.max(maxEntries, 0)).forEach((entry) => {
+ fs.rmSync(entry.absolutePath, { force: true });
+ });
+}
+
+function readCache(options) {
+ const fingerprint = computeCacheKey(options);
+ const cacheFilePath = getCacheFilePath({
+ repoRoot: options.repoRoot,
+ namespace: fingerprint.namespace,
+ key: fingerprint.key,
+ gitEnv: options.gitEnv
+ });
+
+ if (!fs.existsSync(cacheFilePath)) {
+ return {
+ ...fingerprint,
+ cacheFilePath,
+ hit: false,
+ entry: null
+ };
+ }
+
+ const entry = JSON.parse(fs.readFileSync(cacheFilePath, 'utf8'));
+ const hit = entry.key === fingerprint.key && entry.indexTree === fingerprint.indexTree;
+
+ return {
+ ...fingerprint,
+ cacheFilePath,
+ hit,
+ entry
+ };
+}
+
+function writeCache({
+ repoRoot,
+ namespace = DEFAULT_NAMESPACE,
+ watchedFiles = DEFAULT_WATCHED_FILES,
+ metadata = {},
+ maxEntries = DEFAULT_MAX_ENTRIES,
+ gitEnv
+}) {
+ const fingerprint = computeCacheKey({ repoRoot, namespace, watchedFiles, gitEnv });
+ const cacheDir = getCacheDir({ repoRoot, namespace, gitEnv });
+ const cacheFilePath = getCacheFilePath({
+ repoRoot,
+ namespace,
+ key: fingerprint.key,
+ gitEnv
+ });
+
+ fs.mkdirSync(cacheDir, { recursive: true });
+
+ const entry = {
+ key: fingerprint.key,
+ namespace,
+ indexTree: fingerprint.indexTree,
+ watchedFiles: fingerprint.watchedFiles,
+ createdAt: new Date().toISOString(),
+ metadata
+ };
+
+ fs.writeFileSync(cacheFilePath, `${JSON.stringify(entry, null, 2)}\n`, 'utf8');
+ pruneCacheDir(cacheDir, maxEntries);
+
+ return {
+ ...fingerprint,
+ cacheFilePath,
+ entry
+ };
+}
+
+module.exports = {
+ DEFAULT_MAX_ENTRIES,
+ DEFAULT_NAMESPACE,
+ DEFAULT_WATCHED_FILES,
+ computeCacheKey,
+ getCacheDir,
+ getCacheFilePath,
+ normalizeWatchedFiles,
+ readCache,
+ writeCache
+};
diff --git a/tools/lib/script-index.md b/tools/lib/script-index.md
index 51fd3ecf1..031dae260 100644
--- a/tools/lib/script-index.md
+++ b/tools/lib/script-index.md
@@ -36,6 +36,7 @@
| `tools/lib/load-js-yaml.js` | YAML loader utility — resolves js-yaml from repo-local installs and falls back to a minimal parser for task-contract style files in bare worktrees | `node -e "require('./tools/lib/load-js-yaml')"` | docs |
| `tools/lib/load-minimatch.js` | Glob matcher loader — resolves minimatch from repo-local installs and falls back to a simple glob matcher for bare worktrees | `node -e "require('./tools/lib/load-minimatch')"` | docs |
| `tools/lib/mdx-safe-markdown.js` | Shared MDX-safe markdown helpers that collect first-party markdown files, detect unsafe patterns, and apply deterministic repairs. | `node tools/lib/mdx-safe-markdown.js [flags]` | docs |
+| `tools/lib/precommit-staged-cache.js` | Shared pre-commit staged-cache helpers — fingerprint staged content plus hook inputs and persist reusable pass markers | `const cache = require('./precommit-staged-cache');` | docs |
| `tools/lib/script-governance-config.js` | Shared governance constants for script discovery, indexing, classification, and pipeline normalisation across the repo. | `const config = require('../lib/script-governance-config');` | docs |
| `tools/lib/script-header-utils.js` | Shared helpers for extracting and reading top-of-file script governance headers without scanning into executable source. | `const { extractLeadingScriptHeader } = require('../lib/script-header-utils');` | docs |
{/* SCRIPT-INDEX:END */}
diff --git a/v2/gateways/quickstart/gateway-setup.mdx b/v2/gateways/quickstart/gateway-setup.mdx
index 533f8ac81..99b11befe 100644
--- a/v2/gateways/quickstart/gateway-setup.mdx
+++ b/v2/gateways/quickstart/gateway-setup.mdx
@@ -5,7 +5,7 @@ pageType: quickstart
audience: gateway-operator
purpose: how_to
lastVerified: '2026-03-17'
-sidebarTitle: Run a Gateway Quickstart
+sidebarTitle: Run a Gateway
keywords:
- livepeer
- gateways
diff --git a/v2/index.mdx b/v2/index.mdx
index e698b9a5f..204433e83 100644
--- a/v2/index.mdx
+++ b/v2/index.mdx
@@ -2097,77 +2097,78 @@ Run command: node tools/scripts/generate-pages-index.js --write
#### Advanced Operations
- [⚠️ Advanced Sources](orchestrators/guides/advanced-operations/advanced-sources.md)
- [⚠️ Advanced Operations Guide](orchestrators/guides/advanced-operations/dep-guide.mdx)
-- [⚠️ Gateway and Orchestrator Interface](orchestrators/guides/advanced-operations/gateway-orchestrator-interface.mdx)
-- [⚠️ Gateway Relationships](orchestrators/guides/advanced-operations/gateway-relationships.mdx)
-- [⚠️ Pool Operators](orchestrators/guides/advanced-operations/pool-operators.mdx)
-- [⚠️ Scale Operations](orchestrators/guides/advanced-operations/scale-operations.mdx)
+- [Gateway and Orchestrator Interface](orchestrators/guides/advanced-operations/gateway-orchestrator-interface.mdx)
+- [Gateway Relationships](orchestrators/guides/advanced-operations/gateway-relationships.mdx)
+- [Pool Operators](orchestrators/guides/advanced-operations/pool-operators.mdx)
+- [Scale Operations](orchestrators/guides/advanced-operations/scale-operations.mdx)
#### Ai And Job Workloads
-- [⚠️ AI Inference Operations](orchestrators/guides/ai-and-job-workloads/ai-inference-operations.mdx)
+- [AI Inference Operations](orchestrators/guides/ai-and-job-workloads/ai-inference-operations.mdx)
- [⚠️ Ai Sources](orchestrators/guides/ai-and-job-workloads/ai-sources.md)
-- [⚠️ Audio and Vision Pipelines](orchestrators/guides/ai-and-job-workloads/audio-and-vision-pipelines.mdx)
-- [⚠️ Diffusion Pipeline Setup](orchestrators/guides/ai-and-job-workloads/diffusion-pipeline-setup.mdx)
-- [⚠️ LLM Pipeline Setup](orchestrators/guides/ai-and-job-workloads/llm-pipeline-setup.mdx)
-- [⚠️ Model and Demand Reference](orchestrators/guides/ai-and-job-workloads/model-demand-reference.mdx)
-- [⚠️ Model Hosting](orchestrators/guides/ai-and-job-workloads/model-hosting.mdx)
-- [⚠️ Cascade Setup](orchestrators/guides/ai-and-job-workloads/realtime-ai-setup.mdx)
-- [⚠️ Video Transcoding Operations](orchestrators/guides/ai-and-job-workloads/video-transcoding-operations.mdx)
-- [⚠️ Workload Options](orchestrators/guides/ai-and-job-workloads/workload-options.mdx)
+- [Audio and Vision Pipelines](orchestrators/guides/ai-and-job-workloads/audio-and-vision-pipelines.mdx)
+- [Diffusion Pipeline Setup](orchestrators/guides/ai-and-job-workloads/diffusion-pipeline-setup.mdx)
+- [LLM Pipeline Setup](orchestrators/guides/ai-and-job-workloads/llm-pipeline-setup.mdx)
+- [Model and Demand Reference](orchestrators/guides/ai-and-job-workloads/model-demand-reference.mdx)
+- [Model Hosting](orchestrators/guides/ai-and-job-workloads/model-hosting.mdx)
+- [Cascade Setup](orchestrators/guides/ai-and-job-workloads/realtime-ai-setup.mdx)
+- [Video Transcoding Operations](orchestrators/guides/ai-and-job-workloads/video-transcoding-operations.mdx)
+- [Workload Options](orchestrators/guides/ai-and-job-workloads/workload-options.mdx)
#### Config And Optimisation
-- [⚠️ AI Model Management](orchestrators/guides/config-and-optimisation/ai-model-management.mdx)
-- [⚠️ Capacity Planning](orchestrators/guides/config-and-optimisation/capacity-planning.mdx)
-- [⚠️ Pricing Strategy](orchestrators/guides/config-and-optimisation/pricing-strategy.mdx)
-- [⚠️ Reward Call Tuning](orchestrators/guides/config-and-optimisation/reward-call-tuning.mdx)
+- [AI Model Management](orchestrators/guides/config-and-optimisation/ai-model-management.mdx)
+- [Capacity Planning](orchestrators/guides/config-and-optimisation/capacity-planning.mdx)
+- [Pricing Strategy](orchestrators/guides/config-and-optimisation/pricing-strategy.mdx)
+- [Reward Call Tuning](orchestrators/guides/config-and-optimisation/reward-call-tuning.mdx)
#### Deployment Details
-- [⚠️ Dual Mode Configuration](orchestrators/guides/deployment-details/dual-mode-configuration.mdx)
-- [⚠️ Join a Pool](orchestrators/guides/deployment-details/join-a-pool.mdx)
-- [⚠️ Join a Pool](orchestrators/guides/deployment-details/new-join-a-pool.mdx)
-- [⚠️ Orchestrator-Transcoder Split Setup](orchestrators/guides/deployment-details/orchestrator-transcoder-setup.mdx)
-- [⚠️ Setup Options](orchestrators/guides/deployment-details/setup-options.mdx)
-- [⚠️ Siphon Split Setup](orchestrators/guides/deployment-details/siphon-setup.mdx)
+- [Setup Options](orchestrators/guides/deployment-details/draft1-setup-options.mdx)
+- [Dual Mode Configuration](orchestrators/guides/deployment-details/dual-mode-configuration.mdx)
+- [Join a Pool](orchestrators/guides/deployment-details/join-a-pool.mdx)
+- [Join a Pool](orchestrators/guides/deployment-details/new-join-a-pool.mdx)
+- [Orchestrator-Transcoder Split Setup](orchestrators/guides/deployment-details/orchestrator-transcoder-setup.mdx)
+- [Setup Options](orchestrators/guides/deployment-details/setup-options.mdx)
+- [Siphon Split Setup](orchestrators/guides/deployment-details/siphon-setup.mdx)
##### Reports Audits
- [⚠️ Notes](orchestrators/guides/deployment-details/reports-audits/notes.md)
- [⚠️ Setup Sources](orchestrators/guides/deployment-details/reports-audits/setup-sources.md)
#### Monitoring And Tooling
-- [⚠️ Explorer Operations](orchestrators/guides/monitoring-and-tooling/explorer-operations.mdx)
-- [⚠️ Metrics and Alerting](orchestrators/guides/monitoring-and-tooling/metrics-and-alerting.mdx)
+- [Explorer Operations](orchestrators/guides/monitoring-and-tooling/explorer-operations.mdx)
+- [Metrics and Alerting](orchestrators/guides/monitoring-and-tooling/metrics-and-alerting.mdx)
- [⚠️ Monitoring Sources](orchestrators/guides/monitoring-and-tooling/monitoring-sources.md)
-- [⚠️ Operator Toolbox](orchestrators/guides/monitoring-and-tooling/operator-toolbox.mdx)
-- [⚠️ Troubleshooting](orchestrators/guides/monitoring-and-tooling/troubleshooting.mdx)
+- [Operator Toolbox](orchestrators/guides/monitoring-and-tooling/operator-toolbox.mdx)
+- [Troubleshooting](orchestrators/guides/monitoring-and-tooling/troubleshooting.mdx)
#### Operator Considerations
-- [⚠️ Business Case](orchestrators/guides/operator-considerations/business-case.mdx)
+- [Business Case](orchestrators/guides/operator-considerations/business-case.mdx)
- [⚠️ Feasibilits Sources](orchestrators/guides/operator-considerations/feasibilits-sources.md)
-- [⚠️ Operator Impact](orchestrators/guides/operator-considerations/operator-impact.mdx)
-- [⚠️ Operating Rationale](orchestrators/guides/operator-considerations/operator-rationale.mdx)
-- [⚠️ Requirements](orchestrators/guides/operator-considerations/requirements.mdx)
+- [Operator Impact](orchestrators/guides/operator-considerations/operator-impact.mdx)
+- [Operating Rationale](orchestrators/guides/operator-considerations/operator-rationale.mdx)
+- [Requirements](orchestrators/guides/operator-considerations/requirements.mdx)
#### Payments And Pricing
-- [⚠️ Payment Receipts](orchestrators/guides/payments-and-pricing/payment-receipts.mdx)
-- [⚠️ Payments](orchestrators/guides/payments-and-pricing/payments.mdx)
+- [Payment Receipts](orchestrators/guides/payments-and-pricing/payment-receipts.mdx)
+- [Payments](orchestrators/guides/payments-and-pricing/payments.mdx)
#### Roadmap And Funding
-- [⚠️ Funding and Support](orchestrators/guides/roadmap-and-funding/funding-and-support.mdx)
-- [⚠️ Orchestrator Profiles](orchestrators/guides/roadmap-and-funding/orchestrator-profiles.mdx)
+- [Funding and Support](orchestrators/guides/roadmap-and-funding/funding-and-support.mdx)
+- [Orchestrator Profiles](orchestrators/guides/roadmap-and-funding/orchestrator-profiles.mdx)
#### Staking And Rewards
-- [⚠️ Delegate Operations](orchestrators/guides/staking-and-rewards/delegate-operations.mdx)
-- [⚠️ Earning Model](orchestrators/guides/staking-and-rewards/earning-model.mdx)
-- [⚠️ Network Participation](orchestrators/guides/staking-and-rewards/network-participation.mdx)
-- [⚠️ Reward Mechanics](orchestrators/guides/staking-and-rewards/reward-mechanics.mdx)
+- [Delegate Operations](orchestrators/guides/staking-and-rewards/delegate-operations.mdx)
+- [Earning Model](orchestrators/guides/staking-and-rewards/earning-model.mdx)
+- [Network Participation](orchestrators/guides/staking-and-rewards/network-participation.mdx)
+- [Reward Mechanics](orchestrators/guides/staking-and-rewards/reward-mechanics.mdx)
#### Tutorials
-- [⚠️ Add AI to a Video Node](orchestrators/guides/tutorials/add-ai-to-video-node.mdx)
-- [⚠️ AI Earning Quickstart](orchestrators/guides/tutorials/ai-earning-quickstart.mdx)
-- [⚠️ BYOC CPU Smoke Test](orchestrators/guides/tutorials/byoc-cpu-smoke-test.mdx)
+- [Add AI to a Video Node](orchestrators/guides/tutorials/add-ai-to-video-node.mdx)
+- [AI Earning Quickstart](orchestrators/guides/tutorials/ai-earning-quickstart.mdx)
+- [BYOC CPU Smoke Test](orchestrators/guides/tutorials/byoc-cpu-smoke-test.mdx)
- [⚠️ BYOC smoke-test: CPU gateway and orchestrator (off-chain to on-chain)](orchestrators/guides/tutorials/byoc-cpu-tutorial.mdx)
-- [⚠️ Full AI Pipeline Tutorial](orchestrators/guides/tutorials/full-ai-pipeline-tutorial.mdx)
-- [⚠️ Realtime AI Tutorial](orchestrators/guides/tutorials/realtime-ai-tutorial.mdx)
-- [⚠️ Zero to First Reward](orchestrators/guides/tutorials/zero-to-first-reward.mdx)
+- [Full AI Pipeline Tutorial](orchestrators/guides/tutorials/full-ai-pipeline-tutorial.mdx)
+- [Realtime AI Tutorial](orchestrators/guides/tutorials/realtime-ai-tutorial.mdx)
+- [Zero to First Reward](orchestrators/guides/tutorials/zero-to-first-reward.mdx)
##### Gateway Tutorial Composable Pages
@@ -2180,7 +2181,7 @@ Run command: node tools/scripts/generate-pages-index.js --write
- [⚠️ Add AI to Your Node](orchestrators/quickstart/AI-prompt-start.mdx)
- [⚠️ How to Get Started](orchestrators/quickstart/dep-x-setup-paths.mdx)
- [Orchestrator Quickstart](orchestrators/quickstart/guide.mdx)
-- [⚠️ Quickstart Tutorial](orchestrators/quickstart/tutorial.mdx)
+- [Quickstart Tutorial](orchestrators/quickstart/tutorial.mdx)
- [Quickstart: Verify Your Hardware](orchestrators/quickstart/video-transcoding.mdx)
### Resources
@@ -2189,22 +2190,22 @@ Run command: node tools/scripts/generate-pages-index.js --write
- [Community Guides & Tutorials](orchestrators/resources/community-guides.mdx)
- [Community Orchestrator Pools](orchestrators/resources/community-pools.mdx)
- [FAQ and Troubleshooting](orchestrators/resources/faq.mdx)
-- [⚠️ Orchestrator Terminology Glossary](orchestrators/resources/glossary.mdx)
+- [Orchestrator Terminology Glossary](orchestrators/resources/glossary.mdx)
- [GPU Support Matrix](orchestrators/resources/gpu-support.mdx)
-- [Orchestrator Guides](orchestrators/resources/x-guides.mdx)
-- [X-help](orchestrators/resources/x-help.mdx)
-- [Orchestrator Payments](orchestrators/resources/x-payments.mdx)
+- [⚠️ Orchestrator Guides](orchestrators/resources/x-guides.mdx)
+- [⚠️ X-help](orchestrators/resources/x-help.mdx)
+- [⚠️ Orchestrator Payments](orchestrators/resources/x-payments.mdx)
#### Technical
- [CLI Flags Reference](orchestrators/resources/technical/cli-flags.mdx)
-- [X-changelog](orchestrators/resources/technical/x-changelog.mdx)
+- [⚠️ X-changelog](orchestrators/resources/technical/x-changelog.mdx)
- [Livepeer Arbitrum Contract Adresses](orchestrators/resources/technical/x-contract-addresses.mdx)
-- [Support Status](orchestrators/resources/technical/x-support-status.mdx)
-- [Troubleshooting](orchestrators/resources/technical/x-troubleshooting.mdx)
+- [⚠️ Support Status](orchestrators/resources/technical/x-support-status.mdx)
+- [⚠️ Troubleshooting](orchestrators/resources/technical/x-troubleshooting.mdx)
### Setup
-- [⚠️ Configure Your Orchestrator](orchestrators/setup/configure.mdx)
-- [⚠️ Connect to Arbitrum](orchestrators/setup/connect-and-activate.mdx)
+- [Configure Your Orchestrator](orchestrators/setup/configure.mdx)
+- [Connect to Arbitrum](orchestrators/setup/connect-and-activate.mdx)
- [Run an Orchestrator](orchestrators/setup/guide.mdx)
- [Set Up Monitoring](orchestrators/setup/r-monitor.mdx)
- [Setup Checklist](orchestrators/setup/rcs-requirements.mdx)
diff --git a/v2/orchestrators/_workspace/reviews/guides/human-review.md b/v2/orchestrators/_workspace/reviews/guides/human-review.md
index 24643f493..91c1a5f51 100644
--- a/v2/orchestrators/_workspace/reviews/guides/human-review.md
+++ b/v2/orchestrators/_workspace/reviews/guides/human-review.md
@@ -40,6 +40,8 @@ Patterns from human review to feed back into authoring skills.
| # | Issue | Context | Human decision | Type |
|---|-------|---------|---------------|------|
+| 24 | Too many tables on one page | draft1 has 6 StyledTables. Page is almost entirely tabular with almost zero prose. | Max 1-2 tables per page. Tables should support prose, not replace it. | Layout |
+| 25 | No prose, all tables | Page reads like a spreadsheet, not documentation. Tables are data, not explanation. | Pages need prose to explain WHY and WHAT. Tables are supporting evidence, not the content itself. | Content |
| 21 | Proposed rewrite leads with definitions | AI proposed "Ground zero: Definitions" as the first section - defining axes before presenting options | Definitions ARE the options. Don't define axes then present options separately. Combine. | Structure |
| 22 | "What are my options?" is a lazy framing of the reader's question | AI framed the page purpose as answering "what are my options for running an orchestrator?" | The reader is past "should I?" - they're here because they're ready to set up. The real question is "which setup path matches my situation?" | Content |
| 23 | Preamble before the answer | Multiple proposed structures put context, definitions, or framing before the actual options | Answer the reader's question IMMEDIATELY. First thing on the page. No preamble. | Structure |
@@ -63,7 +65,8 @@ Patterns from human review to feed back into authoring skills.
| **Preamble before the answer** - pages put context/definitions/framing before the thing the reader came for | setup-options | Authoring skill: answer the reader's question FIRST. Context supports the answer, it doesn't precede it. |
| **Lazy question framing** - AI identifies the reader's question as generic ("what are my options?") instead of specific | setup-options | Authoring skill: identify the SPECIFIC question the reader has at this point in their journey, not a generic version. The reader's journey position determines the question. |
| **Single value prop anchoring** - AI latches onto one reason per option and repeats it across every response | setup-options (pool node = "no LPT" every time) | Authoring skill: minimum 5 distinct value props per option across different dimensions (financial, operational, risk, time, complexity, flexibility). Challenge own anchoring. |
-| **Consecutive tables** - stacking StyledTable after StyledTable creates a wall of tabular data with no visual relief | setup-options (draft1 has 6 consecutive tables) | Authoring skill: never stack tables. Use tabs, accordions, cards, bordered boxes, or prose between tables. 100+ components exist - use them. |
+| **Consecutive tables** - stacking StyledTable after StyledTable creates a wall of tabular data with no visual relief | setup-options (draft1 has 6 tables) | Authoring skill: never stack tables. Max 1-2 tables per page. Use tabs, accordions, cards, bordered boxes, or prose between tables. |
+| **Tables replacing prose** - page is almost entirely tabular with no explanatory text | setup-options (draft1) | Authoring skill: tables support prose, they don't replace it. A page with no prose is a spreadsheet, not documentation. |
---
diff --git a/v2/orchestrators/index.mdx b/v2/orchestrators/index.mdx
index b4e74e9ba..d3f1782f9 100644
--- a/v2/orchestrators/index.mdx
+++ b/v2/orchestrators/index.mdx
@@ -40,77 +40,78 @@ Run command: node tools/scripts/generate-pages-index.js --write
### Advanced Operations
- [⚠️ Advanced Sources](guides/advanced-operations/advanced-sources.md)
- [⚠️ Advanced Operations Guide](guides/advanced-operations/dep-guide.mdx)
-- [⚠️ Gateway and Orchestrator Interface](guides/advanced-operations/gateway-orchestrator-interface.mdx)
-- [⚠️ Gateway Relationships](guides/advanced-operations/gateway-relationships.mdx)
-- [⚠️ Pool Operators](guides/advanced-operations/pool-operators.mdx)
-- [⚠️ Scale Operations](guides/advanced-operations/scale-operations.mdx)
+- [Gateway and Orchestrator Interface](guides/advanced-operations/gateway-orchestrator-interface.mdx)
+- [Gateway Relationships](guides/advanced-operations/gateway-relationships.mdx)
+- [Pool Operators](guides/advanced-operations/pool-operators.mdx)
+- [Scale Operations](guides/advanced-operations/scale-operations.mdx)
### Ai And Job Workloads
-- [⚠️ AI Inference Operations](guides/ai-and-job-workloads/ai-inference-operations.mdx)
+- [AI Inference Operations](guides/ai-and-job-workloads/ai-inference-operations.mdx)
- [⚠️ Ai Sources](guides/ai-and-job-workloads/ai-sources.md)
-- [⚠️ Audio and Vision Pipelines](guides/ai-and-job-workloads/audio-and-vision-pipelines.mdx)
-- [⚠️ Diffusion Pipeline Setup](guides/ai-and-job-workloads/diffusion-pipeline-setup.mdx)
-- [⚠️ LLM Pipeline Setup](guides/ai-and-job-workloads/llm-pipeline-setup.mdx)
-- [⚠️ Model and Demand Reference](guides/ai-and-job-workloads/model-demand-reference.mdx)
-- [⚠️ Model Hosting](guides/ai-and-job-workloads/model-hosting.mdx)
-- [⚠️ Cascade Setup](guides/ai-and-job-workloads/realtime-ai-setup.mdx)
-- [⚠️ Video Transcoding Operations](guides/ai-and-job-workloads/video-transcoding-operations.mdx)
-- [⚠️ Workload Options](guides/ai-and-job-workloads/workload-options.mdx)
+- [Audio and Vision Pipelines](guides/ai-and-job-workloads/audio-and-vision-pipelines.mdx)
+- [Diffusion Pipeline Setup](guides/ai-and-job-workloads/diffusion-pipeline-setup.mdx)
+- [LLM Pipeline Setup](guides/ai-and-job-workloads/llm-pipeline-setup.mdx)
+- [Model and Demand Reference](guides/ai-and-job-workloads/model-demand-reference.mdx)
+- [Model Hosting](guides/ai-and-job-workloads/model-hosting.mdx)
+- [Cascade Setup](guides/ai-and-job-workloads/realtime-ai-setup.mdx)
+- [Video Transcoding Operations](guides/ai-and-job-workloads/video-transcoding-operations.mdx)
+- [Workload Options](guides/ai-and-job-workloads/workload-options.mdx)
### Config And Optimisation
-- [⚠️ AI Model Management](guides/config-and-optimisation/ai-model-management.mdx)
-- [⚠️ Capacity Planning](guides/config-and-optimisation/capacity-planning.mdx)
-- [⚠️ Pricing Strategy](guides/config-and-optimisation/pricing-strategy.mdx)
-- [⚠️ Reward Call Tuning](guides/config-and-optimisation/reward-call-tuning.mdx)
+- [AI Model Management](guides/config-and-optimisation/ai-model-management.mdx)
+- [Capacity Planning](guides/config-and-optimisation/capacity-planning.mdx)
+- [Pricing Strategy](guides/config-and-optimisation/pricing-strategy.mdx)
+- [Reward Call Tuning](guides/config-and-optimisation/reward-call-tuning.mdx)
### Deployment Details
-- [⚠️ Dual Mode Configuration](guides/deployment-details/dual-mode-configuration.mdx)
-- [⚠️ Join a Pool](guides/deployment-details/join-a-pool.mdx)
-- [⚠️ Join a Pool](guides/deployment-details/new-join-a-pool.mdx)
-- [⚠️ Orchestrator-Transcoder Split Setup](guides/deployment-details/orchestrator-transcoder-setup.mdx)
-- [⚠️ Setup Options](guides/deployment-details/setup-options.mdx)
-- [⚠️ Siphon Split Setup](guides/deployment-details/siphon-setup.mdx)
+- [Setup Options](guides/deployment-details/draft1-setup-options.mdx)
+- [Dual Mode Configuration](guides/deployment-details/dual-mode-configuration.mdx)
+- [Join a Pool](guides/deployment-details/join-a-pool.mdx)
+- [Join a Pool](guides/deployment-details/new-join-a-pool.mdx)
+- [Orchestrator-Transcoder Split Setup](guides/deployment-details/orchestrator-transcoder-setup.mdx)
+- [Setup Options](guides/deployment-details/setup-options.mdx)
+- [Siphon Split Setup](guides/deployment-details/siphon-setup.mdx)
#### Reports Audits
- [⚠️ Notes](guides/deployment-details/reports-audits/notes.md)
- [⚠️ Setup Sources](guides/deployment-details/reports-audits/setup-sources.md)
### Monitoring And Tooling
-- [⚠️ Explorer Operations](guides/monitoring-and-tooling/explorer-operations.mdx)
-- [⚠️ Metrics and Alerting](guides/monitoring-and-tooling/metrics-and-alerting.mdx)
+- [Explorer Operations](guides/monitoring-and-tooling/explorer-operations.mdx)
+- [Metrics and Alerting](guides/monitoring-and-tooling/metrics-and-alerting.mdx)
- [⚠️ Monitoring Sources](guides/monitoring-and-tooling/monitoring-sources.md)
-- [⚠️ Operator Toolbox](guides/monitoring-and-tooling/operator-toolbox.mdx)
-- [⚠️ Troubleshooting](guides/monitoring-and-tooling/troubleshooting.mdx)
+- [Operator Toolbox](guides/monitoring-and-tooling/operator-toolbox.mdx)
+- [Troubleshooting](guides/monitoring-and-tooling/troubleshooting.mdx)
### Operator Considerations
-- [⚠️ Business Case](guides/operator-considerations/business-case.mdx)
+- [Business Case](guides/operator-considerations/business-case.mdx)
- [⚠️ Feasibilits Sources](guides/operator-considerations/feasibilits-sources.md)
-- [⚠️ Operator Impact](guides/operator-considerations/operator-impact.mdx)
-- [⚠️ Operating Rationale](guides/operator-considerations/operator-rationale.mdx)
-- [⚠️ Requirements](guides/operator-considerations/requirements.mdx)
+- [Operator Impact](guides/operator-considerations/operator-impact.mdx)
+- [Operating Rationale](guides/operator-considerations/operator-rationale.mdx)
+- [Requirements](guides/operator-considerations/requirements.mdx)
### Payments And Pricing
-- [⚠️ Payment Receipts](guides/payments-and-pricing/payment-receipts.mdx)
-- [⚠️ Payments](guides/payments-and-pricing/payments.mdx)
+- [Payment Receipts](guides/payments-and-pricing/payment-receipts.mdx)
+- [Payments](guides/payments-and-pricing/payments.mdx)
### Roadmap And Funding
-- [⚠️ Funding and Support](guides/roadmap-and-funding/funding-and-support.mdx)
-- [⚠️ Orchestrator Profiles](guides/roadmap-and-funding/orchestrator-profiles.mdx)
+- [Funding and Support](guides/roadmap-and-funding/funding-and-support.mdx)
+- [Orchestrator Profiles](guides/roadmap-and-funding/orchestrator-profiles.mdx)
### Staking And Rewards
-- [⚠️ Delegate Operations](guides/staking-and-rewards/delegate-operations.mdx)
-- [⚠️ Earning Model](guides/staking-and-rewards/earning-model.mdx)
-- [⚠️ Network Participation](guides/staking-and-rewards/network-participation.mdx)
-- [⚠️ Reward Mechanics](guides/staking-and-rewards/reward-mechanics.mdx)
+- [Delegate Operations](guides/staking-and-rewards/delegate-operations.mdx)
+- [Earning Model](guides/staking-and-rewards/earning-model.mdx)
+- [Network Participation](guides/staking-and-rewards/network-participation.mdx)
+- [Reward Mechanics](guides/staking-and-rewards/reward-mechanics.mdx)
### Tutorials
-- [⚠️ Add AI to a Video Node](guides/tutorials/add-ai-to-video-node.mdx)
-- [⚠️ AI Earning Quickstart](guides/tutorials/ai-earning-quickstart.mdx)
-- [⚠️ BYOC CPU Smoke Test](guides/tutorials/byoc-cpu-smoke-test.mdx)
+- [Add AI to a Video Node](guides/tutorials/add-ai-to-video-node.mdx)
+- [AI Earning Quickstart](guides/tutorials/ai-earning-quickstart.mdx)
+- [BYOC CPU Smoke Test](guides/tutorials/byoc-cpu-smoke-test.mdx)
- [⚠️ BYOC smoke-test: CPU gateway and orchestrator (off-chain to on-chain)](guides/tutorials/byoc-cpu-tutorial.mdx)
-- [⚠️ Full AI Pipeline Tutorial](guides/tutorials/full-ai-pipeline-tutorial.mdx)
-- [⚠️ Realtime AI Tutorial](guides/tutorials/realtime-ai-tutorial.mdx)
-- [⚠️ Zero to First Reward](guides/tutorials/zero-to-first-reward.mdx)
+- [Full AI Pipeline Tutorial](guides/tutorials/full-ai-pipeline-tutorial.mdx)
+- [Realtime AI Tutorial](guides/tutorials/realtime-ai-tutorial.mdx)
+- [Zero to First Reward](guides/tutorials/zero-to-first-reward.mdx)
#### Gateway Tutorial Composable Pages
@@ -123,7 +124,7 @@ Run command: node tools/scripts/generate-pages-index.js --write
- [⚠️ Add AI to Your Node](quickstart/AI-prompt-start.mdx)
- [⚠️ How to Get Started](quickstart/dep-x-setup-paths.mdx)
- [Orchestrator Quickstart](quickstart/guide.mdx)
-- [⚠️ Quickstart Tutorial](quickstart/tutorial.mdx)
+- [Quickstart Tutorial](quickstart/tutorial.mdx)
- [Quickstart: Verify Your Hardware](quickstart/video-transcoding.mdx)
## Resources
@@ -132,22 +133,22 @@ Run command: node tools/scripts/generate-pages-index.js --write
- [Community Guides & Tutorials](resources/community-guides.mdx)
- [Community Orchestrator Pools](resources/community-pools.mdx)
- [FAQ and Troubleshooting](resources/faq.mdx)
-- [⚠️ Orchestrator Terminology Glossary](resources/glossary.mdx)
+- [Orchestrator Terminology Glossary](resources/glossary.mdx)
- [GPU Support Matrix](resources/gpu-support.mdx)
-- [Orchestrator Guides](resources/x-guides.mdx)
-- [X-help](resources/x-help.mdx)
-- [Orchestrator Payments](resources/x-payments.mdx)
+- [⚠️ Orchestrator Guides](resources/x-guides.mdx)
+- [⚠️ X-help](resources/x-help.mdx)
+- [⚠️ Orchestrator Payments](resources/x-payments.mdx)
### Technical
- [CLI Flags Reference](resources/technical/cli-flags.mdx)
-- [X-changelog](resources/technical/x-changelog.mdx)
+- [⚠️ X-changelog](resources/technical/x-changelog.mdx)
- [Livepeer Arbitrum Contract Adresses](resources/technical/x-contract-addresses.mdx)
-- [Support Status](resources/technical/x-support-status.mdx)
-- [Troubleshooting](resources/technical/x-troubleshooting.mdx)
+- [⚠️ Support Status](resources/technical/x-support-status.mdx)
+- [⚠️ Troubleshooting](resources/technical/x-troubleshooting.mdx)
## Setup
-- [⚠️ Configure Your Orchestrator](setup/configure.mdx)
-- [⚠️ Connect to Arbitrum](setup/connect-and-activate.mdx)
+- [Configure Your Orchestrator](setup/configure.mdx)
+- [Connect to Arbitrum](setup/connect-and-activate.mdx)
- [Run an Orchestrator](setup/guide.mdx)
- [Set Up Monitoring](setup/r-monitor.mdx)
- [Setup Checklist](setup/rcs-requirements.mdx)
diff --git a/v2/orchestrators/portal.mdx b/v2/orchestrators/portal.mdx
index 94aa4e691..f2a2cdfff 100644
--- a/v2/orchestrators/portal.mdx
+++ b/v2/orchestrators/portal.mdx
@@ -97,7 +97,7 @@ Get Situated */}
Anyone can add a GPU to the Livepeer network and earn from idle GPU downtimes - either by adding it to a pool or setting up their own orchestrator container.
-