From a62e844503117ca973953a027b097c2e267e3d9f Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Wed, 22 Jul 2026 16:03:32 +0100 Subject: [PATCH] DOC-6876 Rename /pickup skill to /unpark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renamed the parked-PR thaw skill from /pickup to /unpark (dir, frontmatter, prose) to free the /pickup name for another skill where it fits better, and updated the two files that reference it — /park and the shared _shared/park-manifest.md contract — so the park↔unpark pairing stays consistent. park/unpark also reads as a cleaner verb pair than park/pickup. Directive: Two "pickup" strings are left un-renamed on purpose — the historical .claude/state/assess-comments.coverage.md audit log (it records the skill's old name as it was at the time; renaming falsifies history) and the "Trigger to pick up:" manifest field name in park-manifest.md (a header field, not the skill name). Don't "fix" them in a follow-up grep-and-replace. Ticket: DOC-6876 Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/_shared/park-manifest.md | 26 +++++++++++----------- .claude/skills/park/SKILL.md | 20 ++++++++--------- .claude/skills/{pickup => unpark}/SKILL.md | 20 ++++++++--------- 3 files changed, 33 insertions(+), 33 deletions(-) rename .claude/skills/{pickup => unpark}/SKILL.md (92%) diff --git a/.claude/skills/_shared/park-manifest.md b/.claude/skills/_shared/park-manifest.md index 5e3ab2d61d..326c93c47a 100644 --- a/.claude/skills/_shared/park-manifest.md +++ b/.claude/skills/_shared/park-manifest.md @@ -1,10 +1,10 @@ # Park manifest — format & conventions (shared) -Canonical definition of the **park manifest**: the pickup contract embedded in a parked PR. -Shared by **`/park`** (which *writes* it) and **`/pickup`** (which *reads and diffs against* +Canonical definition of the **park manifest**: the unpark contract embedded in a parked PR. +Shared by **`/park`** (which *writes* it) and **`/unpark`** (which *reads and diffs against* it), so the format can't drift between the two. Change it here, once. -> Referenced by `.claude/skills/park/SKILL.md` and `.claude/skills/pickup/SKILL.md`. Not a +> Referenced by `.claude/skills/park/SKILL.md` and `.claude/skills/unpark/SKILL.md`. Not a > skill itself (no `SKILL.md`), so it won't be invoked directly. ## What a parked PR is @@ -20,7 +20,7 @@ three in a place a future agent can find with `gh` alone. ## Where it lives -In the **PR body**, as a markdown block delimited by exact marker lines so `/pickup` can +In the **PR body**, as a markdown block delimited by exact marker lines so `/unpark` can extract it deterministically: ``` @@ -46,25 +46,25 @@ PR, machine-locatable by its markers. 2. **Pinned sources (state observed at park time)** — a table, one row per external source. Each row records the URL **and a snapshot of its state at park time**: for a GitHub PR, `state` / `merged` / `head SHA` / `base` / `milestone` / `updated`. **The snapshot is what - makes pickup a diff rather than a re-read** — without it, `/pickup` sees "now" with nothing + makes unpark a diff rather than a re-read** — without it, `/unpark` sees "now" with nothing to compare against. Include the exact command to re-fetch each source. 3. **Observed shape the page assumes** — a **confidence-tagged** summary of the API/behaviour the docs commit to. Tag it (`LOW`/`MEDIUM`/`HIGH`) — preemptive docs written against an - unmerged diff are usually LOW, and saying so tells pickup how hard to scrutinise. + unmerged diff are usually LOW, and saying so tells unpark how hard to scrutinise. 4. **Re-check checklist** — GitHub task-list (`- [ ]`) of everything to verify or finish on - pickup. **Seed it from the branch's commit trailers** — harvest `Recheck:` / `Gaps:` / + unpark. **Seed it from the branch's commit trailers** — harvest `Recheck:` / `Gaps:` / `Directive:` from `main..HEAD` (see [`commit-trailers.md`](./commit-trailers.md)); those *are* the loose ends. Add anything predicted-to-change not already captured. Mark the highest-risk items. -5. **On pickup, then** — when the trigger fires, run `/pickup `. It reconciles the docs +5. **On unpark, then** — when the trigger fires, run `/unpark `. It reconciles the docs against the now-settled source and takes the PR through the normal `/reflect` → `/finalize` pipeline to merge, lifting the `parked` / `do not merge yet` labels only after `/finalize`. - **The closing sequence and its ordering live solely in `/pickup` Steps 4–5, which are + **The closing sequence and its ordering live solely in `/unpark` Steps 4–5, which are authoritative; this manifest deliberately does not restate them — not even as a list.** (A - hand-copied step list here drifted from `/pickup` on every review round, so it was replaced by + hand-copied step list here drifted from `/unpark` on every review round, so it was replaced by this pointer. Don't re-add one, in any order.) The one guarantee this section makes: the `do not merge yet` guard holds until `/finalize` completes. @@ -78,8 +78,8 @@ not restate them as trailers. ## Finalize is deferred while parked Critical: **do not run `/finalize` at park time.** Finalize squashes away the episodic -`Recheck:` / `Gaps:` trailers — exactly what `/pickup` needs. The durable distill happens -*after* pickup, once the source has settled. The manifest's "On pickup, then" section records +`Recheck:` / `Gaps:` trailers — exactly what `/unpark` needs. The durable distill happens +*after* unpark, once the source has settled. The manifest's "On unpark, then" section records this so it isn't forgotten. ## Labels @@ -88,4 +88,4 @@ this so it isn't forgotten. goes ahead." - `do not merge yet` — the merge guard. -`/pickup` finds parked PRs with `gh pr list --label parked`. +`/unpark` finds parked PRs with `gh pr list --label parked`. diff --git a/.claude/skills/park/SKILL.md b/.claude/skills/park/SKILL.md index ff801734ac..2b23b42ece 100644 --- a/.claude/skills/park/SKILL.md +++ b/.claude/skills/park/SKILL.md @@ -1,6 +1,6 @@ --- name: park -description: "Freeze a release-ready-pending-upstream branch as a parked PR — open (or update) the PR with a machine-diffable pickup manifest, apply the parked / do-not-merge labels, and deliberately defer /finalize so the episodic re-check notes survive. Use when docs are written against an unreleased or still-changing external source (an upstream PR, a preview feature) and must wait for it to ship before merging. Pairs with /pickup." +description: "Freeze a release-ready-pending-upstream branch as a parked PR — open (or update) the PR with a machine-diffable unpark manifest, apply the parked / do-not-merge labels, and deliberately defer /finalize so the episodic re-check notes survive. Use when docs are written against an unreleased or still-changing external source (an upstream PR, a preview feature) and must wait for it to ship before merging. Pairs with /unpark." --- # Park — freeze a PR that's waiting on the world @@ -27,16 +27,16 @@ you'll harvest. This file is *how to build and land the manifest*. ↓ THIS SKILL — when the work can't merge yet /park → parked PR + manifest [frozen; /finalize DEFERRED] ↓ (wait for the upstream trigger) -/pickup → reconcile docs vs source [thaw + delta] +/unpark → reconcile docs vs source [thaw + delta] ↓ /reflect+/finalize → durable squash commit [resume the normal pipeline] ``` ## The one principle: snapshot the source, not just a pointer -A note that says "watch upstream PR X" is nearly useless on pickup — it tells you where to +A note that says "watch upstream PR X" is nearly useless on unpark — it tells you where to look but not *what changed*. The manifest must capture the source's **state at park time** -(merge status, head SHA, milestone, the observed API shape) so pickup is a **diff**, not a +(merge status, head SHA, milestone, the observed API shape) so unpark is a **diff**, not a fresh read. Recording the snapshot is the whole value of parking; everything else is plumbing. @@ -79,7 +79,7 @@ gh api repos///issues/ \ --jq '{state, state_reason, milestone: .milestone.title, updated_at, closed_at}' ``` -Record URL + snapshot in the sources table, and the re-fetch command for pickup. Add a +Record URL + snapshot in the sources table, and the re-fetch command for unpark. Add a **confidence-tagged** summary of the API/behaviour the page assumes (LOW for docs written against an unmerged diff — and say *why* it's low, e.g. "signatures differed between two reads of the diff"). @@ -108,7 +108,7 @@ required sections (per the shared spec). The page itself should already carry a gh pr edit --body-file --add-label parked --add-label "do not merge yet" ``` - Verify the labels stuck (`gh pr view --json labels`). -- **Do not run `/finalize`.** State explicitly that it's deferred until pickup — the manifest +- **Do not run `/finalize`.** State explicitly that it's deferred until unpark — the manifest records this, but say it in your handoff too. Present the PR URL, the trigger condition, and the checklist, then stop. Opening a PR is @@ -117,13 +117,13 @@ outward-facing — if the branch isn't pushed or the user hasn't asked, confirm ## Limits (read honestly) - **A stale snapshot is worse than none** — if you record a head SHA or API shape you didn't - actually verify, pickup diffs against fiction. Snapshot only what you checked; leave the + actually verify, unpark diffs against fiction. Snapshot only what you checked; leave the rest out and flag it in the checklist. - Park **cannot judge whether the source will ship.** It records a trigger; it doesn't predict - the future. A parked PR that never triggers is dead weight — `/pickup`'s scan mode is how you + the future. A parked PR that never triggers is dead weight — `/unpark`'s scan mode is how you find and close those. - It **defers, never distills.** If you're tempted to "just finalize while it's fresh," don't: - you'll squash away the very notes pickup needs. Freshness is preserved *in the manifest*, not + you'll squash away the very notes unpark needs. Freshness is preserved *in the manifest*, not in a premature durable commit. - The manifest is only as good as the checklist. If Step 2's harvest is skipped, the loose ends - live only in scattered trailers and the pickup starts blind. + live only in scattered trailers and the unparking starts blind. diff --git a/.claude/skills/pickup/SKILL.md b/.claude/skills/unpark/SKILL.md similarity index 92% rename from .claude/skills/pickup/SKILL.md rename to .claude/skills/unpark/SKILL.md index 44240ae048..7eb7bff3e6 100644 --- a/.claude/skills/pickup/SKILL.md +++ b/.claude/skills/unpark/SKILL.md @@ -1,9 +1,9 @@ --- -name: pickup +name: unpark description: "Thaw a parked PR — re-fetch each pinned source, diff it against the manifest snapshot taken at park time, report what changed vs what was predicted, then reconcile the docs and resume the normal pipeline (/reflect → /finalize) toward merge. Run with a PR number, or with no argument to scan all parked PRs and report which triggers have fired. Pairs with /park." --- -# Pickup — thaw a parked PR against its moved source +# Unpark — thaw a parked PR against its moved source `/park` froze a PR with a snapshot of the source it tracks. Time passed; the source moved — the upstream PR merged, the API changed, a version shipped. This skill **thaws the PR**: it @@ -20,7 +20,7 @@ vocabulary for the reflect/finalize handoff is in ``` /park → parked PR + manifest snapshot [frozen] ↓ (the trigger fires) -/pickup → diff source now vs snapshot [THIS SKILL: thaw + reconcile] +/unpark → diff source now vs snapshot [THIS SKILL: thaw + reconcile] ↓ /reflect+/finalize → durable squash commit [resume: predicted-vs-actual, distill] ``` @@ -45,10 +45,10 @@ For each, read the manifest's `Trigger to pick up:`, snapshot the current source re-fetch only — don't do the full reconcile), then compare that state to the trigger condition to decide **fired?**. Use only Step 2's *comparison* — **not** its stop-and-report rule: in scan mode a not-met trigger is recorded as `fired?=no` and you continue to the next PR, never aborting the -loop. Output a table: PR / trigger / **fired?** / one-line delta. Recommend which to pick up, which are still waiting, and which look abandoned (source -closed-unmerged, or long dead). Then stop — picking one up is Mode B. +loop. Output a table: PR / trigger / **fired?** / one-line delta. Recommend which to unpark, which are still waiting, and which look abandoned (source +closed-unmerged, or long dead). Then stop — unparking one is Mode B. -## Mode B — pick up one PR (PR number given) +## Mode B — unpark one PR (PR number given) ### Step 1 — Extract the manifest & re-fetch sources @@ -60,7 +60,7 @@ each pinned source, run its recorded re-fetch command and capture current state. Compare current vs park-time, field by field. Has `merged` flipped true? Has `head SHA` moved (the diff may have changed under review)? Is a `milestone` / version now set? For a merged PR, read the **released** source at the merged tag, not the PR branch. Confirm whether the trigger -condition is genuinely met — **if it isn't, stop and report**; picking up early re-freezes bad +condition is genuinely met — **if it isn't, stop and report**; unparking early re-freezes bad info. ### Step 3 — Walk the checklist @@ -80,7 +80,7 @@ changes land (including the rebase and link checks) come next, in order. ### Step 5 — Resume the pipeline & hand off -Pickup **reconciles; it does not merge.** `/finalize` prepares a squash that operates on the +Unpark **reconciles; it does not merge.** `/finalize` prepares a squash that operates on the **pushed remote PR head**, so the invariant governing this whole step is: > Before the `gh pr merge` hand-off, the remote PR branch must already contain **everything @@ -101,7 +101,7 @@ enumerating the exact git steps here drifted out of date every review round. 3. **Remote head == local** — everything above pushed. This is the invariant made true; nothing reaches the squash until it is. 4. **`/finalize`** run — the durable squash deferred at park time, now that the source has - settled; it reconciles the whole arc (park notes + pickup findings + any review) and prepares + settled; it reconciles the whole arc (park notes + unpark findings + any review) and prepares the `gh pr merge … --body-file` command. 5. **Labels dropped last** — remove `parked` / `do not merge yet` and strip the manifest block only after `/finalize`. The merge guard holds until then. @@ -118,7 +118,7 @@ ahead of `origin`). Then present: the delta report, the doc changes, the finaliz - It **trusts the snapshot's honesty.** If `/park` recorded an unverified shape, the diff is against fiction — so re-verify high-risk checklist items from source regardless of what the snapshot claimed, especially anything tagged LOW. -- It **can't recover a checklist that was never written.** With a thin manifest, pickup +- It **can't recover a checklist that was never written.** With a thin manifest, unpark degrades to a blind re-review — still useful, but the park-time context is gone. - Reconciliation edits are real doc changes: drive/verify them like any other, don't assume the released API matches even a HIGH-confidence snapshot.