diff --git a/.agents/skills/aster-code-review/benchmark/overlay_skill.sh b/.agents/skills/aster-code-review/benchmark/overlay_skill.sh index 68225c136..ec52be28a 100755 --- a/.agents/skills/aster-code-review/benchmark/overlay_skill.sh +++ b/.agents/skills/aster-code-review/benchmark/overlay_skill.sh @@ -9,10 +9,12 @@ # The overlaid files (.agents, .claude) are untracked at the historical base, # so they do NOT show up in a `diff`-mode review. # -# Guideline pages are deliberately NOT copied here: +# Guideline pages are deliberately NOT copied into the worktree's tracked book/: # overwriting the snapshot's tracked book/ would pollute a `diff`-mode review. -# The harness instead points the skill at current guidelines via ACR_GUIDELINE_ROOT -# (a guidelines-only tree). +# Instead, bundle a guidelines-only snapshot inside the overlaid skill package. +# build_pass_prompt.sh uses that snapshot by default, so the review still uses +# current guidelines even if the review agent does not preserve ACR_GUIDELINE_ROOT +# when it later runs shell commands. # # CRITICAL (benchmark integrity): # this EXCLUDES benchmark/, which holds problems.yaml — the answer key. @@ -26,6 +28,10 @@ rm -rf "$wt/.agents" "$wt/.claude" mkdir -p "$wt/.agents/skills" cp -r "$SKILL" "$wt/.agents/skills/aster-code-review" rm -rf "$wt/.agents/skills/aster-code-review/benchmark" # <-- drop the answer key +rm -rf "$wt/.agents/skills/aster-code-review/guideline-root" +mkdir -p "$wt/.agents/skills/aster-code-review/guideline-root/book/src/to-contribute" +cp -r "$HERE/../../../../book/src/to-contribute/coding-guidelines" \ + "$wt/.agents/skills/aster-code-review/guideline-root/book/src/to-contribute/" # Claude Code discovers skills under .claude/skills; mirror the repo's symlink layout. mkdir -p "$wt/.claude/skills" diff --git a/.agents/skills/aster-code-review/scripts/build_pass_prompt.sh b/.agents/skills/aster-code-review/scripts/build_pass_prompt.sh index ad2cf7c01..5fc5c9842 100755 --- a/.agents/skills/aster-code-review/scripts/build_pass_prompt.sh +++ b/.agents/skills/aster-code-review/scripts/build_pass_prompt.sh @@ -22,16 +22,74 @@ set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" SKILLDIR="$(cd "$HERE/.." && pwd)" REPO="$(cd "$SKILLDIR/../../.." && pwd)" # .agents/skills/aster-code-review -> repo root + # Where to read the guideline pages from. -# Defaults to the repo; -# the benchmark overrides it (ACR_GUIDELINE_ROOT) to a guidelines-only tree, -# so a historical worktree is reviewed with current guidelines without polluting its diff. -GROOT="${ACR_GUIDELINE_ROOT:-$REPO}" +# Priority: +# 1. explicit ACR_GUIDELINE_ROOT, for tests or external harnesses; +# 2. a guideline snapshot bundled beside the overlaid skill; +# 3. the current repo, for normal in-tree use. +# +# The benchmark cannot rely on the review agent preserving ACR_GUIDELINE_ROOT +# across its own shell commands, so overlay_skill.sh bundles a current snapshot +# into the skill package. This keeps historical worktrees on current guidelines +# without modifying their tracked book/ tree. +if [[ -n "${ACR_GUIDELINE_ROOT:-}" ]]; then + GROOT="$ACR_GUIDELINE_ROOT" +elif [[ -f "$SKILLDIR/guideline-root" ]]; then + GROOT="$SKILLDIR/guideline-root" +else + GROOT="$REPO" +fi input="${1:-}"; shift || true [[ -n "$input" && -f "$input" ]] || { echo "build_pass_prompt.sh: a readable is required" >&2; exit 2; } [[ $# -ge 1 ]] || { echo "build_pass_prompt.sh: at least one is required" >&2; exit 2; } +linked_guideline_pages() { # + python3 - "$1" "$GROOT/$1" <<'PY' +import posixpath +import re +import sys + +root_page = sys.argv[1] +root_file = sys.argv[2] +base_dir = posixpath.dirname(root_page) +seen = set() + +with open(root_file, encoding="utf-8") as file: + page_text = file.read() + +for link in re.findall(r"\[[^\]]+\]\(([^)]+)\)", page_text): + link = link.split("#", 1)[0] + if not link or "://" in link or link.startswith("#"): + continue + if link.endswith("/"): + link += "README.md" + path = posixpath.normpath(posixpath.join(base_dir, link)) + if not path.startswith("book/src/to-contribute/coding-guidelines/"): + continue + if path == root_page or path in seen: + continue + seen.add(path) + print(path) +PY +} + +inline_guidelines() { # + local gp="$1" gfile="$GROOT/$gp" sub + [[ -f "$gfile" ]] || return 0 + + printf 'Rely on the inlined guideline material below as the authoritative guideline context for this pass. Do not re-read `book/src/to-contribute/coding-guidelines/` from the worktree under review for guideline content.\n\n' + printf -- '--- guideline page (%s) ---\n\n' "$gp" + cat "$gfile"; printf '\n' + + while IFS= read -r sub; do + [[ -f "$GROOT/$sub" ]] || continue + printf '\n--- guideline subpage (%s) ---\n\n' "$sub" + cat "$GROOT/$sub"; printf '\n' + done < <(linked_guideline_pages "$gp") +} + # --- STABLE: the shared reviewer contract ------------------------------------ cat "$SKILLDIR/scripts/pass_contract.md" printf '\n' @@ -43,10 +101,7 @@ for persona in "$@"; do printf '===== PERSONA: %s =====\n\n' "$persona" cat "$pf"; printf '\n' gp="$(grep -oE 'book/[A-Za-z0-9/_-]+README\.md' "$pf" | head -1 || true)" - if [[ -n "$gp" && -f "$GROOT/$gp" ]]; then - printf -- '--- guideline page (%s) ---\n\n' "$gp" - cat "$GROOT/$gp"; printf '\n' - fi + [[ -n "$gp" ]] && inline_guidelines "$gp" done # --- VOLATILE: the review input (LAST; everything above is the cache prefix) ---