Finish a feature — run verification, an adversarial review gate (re-grounded on the original design doc + ticket ACs, not the plan) and a deferral-closure gate, then create the PR, retain learnings, and hand off cleanup to the terminal.
60
—
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
You are finishing a feature. Run the full completion pipeline before handing off to the developer for worktree cleanup.
IMPORTANT: Do NOT clean up the worktree or switch branches from inside this session — that is a terminal action performed by the developer after the session ends.
TICKET=$(extract_ticket_id "$(git branch --show-current)") || TICKET=none (lib abstains → none).mark_chapter with {title: "Finish — <TICKET>", summary: "Finishing the feature"}.
If mark_chapter is unavailable (e.g. running outside Claude Code), skip silently.[ -t 1 ] && printf '\e]2;%s — Finish\007' "<TICKET>" || truemark_chapter (step 2).Source the determinism-fix lib once before your bash work:
for f in ~/.claude/lib/determinism/functions/*.sh; do . "$f"; doneThe functions are sound, not complete (~/.claude/lib/determinism/CONTRACT.md): exit
0 = confident value, 10 = abstain → AI, 1 = error → AI. Deterministic-first; the
model only runs on a non-zero exit. Used here: extract_ticket_id, is_protected_branch,
count_commits. The commit message + PR body TEXT stay model-authored (creative) — only
their FORMAT is pinned (Steps 6 & 7).
Assess the current state. Run:
git branch --show-current
git status
git diff --stat
git log --oneline main..HEAD 2>/dev/null || git log --oneline master..HEADBranch guard (D2 — deterministic, hard stop). Do not "confirm by eye"; run the lib predicate:
BRANCH=$(git branch --show-current)
if is_protected_branch "$BRANCH"; then echo "BLOCKED: on protected branch '$BRANCH' — refusing to finish"; exit 1; fiThen confirm there are changes to finalize.
Run verification checks. Execute the full check pipeline:
devflow checkAlso confirm the generated flow mini-plugins are in sync with their canonical skills (a skill edit that forgot make flows must not ship a drifted flow):
make flows-checkIf devflow check is not available, run lint, types, and tests directly:
yarn lint
yarn build
yarn test --changedSince=mainIf checks fail, report the failures clearly and stop. Do NOT continue past this step with failing checks. Help the user fix issues if they ask.
Diff self-test (Surgical Changes). Run git diff origin/main...HEAD and scan for:
If any exist, surface them to the user. Offer to move them to a separate PR or revert. Don't silently ship them.
Source-grounded review gate (the adversarial guardrail).
Why this step exists. Passing the locked tests is necessary but not sufficient. Across this pipeline the requirements get compressed into a spec + plan, and every downstream phase is handed that compression as its "only authoritative input" — so any requirement the plan silently dropped, and any correctness/robustness issue the spec never spelled out, sails through to here unseen. The implementations that beat ours on the same spec earned their edge from an adversarial review loop (a human reviewer, a review bot) that this autonomous pipeline otherwise has no equivalent of. This gate adds that missing pass — and it re-grounds on the ORIGINAL sources, not the plan.
a. Identify the ORIGINAL authoritative sources — NOT the plan.
grep -roEh '[^ ]+\.(md|pdf|txt)' .devflow/state/"$BRANCH"/*.md 2>/dev/null | sort -u. If that yields exactly one artefact, use it; if zero or several, THEN scan the frozen-state "Source-of-truth artefacts", the ticket's linked docs, or ask the user (the model only judges when the grep is ambiguous).b. Capture the COMPLETE feature delta, then review it. Stage everything first so committed, uncommitted, AND untracked changes are all in scope, and diff against the merge-base — git diff HEAD is empty once executing-plans has committed, and /devflow:review's local mode only ever sees the working tree:
git add -A
BASE="$(git merge-base origin/main HEAD)"
git diff --cached "$BASE" --stat # scope sanity-check (see "Fail loud" below)
git diff --cached "$BASE" # the exact diff handed to the reviewersDispatch two subagents in a single message (parallel) against THAT diff:
verifier) — does the diff satisfy EVERY requirement in the original design doc and EVERY ticket AC? Walk the design doc's detail sections (Design, Resilience, edge-case discussion, inline code blocks/comments) — not just its summary or "migration / MR-N" checklist. Behavioral requirements buried in discussion are precisely the ones earlier phases drop while still capturing the headline deliverables. List each requirement unmet or only partially met, with its source citation.debugger) — correctness, error handling, resilience, and how the real runtime dependencies behave (endpoint/payload shapes, failure modes, concurrency, idempotency). Surface issues a careful reviewer would raise even when the spec is silent on them./devflow:review for this gate: pre-PR its local mode reviews only the working tree (empty once the work is committed) and it takes no diff-range argument, so it silently reviews nothing. /devflow:review is the right tool after Step 7, by PR URL. Either way this is a fresh review pass; never self-attest that the work is aligned.git diff --cached "$BASE" --stat is empty or much smaller than the feature, you are reviewing the wrong range — a clean review of an empty diff is NOT a pass. Fix the range before continuing.c. Gate on the findings. Present them as a pinned table (D4), not a free-text blob —
| Finding | Severity | Source | (Severity ∈ Critical/Important/Suggestion), no prose
preamble like "I found the following issues". Then gate by severity. Every Critical/Important alignment-gap or bug must be fixed, or explicitly accepted by the user (via AskUserQuestion, with the reason and any follow-up ticket recorded) before continuing. Do not open the PR with unresolved Critical/Important findings. For every alignment-gap you fix here, add or extend a test that locks the recovered requirement — the locked suite was generated from the same compressed sources and does not yet cover it, so the fix would otherwise ship with zero regression protection.
Deferral closure gate. Enumerate every conscious deferral and open item from this build:
TODO / FIXME introduced in this feature's diff.Deferrals raised only verbally during implementation do not survive into this session (implementation ran in a separate spawned session). Treat "nothing recorded" as suspicious, not as "none": also recall from Hindsight for this branch/feature, and run the deferral grep deterministically (D5 — run it, do not narrate from memory): git diff "$(git merge-base origin/main HEAD)"..HEAD | grep -E '^\+.*(TODO|FIXME)'. If anything was deferred but is written down nowhere, you cannot close this gate — ask the user.
For each, it must be either (a) done now, (b) explicitly accepted by the user as a tracked follow-up (record where it is tracked), or (c) pulled into this MR. A deliberate decision to defer is fine; a deferral that ships unnoticed is the failure mode this gate exists to catch — it is how a correctly-identified-but-blocked deliverable (CI wiring, an ops hook, an alert) ends up missing from the MR with nobody realising.
Stage and commit. If there are uncommitted changes:
git add -A^(feat|fix|refactor|chore|test|docs)(\([^)]+\))?: .{1,72}$ (conventional commits, subject ≤72 chars).$TICKET) if not none.Push and create PR. Push the branch and create a pull request:
git push -u origin HEADThen create the PR using gh:
gh pr create --title "<title>" --body "<body>"The PR body MUST use these exact section headings, in this order (D7 — pinned format):
## Summary — 2-3 bullet points of changes## Ticket — ticket reference (or "none")## Testing — what was verifiedPresent the PR URL to the user.
Retain session learnings. Review the session and retain important discoveries:
retain for each learning, tagged with the project namePresent the summary and hand off cleanup. Compute the counts deterministically (D8 — do not narrate from memory):
COMMITS=$(count_commits "origin/main..HEAD") || COMMITS=$(git rev-list --count origin/main..HEAD)
FILES=$(git diff --stat origin/main..HEAD | tail -1 | grep -oE '[0-9]+ file' | grep -oE '[0-9]+')Emit the block with those exact integers (no fences inside it):
## Feature Complete
**Branch:** <branch-name>
**PR:** <pr-url>
**Commits:** <COMMITS>
**Files changed:** <FILES>
### Checks
- [PASS/FAIL] Lint
- [PASS/FAIL] Types
- [PASS/FAIL] Tests
### Learnings Retained
- [list of retained memories]
### Cleanup (run from your terminal)
To remove the worktree after PR is merged:
devflow done <branch-name>
# or manually:
wt drop <branch-name>main from inside the agent — use PRs.$ARGUMENTS
9556c94
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.