diff --git a/.tessl-plugin/plugin.json b/.tessl-plugin/plugin.json index 78c3efa6..633ce61a 100644 --- a/.tessl-plugin/plugin.json +++ b/.tessl-plugin/plugin.json @@ -19,6 +19,7 @@ "rules/dependency-management.md", "rules/file-hygiene.md", "rules/ci-safety.md", + "rules/autonomous-shipping.md", "rules/no-secrets.md", "rules/code-formatting.md", "rules/language-diagnostics.md", diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b3e3b8d..94aa7890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### Rules + +- **`context-writing-style`: make the multi-aspect budget exemption falsifiable** — the exemption existed ("rules covering several sub-aspects may run larger") but was too vague to apply consistently — a gh-aw reviewer flagged `autonomous-shipping`'s line count as a budget violation across successive rounds while it also demanded atomic bullets, an unsatisfiable pair for a rule with many directives. The exemption now has a countable criterion: a rule with 4+ named H2 sub-aspect sections is multi-aspect and exempt from BOTH the ~25-40 line and 3-6 section budgets, while still owing every non-numeric discipline (atomic bullets, connective/intensifier bans, carve-out format). Verified against the tree: all 12 rules over 40 lines have 5-11 sections, so the criterion describes what's committed. Resolves the atomic-vs-budget catch-22 for `autonomous-shipping` (5 sections) and any future multi-directive rule. +- **`autonomous-shipping` (new, always-on)** — Opening a PR, dismissing superseded bot reviews, merging, and watching through publish are the autonomous next step once the gate reads green; asking on a green gate is a defect. The autonomy statements already lived in `skills/release/SKILL.md` (Step 2, Step 7), but a skill loads only on invocation — an agent that just finished a task never invoked it, so its always-on context carried the PR mandate with no word on who authorizes shipping. `What Counts as Approval` states the operator's position outright: review is the paired bot fleet, a merge needs no human approval, and the gate is exactly Step 7's preconditions (the rule points there, never restating a weaker or longer copy). `What Still Gates` is the authoritative list of what blocks a merge even on green — platform bypass (`--admin`), an owner-approval carve-out like Bootstrap-Red, a human's `CHANGES_REQUESTED` or prose hold or `PENDING` review, draft/label markers, mis-based PRs, ungranted scope. `Asking Is the Violation` covers approval questions the gate answers; `Surfacing Is Required` covers everything it does not, so refusing to surface scope or a hold is itself a defect. Authorization is standing (policy + durable config), never inferred from any conversational turn. Consumers: an always-on `CLAUDE.md` instruction outranks plugin rules — an "ask before pushing" line there defeats this rule. A commit-scoped-verdict clause (verdict must name the head SHA) is deferred until `poll-pr-reviews.sh` emits `commit_id` and the watcher enforces it. +- **`ci-safety`: Superseded-Bot-Review Dismissal Carve-Out** — gains a pointer to `autonomous-shipping` (dismissal is an autonomous action, script or hand-dismissal equally sanctioned); shape and `GATING_BOTS` scoping unchanged. +- **`release` skill Steps 2 and 7** — reference `rules/autonomous-shipping.md` so skill and always-on context agree on one contract. + ## 0.3.93 — 2026-07-17 ### Skills diff --git a/README.md b/README.md index edb61f31..c3c7120f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Coding policy plugin for Baruch's AI agents. Language-agnostic code quality rule ## What's New -- 23 rules — 16 always-on, 7 conditional (scoped via `applyTo:` to the files where the rule's prescriptions actually fire). Breakdown: 10 covering code quality, 8 covering plugin authoring, 1 covering author-model declaration, 1 covering concurrency, 1 covering review discipline, 1 covering reviewer-feedback reading, 1 covering external-repo action scope +- 24 rules — 17 always-on, 7 conditional (scoped via `applyTo:` to the files where the rule's prescriptions actually fire). Breakdown: 10 covering code quality, 8 covering plugin authoring, 1 covering author-model declaration, 1 covering concurrency, 1 covering review discipline, 1 covering reviewer-feedback reading, 1 covering external-repo action scope, 1 covering shipping autonomy - `release` skill — structured PR + merge workflow with Copilot review and paired-reviewer cross-family enforcement - `eval-authoring` skill — generate, review, and curate eval scenarios with score-driven iteration - `install-reviewer` skill — scaffold the paired gh-aw PR review workflows (OpenAI + Anthropic) into a consumer repo @@ -34,6 +34,7 @@ tessl install jbaruch/coding-policy | Deps | [dependency-management](rules/dependency-management.md) | Stdlib-first, pinned versions kept fresh via a renewal mechanism, lock files | | Files | [file-hygiene](rules/file-hygiene.md) | Proper .gitignore, no generated files committed | | CI | [ci-safety](rules/ci-safety.md) | Never skip tests, never modify CI without asking | +| Shipping | [autonomous-shipping](rules/autonomous-shipping.md) | A green gate is the go-ahead — open the PR, dismiss superseded bot reviews, merge and watch through publish without asking; asking on a green gate is the violation | | Secrets | [no-secrets](rules/no-secrets.md) | No credentials in code, env vars or secrets manager | | Style | [code-formatting](rules/code-formatting.md) | Use project's formatter, don't mix style with logic | | Types | [language-diagnostics](rules/language-diagnostics.md) | Enable the project's language server; its findings are non-dismissible without cause; gate the headless checker in CI at zero findings | diff --git a/rules/autonomous-shipping.md b/rules/autonomous-shipping.md new file mode 100644 index 00000000..2168441f --- /dev/null +++ b/rules/autonomous-shipping.md @@ -0,0 +1,53 @@ +--- +alwaysApply: true +description: A green gate is the go-ahead; pausing to ask for approval the gate already granted is the violation. +--- + +# Autonomous Shipping + +## Green Gate Is the Approval + +- A shipping action is the autonomous next step once its gate reads green +- Read the gate to resolve doubt; never ask the operator what reading it answers +- Authorization to ship is standing — it lives in this policy and the operator's durable config, in no conversational turn +- A challenging question, an ambiguous remark, an earlier "ship it when green", or silence is never the grant +- No standing grant covers the action ⇒ the gate is absent, not green (see What Still Gates) +- A harness gate this policy does not govern (safety classifier, permission prompt) is a red gate — surface what it blocked; never re-attempt through another tool + +## What Counts as Approval + +- Review is the paired bot fleet, not a human sign-off — a merge needs no human approval, except where another always-on rule names an owner-approval precondition (see What Still Gates) +- The merge gate has two halves, both required: `skills/release/SKILL.md` Step 7's executable preconditions hold (watcher-checked) AND no What Still Gates condition applies (agent-checked) +- Load Step 7 and confirm What Still Gates before merging; this rule restates neither +- A gating bot that cannot `APPROVE` posts its all-clear as `COMMENTED` — `github-actions[bot]` gets HTTP 422 (see `rules/ci-safety.md` Superseded-Bot-Review Dismissal Carve-Out) + +## The Autonomous Actions + +- **Open the PR** — Step 1 readiness checks pass (`skills/release/SKILL.md`) ⇒ push and open +- **Dismiss superseded bot reviews** — a bot's `CHANGES_REQUESTED` its own later all-clear superseded ⇒ dismiss it via `skills/release/dismiss-stale-reviews.sh`, or a hand dismissal meeting both preconditions (see `rules/ci-safety.md` Superseded-Bot-Review Dismissal Carve-Out) +- **Merge** — Step 7's preconditions hold ⇒ merge and clean up +- **Watch through publish** — the merge lands ⇒ watch the run, the registry advance, the moderation clear per `rules/ci-safety.md` Always Watch CI; part of the merge, not a separate decision + +## Asking vs Surfacing + +- An ask on a green gate is a defect +- Report the action taken, never propose it +- Never re-ask what the policy grants standing +- Surface every decision the gate does not answer: scope, base branch, a human's prose hold, whether an out-of-scope discovery belongs in the task +- A question the gate does not answer is an absent grant, not a green one +- Re-reading this policy never resolves an absent grant +- Uncertainty that the rule covers an action means it does not — report and stop + +## What Still Gates + +- These block a merge even when Step 7's gate reads green; the agent checks them, the watcher does not +- A platform-rejected merge — never `--admin`, never a ruleset or branch-protection bypass; surface the blocking rule +- An owner-approval precondition named by another always-on rule (`rules/ci-safety.md` Bootstrap-Red Carve-Out); no bullet here retires it +- An unplanned CI-config edit, even to turn a red gate green (`rules/ci-safety.md` Hands Off CI Config) +- Force-push over shared or protected history, tag or release deletion — any action with no undo. Force-pushing your own feature branch to land a rebase is routine, not gated +- Direct push to a protected branch outside `rules/ci-safety.md` Content-Only Direct-Push Carve-Out +- A human reviewer's `CHANGES_REQUESTED`, a prose hold ("wait", "I'll approve after X"), or a `PENDING` human review — autonomous dismissal covers bot reviews only +- A PR marked not-ready — draft status, a `do-not-merge` or WIP label, a title marker +- A base branch the task never named — a stacked or mis-based PR is not the agreed task +- A repo the operator does not own (`rules/external-repo-contributions.md`) +- Scope never granted — an out-of-scope boy-scout discovery and drive-by dependency work are new tasks, not ship authorization (in-scope cleanup rolls into the PR per `rules/boy-scout.md` How to Apply) diff --git a/rules/ci-safety.md b/rules/ci-safety.md index f7402afd..66be3991 100644 --- a/rules/ci-safety.md +++ b/rules/ci-safety.md @@ -19,6 +19,7 @@ alwaysApply: true ## Superseded-Bot-Review Dismissal Carve-Out - Narrow exception for dismissing a review gate — not a bypass when the gate is a bot's `CHANGES_REQUESTED` that the same bot later superseded with an all-clear re-review +- Dismissal under this exception is autonomous — never pause for the operator to confirm it (see `rules/autonomous-shipping.md`) - Applies when a gating bot that cannot `APPROVE` (`github-actions[bot]` — GitHub returns HTTP 422) re-reviews clean but cannot post the `APPROVED` verdict that would supersede its earlier `CHANGES_REQUESTED` — the stale request keeps the merge `BLOCKED` until dismissed - Preconditions (all required): 1. The dismissed review is a `CHANGES_REQUESTED` from a gating bot on the allowlist (`GATING_BOTS` in `skills/release/dismiss-stale-reviews.sh`), never a human reviewer — a human can `APPROVE`, so a human's supersession goes through re-request-and-approve, never dismissal diff --git a/rules/context-writing-style.md b/rules/context-writing-style.md index 6ad6e28d..720e7828 100644 --- a/rules/context-writing-style.md +++ b/rules/context-writing-style.md @@ -15,7 +15,8 @@ description: Prose discipline for rules, skills, and READMEs — what to cut, wh - CHANGELOG entries load only on demand, not always-on - CHANGELOG entries are the archive — they carry the motivation and incident references stripped from rules, and follow looser discipline - `What to Cut` and `Structure` do not govern CHANGELOG. `What to Cut` names CHANGELOG as where the stripped explanation goes; a connective ban there would leave it nowhere to live. The rule reaches CHANGELOG only to say what belongs in it -- Line-count and section-count budgets target single-concept rules; rules that cover one coherent policy area with several sub-aspects (e.g., `plugin-evals` covering coverage/lift/persistence/naming/hygiene; `context-artifacts` covering structure/review/sync/audit; `skill-authoring` covering frontmatter/preamble/steps/calls) may run larger +- The ~25–40 line and 3–6 section budgets bind single-concept rules only. A rule with 4 or more named H2 sub-aspect sections is multi-aspect and exempt from both numeric budgets (e.g. `plugin-evals` covering coverage/lift/persistence/naming/hygiene; `context-artifacts` covering structure/review/sync/audit; `autonomous-shipping` covering green-gate/approval/actions/asking/gating) +- A multi-aspect rule still owes every non-numeric discipline in full — atomic bullets, the connective and intensifier bans, carve-out format. Exempt from the counts, never from the prose quality - Lists and quoted literals naming the forbidden terms themselves (e.g., this rule's own bullets enumerating the connectives and intensifiers) are not violations — the directive is the list, not prose use of the listed words ## What to Cut diff --git a/skills/release/SKILL.md b/skills/release/SKILL.md index 48bb0c75..8364b912 100644 --- a/skills/release/SKILL.md +++ b/skills/release/SKILL.md @@ -33,7 +33,7 @@ Structured workflow for shipping code: PR creation, automated policy review, mer ## Step 2 — Create PR -- Once Step 1's readiness checks pass, create the PR automatically — the green readiness checks are the gate. Do not pause to ask a human whether to open it. +- Once Step 1's readiness checks pass, create the PR automatically — the green readiness checks are the gate. Do not pause to ask a human whether to open it (`rules/autonomous-shipping.md`). - Push the branch: `git push -u origin ` - Create the PR with `gh pr create`: - **Title**: `(): ` @@ -110,11 +110,12 @@ It returns the full `poll-pr-reviews.sh` snapshot plus a `watch` object — `{"r Only proceed when: - Step 5's watcher returned `.watch.result` as `ready` — its exit-0 readiness conjunction (mergeable, CI `success`/`none`, both gating bots posted, no `CHANGES_REQUESTED`); the field predicate is the watcher's, not restated here (`rules/script-as-black-box.md` — see `skills/release/watch-pr-reviews.sh` header). `ready` already requires each gating bot's `state` to have left `none`, so a reviewer that never ran cannot satisfy the gate vacuously, AND - Every non-empty `reviews.*.body` in the returned snapshot has been read in full — a `COMMENTED` state with zero inline comments is not a license to skip the body (see `rules/reviewer-feedback-reading.md`), AND -- Every inline comment from Step 5's `inline_comments` count has a `Fixed in ` or `Declining — ` reply per Step 6 (verify by listing the PR's review comments — the poll script tracks counts, not reply state, so the operator confirms thread closure). +- Every inline comment from Step 5's `inline_comments` count has a `Fixed in ` or `Declining — ` reply per Step 6 (verify by listing the PR's review comments — the poll script tracks counts, not reply state, so the operator confirms thread closure), AND +- No `rules/autonomous-shipping.md` What Still Gates condition applies — these are agent-checked, not watcher-checked (a human's prose hold or `PENDING` review, a `do-not-merge`/draft marker, a mis-based branch, an owner-approval carve-out, ungranted scope). This half of the gate is not in the `ready` conjunction; confirm it by hand before merging. A `COMMENTED` review never gates the merge on its state alone — but its body must be read before merge, zero inline comments included. With inline comments, it is mergeable once every thread also has a reply. -Once these conditions hold, merge automatically — the green gates are the approval. Do not pause to ask a human whether to merge. +Once these conditions hold, merge automatically — the green gates are the approval. Do not pause to ask a human whether to merge, and do not ask whether to dismiss the superseded reviews below (`rules/autonomous-shipping.md`). **Clear superseded review gates first.** A policy bot cannot `APPROVE` (`github-actions[bot]` gets HTTP 422), so a clean re-review lands as a `COMMENT` that does NOT supersede the bot's earlier `CHANGES_REQUESTED` in GitHub's merge gate — the stale request keeps `merge_state.status` at `BLOCKED`. Dismiss every such superseded review before merging: