From 33099f27d517a91599356c8c390d6a2bcbea0bcd Mon Sep 17 00:00:00 2001 From: Claude Code Bot Date: Sat, 6 Jun 2026 22:06:39 -0500 Subject: [PATCH 1/2] docs(dev-lead): document concurrency ownership, @main pin, and permission contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codifies the design that petry-projects/.github#402 settled, and corrects the standard where it wrongly described dev-lead as a public .github @v1 reusable: - New "Concurrency, pinning, and the permission contract" subsection: stubs carry no concurrency block (centralized per-lane in the reusable); stubs pin .github-private/...dev-lead-reusable.yml@main for immediate fix propagation; stubs must grant the full permission set the reusable requests (incl. statuses:read) or consumers startup_failure; dev-lead:hands-off label opt-out. - Pinning policy: add a dev-lead carve-out (private repo, @main) and fix the example that showed dev-lead pinned to .github @v1 — it lives in .github-private. Refs petry-projects/.github#402 Co-Authored-By: Claude Opus 4.8 (1M context) --- standards/ci-standards.md | 62 +++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/standards/ci-standards.md b/standards/ci-standards.md index f0ab8c0bc..091426ce6 100644 --- a/standards/ci-standards.md +++ b/standards/ci-standards.md @@ -39,6 +39,12 @@ reusable, not a local edit. > (most are `@v1`; `pr-review-mention` is `@v2`). A tag is bumped deliberately > when a backward-compatible release is ready; breaking changes publish a new > tag that downstream repos opt into explicitly. +> +> **Exception — `dev-lead`.** The dev-lead reusable lives in the private +> `petry-projects/.github-private` repo (it checks out private prompts/scripts) +> and is pinned `@main`, not a tag — so caller-permission and security fixes +> propagate immediately instead of waiting for a tag bump or the monthly +> standards-sync. See [Dev-Lead Agent](#dev-lead-agent). ### Available templates @@ -937,16 +943,19 @@ incorrect pinned one. ### Exception: Internal Reusable Workflow References -Calls to `petry-projects/.github` reusable workflows use tag references -(`@v1`, `@v2`, or `@main`) — **not SHA pins** — and are exempt from this policy. +Calls to `petry-projects/.github` and `petry-projects/.github-private` reusable +workflows use tag or branch references (`@v1`, `@v2`, or `@main`) — **not SHA +pins** — and are exempt from this policy. ```yaml -# CORRECT — tag ref for internal reusable workflow -uses: petry-projects/.github/.github/workflows/dev-lead-reusable.yml@v1 +# CORRECT — tag ref for a public internal reusable workflow uses: petry-projects/.github/.github/workflows/pr-review-mention-reusable.yml@v2 +# CORRECT — dev-lead lives in the private repo and tracks @main (see Dev-Lead Agent) +uses: petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@main + # WRONG — do not SHA-pin internal reusable workflow refs -uses: petry-projects/.github/.github/workflows/dev-lead-reusable.yml@ee22b427cbce9ecadcf2b436acb57c3adf0cb63d +uses: petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@ee22b427cbce9ecadcf2b436acb57c3adf0cb63d ``` **Why:** Pinning the `uses:` line in a Tier 1 caller stub creates a diff from @@ -1180,6 +1189,49 @@ All repos MUST align to the latest version of each action: The dev-lead agent is a reactive, write-enabled automation that keeps pull requests in a clean, approvable, and mergeable state. It responds to CI failures, bot reviews, human `@mentions`, and labeled issues. +### Concurrency, pinning, and the permission contract + +Three things are deliberately **not** tuned in the caller stub — they are owned +centrally so they cannot drift per repo: + +- **Concurrency.** The stub carries **no `concurrency:` block**. Concurrency is + centralized in `dev-lead-reusable.yml` with per-issue / per-PR / ci-relay + lanes (`dev-lead-issue-`, `dev-lead-pr-`, `dev-lead-ci-relay-`, + `cancel-in-progress: false`). This keeps a labeled-issue pickup from being + cancelled by unrelated PR follow-up traffic — per-stub concurrency previously + drifted into three incompatible variants and starved issue pickups + (petry-projects/.github#402). Running lanes in parallel is safe because the + agent checks out PR branches in an isolated worktree (`.github-private#448`). +- **Pin.** The stub pins + `petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@main` + — `@main`, not a tag — so a caller-permission or security fix reaches every + repo immediately rather than waiting for a tag bump or the monthly + standards-sync. +- **Permissions.** The stub's `jobs.dev-lead.permissions` must grant the **full + set the reusable requests**: + + ```yaml + permissions: + contents: write + pull-requests: write + issues: write + actions: read + checks: read + statuses: read + ``` + + A reusable workflow can only use permissions its caller grants; if the + reusable requests a scope the stub lacks, **every consumer fails at startup** + (`startup_failure`, with no runtime error). When the reusable needs a new + scope, add it to the template **and** every shim *before* the reusable + requests it — the `caller-permissions` CI guard in `.github-private` enforces + that ordering. + +To exclude a specific PR or issue from the agent — e.g. a PR that edits the +dev-lead workflow itself, so the agent doesn't pile commits onto its own infra +change — add the **`dev-lead:hands-off`** label; the classifier then skips every +event on it. + ### Adopting the Dev-Lead Agent 1. Copy `standards/workflows/dev-lead.yml` verbatim to `.github/workflows/dev-lead.yml` in your repo. From cc0ac22112d2ead2ebe76fe28c99f693bf95c358 Mon Sep 17 00:00:00 2001 From: Claude Code Bot Date: Sat, 6 Jun 2026 23:58:59 -0500 Subject: [PATCH 2/2] =?UTF-8?q?docs(dev-lead):=20fix=20review=20nits=20?= =?UTF-8?q?=E2=80=94=20terminology,=20grammar,=20autolink?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses bot review feedback on #404: - "caller-permission" -> drop the ambiguous compound ("permission and security fixes") so it doesn't read as an inconsistent spelling of the caller-permissions guard (copilot, x2). - "full set the reusable requests" -> "full set that the reusable requests" (gemini). - `.github-private#448` in backticks -> petry-projects/.github-private#448 so the cross-repo reference autolinks, matching the other references (copilot). Co-Authored-By: Claude Opus 4.8 (1M context) --- standards/ci-standards.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standards/ci-standards.md b/standards/ci-standards.md index 091426ce6..57deabb74 100644 --- a/standards/ci-standards.md +++ b/standards/ci-standards.md @@ -42,7 +42,7 @@ reusable, not a local edit. > > **Exception — `dev-lead`.** The dev-lead reusable lives in the private > `petry-projects/.github-private` repo (it checks out private prompts/scripts) -> and is pinned `@main`, not a tag — so caller-permission and security fixes +> and is pinned `@main`, not a tag — so permission and security fixes > propagate immediately instead of waiting for a tag bump or the monthly > standards-sync. See [Dev-Lead Agent](#dev-lead-agent). @@ -1201,14 +1201,14 @@ centrally so they cannot drift per repo: cancelled by unrelated PR follow-up traffic — per-stub concurrency previously drifted into three incompatible variants and starved issue pickups (petry-projects/.github#402). Running lanes in parallel is safe because the - agent checks out PR branches in an isolated worktree (`.github-private#448`). + agent checks out PR branches in an isolated worktree (petry-projects/.github-private#448). - **Pin.** The stub pins `petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@main` - — `@main`, not a tag — so a caller-permission or security fix reaches every + — `@main`, not a tag — so a permission or security fix reaches every repo immediately rather than waiting for a tag bump or the monthly standards-sync. - **Permissions.** The stub's `jobs.dev-lead.permissions` must grant the **full - set the reusable requests**: + set that the reusable requests**: ```yaml permissions: