Add /ship: verify → review → raise orchestrator (#223)#225
Conversation
Add /ship (.claude/commands/ship.md): a human-invoked, supervised command that runs the full suite first and hard-gates on it (exit code, step 1), then runs a clean-context pr-review-toolkit + /review-slop pass, commits the warranted fixes, raises the PR via /raise-pr, and captures learnings. Change detection across step 2 uses a whole-tracked-tree content hash, not a *.cs porcelain filter. Stop-on-failure at every step. Add an unconditional best-effort per-PR review source to /capture-learnings: fetch the branch PR's review via `gh pr view` and route substantive points through the existing enforceability triage; a no-op when no PR/review exists, never a wait. Tidy /raise-pr: drop the spec-folder confirm AskUserQuestion so the folder is removed and committed without prompting, keeping /raise-pr composable by /ship with no interactive gate. Closes #223 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review A (step 2) findings applied by the /ship main loop: - capture-learnings.md: the unconditional PR-review source was nested under step 3's "skip this step when has_branch_context is false" clause, so a reader following control flow would skip the paragraph marked "runs regardless". Split step 3 into separately-gated git and PR sources so the skip scopes only to the git commands. - ship.md: de-duplicate the intro test-gate statement (was phrased three ways) and condense the trailing Review A/B rationale essay, keeping the non-obvious "never wait on the async review" point. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@claude Review this pull request. Analyse the code changes and provide feedback covering:
|
|
Claude finished @FrankRay78's task in 2m 22s —— View job Review
This PR adds three Claude Code slash-command markdown files (agent instructions, not application code), so most of the review is about the procedure they describe rather than compiled correctness. Overall the design is solid — the step‑1→step‑2 structural gate is real (review genuinely sits downstream of the test exit code, no hook needed), and the split of One correctness gap in the step‑3 change-detection gate (
Minor — dirty-baseline staging is underspecified ( Note, not a bug — hardcoded Convention adherence: no hard-wrapped markdown (good, per CLAUDE.md), no
Test coverage: not applicable in the traditional sense — these are Claude Code agent-instruction files, not testable C#/production code, consistent with sibling commands ( Spec/test-plan mismatches: none — no spec artifacts for this PR to check against. |
Two design changes so /ship can drive an automated (ralph) loop: - Remove the capture-learnings step. Reflection needs human curation and batches better across many features, so inside an unattended loop it would either block on the prompt or be auto-skipped to nothing — a category mismatch. /ship now ends at the raised PR with a soft nudge to run /capture-learnings at a later supervised checkpoint. The standalone /capture-learnings PR-review-source edit stays (independently useful). - Replace step 2's discretionary "decide which findings warrant a change" with a severity policy: confirmed Blocker/P1 must be fixed or /ship STOPs (never ship a known blocker); confirmed Important/P2 fixed when in-scope for the branch, else recorded as a follow-up (preserves scope discipline); Suggestion/P3 discretionary. Findings are validated real before acting, and every fix is re-verified by step 3. Revises #223 AC-7/AC-10 (capture-learnings was step 5 there); the underlying "never wait on the async @claude review" principle is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Design revision to #223 (AC-7 / AC-10) — intentionalAfter dogfooding, we changed two things about
Since #223's author is driving this, the AC-7/AC-10 revision is deliberate. Commit: 7aed36c. |
Review B (the async @claude PR review on #225) caught a correctness gap Review A missed: step 3 detected step-2 changes via `git diff HEAD`, which does not report new untracked files. If a review created a brand-new file (a new test, an extracted helper) as its only change, POST_HASH == PRE_HASH, so step 3 skipped both the re-verify and the commit and the fix silently never reached the PR. - Fold `git status --short` into the PRE_HASH/POST_HASH snapshot so new untracked files change the hash and trigger the re-verify + commit. - Commit the specific paths the step-2 loop edited or created (git add <paths>, includes new files), not `git add -A` — which also resolves the underspecified dirty-baseline staging the review flagged. Deferred (per /ship's own P2 scope policy): hardcoded `main` (reviewer marked not-a-bug; matches raise-pr.md's pattern) and the intended /raise-pr confirmation drop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addressed Review B's untracked-file finding (ed50165)Good catch — this was a real P1 that the in-flow synchronous review missed. Fixed:
Deferred, per |
|
@claude Please re-review, identify only showstoppers or important issues (P1/P2). |
|
Claude finished @FrankRay78's task in 3m 43s —— View job Re-review (P1/P2 only)
Confirmed the untracked-file fix ( P2 — step 3's targeted-path staging has no defined source for
Worst case: Suggested fix: don't rely on No other P1/P2s found. |
The step-3 staging machinery (content-hash baseline, untracked-file special-casing, "commit only the paths the loop edited") existed solely to support running /ship on a dirty working tree and committing only the review's edits. That ambition kept spawning correctness edge cases — the untracked-file gap fixed in ed50165, and Review B's follow-up that code-simplifier's direct edits aren't in the loop's own edited-paths set, so a code-simplifier-only change would never get committed. Drop the ambition. Step 0 now requires a clean tree (STOP with "commit or stash your changes before shipping" if dirty) — the happy path, since you commit your implementation before shipping. With a clean start, whatever git status shows after step 2 IS the review's edits and nothing else, so step 3 collapses to: non-empty status -> re-verify -> git add -A && commit. This is correct for edits from ANY source (the loop's own fixes and code-simplifier's) and closes both edge cases by removing the code that created them. Resolves Review B's P2 on #225. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolved by simplifying, not patching (a08a9f6)You're right that The whole step-3 staging complexity (hash baseline, untracked special-casing, "commit only the paths the loop edited") existed to support one thing: running Fix: step 0 now requires a clean tree (STOP with "commit or stash your changes before shipping" if dirty) — the normal workflow, since you commit your implementation before shipping. With a clean start, whatever |
|
@claude Please re-review, identify only showstoppers or important issues (P1/P2). |
|
Claude finished @FrankRay78's task in 1m 53s —— View job Re-review (P1/P2 only)
No P1/P2 issues found. Confirmed the fix is correct and complete:
|
Why
Closes #223. NetPace already had every ingredient a supervised ship flow composes —
/raise-pr,/review-slop,/capture-learnings, and thepr-review-toolkitplugin — but nothing wired them behind a single hard test-green gate. Today that's 3+ separate manual invocations./shipis the orchestrator that chains them so review and PR creation cannot happen against un-verified or red code.Per the issue, this is the small additive half of IMS#122 — the orchestrator only. NetPace never built IMS's green-ledger/Stop-hook machinery, so none of the "retire the proxy" scope applies here.
What changes
/shipcommand (.claude/commands/ship.md) — steps 0–5 with a structural step‑1→step‑2 gate:mainor no-commits-over-mainbefore any suite/review; capture a working-tree baseline hash);dotnet build ./src && dotnet test ./src, gate on exit code, red ⇒ STOP;pr-review-toolkitreviewers +/review-slop;/ship's own loop turns findings into edits;*.csporcelain filter);/raise-pr;/capture-learningson synchronous sources only./capture-learnings— adds an unconditional, best-effort per-PR review source (gh pr view --json comments,reviews) routed through the existing enforceability triage; a no-op when no PR/review exists, never a wait./raise-prtidy — drops the spec-folder confirmationAskUserQuestionso the folder is removed and committed without prompting, keeping/raise-prcomposable by/shipwith no interactive gate.Non-obvious things a reviewer should know
/shipreview (Review A), never the async@claudePR review (Review B)./shipdeliberately does not wait on or prompt about Review B — it's author-gated (claude.yml) and posts minutes later for a human to read at merge. This is the core design decision (issue AC-10).gh pr createPreToolUsehook re-runs the suite at PR creation anyway, so a skip would save nothing and could let review run before a late hook-block./shipalways runs step 1 (AC-5)..csedits (.csproj,Directory.Packages.props,.json) and ignores files already dirty before the review — a*.cs-onlygit statusfilter would miss both.gh pr createhook is unchanged — control flow is the gate, by design.How this branch was produced
This PR was dogfooded through
/shipitself: step 1 ran green (616 tests), step 2'scode-reviewer+ slop review surfaced a real control-flow contradiction in the/capture-learningsedit (an "unconditional" paragraph nested under a conditionally-skipped step) plus two verbosity trims,/ship's loop applied them, step 3 re-verified green and committed them (0a80e4e), and this PR is step 4.How to verify
ship.md— confirm the step‑1→step‑2 gate is structural (review is downstream of the exit code) with no ordering hook added./capture-learnings's PR-review source is unconditional and clearly not skipped whenhas_branch_contextis false./raise-prno longer prompts to delete the spec folder.settings.jsonand thegh pr createhook are untouched; no Constitution amendment.Related