From d21ff1154b97faaceed9eeefe971f785f31344e6 Mon Sep 17 00:00:00 2001 From: mdsmithaustin <15272014+mdsmithaustin@users.noreply.github.com> Date: Sun, 25 Oct 2026 13:58:11 -0600 Subject: [PATCH 1/6] test(watch-pr): tie the recap start marker to the pr-recap template A recap comment that names a bot review's URL must stay open for triage. The test builds that comment from the block template, so a changed start marker in the template fails it. --- .../scripts/watch-pr/review-bodies.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/skills/poteto-mode/scripts/watch-pr/review-bodies.test.ts b/tests/skills/poteto-mode/scripts/watch-pr/review-bodies.test.ts index 3ba9bc27..4b9be49e 100644 --- a/tests/skills/poteto-mode/scripts/watch-pr/review-bodies.test.ts +++ b/tests/skills/poteto-mode/scripts/watch-pr/review-bodies.test.ts @@ -1,4 +1,6 @@ import { describe, expect, it } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; import { buildReviewState, parseReviewStatePage, @@ -326,6 +328,26 @@ describe("acknowledging a flagged review", () => { ).toEqual(["open"]); }); + describe("the comment the pr-recap skill writes", () => { + const skill = join(import.meta.dir, "../../../../../skills/pr-recap"); + const block = readFileSync(join(skill, "references/block.md"), "utf8"); + const template = block.match(/````markdown\n([\s\S]*?)\n````/)?.[1] ?? ""; + + it("never acknowledges a review, even when it names the review's URL", () => { + expect(template).toStartWith(""); + expect( + statusOf([ + comment({ + id: 1, + body: `${template}\n\nReviewed: ${link}`, + login: "mdsmithaustin", + association: "OWNER", + }), + ]) + ).toEqual(["open"]); + }); + }); + it("rejects a comment that mentions the review without linking it", () => { expect( statusOf([ From 5c3c736f9c37841b935ac93b5689b75ca7a56ae9 Mon Sep 17 00:00:00 2001 From: mdsmithaustin <15272014+mdsmithaustin@users.noreply.github.com> Date: Sun, 25 Oct 2026 13:58:18 -0600 Subject: [PATCH 2/6] docs(pr-recap): ban a bot review's URL and settle two refresh edges The check that clears a review-findings blocker matches the URL anywhere in a comment, code spans included, so the skill now says never include the URL instead of never link it. A threads-only fix push refreshes the recap like any push. An operator's hold wins over a pending refresh. --- skills/poteto-mode/playbooks/babysit.md | 2 +- skills/poteto-mode/references/task-triggers.md | 2 +- skills/pr-recap/SKILL.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/skills/poteto-mode/playbooks/babysit.md b/skills/poteto-mode/playbooks/babysit.md index 0ec6bb55..f62e52d1 100644 --- a/skills/poteto-mode/playbooks/babysit.md +++ b/skills/poteto-mode/playbooks/babysit.md @@ -6,7 +6,7 @@ Babysitting starts when the user asks for it, which is normally once a phase or `drive` reaches merge-ready when forge readiness and the current author result hold, plus a current independent review when that result requires one. Landing the stack is `playbooks/shipping.md`. -1. **Declare the mode and resolve the forge before any poll.** `drive` runs the loop to merge-ready, for "babysit this", "get it green", "merge-ready". `background` triages without blocking, which is the mode for a plan still executing. `threads-only` answers review comments and touches nothing else, for "address the bugbot comments" or "address the copilot comments". `check` is one status pass and a report, for "check on X" and "is it green". Undeclared defaults to `drive`. Small or docs-only PRs get `check`, not `drive`. GitHub CLI (`gh`) is the default. If `command -v origin` succeeds and Origin can resolve the repository, use `origin pr ...` for view, checks, threads, and later shipping. Otherwise stay on `gh` and record the fallback. Never require Graphite (`gt`). +1. **Declare the mode and resolve the forge before any poll.** `drive` runs the loop to merge-ready, for "babysit this", "get it green", "merge-ready". `background` triages without blocking, which is the mode for a plan still executing. `threads-only` answers review comments and touches nothing else, for "address the bugbot comments" or "address the copilot comments". A fix push in this mode still refreshes the PR recap per [task triggers](../references/task-triggers.md). `check` is one status pass and a report, for "check on X" and "is it green". Undeclared defaults to `drive`. Small or docs-only PRs get `check`, not `drive`. GitHub CLI (`gh`) is the default. If `command -v origin` succeeds and Origin can resolve the repository, use `origin pr ...` for view, checks, threads, and later shipping. Otherwise stay on `gh` and record the fallback. Never require Graphite (`gt`). 2. **Work the merge frontier and nothing above it.** The lowest unmerged PR is the only one that matters until it merges. Upstack threads get read and batched, never fixed at the cost of restarting the frontier's checks. If you catch yourself upstack while the frontier is red, stop and go back down. 3. **One babysitter per stack.** Before starting, check nothing else is already on it. 4. **Never mutate stack topology.** No base retarget, rebase, stack-wide submit, or force-push from inside a babysit. Fix on the owning branch, report anything rebase-shaped upward, and let the owner do it. An Autopilot-full owner babysitting its own PR is that owner. Where this playbook says to report a rebase, that owner rebases its own branch and publishes it with `git push --force-with-lease` per `playbooks/autopilot-full.md` step 2. In Autopilot-stack, the root is that owner. The one sanctioned creation: when a fix's owning PR has already merged, it becomes a new PR on top of the remaining stack, never a rewrite of merged history, and it is the single case where the frozen queue list of step 6 changes. In a gated repository, follow the gated publish rules in `playbooks/opening-a-pr.md`. Nobody force-pushes a PR branch, and the owner's rebase follows the `rerun` rule there. diff --git a/skills/poteto-mode/references/task-triggers.md b/skills/poteto-mode/references/task-triggers.md index 95b83bb2..edf8414f 100644 --- a/skills/poteto-mode/references/task-triggers.md +++ b/skills/poteto-mode/references/task-triggers.md @@ -18,7 +18,7 @@ Read this reference for the actions named by the mode entry, or when scope chang - Shipping UI / IDE / CLI → use the project's verification skill (`verify-`, generated by the **create-verification-skill** skill), which drives the real surface — browser, Electron, web UI, CLI, or TUI. For bug fixes, reproduce first on the same surface yourself. Hand to the user only under the narrow Bug fix step 1 exception. - Running a benchmark, measuring perf yourself, or reporting a speedup or regression you measured → use the **benchmark-checklist** skill before you report or act on the number. - Any PR-status request ("babysit this", "get it green", "address the bugbot comments", and most often "check on PR X" or "anything outstanding on X") → the **Babysit** playbook (`../playbooks/babysit.md`), not any built-in babysit skill your CLI ships, even when its description matches the same words. Never triggered by merely opening a PR. Declare its mode before polling. The playbook's step 1 owns the request-to-mode mapping. Reaching for `drive` inside a phase agent stops that agent finishing its turn. -- A push changed an open PR's diff, whether yours, an Autopilot owner's, a Babysit or Shipping wave, or a gate fix round → once the new head is published and any gate run has reached its outcome, use the **pr-recap** skill to refresh the PR's recap. +- A push changed an open PR's diff, whether yours, an Autopilot owner's, a Babysit or Shipping wave, or a gate fix round → once the new head is published and any gate run has reached its outcome, use the **pr-recap** skill to refresh the PR's recap. A `threads-only` Babysit fix push refreshes it like any other push. An operator's hold or zero-writes order wins: post no recap, and report the refresh as pending until the operator releases the hold. - Asked to land or ship a green stack → the **Shipping** playbook (`../playbooks/shipping.md`). Green is not safe. Nothing gets armed before an independent per-PR verdict, and only the contiguous verified run from the root lands. - Bugbot, Copilot code review, GitHub Advanced Security, or another automated security reviewer commented → skeptical posture. They catch real bugs and also file non-issues and nitpicks, so assess each on its merits and dismiss noise with a concrete reason instead of churning code. Triage fix / dismiss / ask per `bugbot-triage.md`. - Broken skill mid-task → fix it in its own PR. Don't block. Don't silently work around it. diff --git a/skills/pr-recap/SKILL.md b/skills/pr-recap/SKILL.md index c87a230d..e7d3f7b1 100644 --- a/skills/pr-recap/SKILL.md +++ b/skills/pr-recap/SKILL.md @@ -64,7 +64,7 @@ When your runtime cannot run Bun, or cannot show you an image, skip the sketch. 1. List each factual sentence in the recap and each label in the sketch. 2. Check each one against a hunk of the diff or a SHA-pinned line. Mark it verified, corrected, unsupported, or unverifiable. 3. Fix each corrected claim. Delete each unsupported or unverifiable claim, or rewrite it as a guess. Re-render the sketch if a label changed. -4. Check each link. Pin source links to the recorded head SHA. Review and CI links must point at records on the PR, with CI runs on that head. Never link a bot's review, because a recap does not triage its findings, and watch-pr and merge-gate never count a recap as acknowledging one. +4. Check each link. Pin source links to the recorded head SHA. Review and CI links must point at records on the PR, with CI runs on that head. Never include a bot review's URL anywhere in the comment, code spans included. A recap does not triage a review's findings, and watch-pr and merge-gate never count a recap as acknowledging one. 5. Read `headRefOid` again. If it moved, rebuild the recap from the new diff. Keep the marks in your notes, not in the comment. Report the counts in your reply. From e63103657d4a3e7671d114e443dddae93a0b655d Mon Sep 17 00:00:00 2001 From: mdsmithaustin <15272014+mdsmithaustin@users.noreply.github.com> Date: Sun, 25 Oct 2026 14:21:59 -0600 Subject: [PATCH 3/6] docs(pr-recap): name the Bun version that reads the sketch lockfile Bun 1.3.14 and older fail on bun.lock with Unknown lockfile version and the sketch exits 2. Bun 1.4.0 reads it. The Setup section now says so and names the older-Bun fallback, so a harness skips the sketch or runs it through npx bun@1.4.0 instead of improvising. --- skills/pr-recap/references/sketch.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/skills/pr-recap/references/sketch.md b/skills/pr-recap/references/sketch.md index c7646d59..ff68bf51 100644 --- a/skills/pr-recap/references/sketch.md +++ b/skills/pr-recap/references/sketch.md @@ -94,8 +94,10 @@ Render again and repeat the read once. Report the reader's model and what you ch ## Setup -The tool needs Bun. Its pinned dependencies are in [its package.json](../scripts/sketch/package.json): Rough.js for the strokes, opentype.js to measure text, and resvg to write the PNG. On its first run, and after `package.json` or `bun.lock` changes, the tool runs `bun install --frozen-lockfile`, which needs network access. It first tries its own folder. If installation there fails, it creates a fresh private temporary folder and installs there for that invocation. None of the packages starts a browser. A sandbox needs a writable output folder and either a writable skill folder or a writable temporary folder for the dependencies. +The tool needs Bun 1.4.0 or later. Bun 1.3.14 and older cannot read its `bun.lock` and fail with `Unknown lockfile version`, so the tool exits 2. With an older Bun, run the same command through `npx bun@1.4.0` in place of `bun`, which needs Node and network access. When that is not possible, skip the sketch and say why in your reply. `npm ci` does not work here, because the folder has no `package-lock.json`. -Image viewing and Bun execution remain untested on Hermes only. Follow the skill's [sketch fallback](../SKILL.md#draw-the-sketch) when either capability is unavailable. +Its pinned dependencies are in [its package.json](../scripts/sketch/package.json): Rough.js for the strokes, opentype.js to measure text, and resvg to write the PNG. On its first run, and after `package.json` or `bun.lock` changes, the tool runs `bun install --frozen-lockfile`, which needs network access. It first tries its own folder. If installation there fails, it creates a fresh private temporary folder and installs there for that invocation. None of the packages starts a browser. A sandbox needs a writable output folder and either a writable skill folder or a writable temporary folder for the dependencies. + +Hermes v0.22.4 has run the tool and viewed the PNG with `vision_analyze`. Follow the skill's [sketch fallback](../SKILL.md#draw-the-sketch) when either capability is unavailable. When the tool exits 2, read its message. If it cannot install a package or write the PNG, skip the sketch and say why in your reply. From 50625b127e0e27820d840249eada13dabb85c282 Mon Sep 17 00:00:00 2001 From: mdsmithaustin <15272014+mdsmithaustin@users.noreply.github.com> Date: Sun, 25 Oct 2026 14:28:21 -0600 Subject: [PATCH 4/6] no-mistakes(document): Centralize recap refresh timing and hold guidance --- skills/pr-recap/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/pr-recap/SKILL.md b/skills/pr-recap/SKILL.md index e7d3f7b1..f860c5c3 100644 --- a/skills/pr-recap/SKILL.md +++ b/skills/pr-recap/SKILL.md @@ -17,7 +17,7 @@ For a skipped PR, post nothing on GitHub. Put one line in your reply: `Recap skipped for PR : , .` -Otherwise, write the recap. Write it again after each push that changes the diff, once the new head is published and any gate run on it has reached its outcome. +Otherwise, write the recap. For post-push refresh timing and operator holds, follow [task triggers](../poteto-mode/references/task-triggers.md). ## Gather the facts From 5a983b74cbf0566ecf141d8bc8bc9956dfab2456 Mon Sep 17 00:00:00 2001 From: mdsmithaustin <15272014+mdsmithaustin@users.noreply.github.com> Date: Sun, 25 Oct 2026 14:40:01 -0600 Subject: [PATCH 5/6] docs(pr-recap): keep the refresh timing sentence in the skill The skill is installed on its own, so a link to a poteto-mode reference can dangle. --- skills/pr-recap/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/pr-recap/SKILL.md b/skills/pr-recap/SKILL.md index f860c5c3..e7d3f7b1 100644 --- a/skills/pr-recap/SKILL.md +++ b/skills/pr-recap/SKILL.md @@ -17,7 +17,7 @@ For a skipped PR, post nothing on GitHub. Put one line in your reply: `Recap skipped for PR : , .` -Otherwise, write the recap. For post-push refresh timing and operator holds, follow [task triggers](../poteto-mode/references/task-triggers.md). +Otherwise, write the recap. Write it again after each push that changes the diff, once the new head is published and any gate run on it has reached its outcome. ## Gather the facts From a464a2f092ca0ab1e72bdaf88d177f42e5fd814d Mon Sep 17 00:00:00 2001 From: mdsmithaustin <15272014+mdsmithaustin@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:25:47 -0600 Subject: [PATCH 6/6] docs(pr-recap): spell out the npx fallback and keep the porting note for babysit The fallback now passes --allow-scripts=bun, because npm 12 skips Bun's install script and the old wording failed there. Setup names 1.4.0 as the minimum without claiming a version range, and the skip rule applies only after the fallback fails. PORTING.md lists the threads-only sentence in Babysit step 1 next to the trigger line. --- PORTING.md | 2 +- skills/pr-recap/references/sketch.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PORTING.md b/PORTING.md index 535629c7..154d704f 100644 --- a/PORTING.md +++ b/PORTING.md @@ -46,7 +46,7 @@ Upstream is the source of truth for the workflows themselves. This file records - `worktree-audit.sh` and the [Worktree cleanup playbook](skills/poteto-mode/playbooks/worktree-cleanup.md) guard kept files, a port fix for #167 from 2026-10 that can be offered upstream. Steps 4 and 5 own the output contract and removal guard. On sync, preserve the script's NUL-delimited status parsing and explicit `--ignored=matching`, `--untracked-files=normal`, and `--ignore-submodules=none` flags. Preserve the nested `.git` scan, which reports a checkout even under an ignored build cache and skips one under an already reported kept directory. Preserve the `git ls-files -v` count of present skip-worktree and assume-unchanged files as `wip`, the case-insensitive fixed-string `rg -F -i` transcript match, and the `unreadable` result with bucket `hold-kept` when status, `ls-files`, or the scan fails. Preserve the porcelain worktree-path parsing with `sed -n 's/^worktree //p'` for paths with spaces. Keep the regression coverage in `tools/test_worktree_audit.py` and `WorktreeAuditPromises` in `evals/promises/test_scripts.py` when upstream rewrites either file, and keep the `ripgrep` install in the `lint.yml` skills job, without which most of `tools/test_worktree_audit.py` skips. Do not restore upstream's disposable `scratch:N` classification. - **documentation-impact** (`skills/documentation-impact/`) is a port addition for authoring and independently reviewing documentation affected by a change. Preserve its auto-invocable metadata, `tools/skill-trigger-cases.json` entry, README and guide entries, central Poteto completion trigger, and Babysit and Shipping readiness hooks during sync. Preserve its canonical author result rules. The pass covers local work without a PR and binds any required independent review verdict to the examined artifact and documentation context. Visual tools remain optional. Keep model selection and lifecycle orchestration in the calling workflow. -- **pr-recap** (`skills/pr-recap/`) is a port addition that posts one reviewer recap comment per pull request: a two-sentence story, one hand-drawn sketch rendered by the bundled Bun tool in `scripts/sketch` and attached with `gh`, a "Not covered" line, and a collapsed details block. `skills/pr-recap/CREDITS.md` carries the MIT notices for the six skills its rules adapt and the OFL notice for the vendored Excalifont subset. On sync, keep the skill, its trigger row, the **Recap** paragraph in Opening a PR, the sketch tests in `tests/skills/pr-recap/`, and their `lint.yml`, `tools/gate-check.sh`, and Dependabot entries. Its refresh trigger in `skills/poteto-mode/references/task-triggers.md` is also a port addition, so keep that line when a sync rewrites the trigger list. +- **pr-recap** (`skills/pr-recap/`) is a port addition that posts one reviewer recap comment per pull request: a two-sentence story, one hand-drawn sketch rendered by the bundled Bun tool in `scripts/sketch` and attached with `gh`, a "Not covered" line, and a collapsed details block. `skills/pr-recap/CREDITS.md` carries the MIT notices for the six skills its rules adapt and the OFL notice for the vendored Excalifont subset. On sync, keep the skill, its trigger row, the **Recap** paragraph in Opening a PR, the sketch tests in `tests/skills/pr-recap/`, and their `lint.yml`, `tools/gate-check.sh`, and Dependabot entries. Its refresh trigger in `skills/poteto-mode/references/task-triggers.md` and the `threads-only` sentence in step 1 of `skills/poteto-mode/playbooks/babysit.md` are also port additions, so keep that line and that sentence when a sync rewrites them. - **statechart** (`skills/statechart/`) keeps upstream's scripts. Its tests live in `tests/skills/statechart/scripts/test/`, per the tests-out-of-`skills/` rule. Upstream runs them in a `validate-plugins.yml` step. Here they run in the `statechart script tests` step of the `lint.yml` skills job and in the `statechart node tests` line of the `gate-check.sh` test tier, both as `node --test` over `*.test.mjs`. CI uses the runner's preinstalled Node, because `tools/test_repository_hardening.py` bans `setup-node`. On sync, carry upstream changes to that step into both places. - **deslop** (`skills/deslop/`) is a port addition that replaces cursor-team-kit's `/deslop` with a pstack-owned code cleanup pass: nineteen numbered rules over the branch's changed hunks, a test run that proves behavior unchanged, and a report. `skills/deslop/CREDITS.md` ships inside the skill directory so the MIT notices travel with every `npx skills` copy. On sync, keep the skill, its trigger row in `tools/skill-trigger-cases.json`, the README and guide entries, poteto-mode's Before every commit or amend trigger, the deslop lines in Opening a PR, both autopilot playbooks, and the multi-phase checklist, step 5's hand-off to the no-comments skill and its Report line, and the ledger promises `deslop-available-for-code`, `opening-a-pr-deslops-diff`, `deslop-cleans-code-slop`, and `deslop-hands-unsettled-comments-to-no-comments`. Upstream never writes `skills/deslop/`; if it ever does, keep whichever version has the rule table. - **Gated publish** (port addition, 2026-10). In a repository that gates pushes through no-mistakes, Opening a PR's **Gated publish** section routes every publish, PR creation, restack, and retarget through the no-mistakes CLI, sends work-in-progress snapshots to `refs/pstack/wip/` or the repository's own agent ref convention, and hands sandbox work to the host. On sync, keep that section, the gated pointers in Babysit, Shipping, Autopilot-full, Autopilot-stack, Orchestrate, and the multi-phase checklist, the guide paragraph in `docs/guide/06-verify-and-ship.md`, the `no-mistakes` line in `tools/cross-suite-foreign.txt`, and the `opening-a-pr-gated-publish-*` ledger promises with the `open-pr-gated-run` case. diff --git a/skills/pr-recap/references/sketch.md b/skills/pr-recap/references/sketch.md index ff68bf51..592cd49a 100644 --- a/skills/pr-recap/references/sketch.md +++ b/skills/pr-recap/references/sketch.md @@ -94,10 +94,10 @@ Render again and repeat the read once. Report the reader's model and what you ch ## Setup -The tool needs Bun 1.4.0 or later. Bun 1.3.14 and older cannot read its `bun.lock` and fail with `Unknown lockfile version`, so the tool exits 2. With an older Bun, run the same command through `npx bun@1.4.0` in place of `bun`, which needs Node and network access. When that is not possible, skip the sketch and say why in your reply. `npm ci` does not work here, because the folder has no `package-lock.json`. +The tool needs Bun 1.4.0 or later. Earlier releases cannot read its `bun.lock`. Most fail, for example with `Unknown lockfile version`, and the tool exits 2. Some ignore the lockfile and install unpinned packages. With a Bun older than 1.4.0, run `npx --allow-scripts=bun bun@1.4.0 "/scripts/sketch/sketch.mjs" scene.json sketch.png`, which needs Node and network access. Without `--allow-scripts=bun`, npm 12 skips Bun's install script and the command fails. `npm ci` does not work here, because the folder has no `package-lock.json`. Its pinned dependencies are in [its package.json](../scripts/sketch/package.json): Rough.js for the strokes, opentype.js to measure text, and resvg to write the PNG. On its first run, and after `package.json` or `bun.lock` changes, the tool runs `bun install --frozen-lockfile`, which needs network access. It first tries its own folder. If installation there fails, it creates a fresh private temporary folder and installs there for that invocation. None of the packages starts a browser. A sandbox needs a writable output folder and either a writable skill folder or a writable temporary folder for the dependencies. Hermes v0.22.4 has run the tool and viewed the PNG with `vision_analyze`. Follow the skill's [sketch fallback](../SKILL.md#draw-the-sketch) when either capability is unavailable. -When the tool exits 2, read its message. If it cannot install a package or write the PNG, skip the sketch and say why in your reply. +When the tool exits 2, read its message. If it could not install a package, run the `npx` command above unless you already did. Skip the sketch and say why in your reply when that command also fails or the tool cannot write the PNG.