From 30326573f628d8af9c25d1f2c2e3422dddc87301 Mon Sep 17 00:00:00 2001 From: Maria Carter Date: Sun, 2 Aug 2026 06:38:59 +0200 Subject: [PATCH] chore: repin the kit's caller stubs to v1.11.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 2 of the release order for v1.11.0 (90f0d06). All six stubs move b394c6d (v1.10.0) -> 90f0d06 (v1.11.0). v1.10.0 tagged the reusable; v1.11.0 tags the caller stub, the DRIVER_AGENTS_REF bump and the Shopify tripwire. Pinning to v1.11.0 is what keeps fleet-pin-audit.sh meaningful — it compares deployed stub pins against the latest tag, so leaving them at v1.10.0 while the tag moved would report the whole fleet stale, and leaving the tag at v1.10.0 while waving v1.11.0 content would report it uniform over a gap. Docs: "latest tag" now v1.11.0 with all six stubs at 90f0d06; the conversion is described as spanning the two tags, since the reusable and its stub genuinely shipped in different ones. References to "the v1.10.0 repin" corrected to v1.11.0 across both scope docs and the kit README — the stub never shipped in a v1.10.0 tag. The canonical stub block in reusable-conversion-scope.md repinned to match the landed file. Wave references now name the v1.11.0 wave. Parity with driver-agents docs/agent-instructions-shopify.md re-checked at the tag per the new release-order step 1: 978 chars both sides, exact. actionlint clean; stub-pin and tokenization guards pass. --- README.md | 33 ++++++++++---------- docs/identity-unification-scope.md | 6 ++-- docs/reusable-conversion-scope.md | 13 ++++---- templates/github/README.md | 4 +-- templates/github/bonsai-status-sync.yml | 2 +- templates/github/dependabot-keep-current.yml | 2 +- templates/github/dependabot-report.yml | 2 +- templates/github/dependabot-validate.yml | 2 +- templates/github/pr-first-review.yml | 2 +- templates/github/ticketed-review.yml | 2 +- 10 files changed, 35 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5df8548..959a41f 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,13 @@ reusables implement, review, and sync status back to Bonsai. ## Status & versions -Latest tag **`v1.10.0`** (`b394c6d`) — **not** kit-only: it adds a **sixth reusable**, -`bonsai-status-sync.yml`, converted from a copied per-repo workflow on 2026-08-02. Its caller stub -landed in the repin commit for this tag, per step 2 of the release order below. The other five -reusables have been byte-identical since `v1.6.0`'s `0a3934f`. +Latest tag **`v1.11.0`** (`90f0d06`, 2026-08-02) — **not** kit-only. It carries three things: the +`bonsai-status-sync.yml` **caller stub** (the reusable itself landed one tag earlier at `v1.10.0` = +`b394c6d`, so the conversion spans the two), the `DRIVER_AGENTS_REF` bump, and the Shopify operator +tripwire. The other five reusables have been byte-identical since `v1.6.0`'s `0a3934f`. All six stubs +are pinned to `90f0d06`. -**Unreleased on `main` (2026-08-02) — `DRIVER_AGENTS_REF` → `4d63371`, lockstep in `claude.yml` + +**In `v1.11.0` — `DRIVER_AGENTS_REF` → `4d63371`, lockstep in `claude.yml` + `shopify-tool-smoke.yml`.** The previous pin `0bbb125` predated the Admin API wrapper: `graphql_guard.py` does not exist at that SHA, so every fleet runner executes `admin-graphql.sh` with **no fail-closed allowlist** and the Driver Engineering scope grant is the only control on @@ -39,16 +40,16 @@ driver-agents `docs/agent-instructions-shopify.md`, which is canonical — edit the kit-side scope lead-in that precedes it), so the fleet gets the wrapper and its instruction block in one wave. -**Decided 2026-08-02: this ships as `v1.11.0`, not folded into the v1.10.0 wave.** Folding it in would -put `claude.yml` content on 18 branches that exists in no tag, and `tools/fleet-pin-audit.sh` compares -only stub pin lines against the latest tag — never `templates/` content — so it would report the fleet -uniform and green over the gap. Sequence: merge the repin PR → tag `v1.11.0` at that merge commit → -repin all six stubs to `v1.11.0` → **one** wave. That is what `v1.7.0` and `v1.8.0` each did. +**Decided 2026-08-02: shipped as `v1.11.0` rather than folded into the v1.10.0 wave.** Folding it in +would have put `claude.yml` content on 18 branches that exists in no tag, and `tools/fleet-pin-audit.sh` +compares only stub pin lines against the latest tag — never `templates/` content — so it would have +reported the fleet uniform and green over the gap. Executed as: merge → tag `v1.11.0` at that merge +commit → repin all six stubs to `v1.11.0` → **one** wave. That is what `v1.7.0` and `v1.8.0` each did. **Note on the pin sequence:** `v1.9.0` (`a54c91e`, the store-secret rename) never got its kit repin commit — the kit's stubs sat at `v1.8.0`'s SHA through that release and jump straight to `v1.10.0` here. Deployed fleet stubs were repinned to `v1.9.0` by the 2026-08-01 wave, so between then and this -tag the fleet was *ahead* of the kit templates. The v1.10.0 wave resolves both. Deployed fleet stubs are +tag the fleet was *ahead* of the kit templates. The v1.11.0 wave resolves both. Deployed fleet stubs are repinned by **manual waves** — Dependabot does NOT bump these reusable-workflow pins in practice (zero such PRs fleet-wide; debugging why is on the backlog). Org Actions secrets (`AGENTS_GH_PAT`, `CLAUDE_CODE_OAUTH_TOKEN`, `BONSAI_BEARER_TOKEN`, `SHOPIFY_ALERT_WEBHOOK`) and cross-repo Actions @@ -129,12 +130,12 @@ npm-install fallback for lockfile-less repos + `actions/checkout` v7) → `v1.5. - **If the release ADDS a reusable**, its stub lands *in this step*, not in the PR that added the reusable — the tag it must pin does not exist until step 1. That is why `dependabot-keep-current`'s reusable and its stub landed in different commits, and how - `bonsai-status-sync.yml`'s stub landed at `v1.10.0`. `lint.yml` fails the build on any stub left + `bonsai-status-sync.yml`'s stub landed at `v1.11.0`. `lint.yml` fails the build on any stub left carrying a placeholder pin, so this step cannot be silently skipped. 3. Only then re-copy `templates/github/` into consumer repos (`tools/fleet-pin-audit.sh --stale` to confirm the fleet converged afterwards). - - **When a full workflow becomes a stub** (as `bonsai-status-sync.yml` did at `v1.10.0` — this - applies to the v1.10.0 wave specifically), the wave diff + - **When a full workflow becomes a stub** (as `bonsai-status-sync.yml` did — this applies to the + v1.11.0 wave specifically), the wave diff contains a `templates/github/` path AND a `.github/workflows/` path with the SAME basename. The wave script rewrites `templates/github/` → `.github/workflows/`, so assert the rewritten diff touches no destination path twice before applying — otherwise the reusable can land in a client @@ -176,13 +177,13 @@ produces a silent `startup_failure` — no check run, no notification). carries the six caller stubs above plus `claude.yml` (the implementer, still a full per-repo workflow), `shopify-tool-smoke.yml` (store repos only) and `pull_request_template.md`. -**`bonsai-status-sync.yml` finished converting at `v1.10.0`.** The reusable landed 2026-08-02 and its stub +**`bonsai-status-sync.yml` finished converting at `v1.11.0`.** The reusable landed 2026-08-02 and its stub landed in this tag's repin commit, so the kit now installs a 66-line stub instead of the old 190-line copy — see *Release + repin order* above and [`docs/reusable-conversion-scope.md`](docs/reusable-conversion-scope.md). The two-step was deliberate and matches how `dependabot-keep-current` was added: a new reusable's stub cannot be pinned until the tag containing that reusable exists, so the reusable lands first and the stub follows in the repin commit. `lint.yml` fails the build on any stub still carrying a placeholder pin. **The fleet has not -been waved yet** — consumer repos still run the 190-line copy until the v1.10.0 wave. +been waved yet** — consumer repos still run the 190-line copy until the v1.11.0 wave. **`claude.yml` stays a per-repo copy** — that half of the conversion is tabled pending the OIDC spike (whether Claude App token minting survives inside a cross-repo reusable), so it remains the kit's main drift surface diff --git a/docs/identity-unification-scope.md b/docs/identity-unification-scope.md index 2a65f41..abaf483 100644 --- a/docs/identity-unification-scope.md +++ b/docs/identity-unification-scope.md @@ -213,7 +213,7 @@ revise loop mid-cutover, then drop the old literal. > > Note `209825114` appears in **no workflow file** in this repo (`git grep 209825114 -- ':!docs/'` → zero > hits; the only occurrences are in this doc), while all **11** occurrences of `261291955` — recounted -> 2026-08-02 after the v1.10.0 repin, and path-qualified because the same basename exists in both halves: +> 2026-08-02 after the v1.11.0 repin, and path-qualified because the same basename exists in both halves: > `templates/github/claude.yml` (6), `templates/github/ticketed-review.yml` (2), > `.github/workflows/bonsai-status-sync.yml` (2) and `README.md` (1) — are bound to `driver-digital-agents`. > **`templates/github/bonsai-status-sync.yml` no longer contains the id at all**: it held 2 occurrences until @@ -234,7 +234,7 @@ mode is selected, `checkContainsTrigger` returns false, and `run.ts:212` logs "N Four things must move in one commit: the four `contains()` clauses (`templates/github/claude.yml:91,95,99,101`), `.github/workflows/bonsai-status-sync.yml:139`'s grep (it moved -out of `templates/github/` at the v1.10.0 repin — the kit file is now a stub carrying neither), a +out of `templates/github/` at the v1.11.0 repin — the kit file is now a stub carrying neither), a `trigger_phrase` input on the action, and **the out-of-repo cron orchestrator that writes `@claude` into issue bodies**. @@ -242,7 +242,7 @@ Note `trigger_phrase` **does not exist in this repo today** (`git grep` → zero default phrase. So it must be *added* in the same commit, not edited. That is a small but real difference: the first time it appears is the first time it can disagree with the workflow gate, which is the #148 signature. -> **Moved (2026-08-02, v1.10.0 repin).** `bonsai-status-sync.yml` finished converting. The grep and the +> **Moved (2026-08-02, v1.11.0 repin).** `bonsai-status-sync.yml` finished converting. The grep and the > `261291955` gate cited above now live ONLY in `.github/workflows/bonsai-status-sync.yml` (`:139` and > `:141`); `templates/github/bonsai-status-sync.yml` is a stub containing neither. Note the *fleet* still > runs the old 190-line copy until the wave, so until then a consumer repo still carries its own gate at the diff --git a/docs/reusable-conversion-scope.md b/docs/reusable-conversion-scope.md index 52c6f6b..02315db 100644 --- a/docs/reusable-conversion-scope.md +++ b/docs/reusable-conversion-scope.md @@ -16,7 +16,8 @@ The README has flagged this as "future work" since the repo split. This document > > **APPROVED and IN PROGRESS — `bonsai-status-sync.yml` (Phases 1–3).** The copy-per-repo cost is real > and this half was never gated on anything. Phase 1 landed 2026-08-02 (`b394c6d`, tag `v1.10.0`): the -> reusable is `.github/workflows/bonsai-status-sync.yml`. The caller stub followed in the v1.10.0 repin +> reusable is `.github/workflows/bonsai-status-sync.yml` (tag `v1.10.0`). The caller stub followed in the +> v1.11.0 repin > (PR #26, same day) — `templates/github/bonsai-status-sync.yml` is now a 67-line stub, not the 190-line > copy. **The fleet has NOT been waved**: consumer repos still run the 190-line copy. See *Phase 1 landed* > below, and read README release-order step 3 before waving — this is the wave its traps were written for. @@ -35,7 +36,7 @@ The README has flagged this as "future work" since the repo split. This document ## Why *As of the Phase 1 conversion (2026-08-02) this argument is half-resolved: `bonsai-status-sync.yml` now has a -central reusable, and the kit copy dropped from 190 lines to a 67-line stub at the v1.10.0 repin. **`claude.yml`'s 477 +central reusable, and the kit copy dropped from 190 lines to a 67-line stub at the v1.11.0 repin. **`claude.yml`'s 477 lines remain copied** — still the single largest thing in the kit, and the drift surface that outlives this conversion. The original framing follows.* @@ -315,7 +316,7 @@ is ordered by dependency, not by gating — do not read Phase 0 sitting at the t `bonsai-status-sync.yml` goes first because **it is the only one of the two with any pre-merge test path at all**. It has no OIDC path and one secret (`BONSAI_BEARER_TOKEN`, -`.github/workflows/bonsai-status-sync.yml:175` — it moved out of the kit file at the v1.10.0 repin; the stub +`.github/workflows/bonsai-status-sync.yml:175` — it moved out of the kit file at the v1.11.0 repin; the stub now just forwards it). Be precise about how much of it is provable pre-merge, because it is **one leg of three**. Its `on:` block @@ -346,7 +347,7 @@ so in the PR body. Merge on review of the diff alone; validate after merge. | 1 | Convert `bonsai-status-sync.yml` + stub + docs + lint | 3h | **done 2026-08-02** | | 2 | Pilot it (only the `pull_request` leg is testable pre-merge — see *Sequencing*) | 2h | **next** | | 3 | Fleet wave for `bonsai-status-sync` — 18 repo@branch pairs across 11 repos | 3–4h | after Phase 2 | -| 5 | Tag + repin the kit stubs (README's mandatory 3-step release order) | 1h | **done 2026-08-02** — tag `v1.10.0` + PR #26 | +| 5 | Tag + repin the kit stubs (README's mandatory 3-step release order) | 1h | **done 2026-08-02** — tag `v1.11.0` + PRs #26/#27 | | | **Approved subtotal** | **9–10h** | Phases 1 + 5 done → **pilot + wave left** | | 0 | Spike: go/no-go on OIDC-in-reusable | 3–4h | **tabled** | | 4 | Convert `claude.yml` — move the 477 lines **faithfully** | 7–9h | **tabled** | @@ -364,7 +365,7 @@ the old copy except one added comment; actionlint + shellcheck clean; `BONSAI_BE **Deferred out of Phase 1, landed at the repin: the caller stub.** A new reusable's stub cannot be pinned until the tag containing that reusable exists, so it landed in step 2 of the release order, not here. This is the house precedent — `dependabot-keep-current`'s reusable landed in `c362604` and its stub arrived later -already carrying a real SHA. **Landed 2026-08-02 in PR #26 (`3056f75`)**, pinned at `b394c6d` = `v1.10.0`; +already carrying a real SHA. **Landed 2026-08-02 in PR #26**, and repinned to `90f0d06` = `v1.11.0`; the kit now installs the 67-line stub. The *fleet* still runs the 190-line copy until the wave. **The stub as landed** (it replaced `templates/github/bonsai-status-sync.yml` wholesale; the pin below is the @@ -429,7 +430,7 @@ jobs: # NOTE: the required-status-check context for this job is `sync / sync` (caller job id / # reusable job id), NOT the bare `sync` it was as a full workflow. Verified 2026-08-02 that # no branch in the org pins either, so this rename breaks nothing — re-check before adding one. - uses: DriverDigital/workflows/.github/workflows/bonsai-status-sync.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/bonsai-status-sync.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 # Explicit, NOT `secrets: inherit`. Two reasons: (1) `inherit` passes whatever set exists, which # defeats the reusable's `required: true` — a missing secret would reach the curl and surface as # an opaque 401 on the first real flip instead of failing at startup; (2) least privilege — this diff --git a/templates/github/README.md b/templates/github/README.md index b5cb3e8..0773763 100644 --- a/templates/github/README.md +++ b/templates/github/README.md @@ -20,7 +20,7 @@ trailing `# vX.Y.Z` comment on the `uses:` line is the only place the version is | File | Rail | |---|---| -| `bonsai-status-sync.yml` | Deterministic (no-agent) Bonsai status flips on issue/PR events; on a PR it resolves the **linked issue** (`closingIssuesReferences`) and reads the task URL from the **issue** body — never from the PR body. Converted from a 190-line per-repo copy at v1.10.0. | +| `bonsai-status-sync.yml` | Deterministic (no-agent) Bonsai status flips on issue/PR events; on a PR it resolves the **linked issue** (`closingIssuesReferences`) and reads the task URL from the **issue** body — never from the PR body. Converted from a 190-line per-repo copy at v1.11.0. | | `pr-first-review.yml` | Human, no-ticket PR → `/code-review` comments + request a human reviewer. | | `ticketed-review.yml` | `claude[bot]` **ticketed** PR → capped `/code-review` revise loop (max 3 passes) → Bonsai reviewer handoff. | | `dependabot-validate.yml` | Credential-less install/build/test → uploads an inert artifact. Carries **no `secrets:` line** — deliberate, do not add one. | @@ -109,7 +109,7 @@ Ready to Deploy → Delivered / Deployed / Completed. The workflows never set th ``` **Re-copying into a repo that already has the kit?** Preserve that repo's own Dependabot action pins — re-copy the workflow bodies, but don't clobber pins Dependabot has since bumped there. -5. **Board strings are no longer edited here.** As of v1.10.0 `bonsai-status-sync.yml` is a caller +5. **Board strings are no longer edited here.** As of v1.11.0 `bonsai-status-sync.yml` is a caller stub; the exact Bonsai status strings live only in the central reusable (`DriverDigital/workflows/.github/workflows/bonsai-status-sync.yml`). A board rename is therefore a kit release + fleet repin, not a local edit — changing the strings in one repo does nothing. diff --git a/templates/github/bonsai-status-sync.yml b/templates/github/bonsai-status-sync.yml index c14f7fb..02efc3f 100644 --- a/templates/github/bonsai-status-sync.yml +++ b/templates/github/bonsai-status-sync.yml @@ -56,7 +56,7 @@ jobs: # NOTE: the required-status-check context for this job is `sync / sync` (caller job id / # reusable job id), NOT the bare `sync` it was as a full workflow. Verified 2026-08-02 that # no branch in the org pins either, so this rename breaks nothing — re-check before adding one. - uses: DriverDigital/workflows/.github/workflows/bonsai-status-sync.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/bonsai-status-sync.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 # Explicit, NOT `secrets: inherit`. Two reasons: (1) `inherit` passes whatever set exists, which # defeats the reusable's `required: true` — a missing secret would reach the curl and surface as # an opaque 401 on the first real flip instead of failing at startup; (2) least privilege — this diff --git a/templates/github/dependabot-keep-current.yml b/templates/github/dependabot-keep-current.yml index d34fb4c..8fbf815 100644 --- a/templates/github/dependabot-keep-current.yml +++ b/templates/github/dependabot-keep-current.yml @@ -17,6 +17,6 @@ permissions: jobs: keep-current: - uses: DriverDigital/workflows/.github/workflows/dependabot-keep-current.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/dependabot-keep-current.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 secrets: AGENTS_GH_PAT: ${{ secrets.AGENTS_GH_PAT }} diff --git a/templates/github/dependabot-report.yml b/templates/github/dependabot-report.yml index a2f9ea7..90545f0 100644 --- a/templates/github/dependabot-report.yml +++ b/templates/github/dependabot-report.yml @@ -20,7 +20,7 @@ concurrency: jobs: report: - uses: DriverDigital/workflows/.github/workflows/dependabot-report.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/dependabot-report.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 with: triggering-run-id: ${{ github.event.workflow_run.id }} head-repository: ${{ github.event.workflow_run.head_repository.full_name }} diff --git a/templates/github/dependabot-validate.yml b/templates/github/dependabot-validate.yml index 122a738..100f53c 100644 --- a/templates/github/dependabot-validate.yml +++ b/templates/github/dependabot-validate.yml @@ -21,5 +21,5 @@ concurrency: jobs: validate: - uses: DriverDigital/workflows/.github/workflows/dependabot-validate.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/dependabot-validate.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 # NO `secrets:` line — intentional and load-bearing. Do not add one. diff --git a/templates/github/pr-first-review.yml b/templates/github/pr-first-review.yml index 60eb18e..9cab0ef 100644 --- a/templates/github/pr-first-review.yml +++ b/templates/github/pr-first-review.yml @@ -23,5 +23,5 @@ jobs: # Only review real, published PRs — skip drafts (many repos open a draft PR first for build-test CI). # `ready_for_review` (in the trigger list above) covers the draft→ready transition. if: ${{ github.event.pull_request.draft == false }} - uses: DriverDigital/workflows/.github/workflows/pr-first-review.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/pr-first-review.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 secrets: inherit diff --git a/templates/github/ticketed-review.yml b/templates/github/ticketed-review.yml index 78dc3a3..e06e829 100644 --- a/templates/github/ticketed-review.yml +++ b/templates/github/ticketed-review.yml @@ -40,7 +40,7 @@ jobs: contains(github.event.comment.body, '') && github.event.comment.user.login == 'driver-digital-agents' && github.event.comment.user.id == 261291955) - uses: DriverDigital/workflows/.github/workflows/ticketed-review.yml@b394c6d73c3060ba3d0b352f51ad589af9d548f5 # v1.10.0 + uses: DriverDigital/workflows/.github/workflows/ticketed-review.yml@90f0d066c140c356c44d5b3d83d795c0256a7b82 # v1.11.0 with: pr_number: ${{ github.event.pull_request.number || github.event.issue.number }} secrets: