Before executing project helpers, read runtime selection and operating rules.
GSD Path Ship PhaseReuse proven review scope; dispatch reviewers for remaining claims. They never fix product code.
After completion, use the executable phase handoff in AGENTS.md. Before completion, preserve the approval and recovery gates below.
Require pipeline: gsd-path/v2 in .project/STATE.md; a missing or different
marker returns to $gsd-path for ownership checking. Read the local
reviewer role and
dispatch contract, resolve them to absolute paths,
and follow that runtime-specific dispatch contract. Resolve
scripts/isolation.py for verify sidecars; do not invent detached checkouts.
Resolve scripts/build_state.py for the landed-task proof and the verify
ledger.
This skill verifies first and never archives or ships before explicit final approval.
Wave reviews are owned by the build orchestrator; this phase never runs them.
Final mode
If STATE.md has a concrete archive path and phase is ship or shipped,
skip ordinary final-mode preconditions and resume Archive transaction
below. Also enter archive recovery when STATE is ship/active, archive is
null, and the only otherwise-unexpected path is the deterministic
.project/.STATE.md.gsd-path-tmp; prepare removes that interrupted temp
before safely persisting a transaction identity. Moved artifacts are
transaction state, not missing inputs. A concrete archive in any other phase
blocks without mutation. Otherwise, first scan ANSWERS.md for pending required
follow-ups under AGENTS.md. Apply an answer addressed to
gsd-path-ship only through current review
artifacts. Pass the record's exact stored owner to dispose so the disposition
receipt preserves that durable owner name; use gsd-path-ship for new records.
If it changes approved intent/plan or names another owner, keep
ship/blocked, link ANSWERS.md and the target artifact, and ask the user
before dispatch or ship. Every ship/blocked write and the step 7 log-only
event use pipeline_state.py transition with expected ship/active and the
exact current branch and archive values: blocking passes --set-status blocked; the log-only event passes --set-status active and the event text,
so the position is unchanged. Then:
-
Require STATE
ship/activeproduced and committed by the build orchestrator,.project/intent/INTENT.md,.project/plan/PLAN.md, all task files, all passing wave reviews, the bound build branch, and no product or unrelated changes. On retry, existing uncommitted assigned final-review outputs may remain. Resolve and record the exact full reviewedHEADbefore dispatch, then prove every task landed through the runtime in step 3. Its landing check must return oneproven-landedorattestedentry per task. For rebase recovery, see$gsd-path-buildstep 1. Its receipt.project/build/rebase-adoption.jsonmay remain uncommitted only after the runtime'sbuild_state.verify_landed_taskscheck passes. Keep bookkeeping in STATE.md and assigned artifacts; never create extra.project/execution reports. Reuse an output only when itsReviewed HEADequals that SHA and the complete numbered gap-risk mapping still equals the freshly derived risk list. Regenerate the exact assigned output set when stale, removing only supersededfinal-gap-N.mdfiles. A stale committed output may be replaced or removed only when Git and task logs prove it is the immediately precedingship/blockedfinding set, the approved patch tasks copied every finding verbatim, and those tasks are now done; otherwise it blocks. Git history preserves the superseded finding, while final review itself still creates no pre-ship commit. -
Derive a stable numbered list of cross-wave integration risks from interfaces and flows that span waves. List only genuine risks that could plausibly fail; never pad the list. Include PLAN.md's project Verify as numbered risk 1. The orchestrator runs that command once in step 3 and writes its gap artifact; do not dispatch a gap reviewer for it. Resolve the local final-review template, gap-review template, patch-findings template, and
scripts/check_handoffs.py. -
Run
python3 <absolute workflow_run.py> prepare-final --repo <absolute primary> --expected-head <HEAD>from this skill's bundled scripts. This owns pending-discussion and landing checks, project Verify isolation, execution, output recording, collection, cleanup, and final-review reuse. Keep its JSON receipt; do not reconstruct those operations in shell calls. For a single-repo milestone, exact stdout/stderr live once in.project/build/verify-ledger.jsonl;final-gap-1.mdis the generated view referencing that entry. For a member milestone, the gap records each member head and holds the exact output; there is no reusable ledger entry. Single-repo re-entry at the same command and commit reuses the execution, including a failed one, and finishes interrupted collection without running the command again. Missing legacy output requires evidence reconciliation, not a blind rerun. Any non-zero result stops this step; preserve its stderr and diagnose through the bundled forensics contract. Do not launch reviewers while project Verify is failing. Record the command failure in STATE.md and link its gap evidence.Read the final step's
result.final.reused: truemeans FINAL.md already proves final scope: do not dispatchreview_finalor rewrite it. For a quick lane with one full wave, reuse requires a committed review explicitly covering final scope, every success criterion and required walkthrough, and unchanged product and approved contracts. The helper generates FINAL.md as a view of that proof. Multiple waves, deep/verify-only reviews, missing evidence, or changed inputs require fresh final review. Existing valid final evidence at the current HEAD is also reused on retry. -
For each numbered risk other than project Verify without a reusable output, dispatch one reviewer through the shared capacity-aware contract at the exact reviewed HEAD. Use logical task name
review_gap_<number>and assign only.project/review/final-gap-N.md. Before each dispatch, create its distinct sidecar withpython3 <absolute isolation.py> isolate-verify --repo <absolute primary> --base <HEAD> --name review-gap-<number>and supply the returned path. Review commands and staged outputs run only there, never in the primary worktree. For every returned artifact, substitute its returned worktree, branch, and assigned.project/review/...path intopython3 <absolute isolation.py> collect-artifact --repo <primary> --source <worktree> --base <HEAD> --branch <branch> --source-path <assigned path> --destination-path <assigned path>. If replacing an admitted stale output, include--expected-destination <its recorded SHA-256>. Require returned fields to match, then runpython3 <absolute isolation.py> retire --repo <primary> --worktree <worktree> --branch <branch>. The helper must observe only the assigned artifact in each sidecar. Model-written copies into the primary do not count as collection. After every gap artifact is present, reuse a valid FINAL.md admitted by step 3 or create a fresh sidecar withisolate-verify --name review-finaland dispatch the integration reviewer under logical task namereview_final, assigning only.project/review/FINAL.md. Its complete brief includes the project Verify evidence from the ledger or the member milestone's gap output, every collected gap verdict so Overall verdict is consistent with them, and PLAN.md's## Surface contractwhen INTENT.md names surfaces — that reviewer performs each Walkthrough and records the surface and what it showed on every criterion the contract lists. Collect FINAL.md and retire its sidecar through the same helper flow. -
Only after
final-gap-1.mdand every dispatched reviewer artifact have been collected and all review sidecars retired, validate every artifact. Every success criterion ismet,not-met, orunverifiablewith checked evidence; every gap ispassorblockedwith checked evidence. Every output must record the same exact full reviewed HEAD, and each numbered gap heading and Risk value must match its dispatch risk. Runpython3 <absolute check_handoffs.py> final --repo <absolute repo root>before any archive question: FINAL.md needs one### SCn — ...block per INTENT success criterion,Overall verdict: passrequires every verdictmetwith a non-noneCheck or Reference, and every criterion listed in PLAN.md's Surface contract requires a matchingSurfacefield and a non-noneCheck. A non-zero exit isship/blocked; never rerun project Verify to repair the evidence. -
Redispatch one complete corrected brief for a missing or invalid reviewer artifact under the same logical task name, following the runtime dispatch contract. Before dispatch, record the invalid destination's exact SHA-256. Give the retry a fresh verify sidecar, collect its corrected artifact with the same
collect-artifactcommand plus--expected-destination <recorded SHA-256>, retire the sidecar, and rerun the final handoff gate. If it remains invalid, setship/blockedwith the exact contract failure and aNEEDS-USERdispatch-failure entry. Present Outcome with the invalid output, Review linking that output or STATE.md when it is missing, and Next naming the required correction; then stop and do not invent a patch finding. Anot-met,unverifiable, or blocked gap with valid evidence setsship/blocked, writes.project/review/PATCH-FINDINGS.mdfrom the patch-findings template, and runspython3 <absolute check_handoffs.py> patch --repo <absolute repo root>. Present the blocked outcome, link the resolved absolute PATCH-FINDINGS.md path, and state that patch planning is next. The manifest contains exactly those FINAL.md and gap rows. When routed by an active$gsd-path, return control so its bundled plan contract opens patch mode. When invoked directly, stop and tell the user to explicitly invoke$gsd-path, which routes those sources to plan patch mode; do not invoke an explicit-only sibling skill yourself. Ship never writes tasks or PLAN.md. The patch build commits this prior finding set with the approved patch artifacts before execution. -
Only when every criterion is
met, every gap passes, project Verify passes, and no required discussion follow-up is pending, keep STATE.md atphase: ship,status: active, appendfinal gate passed; shipping approval pending. Present Outcome with the final verdict, Review linking the resolved absolute FINAL.md path and summarizing the gap artifacts, and Next asking whether toArchive and ship (recommended)orStop for review. The recommendation is grounded in the passing gates. Begin the transaction below only after approval; declining leaves review active and makes no archive mutation. Do not mark or reportshippedyet.
Archive transaction
Resolve the declared runtime with python3 -B <project>/.gsd-path/status_runtime.py --repo <project> --runtime-path; use
archive_milestone.py and pipeline_state.py from that verified directory for prepare,
render-manifest, preflight, record-shipment, validate, integrate, and
validate-integrated. Invoke them with python3; the files need not be
executable. Skill-bundle copies are not the guard's trust anchor, even when
byte-identical. The archive helper is the sole MANIFEST.md and integration writer.
The persisted STATE.archive field is the transaction identity.
-
Normally require STATE
ship/active, the bound build branch, and no non-.projectchange. The sole crash-recovery exception isshipped/donewith a concrete target that is absent from HEAD; this is an uncommitted transaction and resumes without rewinding STATE. On every initial run or retry, run:python3 <absolute archive_milestone.py> prepare --repo <root> --slug <STATE.milestone>. On a fresh transaction,preparerefuses areview/FINAL.mdwhoseReviewed HEADdiffers from current HEAD, before persisting STATE.archive or creating archive directories. Regenerate the final review for the current commit before archiving; preflight and validation retain their own checks. The helper strict-loads STATE.md, requires its canonicalgsd-path/M00Nbranch withN >= 1to equal the next collision-free archive sequence, rejects any000-*archive entry, and writes the exact.project/archive/<NNN>-<slug>path atomically to STATE.md before moving anything, and then moves the active milestone. On every retry run the same command; it reuses STATE.archive and never recomputes N. -
The helper requires exactly one of each active or archived top-level artifact, permits active and archived
research/together only for the byte-identical pending DOCS-AUDIT carry-forward, and recreates its parent before an atomic copy. Any other collision or missing artifact blocks. For a non-off PLAN review-panel policy it also requires exactly one plan resolution artifact:review/PLAN-PANEL.mdforready, or the exact helper JSON inreview/PLAN-PANEL.skipped.jsonforskipped. Each full or deep wave cycle likewise requires exactly one merged.panel.mdartifact or exact.panel.skipped.jsonreceipt. Configuration alone never proves that a panel was ready or skipped. -
Append milestone lessons to
.project/LESSONS.md(create it when missing): one line per repeat-offender criterion across this milestone's wave reviews and one per escalation in the STATE.md log, formatted- <NNN>-<slug> — <lesson>. Skip the file entirely when there are none. LESSONS.md stays in the active root across milestones — it ships inside the ship commit but never archives — and the planner reads it. The same persistence applies to program artifacts when present: CHARTER.md, ROADMAP.md, and a top-level program SYNTHESIS.md ship in the commit but never archive. Then runpython3 <absolute archive_milestone.py> render-manifest --repo <root>. The helper derives final verdicts, wave/task/cycle counts, carry-forward count, and the exact archive inventory, then atomically replaces MANIFEST.md through its deterministic same-directory temporary. Never render or edit the manifest directly.prepareremoves that exact temporary after a crash. If the target exists in HEAD,prepareandrender-manifestrefuse mutation and the only valid action isvalidate. -
Run
python3 <absolute archive_milestone.py> preflight --repo <root>while STATE isship/active, or while it isshipped/donein the uncommitted crash window above. It validates Git root/branch, current target absence from HEAD, immutable older archives, canonical real files, exact active-root allowlist and carry-forward, reviewed revision, manifest metadata and criteria against FINAL.md, exact ordered PLAN wave task/title rows with non-placeholder evidence for every task and owned success criterion, actual cycle counts, completed Notes, and the exact file inventory. Canonicalwave-N.cycleC.repair-T###.jsonreceipts are auxiliary evidence, not review verdicts; their payload identity must match their filename. Same-wave repair tasks enter review coverage only after their receipt's source cycle, and a later review cycle is required. Concrete evidence may contain generic types such asResult<T>or comparisons. Markdown code spans with matching backtick delimiters may contain placeholder-shaped quoted evidence, such asQueues unavailable: <stored reason>. A whole value containing only<record observation>remains invalid, even inside a code span; unquoted template placeholders also remain invalid. Immediately before this command, recheck for an activediscuss/copy created after prepare; if present, rerunprepare, regenerate MANIFEST.md by rerunningrender-manifest, and only then preflight. Do not commit when it fails. A failure over a missing or non-canonical review artifact is never repaired by writing, splitting, or renaming a review file after the fact; report it and let the user rule — a new review cycle at the current HEAD is the only artifact-producing remedy. The archive helper independently binds every FINAL.mdSCnheading id and normalized text to the archived INTENT.md; a renamed or easier criterion blocks even if the earlier handoff gate was bypassed. For a multi-repo milestone (the archive holdsbuild/members.json), runpython3 <absolute archive_milestone.py> close-members --repo <root>after preflight passes and before recording shipment. It closes each locked member in lock order in that member's integration mode and journals each one. When it returnsawaiting-merge, report the member PR link, stop, and rerun the same command after the user merges it; never merge a member PR yourself. When it returnsintegrated, keep itsbodyfor the ship commit below. -
Only after preflight passes, record shipment through the journaled helper; for a program it atomically replaces both ROADMAP.md and STATE.md, setting the current entry to
Status: shippedwith the exactArchive:pointer:python3 <absolute pipeline_state.py> record-shipment --repo <root> --archive <STATE.archive> --event "archive preflight passed; shipment recorded"Require the returned state to be
shipped/donewith the unchanged branch and archive. When this was the last pending roadmap entry, use the eventarchive preflight passed; shipment recorded; program completeinstead. When CHARTER.md and ROADMAP.md are both absent, this same command preserves the single-milestone flow and updates STATE.md only. Retry this exact command after interruption; it resumes its journal and is idempotent after completion. Stage only.project/paths, inspect the staged path list against the transaction and create the ship phase's one commit with exact subjectship: M00N — <milestone-slug>. For a single-repo milestone, its body has exactly two consecutive lines,Archive: .project/archive/<NNN>-<slug>thenReviewed-HEAD: <reviewed SHA>, with no comment lines or blank line between them. A multi-repo milestone's body is exactly thebodythatclose-membersreturned: those two lines, then oneMember-Reviewed-HEAD:and oneMember:line per member. Write the subject, a blank line, and the body lines to a message file, then usegit commit -F <message-file>. M00N and NNN come from STATE.archive. There is no untracked-project exception and no product or older-archive path may enter this commit. -
Immediately run
python3 <absolute archive_milestone.py> validate --repo <root>. It requires the committed shipped state, exact archive and manifest, valid carry-forward, no active milestone artifacts, a clean worktree, exactly one current-milestone commit with the canonical ship subject and body in first-parent history, only.project/paths in that commit, and bound-worktree HEAD exactly equal to that ship commit. Any later product or.project/commit blocks validation. A passing validate completes the archive transaction; record its returned archive path and full commit SHA, and link the archived MANIFEST.md as the final review surface. The milestone is not shipped until integration below passes. -
Integrate only after the postcommit
validatepasses, with the recorded ship commit and exact reviewed HEAD unchanged. Runpython3 <absolute archive_milestone.py> integrate --repo <root> --slug <STATE.milestone>. This helper validates the ship commit, fetches origin, requires remote defaultmain, and follows the lockedSTATE.integrationmode:directowns the resumable merge transaction. It creates the canonical named integration worktree, performs the hook-verified--no-ffmerge, refuses to resolve conflicts, creates the annotated milestone tag, pushes main then the bound branch then the tag, and removes its worktree and branch. Before publishing the bound branch it reads the live origin ref: absence is created with an absent-ref lease, the exact ship commit is an idempotent success, an owner-adopted rebased milestone (archivedbuild/rebase-adoption.json) may advance the ref from the adopted head to its immediate, canonical.project/-only ship child under an exact-SHA lease after the helper proves the clean ship state, receipt, and archived tasks. Every other value blocks. If origin/main advances after the local merge but rejects the push, a retry may discard and rebuild only the unpublished canonical merge and tag under the helper's existing recovery checks.pull-requestrequiresghauthentication for GitHub.com and a GitHub.com origin. It publishes the exact ship commit, reuses only the single PR from origin's bound branch at that commit or creates one with the canonical integration title and body plus the GSD Path credit footer. Any competing PR tomainat the ship commit blocks. While the eligible PR is open, the helper returnsstatus: awaiting-merge. Present Outcome, link the returned PR as Review, and state in Next that the user must merge it with GitHub's merge-commit method. Stop this ship invocation; Path never enables auto-merge or merges the PR. On rerun after a human GitHub user merges it, the helper requires the PR head to remain the ship commit and its landing to be a two-parent merge with that ship commit as second parent onorigin/mainfirst-parent history. It then writes and pushes the annotated milestone tag containing the PR URL, ship SHA, and landing SHA. A closed unmerged PR, squash, rebase, merge queue, moved head, duplicate PR, or non-GitHub.com origin blocks. The remote bound branch may be absent after a valid merge because GitHub may auto-delete it.
A passing run returns the same proof exposed by
validate-integrated. A non-zero result blocks; rerun the exactintegratecommand to resume a safe partial transaction instead of repairing refs or Git state manually. An integration conflict is not a safe retry: the helper aborts the merge and leaves the closed milestone branch unchanged. Invoke$gsd-path-forensicsand obtain a user-approved recovery plan before continuing. Never merge into or re-ship the closed branch. For a later validation recheck with origin network access, runpython3 <absolute archive_milestone.py> validate-integrated --repo <root> --slug <STATE.milestone>. Both integration modes refresh the remote-default and mirrored milestone-tag refs when anoriginremote exists. Without that remote, validation resolves the existing remote-default refs locally, preserving offline direct-mode fixtures. PR mode also revalidates the PR identity, state, merge provenance, and live branch and tag publication. Report shipped only when the integration result passes. Leave the primary worktree and STATE.branch on the shippedgsd-path/M00Nat the ship commit. The router owns the later handoff to a new milestone branch after this gate. -
If a crash occurs before STATE's atomic rename, discard only the exact deterministic state temp through
prepare. If it occurs after STATE becomesshipped/donebut before commit, runprepareandpreflightunder the explicit uncommitted exception, then create the one ship commit. Resume the named transaction even when active final-review inputs have moved. If the target exists in HEAD, validate it rather than runningprepareor creating another commit. Any inconsistent committed transaction blocks; never mutate a committed archive. The fourth crash window is integration. Its transaction id is the ship commit, and partial merge, tag, push, and cleanup states are resumed only by rerunningintegrate; it reuses NNN from STATE.archive. While integration is pending, never report shipped or start the next milestone; route back to ship.
Published validation recovery
Use this recovery only when STATE is shipped/done, the archive and ship
commit are already published, and validate-integrated is blocked by a defect
fixed in a newer trusted GSD Path checkout. Never run prepare,
render-manifest, preflight, record-shipment, or integrate, and never
edit the committed archive, STATE.md, Git history, or published refs and tags.
Only the validation checkout's local refs may be refreshed by the commands below.
Run this recovery setup from a separate checkout, outside the closed primary
worktree's guard.
-
Create separate disposable trust and validation checkouts from the same published origin and
STATE.branch. This separation is required because an explicit runtime upgrade changes the trust checkout's declaration and launcher, while archive validation requires a clean checkout. Never use the primary worktree for either role. -
From the trusted fixed GSD Path checkout, preview and then explicitly upgrade only the disposable trust checkout's managed trust anchor:
node <trusted-gsd-path>/scripts/install.mjs --runtime-upgrade --dry-run --project <trust-root> node <trusted-gsd-path>/scripts/install.mjs --runtime-upgrade --project <trust-root>Confirm that the preview identifies the intended fixed version and digest. Upgrade changes only the disposable trust project's declaration and compatible launcher. For a legacy trust checkout with no declaration, use the explicit
--runtime-migratepreview and migration first. Resolve the upgraded runtime:python3 -B <trust-root>/.gsd-path/status_runtime.py --repo <trust-root> --runtime-pathUse the returned absolute directory as
<verified-runtime>below. Stop on any error; do not substitute the validation checkout's older selected runtime. -
Use only this verified upgraded runtime to refresh publication refs in the clean validation checkout and validate its integrated milestone:
python3 -B <verified-runtime>/archive_milestone.py refresh-origin --repo <validation-root> python3 -B <verified-runtime>/archive_milestone.py validate-integrated --repo <validation-root> --slug <STATE.milestone> -
A pass restores the normal shipped handoff without another commit or publication action. Remove only the disposable checkouts. A failure is a new validation finding: report it with the primary worktree's archived MANIFEST.md and stop. Never repair an already-committed archive to satisfy a newer validator.
Legacy ship and integration subjects may be ignored only while scanning older milestones. They never satisfy the current milestone transaction. Current validation requires exactly one canonical ship commit. Direct integration also requires the canonical integration subject and body; PR integration uses the exact PR metadata, annotated tag metadata, and merge topology instead.
Rules
- Judge written expectations only: INTENT.md criteria in final mode, walked through PLAN.md's Surface contract for every criterion covering a surface.
- Require criterion, observed result, exact file or command evidence, and fix direction for every failure.
- Warn on ambiguity, but do not invent stronger requirements.
- Never count
unverifiable, an unreviewed risk, or an unvalidated archive as shipped. - Never merge or back-merge into the bound branch; ship's integration is its only path to the default branch. Never enter the default checkout; its local default branch ref may lag origin.