Skip to content
8 changes: 8 additions & 0 deletions .claude/skills/newtask/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ This repo moves fast (`claude/*` branches auto-merge on green) and shares ~40 wo
and one stash stack, so starting work on a stale base or a cold worktree is the default
failure. This skill sets up an isolated, current worktree so new work starts clean.

## Before you start

Check whether this task can ride an already-open PR you own or bundle with other queued
low-risk work instead of minting a new branch — see AGENTS.md "PR bundling (reduce
one-task-one-PR churn)". Only proceed to the steps below (which create a new branch and
worktree) once bundling doesn't apply: the work isn't independently low-risk by that
rule's test, or there's no suitable open PR to ride.

## Steps

1. **Sync main.** `git fetch --quiet origin main`.
Expand Down
81 changes: 81 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,87 @@ Record one `docs/branch-review-ledger.md` row per PR touched, and end with the p

<!-- END:run-pr-shortcut -->

## PR bundling (reduce one-task-one-PR churn)

Every `newtask`/`handoff` cycle mints a dedicated `claude/<task-slug>` branch and PR, so a
single docs/ledger-append line pays the same required-CI bill as a large change:
`static-pr`, `pr-required`, and whatever path-scoped job the diff happens to trigger.
Measured 2026-07-30 (PR #1406, sampling the last 500 CI workflow runs, ~3 days of PR
traffic): 437 PR-triggered runs, ~40% cancelled mid-run (mostly superseded by a newer
push before Production UI finished), roughly 12 Production-UI-hours burned on runs that
never completed. More PRs also means more `docs/branch-review-ledger.md` rows and more
of the anti-churn re-syncing described above.

Before opening a new branch, check whether the task can ride an **already-open PR you
still own** or be bundled with **other currently-queued low-risk work** instead of
Comment thread
BigSimmo marked this conversation as resolved.
minting a new one. If the target PR's CI is already running, either wait for it to settle
before pushing the addition or assemble every commit before that PR's first push —
Comment thread
BigSimmo marked this conversation as resolved.
Comment thread
BigSimmo marked this conversation as resolved.
`.github/workflows/ci.yml` sets `cancel-in-progress: true`, so a push mid-run cancels and
restarts CI rather than saving an invocation, reproducing the exact cancellation waste
this rule exists to cut (reproduced 2026-07-30 pushing a second commit to PR #1406: the
in-flight `static-pr` run was cancelled, failing `pr-required` on the now-stale head).
A settle-then-push addition also lands after this repo's one automatic Codex review may
already have run against the earlier head — in practice the connector re-reviews each new
push (observed on this same PR), but if it doesn't, request a fresh review explicitly
before merging rather than assuming the addition was covered. **If the target PR has
auto-merge armed, settling-then-pushing races the merge itself** — `claude/*` branches
auto-merge on green by this repo's own default (`.claude/skills/newtask/SKILL.md`), so
"wait for CI to settle" can mean "wait for it to squash-merge and close" before the
bundled commit ever gets pushed, silently dropping it. `guard-push.mjs`'s auto-merge
sentinel exists to catch this but fails open without `gh` available (observed directly
in this repo's own sessions) — don't rely on it. Before using the settle-then-push path,
confirm the target PR does not have auto-merge enabled, or disable it first and
re-enable only after the bundled commit is pushed.
Bundle only when every item being combined is:

- **Independently low-risk, checked two ways — neither is exhaustive alone.**
First, `scripts/pr-policy.mjs` / `classifyPullRequestFiles` must return
`clinicalRisk: false`, `operationalRisk: false` (dependency manifests, lockfiles,
`.github/workflows/**`, build/test-runner config), and no RAG-ranking-surface path.
Second, the diff must not touch anything in this repo's own broader "PR risk
detection" list below (auth, privacy, migrations/RLS, clinical/RAG/retrieval,
**background jobs/workers/queue processing**, payment/billing, public API contracts,
production config/deployment, file upload/download, provider/paid-API calls) —
that list catches real high-risk paths the narrower classifier doesn't flag at all
(e.g. `worker/**` trips neither `clinicalRisk` nor `operationalRisk`, but ingestion
workers are exactly the kind of change this exclusion exists for). When a path's risk
category is genuinely unclear under either check, default to its own PR rather than
extending the exclusion list further — the two checks together are a floor, not a
closed enumeration.
- **Still its own committed, separately revertible commit while the PR is open** —
bundling means one PR with multiple commits, never one squashed diff; `git revert <sha>`
must undo any one item without touching the others before merge. That guarantee ends at
merge: this repo's normal squash-merge folds every commit into one on `main`, and once
the feature branch is deleted those original SHAs are unreachable. Reverting a single
bundled item after merge means reverting the relevant hunks of the squash commit by
hand, not `git revert <sha>` on an item's original commit — keep an item out of the
bundle if it might need its own durable post-merge revert.
- **Listed as its own bullet** in the PR body's Summary, not blended into one narrative
— a reviewer (and `pr-policy.mjs`) still needs to find each item's own
governance/RAG-impact statement if it needs one.
- **Not already mid-edit** in another open PR or session — check local context first
(`docs/branch-review-ledger.md`, `git branch`/`git log`). Confirming against the live
open-PR list means a GitHub API read: only do that with this session's already-
authorized GitHub access, or ask before querying GitHub, per "API and provider
confirmation boundary" — do not treat it as a silent, unconditional prerequisite that
blocks starting ordinary work.

**Best candidates:** queued `docs/branch-review-ledger.md` / `docs/outstanding-issues.md`
append-only tasks. They carry no revert risk of their own, always pass the same static
gates, and are exactly the single-line-diff PRs the #1406 measurement counted — batch
several into one PR/session rather than a dedicated branch each.

**Never bundle:**

- A change needing its own `RAG impact:` line together with one that doesn't.
- A change needing `## Clinical Governance Preflight` together with unrelated chores.
- Anything explicitly scoped "1 PR per work order" by its own tracking doc (e.g. the
maturity backlog in `docs/maturity-backlog-workorders.md`, ledger `#086`) — those are
deliberately isolated for staged rollout and review.

Bundling saves PR/CI-invocation count, not verification rigor — every bundled item still
gets the smallest correct gate run against it before it joins the PR.

<!-- BEGIN:codex-productivity-defaults -->

## Codex productivity defaults
Expand Down
16 changes: 16 additions & 0 deletions docs/process-hardening.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ artifact before release; see
dozens of long-lived feature branches that all touch shared docs like the
branch-review ledger.

## PR bundling reduces per-task CI churn (2026-07-30)

- **Problem, measured:** PR #1406 sampled the last 500 CI workflow runs (~3 days of PR
traffic, 437 PR-triggered): 213 succeeded, 45 failed, 176 (~40%) cancelled — mostly
superseded by a newer push before Production UI finished, burning roughly 12
Production-UI-hours on runs that never completed. Every task minting its own
`claude/<task-slug>` branch and PR means a single ledger-append line pays the same
required-CI bill as a large change.
- **Rule:** see AGENTS.md "PR bundling (reduce one-task-one-PR churn)" — bundle
same-scope, independently low-risk, separately-revertible-commit work into one PR
instead of minting a branch per task. Queued `docs/branch-review-ledger.md` /
`docs/outstanding-issues.md` append-only tasks are the best candidate.
- **Does not change:** required-check scoping, per-commit verification rigor, or the
deliberate "1 PR per work order" convention for tracked staged rollouts (maturity
backlog, `#086`) or anything crossing a clinical-risk/RAG-ranking-surface path.

## Phase 1 - Active now

- `npm run verify:cheap` is the default broad local gate for source/config/test changes: `check:runtime`, `sitemap:check`, lint, typecheck, and unit tests.
Expand Down