Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ Per-skill host-conditional audit: [tests/cross-llm-coverage.md](tests/cross-llm-

7. **alignment-check** - Activates after adversarial review of plan passes. Narrowly structural: every design requirement maps to a plan task; every plan task traces to a design requirement; the Scope Manifest is well-formed (forward + reverse + manifest trace via `tests/plan-scope-check.sh`).

8. **scope-lock** - Activates immediately after `alignment-check` PASS. Stamps the plan with `Locked <timestamp>`, computes the manifest's sha256 into `<plan>.scope-lock`, commits both. From this point until completion (or an explicit user-approved amendment), the task list, PR count, and feature scope are immutable. Design backports that do not change the manifest are allowed; manifest changes go through ADR + alignment. The lock hash covers only the `## Scope Manifest` block, so explanatory design/task notes can evolve without invalidating scope. `subagent-driven-development` re-checks the lock between tasks; `finishing-a-development-branch` re-checks before any PR is created. Resume claims are session-owned: `scope-lock-claim` records repo/branch/objective metadata and blocks mismatched objective claims unless the handoff is explicit with `--confirmed`. When the design is fully complete, `bash "${CLAUDE_PLUGIN_ROOT:-.}/hooks/scope-lock-complete" <plan> --evidence "<verification>"` marks it `Complete`, removes the lock file, and prunes session reminder traces.
8. **scope-lock** - Activates immediately after `alignment-check` PASS. Stamps the plan with `Locked <timestamp>`, computes the manifest's sha256 into `<plan>.scope-lock`, commits both. From this point until completion (or an explicit user-approved amendment), the task list, PR count, and feature scope are immutable. Design backports that do not change the manifest are allowed; manifest changes go through ADR + alignment. The lock hash covers only the `## Scope Manifest` block, so explanatory design/task notes can evolve without invalidating scope. `subagent-driven-development` re-checks the lock between tasks; `finishing-a-development-branch` re-checks before any PR is created. Resume claims are session-owned: `scope-lock-claim` records repo/branch/objective metadata and blocks mismatched objective claims unless the handoff is explicit with `--confirmed`. When the design is fully complete, run `bash hooks/scope-lock-complete <plan> --evidence "<verification>"` from the autodev checkout/plugin root to mark it `Complete`, remove the lock file, and prune session reminder traces.

9. **subagent-driven-development** or **executing-plans** - Activates with a locked plan. Dispatches fresh subagent per task with two-stage review (spec compliance, then code quality). Between tasks, re-runs the scope-lock check; on lock drift, stops the line and surfaces the discrepancy. Phase/task completions are logged in compressed JSONL to `.autodev/state/phase-progress.jsonl` when a locked plan continues.

Expand Down
5 changes: 3 additions & 2 deletions hooks/completion-claim-guard
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ hook_input=$(cat || true)

cwd_dir=$(printf '%s' "$hook_input" | jq -r '.cwd // empty' 2>/dev/null || true)
[ -z "$cwd_dir" ] && cwd_dir="${PWD}"
. "$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" && pwd)/lib-autodev-paths.sh" 2>/dev/null || true
hook_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" && pwd)"
. "${hook_dir}/lib-autodev-paths.sh" 2>/dev/null || true
declare -f autodev_repo_root >/dev/null 2>&1 || autodev_repo_root() { printf '%s\n' "${1:-$PWD}"; }
ADK_ROOT="$(autodev_repo_root "$cwd_dir")"

Expand Down Expand Up @@ -157,7 +158,7 @@ If this is only a phase/task completion:
- Continue automatically into the next phase/task from the Scope Manifest.

Only stop if one of these is true:
- The entire locked design is complete and verified; run bash \"\${CLAUDE_PLUGIN_ROOT:-.}/hooks/scope-lock-complete\" <plan> --evidence \"<verification>\" to mark it complete and remove lock traces.
- The entire locked design is complete and verified; run bash \"${hook_dir}/scope-lock-complete\" <plan> --evidence \"<verification>\" to mark it complete and remove lock traces.
- There is a hard blocker that requires human input.
Comment on lines 160 to 162
- The next action is a production deploy or destructive production change without already-recorded human approval.

Expand Down
4 changes: 2 additions & 2 deletions hooks/pre-tool-scope-guard
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,14 @@ case "$tool_name" in
[ -z "$fpath" ] && continue

# ── 5. scope-lock files ──────────────────────────────────────────────
# Agent path: bash "${CLAUDE_PLUGIN_ROOT}/hooks/scope-lock-apply" <plan-path>
# Agent path: bash hooks/scope-lock-apply <plan-path> from the autodev checkout/plugin root.
# Operator path (pre-session): export SUPERPOWERS_SCOPE_LOCK_WRITE=1
if printf '%s' "$fpath" | grep -qE '\.scope-lock$'; then
if [ "${SUPERPOWERS_SCOPE_LOCK_WRITE:-}" != "1" ]; then
_reason="Writing to '$(basename "$fpath")' is blocked —"
_reason="${_reason} .scope-lock files must be written by the scope-lock skill's helper,"
_reason="${_reason} not via the Write tool."
_reason="${_reason} Run: bash \"\${CLAUDE_PLUGIN_ROOT}/hooks/scope-lock-apply\" <plan-path>."
_reason="${_reason} Run: bash hooks/scope-lock-apply <plan-path> from the autodev checkout/plugin root."
_reason="${_reason} The helper extracts the Scope Manifest section, computes its sha256,"
_reason="${_reason} and writes the lock file via shell redirection (which is not blocked)."
_reason="${_reason} Direct Write/Edit calls break the manifest integrity guarantee"
Expand Down
2 changes: 1 addition & 1 deletion skills/alignment-check/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ Re-run alignment check after revision. **Max 2 revision cycles** before escalati
After alignment passes, **lock the plan's scope** so subsequent execution cannot silently rescope. Invoke `autodev:scope-lock` with the plan path. The scope-lock skill:

1. Stamps the plan's `**Status:**` line with `Locked <UTC ISO-8601 timestamp>`.
2. Writes the lock file by running the repo/plugin helper, e.g. `bash hooks/scope-lock-apply <plan-path>` from the autodev checkout or `bash "${CLAUDE_PLUGIN_ROOT}/hooks/scope-lock-apply" <plan-path>` when that host env var is present. Do **not** use the Write tool for `*.scope-lock` paths. The helper computes the manifest's sha256 and writes `<plan-path>.scope-lock` via shell redirection.
2. Writes the lock file by running the repo/plugin helper, e.g. `bash hooks/scope-lock-apply <plan-path>` from the autodev checkout/plugin root. Do **not** use the Write tool for `*.scope-lock` paths. The helper computes the manifest's sha256 and writes `<plan-path>.scope-lock` via shell redirection.
3. Commits both files (`chore: lock scope for <feature> (alignment passed)`).

After the lock is in place, proceed to execution:
Expand Down
18 changes: 9 additions & 9 deletions skills/scope-lock/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,14 @@ When the whole locked design is genuinely complete and verified, close the lock
instead of leaving stale reminders in the workspace:

```bash
bash "${CLAUDE_PLUGIN_ROOT:-.}/hooks/scope-lock-complete" docs/plans/<plan>.md --evidence "<verification summary>"
bash hooks/scope-lock-complete docs/plans/<plan>.md --evidence "<verification summary>"
```

The helper verifies the current manifest hash when the checker is available,
changes the plan status from `Locked` to `Complete <UTC>`, removes
`<plan>.scope-lock`, prunes matching `.claude/autodev-state/session-locks.jsonl`
and lock snapshot rows, and appends a compact completion row to
`.autodev/state/phase-progress.jsonl`.
Run the command from the autodev checkout/plugin root. The helper verifies the
current manifest hash when the checker is available, changes the plan status
from `Locked` to `Complete <UTC>`, removes `<plan>.scope-lock`, prunes matching
`.claude/autodev-state/session-locks.jsonl` and lock snapshot rows, and appends
a compact completion row to `.autodev/state/phase-progress.jsonl`.

Do not manually edit `.scope-lock` files or leave a completed design in
`Locked` state. Stale locks cause future prompt/stop/pre-compact hooks to
Expand All @@ -204,7 +204,7 @@ and does not survive across sessions — a fresh agent inherits no rows from
the killed one.

```bash
bash "${CLAUDE_PLUGIN_ROOT:-.}/hooks/scope-lock-claim" docs/plans/<plan>.md
bash hooks/scope-lock-claim docs/plans/<plan>.md
```

The helper verifies the plan is Locked, has a `.scope-lock` sidecar, and that
Expand All @@ -231,7 +231,7 @@ resume-target checkpoint showing:
Intentional handoff is still allowed, but it must be explicit:

```bash
bash "${CLAUDE_PLUGIN_ROOT:-.}/hooks/scope-lock-claim" docs/plans/<plan>.md --confirmed
bash hooks/scope-lock-claim docs/plans/<plan>.md --confirmed
```

Use `--confirmed` only after the user-visible task, repo, branch, and locked
Expand All @@ -256,7 +256,7 @@ out of capacity), close the lock as **Abandoned** rather than leaving stale
state:

```bash
bash "${CLAUDE_PLUGIN_ROOT:-.}/hooks/scope-lock-abandon" docs/plans/<plan>.md \
bash hooks/scope-lock-abandon docs/plans/<plan>.md \
--reason "user pivoted away from feature X"
```

Expand Down
44 changes: 44 additions & 0 deletions tests/hook-contracts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,49 @@ PLAN
pass "completion-claim-guard: flattened checkpoint keeps heading separator"
}

test_completion_continuation_block_uses_host_neutral_helper_guidance() {
local tmp output reason
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' RETURN
mkdir -p "$tmp/docs/plans" "$tmp/tests"
cat >"$tmp/docs/plans/example.md" <<'PLAN'
# Example Plan

## Scope Manifest

**PR Count:** 1
**Tasks:** 1
**Out of scope:**
- (none)

**PR Grouping:**

| PR # | Title | Tasks | Branch |
|------|-------|-------|--------|
| 1 | Example | Task 1 | feat/example |

**Status:** Locked 2026-05-25T00:00:00Z

### Task 1: Example
PLAN
cp tests/plan-scope-check.sh "$tmp/tests/plan-scope-check.sh"
chmod +x "$tmp/tests/plan-scope-check.sh"
bash hooks/scope-lock-apply "$tmp/docs/plans/example.md" >/dev/null

output="$(run_hook completion-claim-guard '{"cwd":"'"$tmp"'","stop_hook_active":false,"last_assistant_message":"Task 1 complete."}')"
reason="$(printf '%s' "$output" | jq -r '.reason')"

if printf '%s' "$reason" | grep -q 'CLAUDE_PLUGIN_ROOT'; then
fail "completion-claim-guard: helper guidance must not assume Claude host env vars: ${reason}"
return
fi
if ! printf '%s' "$reason" | grep -q 'scope-lock-complete'; then
fail "completion-claim-guard: expected scope-lock-complete helper guidance, got: ${reason}"
return
fi
pass "completion-claim-guard: helper guidance is host-neutral"
}

test_pretool_records_session_lock_for_scope_lock_apply() {
local tmp transcript output state_file
tmp="$(mktemp -d)"
Expand Down Expand Up @@ -1891,6 +1934,7 @@ test_scope_lock_complete_preflights_progress_write
test_scope_lock_complete_rejects_progress_directory
test_completion_continuation_block
test_completion_continuation_block_keeps_heading_separator_when_flattened
test_completion_continuation_block_uses_host_neutral_helper_guidance
test_pretool_records_session_lock_for_scope_lock_apply
test_pretool_ignores_prose_mention_of_locked_status
test_completion_ignores_ambiguous_workspace_locks_when_session_has_no_lock
Expand Down
Loading