diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 21b0ae0..ff2f26d 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ { "name": "autodev", "description": "Autonomous development workflow skills for coding agents", - "version": "6.1.0", + "version": "6.1.1", "source": "./", "author": { "name": "Jon Langevin", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 6927941..d764e78 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "autodev", "description": "Autonomous development workflow skills for coding agents: design, review, planning, execution, monitoring, and retrospectives", - "version": "6.1.0", + "version": "6.1.1", "author": { "name": "Jon Langevin", "email": "jon@gocodealone.com" diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index 8ad65b9..c6375bf 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "autodev", "displayName": "Autonomous Dev Kit", "description": "Autonomous development workflow skills for coding agents", - "version": "6.1.0", + "version": "6.1.1", "author": { "name": "Jon Langevin", "email": "jon@gocodealone.com" diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 27df6f3..0b6cac2 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,26 @@ # Autonomous Dev Kit Release Notes +## v6.1.1 — 2026-05-27 + +Cascade retro plugin-level follow-ups bundle. + +- **adversarial-design-review**: added "plugin-loader runtime layout" + "config-validation schema rules" plan-phase bug classes +- **writing-plans / verification-before-completion**: added `golangci-lint run` pre-push verification for Go-repo PRs +- **scope-lock**: new `hooks/scope-lock-publish` sibling helper publishes a Locked plan + `.scope-lock` sidecar via a chore PR on the default branch (sidesteps the case where design+plan branch never merges) +- **scope-lock**: new `tests/cascade-preflight.sh` verifies each plugin repo's last Release workflow was green before cascade launch (catches ManifestProvider-class gaps cheap) +- **subagent-driven-development**: spec-reviewer for IaC-test-scenario PRs must now execute ≥1 scenario end-to-end before approving (`bash -n` insufficient) +- **RELEASE-NOTES**: backfilled missing v6.1.0 entry + +All 5 follow-ups originate from `workflow-plugin-infra/docs/retros/2026-05-27-dns-provider-cascade-retro.md`. + +## v6.1.0 — 2026-05-26 + +Session-scoped lock nag + claim/abandon helpers (PR #42 + #43). + +- Anchor-match `Status: Locked` substring (eliminates substring-bug demoed live during PR review) +- Workspace-fallback removed when session has no attribution +- New helpers: `scope-lock-claim` (resume after restart), `scope-lock-abandon` (close never-completed lock) + ## v6.0.5 (2026-05-26) ### Scope-lock completion cleanup diff --git a/hooks/scope-lock-publish b/hooks/scope-lock-publish new file mode 100755 index 0000000..b05951c --- /dev/null +++ b/hooks/scope-lock-publish @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# hooks/scope-lock-publish +# Publishes a Locked plan + its .scope-lock sidecar to the default branch +# via a chore PR so the lock survives even when the design+plan feature +# branch never merges to main/master. +# +# Usage: +# hooks/scope-lock-publish docs/plans/example.md [--base main] +# +# Preconditions: +# - plan exists at given path AND is committed on the current branch +# (along with its .scope-lock sidecar) +# - plan Status: line shows "Locked YYYY-MM-DD..." +# - working tree clean (no staged/unstaged changes) +# - gh CLI authenticated +set -euo pipefail +[ "${SUPERPOWERS_HOOKS_DISABLE:-}" = "1" ] && exit 0 + +plan="" +base="main" +while [ "$#" -gt 0 ]; do + case "$1" in + --base) base="$2"; shift 2;; + --base=*) base="${1#--base=}"; shift;; + -h|--help) printf 'Usage: %s [--base ]\n' "$0"; exit 0;; + *) if [ -z "$plan" ]; then plan="$1"; shift; else printf 'unexpected arg: %s\n' "$1" >&2; exit 2; fi;; + esac +done + +[ -n "$plan" ] || { printf 'scope-lock-publish: missing plan path\n' >&2; exit 2; } +[ -f "$plan" ] || { printf 'scope-lock-publish: plan not found: %s\n' "$plan" >&2; exit 2; } +[ -f "${plan}.scope-lock" ] || { printf 'scope-lock-publish: lock file not found: %s.scope-lock — run scope-lock-apply first\n' "$plan" >&2; exit 2; } +grep -q '^\*\*Status:\*\* Locked ' "$plan" || { printf 'scope-lock-publish: plan Status: is not Locked — refuse\n' >&2; exit 2; } + +# Committed-file guard (files must be tracked; clean-tree guard ensures +# they're also committed — staged-only files would fail the cached diff check). +git ls-files --error-unmatch "$plan" "${plan}.scope-lock" >/dev/null 2>&1 || { + printf 'scope-lock-publish: plan+lock must be committed on current branch before publishing\n' >&2 + exit 2 +} + +git diff --quiet && git diff --cached --quiet || { + printf 'scope-lock-publish: working tree has uncommitted changes; stash or commit first\n' >&2 + exit 2 +} + +orig_branch=$(git symbolic-ref --short HEAD 2>/dev/null) || { + printf 'scope-lock-publish: HEAD is detached; check out a branch first\n' >&2 + exit 2 +} + +slug=$(basename "$plan" .md) +branch="chore/scope-lock-init-${slug}" + +if git rev-parse --verify -q "refs/heads/$branch" >/dev/null 2>&1; then + printf 'scope-lock-publish: branch %s already exists locally; aborting\n' "$branch" >&2 + exit 2 +fi +if git ls-remote --exit-code origin "refs/heads/$branch" >/dev/null 2>&1; then + printf 'scope-lock-publish: branch %s already exists on origin; aborting\n' "$branch" >&2 + exit 2 +fi + +src_ref=$(git rev-parse HEAD) + +git fetch origin "$base" --quiet +git checkout -b "$branch" "origin/$base" --quiet + +git checkout "$src_ref" -- "$plan" "${plan}.scope-lock" +git add "$plan" "${plan}.scope-lock" +git commit -m "chore: publish scope-lock for $slug" --quiet + +git push -u origin "$branch" --quiet +pr_url=$(gh pr create --title "chore: publish scope-lock for $slug" \ + --body "Auto-published by scope-lock-publish so the locked plan + sidecar land on $base before execution dispatches." \ + --base "$base") +pr_num=$(printf '%s' "$pr_url" | grep -oE '[0-9]+$') + +gh pr checks "$pr_num" --watch --fail-fast >/dev/null 2>&1 || true + +# Switch back BEFORE delete-branch fires (cycle-4 fix: gh pr merge --delete-branch +# deletes local copy too; Git blocks deleting currently-checked-out branch). +git checkout "$orig_branch" --quiet +gh pr merge "$pr_num" --squash --admin --delete-branch +git branch -D "$branch" 2>/dev/null || true + +printf 'scope-lock-publish: PR %s merged; plan + sidecar now on %s\n' "$pr_url" "$base" diff --git a/skills/adversarial-design-review/SKILL.md b/skills/adversarial-design-review/SKILL.md index 909382d..6d70686 100644 --- a/skills/adversarial-design-review/SKILL.md +++ b/skills/adversarial-design-review/SKILL.md @@ -109,6 +109,8 @@ inherits the design's blast radius) and adds: | **Missing rollback wiring** | The design specifies a rollback story (per the design-phase class above). Is it actually implemented in the plan as a task or step? Or is it a paragraph nobody is going to write code for? | | **Missing integration proof** | For multi-component changes, does the plan include an end-to-end or integration verification that exercises the real boundary? If it only tests each component with mocks, flag it unless the design explicitly justified that as sufficient. | | **Infrastructure verification mismatch** | For infrastructure-affecting changes, does the plan verify render/plan/apply/dry-run, secret wiring, migration order, rollback, and post-deploy health as appropriate? If not, flag it. | +| **Plugin-loader runtime layout** | Plans that spawn or load an external plugin process must build the binary in a layout the host's discovery code accepts. For wfctl: `$WFCTL_PLUGIN_DIR//` + sibling `plugin.json`. Plans that `go build -o /tmp/single-binary` without the subdir + manifest sidecar will fail at runtime. | +| **Config-validation schema rules** | Plans that create new config files validated by a schema or CLI tool must satisfy that tool's invariants (e.g., for wfctl: `checkEntryPoints` requires ≥1 entry-point module like `http.server`/`scheduler.modular`/`messaging.broker`, OR a trigger/route/subscription/job/pipeline). Plans omitting required entry-point modules pass `bash -n` but fail schema validation at CI. | ## Process diff --git a/skills/scope-lock/SKILL.md b/skills/scope-lock/SKILL.md index 0b7cd55..8d776c3 100644 --- a/skills/scope-lock/SKILL.md +++ b/skills/scope-lock/SKILL.md @@ -25,6 +25,7 @@ Manual invocation: - **At execution checkpoints** (between tasks): verify reality still matches the lock. - **At completion time** (before PR creation): assert manifest is fully satisfied. - **At amendment time** (user-approved scope change, or bug/assumption backport that changes the manifest): record the amendment as an ADR, update the design/plan/manifest, re-stamp. +- **At cascade launch time** (before scope-lock-apply when the plan's PR Grouping table touches multiple plugin repos that will be re-tagged): run `tests/cascade-preflight.sh` to verify each repo's most-recent Release workflow on main was SUCCESS. ## The Scope Manifest @@ -271,6 +272,7 @@ status line back to `Locked YYYY-MM-DDTHH:MM:SSZ` by hand and re-run - `scope-lock-claim ` — attribute an existing lock to the current session (resume after restart). - `scope-lock-complete --evidence ""` — close the lock as Complete. - `scope-lock-abandon --reason ""` — close the lock as Abandoned (no completion verification). +- `scope-lock-publish [--base ]` — publish a Locked plan + its `.scope-lock` sidecar to the default branch via a chore PR. Use when the design+plan branch will not merge to main (e.g., separate per-PR feature branches consume the plan markdown but not the lock file). The set of helper names that update `session-locks.jsonl` is centralized in `hooks/pre-tool-scope-guard`'s `SESSION_LOCK_RECOGNIZED` variable; helpers and diff --git a/skills/subagent-driven-development/spec-reviewer-prompt.md b/skills/subagent-driven-development/spec-reviewer-prompt.md index aee6f0c..1bca3c5 100644 --- a/skills/subagent-driven-development/spec-reviewer-prompt.md +++ b/skills/subagent-driven-development/spec-reviewer-prompt.md @@ -48,6 +48,12 @@ Task tool (general-purpose): If any acceptance bullet has no corresponding change: **MISSING**. + ### Pre-approval gate (for IaC-test-scenario PRs) + + For PRs whose changes include `scenarios/`, `tests/integration/`, or files matching `*/test/run.sh`: run AT LEAST ONE scenario end-to-end before approving. `bash -n` (syntax check) is insufficient — past cascade reviews have caught Critical bugs (state-backend mismatch, plugin-loader layout) only when the reviewer actually executed the script. + + Heuristic scope: file path contains `scenarios/`, `tests/integration/`, OR matches `*/test/run.sh`. + 3. **For TDD tasks, run the test yourself**. Do not trust "I ran it": - "RED" task (failing test): `go test ./...` (or equivalent) MUST FAIL when you run it. If it passes, the test isn't asserting what the diff --git a/skills/verification-before-completion/SKILL.md b/skills/verification-before-completion/SKILL.md index 2ebba41..04c9a45 100644 --- a/skills/verification-before-completion/SKILL.md +++ b/skills/verification-before-completion/SKILL.md @@ -36,6 +36,7 @@ Skip step = unverified claim. | regression test works | red → green proof | green only | | agent completed | inspect diff + verify | agent report | | requirements met | checklist vs plan/design | tests alone | +| lint clean (Go-repo PR) | `golangci-lint run` exit 0 | tests green alone | ## Red Flags diff --git a/skills/writing-plans/SKILL.md b/skills/writing-plans/SKILL.md index 6732235..250f814 100644 --- a/skills/writing-plans/SKILL.md +++ b/skills/writing-plans/SKILL.md @@ -97,6 +97,7 @@ When writing a plan task, the verification step must match the change class. A g | Hook / trigger / event handler | fire the event; observe handler runs | logged side effect confirmed; assertion passes | | Multi-component boundary | run an integration/E2E path with real adjacent components where feasible | request/event crosses boundary; downstream side effect observed | | Infrastructure change | render/validate/plan/dry-run plus targeted apply in safe env when available | expected resource diff; no destructive prod action without approval | +| Go-repo code change | `golangci-lint run --new-from-rev=origin/` before push | exit 0 | These examples are illustrative minimums; per-task `Expected:` fields must be literal values the check can assert against. diff --git a/tests/cascade-preflight.sh b/tests/cascade-preflight.sh new file mode 100755 index 0000000..a7e0ca6 --- /dev/null +++ b/tests/cascade-preflight.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# tests/cascade-preflight.sh +# Pre-cascade gate: verify each plugin repo's most-recent Release +# workflow run was SUCCESS. Catches release-pipeline-class gaps +# (e.g., ManifestProvider missing) before scope-lock + dispatch. +# +# Usage: +# tests/cascade-preflight.sh ... +# tests/cascade-preflight.sh GoCodeAlone/workflow-plugin-cloudflare GoCodeAlone/workflow-plugin-namecheap +# +# Note: Release workflows typically trigger on tag-push (push: tags: 'v*'), +# not branch-push. headBranch for tag-triggered runs is the tag name (e.g., +# 'v1.0.0'), not 'main'. Don't filter --branch. +set -euo pipefail + +[ "$#" -ge 1 ] || { printf 'Usage: %s [...]\n' "$0" >&2; exit 2; } + +failed=0 +for repo in "$@"; do + conclusion="" + for wf in release.yml Release.yml; do + result=$(gh run list --repo "$repo" --workflow "$wf" --limit 1 \ + --json conclusion --jq '.[0].conclusion // ""' 2>/dev/null || echo "") + if [ -n "$result" ]; then + conclusion="$result" + break + fi + done + conclusion="${conclusion:-not-found}" + + if [ "$conclusion" = "success" ]; then + printf ' ✓ %s: Release workflow last run = success\n' "$repo" + else + printf ' ✗ %s: Release workflow last run = %s — FIX BEFORE CASCADE\n' "$repo" "$conclusion" >&2 + failed=$((failed+1)) + fi +done + +[ "$failed" -eq 0 ] || { printf '\nPreflight FAIL: %d repo(s) have broken Release pipelines\n' "$failed" >&2; exit 1; } +printf '\nPreflight PASS: all %d repo(s) have green Release workflows\n' "$#"