diff --git a/claude-code/.claude/skills/issue/SKILL.md b/claude-code/.claude/skills/issue/SKILL.md deleted file mode 100644 index 25f7132..0000000 --- a/claude-code/.claude/skills/issue/SKILL.md +++ /dev/null @@ -1,272 +0,0 @@ ---- -name: issue -description: File one or many GitHub issues from any input — a sentence, a meeting transcript, a funder email. Auto-detects single-vs-batch and asks for approval before filing anything in batch mode. -disable-model-invocation: true -argument-hint: " [--repo ] [--dry-run] [--no-confirm]" -allowed-tools: Bash(gh:*), Read, Grep, Glob -model: opus ---- - -# /issue — file GitHub issues from arbitrary input - -Operator-only command. Takes anything from a one-sentence note to a pasted meeting transcript and turns it into well-formed GitHub issues that `scout`/`triage` would themselves accept. Auto-detects single-vs-batch — the operator never declares a mode. - -Read these every fire (auto-load via `InstructionsLoaded`; this skill must respect them, not work around them): - -- `~/.claude/rules/pipeline-nevers.md` — conventional-commit prefixes, never apply `auto:approved`, never apply `override:*` -- `~/.claude/rules/context-repo.md` — sensitivity taxonomy and STAGE 13 confidentiality leak rule (load-bearing for sanitization) -- `~/.claude/rules/advocacy-domain.md` — ubiquitous-language terms; titles and bodies must use them -- `~/.claude/rules/voice.md` — no flattery, no corporate filler in issue bodies either - -Issues this skill files must be drop-in acceptable to `~/.claude/agents/scout.md` (well-formed: real observation, no fabricated paths, dedup-checked) and `~/.claude/agents/triage.md` (label set + sensitivity reasoning ready to be confirmed). If you find yourself wanting to relax those agents to make this skill easier, stop and report instead. - -`/issue` runs under whichever `gh auth` identity is active — operator or bot. The bot/operator split governs commits and automation (`~/.claude/rules/git-identity.md`), not issue authorship; a manufactured "switch identities first" gate would manufacture an approval gate the pipeline doesn't need. - -## Argument parsing - -`$ARGUMENTS` is the raw input. Parse out flags first, then everything remaining (in original order) is the input text: - -- `--repo ` — explicit target repo. Overrides any inferred repo. In Mode B, applied as a default to all extracted candidates (per-candidate inference can still override if the candidate explicitly names a different repo). -- `--dry-run` — compute the full plan but never call `gh issue create`. Output everything that would be filed. -- `--no-confirm` — Mode A only: skip the confirm prompt and file immediately. **Forbidden in Mode B.** If `--no-confirm` is set and detection lands on Mode B, error out: `--no-confirm is forbidden in batch mode; remove the flag and re-run`. - -Empty input after flag-stripping → output one-line usage hint and stop. - -## Algorithm - -### STEP 1 — Mode detection (deterministic, first match wins) - -1. **Mode A (Direct file)** — input is ≤3 sentences AND a repo can be resolved per STEP 2. -2. **Mode B (Decompose and triage)** — input is >3 sentences OR contains multi-item markers. -3. **Mode C (Clarify)** — anything else (chiefly: short input where repo can't be resolved). - -**Sentence count.** Count terminal punctuation (`.`, `!`, `?`) outside code blocks (` ``` ... ``` ` and ` ` ... ` `), URLs (anything matching `https?://...`), and the abbreviation set: `e.g.`, `i.e.`, `etc.`, `vs.`, `Mr.`, `Mrs.`, `Dr.`, `St.`, `Inc.`, `Ltd.`, `U.S.`, `U.K.`, `cf.`. Be conservative — "I noticed the deploy is broken. Can you file something?" is **2 sentences**, Mode A. - -**Multi-item markers.** Any of: - -- Two or more lines starting with bullet glyphs at column 0 (after optional whitespace): `-`, `*`, `•`, `–` -- Two or more numbered list lines: `1.`, `1)`, `2.`, `2)`... -- Conjunctive phrases (case-insensitive): `and also`, `another thing`, `another issue`, `separately`, `second issue`, `third issue`, `next thing` -- Two or more paragraph breaks (`\n\n`) with topic shifts. Topic-shift detection is judgment — paragraphs that share subject/error/repo are not topic shifts; paragraphs that cover unrelated systems are. When uncertain, prefer Mode B (decompose) over Mode A — Mode B has an explicit approval gate, Mode A does not. - -### STEP 2 — Repo inference (deterministic, fail-safe; first success wins) - -a. `--repo` flag is set → use it. Stop. -b. **Literal repo-name token in input.** Tokenize the input on whitespace + punctuation; if any token exactly matches a name in the canonical Open-Paws repo list (cached via `gh repo list Open-Paws --limit 200 --json name`), use that repo. Stop. -c. **Nickname in input** — match against the alias map below (case-insensitive, whole-word match only). Stop on first hit. -d. **Cwd inside an Open-Paws checkout** — `git rev-parse --show-toplevel` inside cwd; if it resolves and the basename matches an Open-Paws repo, use that. Stop. -e. **Fail.** Mode A falls through to Mode C. (Inference NEVER falls back on content keywords. "There's an auth bug" without a repo token does NOT become `ai-security`. Misfiling is worse than asking.) - -### STEP 3a — Mode A (Direct file) - -1. **Draft.** - - - **Title** — imperative, specific, ≤80 chars. Use ubiquitous-language terms from `advocacy-domain.md` where applicable. Good: `Add --delete-branch to /merge command output`. Bad: `merge command thing`, `fix this`. - - **Body** — exactly three sections: - - ``` - **Observed:** - - **Expected:** - - **Next step:** - ``` - - - **Labels** — type (`type:bug` / `type:feature` / `type:chore` / `type:docs` / `type:refactor` / `type:security` / `type:proposal`), severity (`severity:trivial` / `severity:minor` / `severity:major` / `severity:blocker`), and component if obvious from input. Apply `stage:triaged` so triage picks it up. **Never** apply `auto:approved`, `auto:auto-fixable`, `auto:requires-human`, or any `override:*` label — those are gates triage owns, not defaults filing owns. - - Confirm every label exists in the target repo via `gh label list --repo Open-Paws/` before applying. Drop labels that don't exist; do not auto-create. - -2. **Sanitize.** Run STEP 4 on the body. - -3. **Dedup probe.** `gh issue list --repo Open-Paws/ --search "<3-5 keywords from title>" --state all --limit 10`. If a clear duplicate exists, surface it: `Possible duplicate: # "" (<state>) — file anyway? (y/n)`. Operator confirms or aborts. - -4. **Display the draft.** - - ``` - ## /issue — Mode A (direct file) → Open-Paws/<repo> - - **Title:** <title> - **Labels:** <comma-separated> - - **Body:** - <rendered body> - - --- - File this? (y / edit / n) - ``` - -5. **Operator response.** - - - `y` → file via `gh issue create --repo Open-Paws/<repo> --title "<title>" --body "<body>" --label "<l1>" --label "<l2>" ...`. Emit the URL gh prints. - - `edit` → drop the operator into editing the title and/or body inline (one prompt for title, one for body; empty input keeps existing). After edits, file directly. **Do not re-sanitize after operator edits** — the operator's edit is the final word; they may have intentionally added something (per Hard Rules). - - `n` → abort, no file, no follow-up. - -6. **`--no-confirm`** — skip step 4's prompt and file the draft directly. Still run sanitization (step 2) and the dedup probe (step 3). If dedup finds a clear duplicate, abort and surface the duplicate URL — `--no-confirm` does not override dedup safety. - -7. **`--dry-run`** — render the full draft block above, append `(dry-run; nothing filed)` and stop. No `gh issue create` call. - -### STEP 3b — Mode B (Decompose and triage) - -1. **Extract candidates.** Walk the input and pull every actionable item — anything that, if isolated, could become its own issue. Skip: - - - Pure discussion ("we should think about X someday") - - Strategy / fundraising debate - - Philosophical asides - - Status updates with no action ("the deploy went fine") - - Each kept candidate gets: a short summary (becomes draft title), the literal source span (for sanitization), and any repo-relevant tokens. - -2. **Per-candidate processing.** - - For each candidate: - - - **Repo.** Run STEP 2 inference per-candidate. `--repo` is the default but explicit per-candidate naming overrides. If unresolved → mark as `???` (operator must set before that row can be filed). - - **Dedup classification.** `gh issue list --repo Open-Paws/<repo> --search "<keywords>" --state all --limit 10`. Classify into one bucket: - - `NEW` — no matching open or recently-closed (≤90d) issue - - `DUPLICATE_OF #N` — matches an open issue or a recent close that addresses the same thing (link `#N`) - - `ALREADY_RESOLVED` — matches a closed issue that already addresses it (link `#N`, note the closing PR if any) - - `OUT_OF_SCOPE` — judged not-actionable on closer read (discussion / strategy / opinion). Always show this with a one-line reason; never silently drop. - - **Draft.** For NEW only, draft title + body using the same shape as Mode A. Run STEP 4 (sanitize) on each. - - **Labels.** Same rules as Mode A. - -3. **Display the classification table.** - - ``` - ## /issue — Mode B → extracted N candidates from input - - | # | Action | Repo | Title | Reason | - |---|-------------------|-----------------------|----------------------------------|--------------------------------------| - | 1 | NEW | <repo> | <draft title> | not present in open or recent issues | - | 2 | DUPLICATE_OF #299 | <repo> | (matches #299) | #299 opened 4d ago, same root cause | - | 3 | NEW | ??? | <draft title> | could not infer repo — needs operator| - | 4 | OUT_OF_SCOPE | — | <one-line summary> | strategy discussion, not actionable | - - Approve which rows for filing? - all — file every NEW row with a resolved repo - 1,3,6-9 — file these row numbers only - all except 4 — file every NEW row with a resolved repo, minus #4 - none — abort everything - edit <n> — edit row <n>'s draft (title/body/labels) before filing - set repo <n> <reponame> — resolve a ??? row's repo - ``` - -4. **Operator selects.** Loop on `set repo` and `edit` until the operator says `all`, a row list, `all except ...`, or `none`. **Any row whose repo is `???` is unfileable** — operator must explicitly resolve before that row can be approved. If the operator's selection includes a still-`???` row, refuse the selection and re-display the table. - -5. **File approved rows.** For each, render the draft and call `gh issue create --repo Open-Paws/<repo> ...`. Emit a final list grouped by repo: - - ``` - Filed: - Open-Paws/<repo-a>: - - #<n> <url> - - #<n> <url> - Open-Paws/<repo-b>: - - #<n> <url> - ``` - -6. **Atomic-ish failure mode.** If the first `gh issue create` in the batch fails, abort the rest. Print partial state explicitly: `Filed N of M before failure on row K (<reason>). Remaining rows NOT filed; re-run /issue or file manually`. Do not retry inline. - -7. **`--dry-run`** — render the table and (for every NEW row) the full sanitized draft body in a collapsed-list format. No `gh issue create` calls. Skip the approval prompt; instead append `(dry-run; nothing filed)`. - -### STEP 3c — Mode C (Clarify) - -1. **Ask exactly ONE question.** Pick the question that most reduces the search space: - - - If repo is the blocker: `Which repo? Recent activity in: <list 3 most plausible based on input>` (use `gh repo list Open-Paws --limit 200 --json name,pushedAt --sort pushedAt` and the alias map). - - If scope is the blocker (input is unclear about whether it's one issue or many): `Is this one issue or multiple? A one-line summary of what you're filing helps.` - - If intent is the blocker (input doesn't make clear what kind of issue): `Is this a bug, an enhancement, or a discussion item?` - -2. **Wait for the operator.** Once they reply, concatenate their answer onto the original input and re-run STEP 1 with combined input. - -3. **One question, no second.** If the combined input is still ambiguous, output: `I can't pick this up from what's been described. Want to draft it manually and I'll polish?` Stop. No second clarifying question — that's nagging. - -### STEP 4 — Sensitivity sanitization (every body, both modes) - -1. **Tier the target repo.** Per `~/.claude/rules/context-repo.md`: - - - `Open-Paws/context` → tier is `staff-ok` by default for context-repo issues; treat as **mild strip**. Never paste verbatim if input was clearly meeting-transcript or email-private. - - All other public Open-Paws code repos → `public` → **strict strip**. - - Private Open-Paws repos (if any) → `private` → sanitization step is **bypassed** unless the input was sourced from a confidential origin (Slack DM, locked CryptPad, private email thread, etc.). If the input came from a confidential origin, verbatim copying is forbidden — paraphrase, even though the target repo itself is private. - - **Unknown tier** → ask once: `<repo> sensitivity tier? (public / staff-ok / private)`. Do not assume. Cache the answer for this fire. - -2. **Strict-strip rules (`public` tier).** - - - Remove names of external individuals (funders, partners, third parties, journalists, consultants). Replace with role: `the funder`, `a partner org rep`, `the consultant`, `the journalist`. - - Remove names of external organizations that are not already public. Use generic descriptors: `a foundation`, `a coalition partner`, `a vendor`. - - Remove email addresses, phone numbers, internal URLs, dashboard links containing tokens or session ids, anything that looks like a credential or secret. - - Remove any verbatim Slack/CryptPad/email source paste — paraphrase. - - **Keep:** technical detail, error messages, public-facing URLs, repo references, public issue numbers, public PR numbers, public commit SHAs. - -3. **Mild-strip rules (`staff-ok` tier).** - - - Same as strict, EXCEPT internal staff names and internal program names may stay. External individuals/orgs still get stripped per strict. - -4. **Verbatim is forbidden.** NEVER paste raw input verbatim into an issue body. Quote sparingly — at most one sentence — and paraphrase the rest. For Mode B candidates derived from a transcript or email, prepend the body with one provenance line: - - ``` - > from: <one-sentence paraphrase or sanitized quote of the source> - ``` - - DO NOT dump the whole transcript or email into the body. Ever. - -5. **STAGE 13 self-check.** Before emitting any body bound for a `public`-tier repo, re-read the STAGE 13 confidentiality-leak patterns in `context-repo.md`: - - - Closed decision citing a specific funder's objection - - Priority justified by "we lost trust with X partner" - - Program doc listing specific individuals as "struggling" - - Playbook referencing active campaign targets by name before launch - - If anything in the draft would fail STAGE 13 if it were a PR comment, strip it harder — abstract up a level or remove. When in doubt, the rule from `context-repo.md` applies: *the default direction is out, not in*. - -## Hard rules - -These are non-negotiable. If a rule and a plausible operator request conflict, the rule wins; surface the conflict. - -1. **Never apply `auto:approved`, `auto:auto-fixable`, `auto:requires-human`, or any `override:*` label.** Those are gates triage and humans own; filing only sets `stage:triaged` plus type/severity/component. -2. **Never file an issue body that contains raw transcript or email content.** Paraphrase, quote sparingly (one sentence max), strip per the sensitivity tier. -3. **Never silently drop a candidate in Mode B.** Every extracted item appears in the table — even `OUT_OF_SCOPE` ones, with a one-line reason. -4. **Never infer repo from content keywords alone.** STEP 2 rule (c) is strict: explicit token / alias whole-word match only. "There's an auth bug" without a repo token does not become `ai-security`. -5. **Never ask more than one clarifying question per turn** (Mode C). If still ambiguous after one round, hand it back to the operator with a "draft it manually and I'll polish" offer. -6. **`--no-confirm` is forbidden in Mode B.** Batch filing always requires explicit approval. Detection-time conflict → error out, do not silently downgrade to Mode A. -7. **The operator's edit on a Mode A draft is the final word.** Do not re-sanitize after their edit; they may have intentionally added something. (Strict sanitization runs *before* showing the draft, exactly once.) -8. **`gh` errors stop the run.** If `gh issue create` returns an error, surface it verbatim and stop. Do not retry inline. Do not half-file a Mode B batch — file all approved rows in order, abort at the first failure, surface partial state explicitly. -9. **Refuse under bot identity.** The startup gate above is mandatory. No `--force`, no env-var override. - -## Repo aliases - -Whole-word, case-insensitive match. Operator extends this map over time. - -| Alias | Resolves to | -|--------------------------------------|---------------------------| -| `slingshot` | `slingshot-uk-phase1` | -| `platform` | `platform` | -| `bot`, `gary` | `gary` | -| `language tooling`, `nav`, `no-animal-violence` | `no-animal-violence` | -| `context`, `why` | `context` | -| `desloppify` | `desloppify` | -| `coderabbit` | `coderabbit` | -| `graze` | `graze-cli` | -| `where they stand`, `wts` | `where-they-stand` | -| `ai security`, `ai-security` | `ai-security` | -| `c4c`, `bootcamp` | `c4c-bootcamp` | -| `c4c website` | `c4c-campus-website` | -| `mobius` | `mobius-real-estate` | -| `avs`, `vegan recommendations` | `avs-vegan-recommendations` | -| `protein library` | `Protein-Research-Library` | -| `ace` | `ace-research-library` | -| `cryptpad pm` | `cryptpad-project-management` | -| `n8n` | `n8n-workflow-history` | -| `proxy`, `privatemode` | `privatemode-proxy` | -| `api gateway` | `api-gateway` | -| `compassionate code` | `project-compassionate-code` | -| `docs` | `documentation` | -| `structured`, `instruction files` | `structured-coding-with-ai` | -| `org-default`, `.github` | `.github` | - -Multi-word aliases match as whole phrases (e.g. `language tooling` matches `... the language tooling repo ...` but not `language` alone). Single-word aliases require word-boundary match (the regex `\b<alias>\b`). - -When a candidate has both an explicit repo-name token (rule b) and a nickname (rule c), the repo-name token wins — explicit beats inferred. - -## End-to-end behavior summary - -- Operator pastes input → bot-identity gate → flags parsed → mode detected → repo inferred → draft(s) built → sanitized → (Mode A: confirm) / (Mode B: classification table + approval) / (Mode C: one question) → `gh issue create` calls → URLs back to operator. -- `--dry-run` short-circuits the `gh issue create` calls only; everything else (drafting, sanitization, dedup probes, classification) runs as normal. -- Nothing about this skill drives the pipeline forward. It's a feeder for STAGE 1 (scout) → STAGE 2 (triage). What it files, scout/triage will pick up next. diff --git a/claude-code/.claude/skills/merge/SKILL.md b/claude-code/.claude/skills/merge/SKILL.md deleted file mode 100644 index a76d132..0000000 --- a/claude-code/.claude/skills/merge/SKILL.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -name: merge -description: Ranked merge queue with honest confidence scoring. Replaces "open 12 PR tabs" with one table. Pulls open PRs from gh, filters to `stage:ready-for-merge` (plus all-gates-green PRs without a blocking stage label), runs its own per-PR evaluation, computes calibrated HIGH/MED/LOW confidence, emits a markdown table with clickable PR links and copy-paste merge commands. Read-only — never merges, never invokes subagents. Operator-only. -disable-model-invocation: true -argument-hint: "[--risky] [--repo <name>]" -allowed-tools: Bash(gh:*), Bash(head:*), Bash(ls:*), Bash(date:*), Bash(stat:*), Read, Grep, Glob -model: opus ---- - -# /merge — ranked merge queue, no auto-merge - -Read-only operator HUD. Pulls open PRs directly from gh, filters to `stage:ready-for-merge` (and all-gates-green PRs without a blocking stage label), runs its own per-PR evaluation against the calibration rules below, emits clickable PR links and copy-paste merge commands the operator runs themselves. - -`/merge` does NOT merge. It does NOT drive the pipeline (that's `/run`). It does NOT invoke subagents. It does NOT depend on the latest `/run` report — gh is the source of truth, and this command does its own eval. - -Read these every fire (auto-load via `InstructionsLoaded`; cite by name in any followup question): - -- `~/.claude/rules/pipeline-nevers.md` — `override:skip-adversarial`, `override:allow-score-drop` are MED-cap signals (never HIGH); never merges to main directly -- `~/.claude/rules/context-repo.md` — sensitivity:private files in a PR cap confidence at MED -- `~/.claude/rules/advocacy-domain.md` — bounded contexts list (used to detect scope-creep) - -## Argument parsing - -`$ARGUMENTS`: -- `--risky` — invert sort to ascending (LOW first); default sort is descending (HIGH first) -- `--repo <name>` — single-repo scope (`Open-Paws/<name>`) - -## Algorithm - -### 1. Pull candidate PRs from gh (primary path — always run this) - -The canonical input is `gh pr list`, not the run log. Always derive live. - -**Step A — labelled `stage:ready-for-merge` PRs:** - -```bash -gh pr list --repo Open-Paws/<repo> --state open \ - --label 'stage:ready-for-merge' \ - --json number,title,labels,url,statusCheckRollup,reviewDecision,mergeStateStatus,mergeable,headRefName,additions,deletions,changedFiles \ - --limit 100 -``` - -**Step B — all-gates-green sweep** (catches PRs that are functionally ready but missing the label, e.g. label-application drift): - -```bash -gh pr list --repo Open-Paws/<repo> --state open \ - --json number,title,labels,url,statusCheckRollup,reviewDecision,mergeStateStatus,mergeable \ - --limit 200 -``` - -Client-side filter: keep PRs where `statusCheckRollup` is all-SUCCESS AND labels contain none of `stage:plan-in-progress`/`stage:tests-in-progress`/`stage:impl-in-progress`/`stage:fix-needed`/`stage:adversarial-pending`. Tag these as "no label, all green" in the source column so the operator knows they came in via the sweep, not the official label. - -**Repo scope:** - -- `--repo <name>` set → just that repo -- Not set → walk every Open-Paws repo where `OpenGaryBot` has push access. Get the list with `gh repo list Open-Paws --limit 100 --json name,viewerPermission` and keep entries where `viewerPermission` is `WRITE` or `ADMIN`. - -**Deduplicate** between Step A and Step B by `(repo, number)`. - -### 1b. Optional: cross-reference the latest run log (secondary signal only) - -```bash -FIXTURE_LATEST=$(ls -t ~/.claude/orchestrator-log/run-*-fixture.md 2>/dev/null | head -1) -ORCH_LATEST=$(ls -t ~/.claude/orchestrator-log/run-*.md 2>/dev/null | grep -v -- '-fixture\.md$' | head -1) -if [ -z "$FIXTURE_LATEST" ]; then - LATEST="$ORCH_LATEST" -elif [ -z "$ORCH_LATEST" ]; then - LATEST="$FIXTURE_LATEST" -elif [ "$FIXTURE_LATEST" -nt "$ORCH_LATEST" ]; then - LATEST="$FIXTURE_LATEST" -else - LATEST="$ORCH_LATEST" -fi -``` - -Newest-of-both, not fixture-first. A stale fixture must not shadow a fresh real run report. - -If `LATEST` exists AND its mtime is within the last 30 minutes, read it ONLY to harvest two specific signals that are otherwise expensive to recompute live: - -- Adversarial subagent verdicts mentioned per-PR (cheap signal for the LOW caps below) -- Decision-conflict flags raised by the planner / plan-reviewer - -Do NOT use the run log to determine which PRs are candidates. Do NOT inherit the run log's HIGH/MED/LOW classification — recompute from scratch against the rules below. The run log is a hint store; gh is the source of truth. - -If `LATEST` is stale or missing, skip this step entirely. The eval still works; you just lose the prior-context shortcut. - -### 2. Per-PR signals to gather - -For each candidate PR, fetch: - -```bash -gh pr view <repo>/<num> --json number,title,labels,url,statusCheckRollup,reviewDecision,mergeStateStatus,mergeable,headRefName,additions,deletions,changedFiles,files,comments,body -``` - -Plus, if the PR touches a deployed surface, look for "live HTTP check" evidence in PR comments — search for `gh pr view --comments` output containing patterns like `curl -i`, `health check`, `200 OK`, `live check passed`. If none, the deployed-surface MED-cap fires. - -### 3. Confidence calibration (read carefully — calibration is half the value of this command) - -**A PR is NEVER HIGH if any of the following are true** (these always cap at MED or lower): - -- Label `override:skip-adversarial` is present -- Label `override:allow-score-drop` is present -- PR deploys application code AND no live HTTP check post-build is recorded in PR comments - - Detect deployed service via files matched: `Dockerfile`, `cloudrun*.yaml`, `vercel.json`, `supabase/functions/`, `.github/workflows/deploy*.yml`, etc. - - **Workflow-only carve-out:** If the ONLY deploy-surface files in the PR are themselves the deploy mechanism (e.g., the PR adds or modifies `.github/workflows/deploy*.yml` or a `Dockerfile`) AND no application code files are touched (no `src/`, `app/`, `lib/`, `pages/`, `components/`, `*.ts`/`*.tsx`/`*.py`/`*.go` etc. outside `tests/`), the cap does NOT fire. Adding the deploy mechanism doesn't deploy anything until the next code change merges. Live HTTP checks become relevant when the PR after this one ships actual code. -- Files touched include any path tagged `sensitivity:private` per `context-repo.md` -- CodeRabbit found anything above informational severity (parse PR comments for `**Issue:**`/`**Refactor:**`/`**Bug:**`/`**Note:**` blocks; the `chill` profile uses `Note:` for informational, so anything else is above-informational) -- Any test in the PR was classified as `skip:flaky` by test-reviewer (look for that label OR comment from `test-reviewer` mentioning the classification) -- Time since `stage:verified` was applied (or last `verifier` completion comment) exceeds 24h (stale verification) -- PR touches a UI surface (`*.tsx`, `*.jsx`, `*.vue`, `*.svelte`, `app/`, `pages/`, `components/`) AND no `persona-qa` completion comment is present on the PR -- `reviewDecision == CHANGES_REQUESTED` (a reviewer — CodeRabbit or human — flagged a change still unaddressed; merging now ignores that feedback) -- `mergeStateStatus == BEHIND` (head ref out of date; merge command will bounce until the branch is rebased onto base — content may be clean but the operation can't complete) -- `mergeStateStatus == BLOCKED` (branch protection blocks direct merge — content may be clean, but a required check is missing, the branch needs an admin override, or branch-protection criteria aren't met). - -**A PR is LOW if any of the following are true:** - -- `mergeable == CONFLICTING` or `mergeStateStatus == DIRTY` (actual merge conflict — needs manual rebase + conflict resolution before any merge command will work, regardless of content quality) -- Multiple of the MED-cap conditions above stack (count ≥ 2) -- The `adversarial` subagent flagged anything as `needs-human-review` (look for that phrase in adversarial completion comment) -- PR conflicts with a closed decision in `$OP_CONTEXT_REPO/decisions.md` (cross-reference any decision-conflict entry from the run log; on direct derivation, scan PR body + diff for keywords against `$OP_CONTEXT_REPO/decisions.md` headings) -- Files touched span more than 3 of the bounded contexts in `~/.claude/rules/advocacy-domain.md` (Investigation Operations / Public Campaigns / Coalition Coordination / Legal Defense). Use heuristic: any file under `*/investigations/*` → Investigation Operations; under `*/campaigns/*` or `*/petitions/*` → Public Campaigns; under `*/coalitions/*` or `*/partners/*` → Coalition Coordination; under `*/legal/*` or `*/cases/*` → Legal Defense. Probable scope creep. - -**Otherwise: HIGH.** - -### 4. Calibration intent (this is why the score is useful) - -The score answers ONE question: *is this PR safe to merge right now with no further pipeline action?* If a required check is missing, branch protection is unsatisfied, or the merge command will bounce, the answer is no — and that drops confidence by design. The score is mechanical, not aspirational. - -A clean bot-authored PR — CI green, no CodeRabbit issues, adversarial cleared, no merge conflict, no stale verifier, no UI-without-persona-qa, no deploy-without-live-check, AND `mergeStateStatus` is mergeable (not BLOCKED, BEHIND, or DIRTY) — is HIGH. If `mergeStateStatus == BLOCKED` for any reason — missing required check, missing required approval, branch-protection criteria unmet — that's a MED cap, no exceptions. The cap fires on the mechanical state regardless of why it's blocked. - -The MED-cap conditions exist to surface real content concerns: reviewer flagged unaddressed changes, deployed surface lacks a live HTTP check, UI lacks persona-qa, override label bypassed adversarial. When the operator sees MED, it means "look at this — there's something the pipeline noticed but couldn't resolve." When they see HIGH, it means "the pipeline thinks this is clean; your call." - -If you find yourself reasoning "this PR is fine, let's call it HIGH despite a MED-cap firing" — STOP. The score is mechanical. Don't soften it. Surface the cap reason in the "Top reason not HIGH" column and let the operator decide. - -## Output format - -```markdown -## /merge queue — <ISO timestamp> — N PRs ready - -| Conf | Repo | PR | Title | Top reason not HIGH | Approve+merge command | -|------|------|----|----|---------------------|-----------------------| -| HIGH | <repo> | [#<num>](<url>) | <title 60ch> | — | gh pr review --approve <url> && gh pr merge --squash --delete-branch <url> | -| MED | <repo> | [#<num>](<url>) | <title 60ch> | <one-line reason> | gh pr review --approve <url> && gh pr merge --squash --delete-branch <url> | -| LOW | <repo> | [#<num>](<url>) | <title 60ch> | <one-line reason> | gh pr review --approve <url> && gh pr merge --squash --delete-branch <url> | - -Distribution: HIGH: N | MED: N | LOW: N -Source: live gh derivation (<N> repos walked, <M> PRs evaluated). Run-log cross-reference: <used / skipped — stale / skipped — none>. -``` - -**PR column always renders as `[#<num>](<url>)`, never bare `#<num>`** — clickable links per the standing operator-output rule. Same goes for any followup answer that names a PR. - -Default sort: descending — HIGH first, MED second, LOW last. With `--risky`: ascending — LOW first. - -Title truncation: hard 60-char limit. Suffix with `…` if truncated. Don't try to be clever; truncation is fine because the merge command has the full URL. - -The "Top reason not HIGH" column for HIGH PRs is **always em-dash (`—`), never a sycophantic comment**. If you find yourself writing "looks clean!" or "all gates green ✓" — that's wrong. Em-dash is the contract. - -If only one cap fires for a MED, write the one cap. If multiple cap conditions fire on a LOW, write the most decision-relevant one (typically: adversarial flag > decision conflict > scope creep > stacked MED-caps). Reserve the long explanation for follow-up questions; the column is a glance. - -Merge command always uses `--squash --delete-branch` per `pipeline-reference.md` STAGE 14. - -The chained `gh pr review --approve <url> && gh pr merge ...` lets the operator paste once. If they've already approved the PR via the UI, the first half is a benign re-approval; if they haven't, it satisfies branch protection's "review required" gate immediately before the merge attempt. Caveat: on a MED with `reviewDecision == CHANGES_REQUESTED`, the operator pasting this is explicitly overriding the reviewer's flagged concerns — the cap reason is in column 5 to make that visible. If they want to handle the change first, they don't paste; that's the whole point of MED. - -## Hard rules - -- **Never actually merge.** `/merge` is read-only. It produces copy-paste commands the operator runs. -- **Never invoke subagents.** This skill reads existing pipeline state. Driving the pipeline is `/run`'s job. -- **Never apply labels.** Including `ready-for-merge` itself. -- **HIGH means HIGH.** Don't soften the calibration to make the report feel friendlier. The whole value of the column is that it discriminates. - -## Followup questions - -After surfacing the table, the operator can ask "why is platform#118 LOW?" — answer from the data already gathered, citing the specific cap conditions that fired. Stay in main session for these followups; that's why this skill has no `agent:` field. diff --git a/claude-code/.claude/skills/run/SKILL.md b/claude-code/.claude/skills/run/SKILL.md deleted file mode 100644 index a06aa9f..0000000 --- a/claude-code/.claude/skills/run/SKILL.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -name: run -description: On-demand operator drive of the 14-stage Open Paws pipeline. Walks pipeline-tracked issues + PRs across in-scope Open-Paws repos, dispatches the right subagent per stage label, classifies every touched item into one outcome bucket, and writes a structured report to ~/.claude/orchestrator-log/run-<UTC-timestamp>.md that /merge and /unblock consume. Idempotent and interruptible — partial runs leave nothing in a corrupt half-stage. Operator-only — never auto-invoked. -disable-model-invocation: true -argument-hint: "[--repo <name>] [--since <duration>] [--stage <name>] [--fix-mode]" -allowed-tools: Bash(gh:*), Bash(git:*), Bash(ls:*), Bash(date:*), Bash(mkdir:*), Read, Grep, Glob, Write, Task -model: opus -agent: general-purpose ---- - -# /run — operator drive of the pipeline - -Operator HUD on top of the same machinery `~/.claude/scheduled-tasks/op-pipeline-orchestrator/SKILL.md` runs on cron. Same wave gates, same subagents, same hard-nevers. Only differences: invoked on demand, scoped by flags, produces a report consumed downstream by `/merge` and `/unblock`. - -Read these every fire (they auto-load via `InstructionsLoaded`; cite by name in the report's preamble): - -- `~/.claude/rules/pipeline-nevers.md` — never apply override labels, never wildcard `git add`, never write production code before tests, never fold scope creep -- `~/.claude/rules/parallelization.md` — wave gates, file ownership, worktree isolation, orchestrator cwd preflight, subagent recovery -- `~/.claude/rules/context-repo.md` — sensitivity taxonomy, org-wide read test, STAGE 13 confidentiality leak -- `~/.claude/rules/git-identity.md` — `Original Gary <276612211+OpenGaryBot@users.noreply.github.com>` for any commit a recovered subagent left behind -- `~/.claude/rules/cost-optimization.md` — Haiku/Sonnet/Opus routing inside dispatched subagents - -## Argument parsing - -`$ARGUMENTS` is the raw flag string. Parse: - -- `--repo <name>` — single-repo scope (matches `Open-Paws/<name>`) -- `--since <duration>` — only items with `pushedAt`/`updatedAt` inside the window (e.g. `30m`, `2h`, `1d`) -- `--stage <name>` — drain only items currently sitting at the named stage label (e.g. `stage:plan-approved`) -- `--fix-mode` — emit ONLY the credential-gated section + summary; suppress everything else (use after rotating a credential, to confirm the unblock cleared the queue) - -Default scope: every Open-Paws repo OpenGaryBot has push access to, every pipeline-tracked item, no time filter. - -## Delegation: orchestrate inside a subagent, not in main context - -Per the `agent: general-purpose` directive, the first thing this skill does is delegate the orchestration sweep to a `general-purpose` subagent via the `Task` tool. Per-stage subagent dispatches happen inside *that* subagent's context, not in main session — keeps the operator's main thread clean for follow-up questions. - -Spawn one Task call with `subagent_type: general-purpose`, hand it the parsed args + the algorithm below + the load-bearing report format, instruct it to write the report file and return the path. Main session reads the report and surfaces it to the operator. - -## Algorithm (the subagent runs this) - -### 1. Discover scope - -```bash -# All in-scope repos. Cache once per fire. -gh repo list Open-Paws --limit 200 --json name,pushedAt,defaultBranchRef -``` - -If `--repo <name>` set, filter to that one. If `--since <duration>` set, drop repos whose `pushedAt` is older than the window — no point walking quiet repos. - -For each repo, list pipeline-tracked items: - -```bash -# Issues with any pipeline label -gh issue list --repo Open-Paws/<repo> --state open --label 'stage:*' --json number,title,labels,updatedAt,url --limit 200 -gh issue list --repo Open-Paws/<repo> --state open --label 'auto:*' --json number,title,labels,updatedAt,url --limit 200 -# PRs with any pipeline label -gh pr list --repo Open-Paws/<repo> --state open --json number,title,labels,updatedAt,url,statusCheckRollup,reviewDecision --limit 200 -``` - -Dedupe (an issue can have both `stage:*` and `auto:*`). If `--since` set, additionally filter on `updatedAt`. If `--stage` set, filter to items currently carrying that label. - -### 2. Identify current stage from labels - -Stage label is the source of truth. The full taxonomy lives in `$OP_CONTEXT_REPO/.github/labels.yaml` and the stage-by-stage dispatch table is in `~/.claude/scheduled-tasks/op-pipeline-orchestrator/SKILL.md` — re-read that table before dispatching, do not duplicate it here. - -### 3. Attempt advancement (one Task per item, never reimplement stage logic inline) - -For each item, dispatch the correct subagent via the `Task` tool using the dispatch table in op-pipeline-orchestrator. Use `subagent_type` matching the agent name (`scout`, `triage`, `planner`, `plan-reviewer`, `test-writer`, `test-reviewer`, `implementer`, `verifier`, `desloppifier`, `adversarial`, `persona-qa`). - -**Wave gate discipline:** advance a stage only when the prior stage's subagent posted a completion comment AND the label transition makes sense. Don't force it. - -**Worktree-isolated subagents** (`test-writer`, `implementer`, `desloppifier`) require cwd to be inside a git repo. Before dispatching, `cd` into the repo's checkout (e.g. `~/Desktop/Open-Paws/<repo>`). Verify with `git rev-parse --show-toplevel` — if it returns nothing, classify the item as `stopped-at-human-gate` with reason `cwd preflight failed: <repo> not checked out at expected path` and continue. - -**Idempotency:** every stage commits its output (label transition, completion comment) before advancement is recorded. If interrupted (Ctrl-C, token cap, wallclock), the next `/run` picks up cleanly from the last committed state — no half-stage corruption. - -**Token + wallclock cap:** soft 22 minutes wallclock, ~200k tokens (matches the cron orchestrator's cap). On approach: finish current dispatch cleanly, write the partial report with whatever's classified, exit. Do not start new dispatches past the cap. - -### 4. Classification - -Every touched item lands in exactly one bucket. Don't double-classify. - -| Outcome | Triggered by | -|---|---| -| `advanced` | Subagent succeeded, label transitioned forward, completion comment posted | -| `stopped-at-human-gate` | `auto:requires-human` was applied; OR subagent classified the item as needing judgment; OR `stage:awaiting-human-review`; OR a subagent invocation FAILED (subagent failure: <error>); OR cwd preflight failed for a worktree-isolated stage | -| `stopped-at-credential-gate` | Subagent reported a missing credential / IAM role / API key / secret it cannot self-resolve | -| `stopped-at-ci` | PR has failing CI checks (`statusCheckRollup` shows FAIL/ERROR), no other forward-motion possible until CI clears | -| `stopped-at-decision-conflict` | Subagent flagged that proceeding would silently resolve an open `$OP_CONTEXT_REPO/proposals/*.md` OR contradict `$OP_CONTEXT_REPO/decisions.md` | -| `no-action-needed` | Item already at terminal stage (`stage:ready-for-merge` — humans only); OR walked but no advancement possible this fire (still inside another wave) | - -### 5. Hard rules (never violate) - -- **Never apply override labels.** `override:skip-adversarial` and `override:allow-score-drop` are human-only per `pipeline-nevers.md`. If a subagent thinks an override is warranted, classify the item as `stopped-at-human-gate` with the override request as the reason. -- **Never merge PRs.** `/run` advances stages; merging is `/merge`'s job and is human-confirmed. Items at `stage:ready-for-merge` are `no-action-needed`. -- **Never modify files outside `~/.claude/orchestrator-log/`.** This skill's only filesystem write is the report file. Any code changes happen inside dispatched subagents' worktrees. -- **Never silently resolve open decisions.** If a planner dispatch would touch `$OP_CONTEXT_REPO/decisions.md` or `$OP_CONTEXT_REPO/proposals/*.md` content, classify as `stopped-at-decision-conflict`. -- **Sensitivity gate (context-repo only).** Issues in `Open-Paws/context` lacking `sensitivity:public-ok` or `sensitivity:staff-ok` cannot advance past triage. `sensitivity:private` items get a redirect comment + close — they're `no-action-needed`, not advanced. -- **Subagent failure ≠ retry.** If a Task invocation fails, log the item under `stopped-at-human-gate` with `reason: subagent failure: <one-line error>`. Don't retry inline. Operator decides. - -## Report format (LOAD-BEARING — `/merge` and `/unblock` parse this verbatim) - -The report is markdown but the section headers and per-row formats are stable contracts. Do not change them. If a future need requires a new field, add a new section rather than mutating an existing one. - -Write to `~/.claude/orchestrator-log/run-<UTC-ISO8601-timestamp>.md`. Filename example: `run-2026-04-25T19:42:13Z.md`. Use `Write` tool. Create the parent dir if missing (it should already exist). - -````markdown -## /run report — <ISO timestamp> — scope: <args summary> - -### Preamble -- Repos walked: N -- Items inspected: N -- Subagents dispatched: <count by name> -- Rules read: pipeline-nevers, parallelization, context-repo, git-identity, cost-optimization -- Cap hit: yes/no <reason if yes> -- Total runtime: <duration> - -### Advanced (N) -- <repo>#<num> — <stage from> → <stage to> — <one-line title> — <html_url> - -### Stopped at human gate (N) -- <repo>#<num> — sitting at <stage> — needs: <one-line reason> — <html_url> - -### Stopped at credential gate (N) -- <repo>#<num> — sitting at <stage> — missing: <specific credential name / IAM role / secret name> — <html_url> - -### Stopped at CI (N) -- <repo>#<num> — failing: <check name> — <html_url> — <CI run URL> - -### Stopped at decision conflict (N) -- <repo>#<num> — conflicts with: <decision-id or proposal filename from $OP_CONTEXT_REPO> — <html_url> - -### No action needed (N) -- <repo>#<num> — at <stage> — <one-line reason> — <html_url> - -### Summary -Advanced: N | Human-gated: N | Credential-gated: N | CI-stuck: N | Decision-conflict: N | No-action: N -Total runtime: <duration> -```` - -Empty sections still render with `(0)` count and one line: `- none`. Do not omit empty sections — `/merge` and `/unblock` parse by section header presence. - -## --fix-mode - -When `--fix-mode` is set, the report contains ONLY: -- A short preamble line: `## /run report (fix-mode) — <ISO timestamp> — scope: <args summary>` -- The `### Stopped at credential gate (N)` section -- The `### Summary` line (still includes all six counts so the operator can confirm zero credential-gated remain) - -All other sections are suppressed from the file. Use this immediately after rotating a credential to confirm the unblock cleared the queue without re-emitting the full report. - -## Persistence + log discovery - -`/merge` and `/unblock` find the latest run by `ls -t ~/.claude/orchestrator-log/run-*.md | head -1`. Make sure the filename sorts correctly — UTC ISO8601 with `Z` suffix sorts lexicographically. Do not write partial files under the same name; if the report is incomplete because of a cap hit, write it anyway with the partial classifications + cap-hit preamble line. Subsequent `/run` produces a new file. - -## Surfacing the report to the operator - -After the subagent returns the report path: - -1. Confirm the file exists: `ls -lh <path>` -2. Print the report verbatim to the operator (Read the file, output its contents). -3. Note the path explicitly: `Report written to <absolute path>` so the operator can hand it to `/merge` or `/unblock` later. diff --git a/claude-code/.claude/skills/unblock/SKILL.md b/claude-code/.claude/skills/unblock/SKILL.md deleted file mode 100644 index 4c37fb5..0000000 --- a/claude-code/.claude/skills/unblock/SKILL.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -name: unblock -description: Surfaces every pending decision that only the operator can make, with copy-paste-ready next actions. Three sections — credentials needed, decisions needed, sensitivity escalations. Reads the latest /run report (<30min) or derives directly. Every item has a specific actionable next step; if it doesn't, it doesn't belong here. Operator-only. -disable-model-invocation: true -argument-hint: "[--section credentials|decisions|sensitivity] [--repo <name>]" -allowed-tools: Bash(gh:*), Bash(ls:*), Bash(date:*), Bash(stat:*), Read, Grep, Glob -model: sonnet ---- - -# /unblock — operator decisions queue - -Surfaces only items that need the operator. Filters out everything else. If `/unblock` lists something, the operator has a specific action to take — not "wait", not "rerun later". - -`/unblock` does NOT apply override labels. Does NOT close PRs. Does NOT merge. It surfaces; the operator executes. - -Read these every fire (auto-load via `InstructionsLoaded`; cite by name in any followup): - -- `~/.claude/rules/context-repo.md` — **STAGE 13 confidentiality leak rule applies to the sensitivity section. Re-read before formatting any sensitivity item.** No private content goes in the report — repo+number + non-sensitive summary only. -- `~/.claude/rules/pipeline-nevers.md` — override labels are human-only; never apply them -- `~/.claude/rules/git-identity.md` — for credential references (e.g. when an item needs OpenGaryBot to gain a permission) - -## Argument parsing - -`$ARGUMENTS`: -- `--section <name>` — show only one of: `credentials`, `decisions`, `sensitivity` -- `--repo <name>` — single-repo scope (`Open-Paws/<name>`) - -## Algorithm - -### 1. Find the input - -```bash -FIXTURE_LATEST=$(ls -t ~/.claude/fixture-logs/*.md 2>/dev/null | head -1) -ORCH_LATEST=$(ls -t ~/.claude/orchestrator-log/run-*.md 2>/dev/null | head -1) -if [ -z "$FIXTURE_LATEST" ]; then - LATEST="$ORCH_LATEST" -elif [ -z "$ORCH_LATEST" ]; then - LATEST="$FIXTURE_LATEST" -elif [ "$FIXTURE_LATEST" -nt "$ORCH_LATEST" ]; then - LATEST="$FIXTURE_LATEST" -else - LATEST="$ORCH_LATEST" -fi -``` - -If `LATEST` exists AND mtime within last 30 minutes: -- Pull `### Stopped at credential gate` rows → credentials section -- Pull `### Stopped at decision conflict` rows → decisions section -- Pull `### Stopped at human gate` rows whose reason matches `sensitivity-escalation:*` or whose label list includes `sensitivity:*` (excluding `sensitivity:public-ok`/`staff-ok`) → sensitivity section -- Also pull any `auto:requires-human` items from `### Stopped at human gate` into the appropriate section based on the `needs:` reason - -Otherwise (no recent log, or `--repo` set forcing fresh derivation): -```bash -gh issue list --repo Open-Paws/<repo> --state open --label 'auto:requires-human' --json number,title,labels,url,body --limit 100 -gh pr list --repo Open-Paws/<repo> --state open --label 'auto:requires-human' --json number,title,labels,url,body --limit 100 -gh issue list --repo Open-Paws/<repo> --state open --label 'sensitivity-escalation' --json number,title,labels,url,body --limit 100 -``` - -### 2. Per-item action generation - -Every item must have a SPECIFIC actionable next step. Generic instructions are not allowed. - -**Credentials section:** -- Identify the specific missing credential from the `missing:` field. Look it up: - - GCP service account / IAM role → fix at `https://console.cloud.google.com/iam-admin/iam?project=<inferable from repo or `gh secret list`>` - - GitHub Actions secret → fix command: `gh secret set <NAME> --repo Open-Paws/<repo>` - - Supabase service role key → fix at the project's Supabase dashboard (look up project ref via `mcp__claude_ai_Supabase__list_projects` if available, otherwise label as "operator looks up project ref") - - npm / PyPI / Cargo publish token → fix at the corresponding registry settings - - Vercel deploy hook / token → fix at Vercel project settings - - API key for external service (Stripe, SendGrid, etc.) → fix at the service's dashboard, with specific URL where derivable -- Count downstream items waiting on this credential — items whose `missing:` field references the same credential — and link to a `--fix-mode` filtered run report so the operator can confirm unblocking after rotation: - ``` - Confirm with: /run --fix-mode --repo <repo> - ``` - -**Decisions section:** -- Identify the conflicting decision/proposal from the `conflicts with:` field -- Resolve to one of three concrete operator actions (offer all three; operator picks): - - **a)** Update the decision/proposal: cite the decision-id (e.g. `decisions.md#sync-labels-pr-mode`) and suggest a one-line revision in the resolution column - - **b)** Close the PR/issue: provide `gh issue close <repo>/<num> --comment "<one-line reason>"` or `gh pr close <repo>/<num> --comment "<one-line reason>"` - - **c)** Apply override label: `gh pr edit <repo>/<num> --add-label override:<label>` with a suggested `--body "<reason>"` comment - -Per `pipeline-nevers.md`, /unblock NEVER applies the override itself — it only surfaces the command for the operator to run. - -**Sensitivity escalations:** - -**🔒 STAGE 13 confidentiality leak check applies here.** Re-read `~/.claude/rules/context-repo.md` § "What Must Not Go In" before formatting any sensitivity row. The report must NOT contain: -- The private content itself (no quotes, no excerpts) -- Personal information about anyone named in the original issue -- Active negotiation positions, funder dynamics, HR/performance content -- Anything from a sensitivity:private classification - -For each sensitivity item, render ONLY: -- `<repo>#<num>` — issue/PR identifier -- A non-sensitive summary in the operator's words: e.g. "issue body contains personal information about a named contractor" — NOT the content of that information -- Triage's proposed sensitivity tier (e.g. "triage suggested sensitivity:private redirect") -- Three resolution options: - - **approve** — accept triage's classification; provide command to apply the label - - **recategorize** — to a different tier; provide command for the alternative - - **reject** — close as out-of-scope; provide close command - -If you find yourself about to write a sensitivity row that quotes from the issue body, **stop**. Use the non-sensitive summary instead. The whole point of this section is that the operator needs to see WHICH items need a call without seeing WHAT they contain. - -### 3. "Specific action" filter — drop items without one - -Items lacking a specific actionable next step do NOT belong in `/unblock`. Drop them. They belong in `/run`'s report under "Stopped at human gate" with a "needs: more diagnostic info" reason. - -If no actionable items remain in a section, the section still renders with `(0)` and one line: `- none`. Don't omit empty sections. - -## Output format - -```markdown -## /unblock queue — <ISO timestamp> -Source: <log path> (mtime: <H>m ago) OR Source: live gh derivation (no recent run log) - -### Credentials needed (N) -- <repo>#<num> — <one-line non-sensitive context> - Missing: <specific credential — IAM role, secret name, API key> - Fix at: <actual URL or exact command — never generic instructions> - Unblocks downstream: <count> items - Confirm: /run --fix-mode --repo <repo> - -### Decisions needed (N) -- <repo>#<num> — <what the bot wants to do, one line> - Blocks on: <decision-id or rule from $OP_CONTEXT_REPO that conflicts> - Resolutions: - a) Update decision <decision-id> to permit this case (<one-line suggested revision>) - b) Close PR/issue: gh <pr|issue> close Open-Paws/<repo>#<num> --comment "<suggested one-line reason>" - c) Apply override:<label>: gh pr edit Open-Paws/<repo>#<num> --add-label override:<label> --body "<suggested reason>" - -### Sensitivity escalations (N) -- <repo>#<num> — <non-sensitive summary of the category, NEVER the content> - Triage flagged: <proposed tier, e.g. sensitivity:private redirect> - Options: - approve — gh issue edit Open-Paws/<repo>#<num> --add-label sensitivity:private (then close per redirect rule) - recategorize — gh issue edit Open-Paws/<repo>#<num> --add-label sensitivity:staff-ok - reject — gh issue close Open-Paws/<repo>#<num> --comment "out of scope" - -### Summary -Credentials: N | Decisions: N | Sensitivity: N | Total: N -``` - -If `--section <name>` is set, render only that section (still with header + summary). Other sections are suppressed. - -## Hard rules - -- **Sensitivity section never leaks content.** Repo+number + non-sensitive summary only. Re-read `context-repo.md` § "What Must Not Go In" before formatting. If you can't write the row without quoting the issue body, that's the signal that the operator needs to read the issue directly — write "operator: read issue body, no summary safe in this report" and link to the issue URL. -- **Every row has a specific action.** No "wait", no "rerun later", no "investigate". If there isn't an action, it isn't `/unblock`'s job — it belongs in `/run`'s human-gate section. -- **Never apply override labels itself.** Surface the gh command; operator runs it. Per `pipeline-nevers.md`, override labels are human-only. -- **Never close PRs or issues itself.** Same: surface the close command, operator runs it. -- **Never merge.** That's `/merge`'s read-only suggestion + operator action. -- **Never invoke subagents.** This skill reads existing pipeline state and formats it. - -## Followup questions - -After surfacing the queue, the operator can ask "what's the actual conflict on context#76?" or "which downstream items will the GCP_DEPLOY_KEY rotation unblock?" — answer from data already gathered. Stay in main session for these followups; that's why this skill has no `agent:` field. - -For sensitivity-section followups, the operator may explicitly ask "show me the issue body for context#X." That's allowed because the operator has already chosen to read the private content. The `/unblock` report itself stays clean.