Makes the public contract match how the fleet now pins. The example stub + README pointed at @main/@<sha>; update to recommend @v1 — gadfly's curated release tag, re-moved on deliberate releases so central swarm tuning propagates without per-consumer re-pinning. A full @<sha> is still offered for an immutable pin; @main is discouraged (moves on every push).
Makes the public contract match how the fleet now pins. The example stub + README pointed at `@main`/`@<sha>`; update to recommend **`@v1`** — gadfly's curated release tag, re-moved on deliberate releases so central swarm tuning propagates without per-consumer re-pinning. A full `@<sha>` is still offered for an immutable pin; `@main` is discouraged (moves on every push).
- `examples/reusable.yml`: `uses: …@main` → `@v1` + updated pin comments.
- `README.md`: pin guidance now covers the reusable workflow ref (`@v1` / `@<sha>`), not just the image `:vN` tag.
Docs-only. Advisory-only invariant unchanged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The example stub + README pinned guidance pointed at @main/@<sha>; update them to
recommend @v1 — gadfly's curated release tag that's moved on deliberate releases
so central swarm tuning propagates without per-consumer re-pinning (full @<sha>
still offered for an immutable pin; @main discouraged).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Live status board. Findings are posted in each model's own comment. Advisory only — does not block merge.
<!-- gadfly-status-board -->
## 🪰 Gadfly — live review status
6/6 reviewers finished · updated 2026-06-28 04:14:05Z
#### `claude-code/opus` · claude-code — ✅ done
- ✅ **security** — No material issues found
- ✅ **correctness** — Minor issues
- ✅ **maintainability** — Minor issues
- ✅ **performance** — No material issues found
- ✅ **error-handling** — No material issues found
#### `claude-code/opus:max` · claude-code — ✅ done
- ✅ **security** — No material issues found
- ✅ **correctness** — No material issues found
- ✅ **maintainability** — Minor issues
- ✅ **performance** — No material issues found
- ✅ **error-handling** — No material issues found
#### `claude-code/sonnet` · claude-code — ✅ done
- ✅ **security** — Minor issues
- ✅ **correctness** — Blocking issues found
- ✅ **maintainability** — Minor issues
- ✅ **performance** — No material issues found
- ✅ **error-handling** — No material issues found
#### `deepseek-v4-pro:cloud` · ollama-cloud — ✅ done
- ✅ **security** — No material issues found
- ✅ **correctness** — Minor issues
- ✅ **maintainability** — Minor issues
- ✅ **performance** — No material issues found
- ✅ **error-handling** — No material issues found
#### `glm-5.2:cloud` · ollama-cloud — ✅ done
- ✅ **security** — No material issues found
- ✅ **correctness** — Minor issues
- ✅ **maintainability** — No material issues found
- ✅ **performance** — No material issues found
- ✅ **error-handling** — No material issues found
#### `minimax-m3:cloud` · ollama-cloud — ✅ done
- ✅ **security** — No material issues found
- ✅ **correctness** — Blocking issues found
- ✅ **maintainability** — Minor issues
- ✅ **performance** — No material issues found
- ✅ **error-handling** — No material issues found
<sub>Live status board. Findings are posted in each model's own comment. Advisory only — does not block merge.</sub>
This is a docs-only change that steers consumers from @main (moves on every push — highest supply-chain risk) toward either @v1 (curated release tag, moves only on deliberate releases) or @<sha> (immutable). From a security perspective, this is a net improvement: it reduces the window during which a compromised push to main would silently propagate into every consumer's workflow with their forwarded secrets.
The tradeoffs are transparently documented: @v1 auto-updates on releases (convenience, central tuning propagates) vs. @<sha> (immutable, no surprise changes). Both are strictly better than @main, which the diff now explicitly discourages.
No injection, credential leakage, authz bypass, or other security regression is introduced — the change touches only advisory prose and a comment in an example stub.
One minor observation (not a security issue, but noted for completeness): the reusable workflow's own doc comment at .gitea/workflows/review-reusable.yml:28 still says "Consumers should likewise pin uses: ...@<sha> (not @main)" without mentioning @v1. That file wasn't in this diff, so it's outside scope, but it's now slightly out of step with the new guidance.
🎯 Correctness — Minor issues
Now I have all the information I need. Let me evaluate each finding:
Finding 1 (@v1 tag may not exist): The draft reviewer explicitly labels this as "Unverified" and acknowledges it's a shallow clone where the tag could exist on the remote. I confirmed there is no local v1 tag. Since the reviewer themselves cannot confirm it, and I also cannot positively confirm it (the tag's absence in a shallow clone of a feature branch proves nothing), this finding must be dropped per the instructions: "DROP the finding if you cannot confirm it."
Finding 2 (docstring drift): I confirmed that .gitea/workflows/review-reusable.yml was not modified in this diff. Its header comment at line 9 still documents the consumer call as @<sha> only, and lines 28-29 still say "Consumers should likewise pin uses: ...@<sha> (not @main)." Meanwhile, the PR updates examples/reusable.yml and README.md to recommend @v1. This is a real inconsistency — the reusable workflow's own docstring contradicts the new guidance. Kept.
Verdict: Minor issues
Docstring drift in the reusable workflow itself. The reusable workflow's own header comment at .gitea/workflows/review-reusable.yml:9 still documents the consumer call as @<sha> only:
And lines 28–29 reinforce that with "Consumers should likewise pin uses: ...@<sha> (not @main)." This file is not in the diff, but it's the canonical documentation inside the workflow being referenced. Now the example stub says @v1 while the reusable workflow's own docstring says @<sha> with no mention of @v1. A consumer who opens the reusable workflow to understand their pin options will see only the @<sha> recommendation — contradicting the new guidance. Not a runtime bug, but a correctness-of-documentation inconsistency that undermines the PR's purpose.
🧹 Code cleanliness & maintainability — Minor issues
Verdict: Minor issues
.gitea/workflows/review-reusable.yml:9,28-29 — stale pin guidance in the reusable workflow's own header comment. The PR updates consumer-facing docs (examples/reusable.yml, README.md) to recommend @v1 as the primary ref, but the reusable workflow's own docstring still says uses: ...@<sha> (line 9) and "Consumers should likewise pin uses: ...@<sha> (not @main)" (lines 28-29) with no mention of @v1. A maintainer reading this file gets different guidance than a consumer reading the examples. Over time these two sources of truth will drift further. (Verified by reading the file at lines 1-30.)
Fix: Update lines 9 and 28-29 to match the new guidance — e.g., @v1 (or @<sha>) and mention the curated-tag approach, so the reusable workflow's own documentation stays in sync with the consumer-facing examples.
⚡ Performance — No material issues found
Verdict: No material issues found
This is a docs-only change — it updates comments in examples/reusable.yml and guidance in README.md to recommend @v1 (a curated release tag) over @main for the reusable workflow ref. There is no code, no logic, no runtime path, and therefore nothing to evaluate through the performance lens. The change has zero impact on allocations, queries, loops, blocking calls, or any other performance characteristic.
🧯 Error handling & edge cases — No material issues found
Verdict: No material issues found
This is a docs-only change — it updates comments in examples/reusable.yml and prose in README.md. There are no code paths, no new functions, no error returns, no panics, and no data handling introduced. The error-handling & edge-cases lens (ignored errors, missing cleanup/rollback, panics on bad input, nil/empty/zero/negative/overflow/off-by-one) has nothing to evaluate here.
The one thing that brushes against "edge case" territory — whether the @v1 tag actually exists on the repo right now (if it doesn't, consumers following the new guidance would get an immediate workflow-resolution failure) — is a deployment-coordination concern, not an error-handling defect in the diff. I can't verify tag existence with the available file-reading tools, but even if the tag were missing, that's a release-process gap, not something the diff's code/configuration mishandles.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 13s
<!-- gadfly-review:ollama:deepseek-v4-pro:cloud -->
### 🪰 Gadfly review — `deepseek-v4-pro:cloud` (ollama-cloud)
**Verdict: Minor issues** — 5 reviewers: security, correctness, maintainability, performance, error-handling
<details><summary><b>🔒 Security</b> — No material issues found</summary>
## Verdict: No material issues found
This is a docs-only change that steers consumers from `@main` (moves on every push — highest supply-chain risk) toward either `@v1` (curated release tag, moves only on deliberate releases) or `@<sha>` (immutable). From a security perspective, this is a net improvement: it reduces the window during which a compromised push to `main` would silently propagate into every consumer's workflow with their forwarded secrets.
- The tradeoffs are transparently documented: `@v1` auto-updates on releases (convenience, central tuning propagates) vs. `@<sha>` (immutable, no surprise changes). Both are strictly better than `@main`, which the diff now explicitly discourages.
- No injection, credential leakage, authz bypass, or other security regression is introduced — the change touches only advisory prose and a comment in an example stub.
One minor observation (not a security issue, but noted for completeness): the reusable workflow's own doc comment at `.gitea/workflows/review-reusable.yml:28` still says "Consumers should likewise pin `uses: ...@<sha>` (not @main)" without mentioning `@v1`. That file wasn't in this diff, so it's outside scope, but it's now slightly out of step with the new guidance.
</details>
<details><summary><b>🎯 Correctness</b> — Minor issues</summary>
Now I have all the information I need. Let me evaluate each finding:
**Finding 1 (`@v1` tag may not exist):** The draft reviewer explicitly labels this as "Unverified" and acknowledges it's a shallow clone where the tag could exist on the remote. I confirmed there is no local `v1` tag. Since the reviewer themselves cannot confirm it, and I also cannot positively confirm it (the tag's absence in a shallow clone of a feature branch proves nothing), this finding must be **dropped** per the instructions: "DROP the finding if you cannot confirm it."
**Finding 2 (docstring drift):** I confirmed that `.gitea/workflows/review-reusable.yml` was not modified in this diff. Its header comment at line 9 still documents the consumer call as `@<sha>` only, and lines 28-29 still say "Consumers should likewise pin `uses: ...@<sha>` (not @main)." Meanwhile, the PR updates `examples/reusable.yml` and `README.md` to recommend `@v1`. This is a real inconsistency — the reusable workflow's own docstring contradicts the new guidance. **Kept.**
---
## Verdict: Minor issues
- **Docstring drift in the reusable workflow itself.** The reusable workflow's own header comment at `.gitea/workflows/review-reusable.yml:9` still documents the consumer call as `@<sha>` only:
```
# uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>
```
And lines 28–29 reinforce that with "Consumers should likewise pin `uses: ...@<sha>` (not @main)." This file is not in the diff, but it's the canonical documentation inside the workflow being referenced. Now the example stub says `@v1` while the reusable workflow's own docstring says `@<sha>` with no mention of `@v1`. A consumer who opens the reusable workflow to understand their pin options will see only the `@<sha>` recommendation — contradicting the new guidance. Not a runtime bug, but a correctness-of-documentation inconsistency that undermines the PR's purpose.
</details>
<details><summary><b>🧹 Code cleanliness & maintainability</b> — Minor issues</summary>
## Verdict: Minor issues
- **`.gitea/workflows/review-reusable.yml:9,28-29` — stale pin guidance in the reusable workflow's own header comment.** The PR updates consumer-facing docs (`examples/reusable.yml`, `README.md`) to recommend `@v1` as the primary ref, but the reusable workflow's own docstring still says `uses: ...@<sha>` (line 9) and "Consumers should likewise pin `uses: ...@<sha>` (not @main)" (lines 28-29) with no mention of `@v1`. A maintainer reading this file gets different guidance than a consumer reading the examples. Over time these two sources of truth will drift further. *(Verified by reading the file at lines 1-30.)*
**Fix:** Update lines 9 and 28-29 to match the new guidance — e.g., `@v1` (or `@<sha>`) and mention the curated-tag approach, so the reusable workflow's own documentation stays in sync with the consumer-facing examples.
</details>
<details><summary><b>⚡ Performance</b> — No material issues found</summary>
## Verdict: No material issues found
This is a docs-only change — it updates comments in `examples/reusable.yml` and guidance in `README.md` to recommend `@v1` (a curated release tag) over `@main` for the reusable workflow ref. There is no code, no logic, no runtime path, and therefore nothing to evaluate through the performance lens. The change has zero impact on allocations, queries, loops, blocking calls, or any other performance characteristic.
</details>
<details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary>
## Verdict: No material issues found
This is a docs-only change — it updates comments in `examples/reusable.yml` and prose in `README.md`. There are no code paths, no new functions, no error returns, no panics, and no data handling introduced. The error-handling & edge-cases lens (ignored errors, missing cleanup/rollback, panics on bad input, nil/empty/zero/negative/overflow/off-by-one) has nothing to evaluate here.
The one thing that brushes against "edge case" territory — whether the `@v1` tag actually exists on the repo right now (if it doesn't, consumers following the new guidance would get an immediate workflow-resolution failure) — is a deployment-coordination concern, not an error-handling defect in the diff. I can't verify tag existence with the available file-reading tools, but even if the tag were missing, that's a release-process gap, not something the diff's code/configuration mishandles.
</details>
<sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 13s</sub>
Reviewed through the security lens. This is a docs-only change adjusting pin guidance for the reusable-workflow uses: ref.
examples/reusable.yml:54 now pins @v1 instead of @main, and the comment block (:17-20, :52-53) accurately explains the security trade-off: @v1 is a curated tag moved only on deliberate releases (so central tuning propagates), @<sha> is offered for an immutable pin, and @main is explicitly discouraged because it moves on every push and "would change what runs with your forwarded secrets." The least-privilege secrets-forwarding guidance (:14-16, :58-62) and the comment-trigger actor gate (:49-51, github.actor == 'your-username') are untouched and remain sound.
README.md:315-318 mirrors the same guidance consistently. No secret leakage, injection, authn/authz, or unsafe-input handling is introduced — the only tainted surface (forwarded secrets to a third-party workflow) is already addressed by the explicit secrets: block advice, which this PR preserves.
The change is a net security improvement (moving the recommended example off the highest-churn mutable ref while still documenting the immutable option). Nothing in my lane to flag.
🎯 Correctness — Minor issues
The finding is confirmed. Lines 9 and 28-29 of .gitea/workflows/review-reusable.yml still recommend @<sha> with no mention of @v1, directly contradicting the updated README and examples/reusable.yml guidance.
VERDICT: Minor issues
.gitea/workflows/review-reusable.yml:9 and :28-29 — The PR rewrites the pin guidance in README.md and examples/reusable.yml to recommend @v1 as the primary ref (with @<sha> as the immutable alternative, avoid @main), but the reusable workflow's own header comments — consumer-facing documentation embedded in the file consumers actually point at — were not updated. Line 9's example still shows ...review-reusable.yml@<sha> with no mention of @v1, and lines 28–29 explicitly state "Consumers should likewise pin uses: ...@<sha> (not @main)", framing @<sha> as the recommendation. This now directly contradicts the new README/example guidance (@v1 first, @<sha> as the immutable alternative). A consumer reading the workflow file they're subscribing to gets the old, conflicting advice. Suggested fix: update those two comment spots to match the new @v1-first / @<sha>-immutable / avoid-@main ordering. (Note: the v1 git tag's existence could not be confirmed with read-only tools; worth verifying it exists before/with merge so the example's @v1 ref resolves.)
🧹 Code cleanliness & maintainability — No material issues found
No material issues found.
The diff is docs/comment-only and cleanly updates the pin guidance to @v1 consistently across both files. The example file (examples/reusable.yml) and README prose both use the same framing (@v1 curated release tag → auto-updating stability; @<sha> → immutable pin; avoid @main), so the duplicated messaging stays consistent rather than drifting. No dead code, naming, or structural concerns introduced.
⚡ Performance — No material issues found
No material issues found.
This is a docs-only change (comments in examples/reusable.yml and prose in README.md) updating recommended pin references (@main → @v1). It touches no runtime code, queries, loops, allocations, or hot paths — there is nothing to evaluate through the performance lens.
🧯 Error handling & edge cases — No material issues found
No material issues found
This is a docs-only change: it rewrites comments in examples/reusable.yml (lines 17-20, 52-54) and prose in README.md (lines 315-318) to recommend @v1 over @main. No executable code, logic, error-handling, input parsing, or control flow is touched.
Through the error-handling / edge-case lens specifically:
No new unhappy paths are introduced — the only edited runtime-adjacent line is the uses: ref (@main → @v1), which is a ref string, not logic. A missing/non-existent @v1 tag would surface as a Gitea Actions checkout/reusable-resolution failure at job start (same failure mode as any bad ref), not a swallowed error or panic in this repo's code.
No nil/empty/zero/overflow/boundary concerns apply to ref strings or documentation prose.
Nothing in my lane to flag.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 10s
<!-- gadfly-review:ollama:glm-5.2:cloud -->
### 🪰 Gadfly review — `glm-5.2:cloud` (ollama-cloud)
**Verdict: Minor issues** — 5 reviewers: security, correctness, maintainability, performance, error-handling
<details><summary><b>🔒 Security</b> — No material issues found</summary>
**VERDICT: No material issues found**
Reviewed through the security lens. This is a docs-only change adjusting pin guidance for the reusable-workflow `uses:` ref.
- `examples/reusable.yml:54` now pins `@v1` instead of `@main`, and the comment block (`:17-20`, `:52-53`) accurately explains the security trade-off: `@v1` is a curated tag moved only on deliberate releases (so central tuning propagates), `@<sha>` is offered for an immutable pin, and `@main` is explicitly discouraged because it moves on every push and "would change what runs with your forwarded secrets." The least-privilege secrets-forwarding guidance (`:14-16`, `:58-62`) and the comment-trigger actor gate (`:49-51`, `github.actor == 'your-username'`) are untouched and remain sound.
- `README.md:315-318` mirrors the same guidance consistently. No secret leakage, injection, authn/authz, or unsafe-input handling is introduced — the only tainted surface (forwarded secrets to a third-party workflow) is already addressed by the explicit `secrets:` block advice, which this PR preserves.
The change is a net security improvement (moving the recommended example off the highest-churn mutable ref while still documenting the immutable option). Nothing in my lane to flag.
</details>
<details><summary><b>🎯 Correctness</b> — Minor issues</summary>
The finding is confirmed. Lines 9 and 28-29 of `.gitea/workflows/review-reusable.yml` still recommend `@<sha>` with no mention of `@v1`, directly contradicting the updated README and `examples/reusable.yml` guidance.
VERDICT: Minor issues
- `.gitea/workflows/review-reusable.yml:9` and `:28-29` — The PR rewrites the pin guidance in `README.md` and `examples/reusable.yml` to recommend `@v1` as the primary ref (with `@<sha>` as the immutable alternative, avoid `@main`), but the reusable workflow's **own header comments** — consumer-facing documentation embedded in the file consumers actually point at — were not updated. Line 9's example still shows `...review-reusable.yml@<sha>` with no mention of `@v1`, and lines 28–29 explicitly state *"Consumers should likewise pin `uses: ...@<sha>` (not @main)"*, framing `@<sha>` as the recommendation. This now directly contradicts the new README/example guidance (`@v1` first, `@<sha>` as the immutable alternative). A consumer reading the workflow file they're subscribing to gets the old, conflicting advice. Suggested fix: update those two comment spots to match the new `@v1`-first / `@<sha>`-immutable / avoid-`@main` ordering. (Note: the `v1` git tag's existence could not be confirmed with read-only tools; worth verifying it exists before/with merge so the example's `@v1` ref resolves.)
</details>
<details><summary><b>🧹 Code cleanliness & maintainability</b> — No material issues found</summary>
No material issues found.
The diff is docs/comment-only and cleanly updates the pin guidance to `@v1` consistently across both files. The example file (`examples/reusable.yml`) and README prose both use the same framing (`@v1` curated release tag → auto-updating stability; `@<sha>` → immutable pin; avoid `@main`), so the duplicated messaging stays consistent rather than drifting. No dead code, naming, or structural concerns introduced.
</details>
<details><summary><b>⚡ Performance</b> — No material issues found</summary>
No material issues found.
This is a docs-only change (comments in `examples/reusable.yml` and prose in `README.md`) updating recommended pin references (`@main` → `@v1`). It touches no runtime code, queries, loops, allocations, or hot paths — there is nothing to evaluate through the performance lens.
</details>
<details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary>
No material issues found
This is a docs-only change: it rewrites **comments** in `examples/reusable.yml` (lines 17-20, 52-54) and prose in `README.md` (lines 315-318) to recommend `@v1` over `@main`. No executable code, logic, error-handling, input parsing, or control flow is touched.
Through the error-handling / edge-case lens specifically:
- No new unhappy paths are introduced — the only edited runtime-adjacent line is the `uses:` ref (`@main` → `@v1`), which is a ref string, not logic. A missing/non-existent `@v1` tag would surface as a Gitea Actions checkout/reusable-resolution failure at job start (same failure mode as any bad ref), not a swallowed error or panic in this repo's code.
- No nil/empty/zero/overflow/boundary concerns apply to ref strings or documentation prose.
Nothing in my lane to flag.
</details>
<sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 10s</sub>
The finding is confirmed. Lines 28-29 of review-reusable.yml still say pin uses: ...@<sha> (not @main), which directly contradicts the new guidance in examples/reusable.yml that recommends @v1 as the primary recommendation. The second finding (mutable tag trust model) is a design-level observation about the PR's documented intent — the PR description acknowledges the tradeoff — and there is no code to confirm or deny it against; it's a documentation quality concern the draft labels as intentional.
Minor issues
review-reusable.yml still contradicts the new guidance (review-reusable.yml:28-29):
The reusable workflow's own header comment still says:
"Consumers should likewise pin uses: ...@<sha> (not @main) so a push to this repo can't silently change the code that runs with their forwarded secrets."
The updated example stub now defaults to @v1 (mutable tag), but this authoritative comment in the reusable workflow was not updated. A security-aware consumer reading review-reusable.yml directly will get the opposite recommendation from what the example stub models — the two pieces of guidance now contradict each other.
Suggested fix: Update review-reusable.yml lines 28–29 to align with the new guidance (e.g., mention @v1 as the recommended starting point and @<sha> for an immutable pin).
🎯 Correctness — Blocking issues found
The git repository has no tags at all — git tag -l returns empty, and packed-refs contains only the remote branch ref. The build-image workflow (lines 73–74) confirms it publishes Docker image tags in response to a pushed v* git tag, but it does not create the git tag itself. The diff in examples/reusable.yml:54 changes @main to @v1, and README.md instructs consumers to pin review-reusable.yml@v1. The finding is confirmed.
Blocking issues found
@v1 tag does not exist — examples/reusable.yml:54 / README.md:315
No v1 git tag has been pushed to this repository (git tag -l returns empty; .git/packed-refs contains only the remote branch ref for docs/recommend-v1). The diff changes uses: …@main to uses: steve/gadfly/.gitea/workflows/review-reusable.yml@v1 and updates the README to tell consumers to pin review-reusable.yml@v1, but in Gitea Actions the @ref in a uses: directive resolves to a live git ref. A consumer who follows this guidance right now will get a workflow resolution failure — the ref simply doesn't exist.
The build-image workflow (.gitea/workflows/build-image.yml:21,73-74) publishes Docker image tags when a v* git tag is pushed; it does not create the git tag itself. Git tags must be pushed separately via git tag v1 && git push origin v1.
Fix: Push a v1 git tag to the repository (or the release cut that creates it) before — or atomically with — merging this PR. Without that tag, any consumer following the updated docs or example stub will have a broken workflow.
🧹 Code cleanliness & maintainability — Minor issues
Verdict: Minor issues
README:315 — terminology mismatch. The PR introduces the term "full-stub consumers" in the Release section (line 315), but the README's own intro (lines 40–44) refers to the same adversarial-review.yml path as "the full self-contained adversarial-review.yml". A reader scanning only the Release section encounters "full-stub consumers" without a prior definition tying it to adversarial-review.yml; the intro's "full self-contained" phrasing is the more anchored reference. Fix: match the intro's wording — e.g. "Pin full-self-contained-stub consumers…" or append (\adversarial-review.yml`)` inline. Verified against README lines 39–46 and 313–318.
Slightly inconsistent phrasing for the same concept across files.@v1 is described three ways:
README line 317: "a curated tag moved on releases"
examples/reusable.yml line 18: "a curated pointer moved on deliberate releases"
examples/reusable.yml line 52: "curated release tag (auto-updates on releases)"
"Tag" vs "pointer," "moved on releases" vs "moved on deliberate releases" vs "auto-updates on releases" — not a runtime issue, but when the wording drifts across three spots for the same concept, the next editor won't know which phrasing is authoritative and will need to update all three again. Picking one phrasing and using it consistently reduces future churn. Verified by reading both files.
Neither finding is blocking. The docs are broadly coherent and the actual @v1 pin on examples/reusable.yml:54 is correctly placed.
⚡ Performance — No material issues found
No material issues found.
This is a docs-only change (README prose and a comment + uses: ref in an example YAML). There is no executable code, no queries, no allocations, no loops, and no hot paths touched. Nothing to evaluate through a performance lens.
🧯 Error handling & edge cases — No material issues found
No material issues found
This is a pure documentation change — updated prose in README.md and revised comments plus a single uses: ref string in examples/reusable.yml. There are no code paths, error returns, input handling, or runtime logic of any kind introduced or modified. My lens (error handling & edge cases) has nothing to evaluate here.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 30s
<!-- gadfly-review:ollama:claude-code/sonnet -->
### 🪰 Gadfly review — `claude-code/sonnet` (claude-code)
**Verdict: Blocking issues found** — 5 reviewers: security, correctness, maintainability, performance, error-handling
<details><summary><b>🔒 Security</b> — Minor issues</summary>
The finding is confirmed. Lines 28-29 of `review-reusable.yml` still say `pin uses: ...@<sha> (not @main)`, which directly contradicts the new guidance in `examples/reusable.yml` that recommends `@v1` as the primary recommendation. The second finding (mutable tag trust model) is a design-level observation about the PR's documented intent — the PR description acknowledges the tradeoff — and there is no code to confirm or deny it against; it's a documentation quality concern the draft labels as intentional.
---
**Minor issues**
- **`review-reusable.yml` still contradicts the new guidance** (`review-reusable.yml:28-29`):
The reusable workflow's own header comment still says:
> "Consumers should likewise pin `uses: ...@<sha>` (not `@main`) so a push to this repo can't silently change the code that runs with their forwarded secrets."
The updated example stub now defaults to `@v1` (mutable tag), but this authoritative comment in the reusable workflow was not updated. A security-aware consumer reading `review-reusable.yml` directly will get the opposite recommendation from what the example stub models — the two pieces of guidance now contradict each other.
**Suggested fix**: Update `review-reusable.yml` lines 28–29 to align with the new guidance (e.g., mention `@v1` as the recommended starting point and `@<sha>` for an immutable pin).
</details>
<details><summary><b>🎯 Correctness</b> — Blocking issues found</summary>
The git repository has no tags at all — `git tag -l` returns empty, and `packed-refs` contains only the remote branch ref. The build-image workflow (lines 73–74) confirms it publishes *Docker image* tags in response to a pushed `v*` git tag, but it does not create the git tag itself. The diff in `examples/reusable.yml:54` changes `@main` to `@v1`, and `README.md` instructs consumers to pin `review-reusable.yml@v1`. The finding is confirmed.
---
**Blocking issues found**
- **`@v1` tag does not exist — `examples/reusable.yml:54` / `README.md:315`**
No `v1` git tag has been pushed to this repository (`git tag -l` returns empty; `.git/packed-refs` contains only the remote branch ref for `docs/recommend-v1`). The diff changes `uses: …@main` to `uses: steve/gadfly/.gitea/workflows/review-reusable.yml@v1` and updates the README to tell consumers to pin `review-reusable.yml@v1`, but in Gitea Actions the `@ref` in a `uses:` directive resolves to a live git ref. A consumer who follows this guidance right now will get a workflow resolution failure — the ref simply doesn't exist.
The build-image workflow (`.gitea/workflows/build-image.yml:21,73-74`) publishes *Docker image* tags when a `v*` git tag is pushed; it does not create the git tag itself. Git tags must be pushed separately via `git tag v1 && git push origin v1`.
**Fix:** Push a `v1` git tag to the repository (or the release cut that creates it) before — or atomically with — merging this PR. Without that tag, any consumer following the updated docs or example stub will have a broken workflow.
</details>
<details><summary><b>🧹 Code cleanliness & maintainability</b> — Minor issues</summary>
**Verdict: Minor issues**
- **README:315 — terminology mismatch.** The PR introduces the term "full-stub consumers" in the Release section (line 315), but the README's own intro (lines 40–44) refers to the same `adversarial-review.yml` path as **"the full self-contained `adversarial-review.yml`"**. A reader scanning only the Release section encounters "full-stub consumers" without a prior definition tying it to `adversarial-review.yml`; the intro's "full self-contained" phrasing is the more anchored reference. Fix: match the intro's wording — e.g. `"Pin full-self-contained-stub consumers…"` or append `(\`adversarial-review.yml\`)` inline. Verified against README lines 39–46 and 313–318.
- **Slightly inconsistent phrasing for the same concept across files.** `@v1` is described three ways:
- README line 317: "a curated tag moved on releases"
- `examples/reusable.yml` line 18: "a curated pointer moved on deliberate releases"
- `examples/reusable.yml` line 52: "curated release tag (auto-updates on releases)"
"Tag" vs "pointer," "moved on releases" vs "moved on deliberate releases" vs "auto-updates on releases" — not a runtime issue, but when the wording drifts across three spots for the same concept, the next editor won't know which phrasing is authoritative and will need to update all three again. Picking one phrasing and using it consistently reduces future churn. Verified by reading both files.
Neither finding is blocking. The docs are broadly coherent and the actual `@v1` pin on `examples/reusable.yml:54` is correctly placed.
</details>
<details><summary><b>⚡ Performance</b> — No material issues found</summary>
No material issues found.
This is a docs-only change (README prose and a comment + `uses:` ref in an example YAML). There is no executable code, no queries, no allocations, no loops, and no hot paths touched. Nothing to evaluate through a performance lens.
</details>
<details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary>
**No material issues found**
This is a pure documentation change — updated prose in `README.md` and revised comments plus a single `uses:` ref string in `examples/reusable.yml`. There are no code paths, error returns, input handling, or runtime logic of any kind introduced or modified. My lens (error handling & edge cases) has nothing to evaluate here.
</details>
<sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 30s</sub>
This is a docs-only change to supply-chain pinning guidance, which is squarely in scope for the security lens — so I checked it on the merits rather than waving it through.
examples/reusable.yml:54 and the surrounding comment (:17-20, :52-53), plus README.md:315-318 — the change swaps the recommended reusable-workflow ref from @main to @v1. Verified by reading both files at the PR state. Security-relevant facts:
A reusable workflow runs with the consumer's forwarded secrets, so the immutability of its uses: ref is a genuine supply-chain control. @v1 is a mutable tag ("re-moved on deliberate releases"), meaning a moved/compromised v1 would execute new code against forwarded secrets.
However, this is a net improvement, not a regression: the prior recommendation was @main, which mutates on every push (strictly larger attack surface). @v1 moves only on deliberate releases.
The guidance honestly discloses the tradeoff and offers the immutable @<sha> pin for consumers who want it, and explicitly discourages @main. This mirrors standard practice (actions/checkout@v4).
The least-privilege secret guidance (explicit secrets: forwarding over secrets: inherit) is preserved (:14-16, :55-62).
No injection, secret leakage, authz, or untrusted-data handling is introduced or weakened. Nothing material in my lane.
One note, not a finding: a careless copy-paste consumer gets a mutable pin by default — but that's already mitigated by the explicit inline comment recommending @<sha>, and it's a security upgrade over the previous @main default.
🎯 Correctness — No material issues found
I've verified the change against the actual repo. My investigation is complete.
VERDICT: No material issues found
This is a docs-only change. Through the Correctness lens, the factual claims hold up against how the system actually works, and the two edited files are internally consistent.
What I verified:
Moving-@v1 claim is consistent with the release model. README:317 and examples/reusable.yml:52 describe @v1 as a curated tag "moved on releases" so swarm tuning propagates. I confirmed the mechanism: review-reusable.yml:93 hardcodes the image at :sha-c342bdb and its header (:26-27) says that sha is "bumped per Gadfly release." So re-pointing the v1 git tag to a newer commit does propagate a newer pinned image — the auto-update story is coherent, not contradictory. A force-moved v* tag also re-triggers build-image.yml (:19-21), republishing :v1/:latest, so the image and workflow-ref stories line up.
:vN image vs @v1 workflow-ref guidance is accurate.build-image.yml:73-74 publishes :${GITHUB_REF_NAME} (+:latest) on a v* tag push, matching README:315's :vN advice.
No stale/contradictory refs left behind. Grepped README, examples/, and CLAUDE.md: every consumer-facing ref now recommends @v1/@<sha> and discourages @main; README:41 uses a neutral @… placeholder. No leftover @main recommendation that would contradict the new guidance.
owner/repo path unchanged.steve/gadfly/.gitea/workflows/review-reusable.yml matches the registry path gitea.stevedudenhoeffer.com/steve/gadfly; only the ref suffix changed.
One caveat I could not verify (flagging, not asserting as a bug):
Existence of the v1 tag.git tag -l returns nothing at this checkout, and I was denied network access to git ls-remote, so I cannot confirm a v1 tag actually exists on the remote yet. If the release process cuts only semver tags (e.g. v1.0.0) and never pushes/moves a bare v1, then a consumer copy-pasting examples/reusable.yml:54 (...review-reusable.yml@v1) would hit a workflow-resolution failure, and :v1 image pins would also break. This is a release-process/sequencing concern external to the diff text — worth a one-line confirmation from the author that the v1 tag is (or will be) published before/with these docs, but it is not a logic defect in the change itself.
Outside my lens: none worth raising.
🧹 Code cleanliness & maintainability — Minor issues
Both findings verify against the code. review-reusable.yml:9 still shows …@<sha> and :28 still says pin uses: ...@ (not @main) with no mention of @v1, while README.md:317-318 and examples/reusable.yml now lead with @v1. And git tag -l is empty — no v1 tag exists.
VERDICT: Minor issues
Finding — stale duplicate of the pin guidance left un-updated (@<sha>/@main, no @v1) .gitea/workflows/review-reusable.yml:9 and :28
The "how to pin the reusable" advice exists in three consumer-facing places. This PR updated two of them (README.md:315-318, examples/reusable.yml:17-19,52-54) to recommend @v1, but the third copy — the worked consumer-stub example and pin note in the reusable workflow's own header — still reads:
line 9: uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>
line 28: Consumers should likewise pin uses: ...@ (not @main)…
So the contract now gives inconsistent guidance depending on which file a consumer opens: README/example say "use @v1, sha is the immutable alternative," while review-reusable.yml's header still presents @<sha> as the recommendation and never mentions @v1. CLAUDE.md's maintenance rule ("the example workflows are the contract users rely on — stale docs are a bug") applies directly here.
Fix (low-churn): update review-reusable.yml:9 to …@v1 and reword :28 to mirror the new phrasing ("pin @v1 for auto-updating stability, or @<sha> for an immutable pin; avoid @main"). Keeps the three copies in sync.
Note the duplication itself is the root maintainability smell — the same paragraph is now hand-maintained in three spots and has already drifted once. Not worth refactoring docs into a single source here, but the fix above should bring all three back into agreement in this same change.
Outside my lens (flagging because it's potentially blocking):git tag -l returns no tags — there is currently no v1 tag (or any tag) in the repo. If the curated @v1 ref isn't actually created/moved as part of this release, every doc now points consumers at a ref that won't resolve. That's a correctness/release-process concern for another reviewer, not a cleanliness one.
Nothing else in my lens: the wording changes in the two edited files are clear, consistent with each other, and follow the surrounding comment style.
⚡ Performance — No material issues found
VERDICT: No material issues found
This is a documentation-only change — README.md pin guidance and examples/reusable.yml comments/ref, swapping @main → @v1. There is no code, query, loop, allocation, or hot path touched, so there is nothing for the performance lens to evaluate.
No runtime behavior changes: both files are docs/config-comment edits; the only functional line is the uses: workflow ref, which affects which image/workflow consumers pin to, not execution efficiency. Verified by reading the full diff — both hunks are comment text and prose.
Nothing in my lane to flag here.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
This is a docs-only change — prose in README.md and YAML comments plus a single uses: ref string (@main → @v1) in examples/reusable.yml. There is no executable code, no control flow, and therefore no error paths, cleanup/rollback, boundary conditions, nil/empty handling, or overflow surface for my lens to evaluate.
I confirmed from the diff that the only non-comment change is the workflow ref tag in the uses: line; everything else is comment/prose. Nothing in the error-handling & edge-case lens is materially wrong here.
Outside my lens: the docs now recommend consumers pin to review-reusable.yml@v1. Whether that tag actually exists in the gadfly repo is a real correctness concern (a dangling ref would break every consumer's workflow resolution), but that belongs to the correctness lens, not mine.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 20s
<!-- gadfly-review:ollama:claude-code/opus:max -->
### 🪰 Gadfly review — `claude-code/opus:max` (claude-code)
**Verdict: Minor issues** — 5 reviewers: security, correctness, maintainability, performance, error-handling
<details><summary><b>🔒 Security</b> — No material issues found</summary>
**VERDICT: No material issues found**
This is a docs-only change to supply-chain pinning guidance, which is squarely in scope for the security lens — so I checked it on the merits rather than waving it through.
- `examples/reusable.yml:54` and the surrounding comment (`:17-20`, `:52-53`), plus `README.md:315-318` — the change swaps the recommended reusable-workflow ref from `@main` to `@v1`. Verified by reading both files at the PR state. Security-relevant facts:
- A reusable workflow runs **with the consumer's forwarded secrets**, so the immutability of its `uses:` ref is a genuine supply-chain control. `@v1` is a *mutable* tag ("re-moved on deliberate releases"), meaning a moved/compromised `v1` would execute new code against forwarded secrets.
- However, this is a **net improvement, not a regression**: the prior recommendation was `@main`, which mutates on *every* push (strictly larger attack surface). `@v1` moves only on deliberate releases.
- The guidance honestly discloses the tradeoff and offers the immutable `@<sha>` pin for consumers who want it, and explicitly discourages `@main`. This mirrors standard practice (`actions/checkout@v4`).
- The least-privilege secret guidance (explicit `secrets:` forwarding over `secrets: inherit`) is preserved (`:14-16`, `:55-62`).
No injection, secret leakage, authz, or untrusted-data handling is introduced or weakened. Nothing material in my lane.
One note, not a finding: a careless copy-paste consumer gets a mutable pin by default — but that's already mitigated by the explicit inline comment recommending `@<sha>`, and it's a security upgrade over the previous `@main` default.
</details>
<details><summary><b>🎯 Correctness</b> — No material issues found</summary>
I've verified the change against the actual repo. My investigation is complete.
## VERDICT: No material issues found
This is a docs-only change. Through the **Correctness lens**, the factual claims hold up against how the system actually works, and the two edited files are internally consistent.
What I verified:
- **Moving-`@v1` claim is consistent with the release model.** README:317 and `examples/reusable.yml:52` describe `@v1` as a curated tag "moved on releases" so swarm tuning propagates. I confirmed the mechanism: `review-reusable.yml:93` hardcodes the image at `:sha-c342bdb` and its header (`:26-27`) says that sha is "bumped per Gadfly release." So re-pointing the `v1` git tag to a newer commit does propagate a newer pinned image — the auto-update story is coherent, not contradictory. A force-moved `v*` tag also re-triggers `build-image.yml` (`:19-21`), republishing `:v1`/`:latest`, so the image and workflow-ref stories line up.
- **`:vN` image vs `@v1` workflow-ref guidance is accurate.** `build-image.yml:73-74` publishes `:${GITHUB_REF_NAME}` (+`:latest`) on a `v*` tag push, matching README:315's `:vN` advice.
- **No stale/contradictory refs left behind.** Grepped README, `examples/`, and CLAUDE.md: every consumer-facing ref now recommends `@v1`/`@<sha>` and discourages `@main`; README:41 uses a neutral `@…` placeholder. No leftover `@main` recommendation that would contradict the new guidance.
- **owner/repo path unchanged.** `steve/gadfly/.gitea/workflows/review-reusable.yml` matches the registry path `gitea.stevedudenhoeffer.com/steve/gadfly`; only the ref suffix changed.
One caveat I could **not** verify (flagging, not asserting as a bug):
- **Existence of the `v1` tag.** `git tag -l` returns nothing at this checkout, and I was denied network access to `git ls-remote`, so I cannot confirm a `v1` tag actually exists on the remote yet. If the release process cuts only semver tags (e.g. `v1.0.0`) and never pushes/moves a bare `v1`, then a consumer copy-pasting `examples/reusable.yml:54` (`...review-reusable.yml@v1`) would hit a workflow-resolution failure, and `:v1` image pins would also break. This is a release-process/sequencing concern external to the diff text — worth a one-line confirmation from the author that the `v1` tag is (or will be) published before/with these docs, but it is not a logic defect in the change itself.
Outside my lens: none worth raising.
</details>
<details><summary><b>🧹 Code cleanliness & maintainability</b> — Minor issues</summary>
Both findings verify against the code. `review-reusable.yml:9` still shows `…@<sha>` and `:28` still says `pin `uses: ...@<sha>` (not @main)` with no mention of `@v1`, while `README.md:317-318` and `examples/reusable.yml` now lead with `@v1`. And `git tag -l` is empty — no `v1` tag exists.
## VERDICT: Minor issues
**Finding — stale duplicate of the pin guidance left un-updated (`@<sha>`/`@main`, no `@v1`)**
`.gitea/workflows/review-reusable.yml:9` and `:28`
The "how to pin the reusable" advice exists in **three** consumer-facing places. This PR updated two of them (`README.md:315-318`, `examples/reusable.yml:17-19,52-54`) to recommend `@v1`, but the third copy — the worked consumer-stub example and pin note in the reusable workflow's own header — still reads:
- line 9: `uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>`
- line 28: `Consumers should likewise pin `uses: ...@<sha>` (not @main)…`
So the contract now gives **inconsistent guidance depending on which file a consumer opens**: README/example say "use `@v1`, sha is the immutable alternative," while `review-reusable.yml`'s header still presents `@<sha>` as the recommendation and never mentions `@v1`. CLAUDE.md's maintenance rule ("the example workflows are the contract users rely on — stale docs are a bug") applies directly here.
- *Fix (low-churn):* update `review-reusable.yml:9` to `…@v1` and reword `:28` to mirror the new phrasing ("pin `@v1` for auto-updating stability, or `@<sha>` for an immutable pin; avoid `@main`"). Keeps the three copies in sync.
Note the duplication itself is the root maintainability smell — the same paragraph is now hand-maintained in three spots and has already drifted once. Not worth refactoring docs into a single source here, but the fix above should bring all three back into agreement in this same change.
**Outside my lens (flagging because it's potentially blocking):** `git tag -l` returns no tags — there is currently no `v1` tag (or any tag) in the repo. If the curated `@v1` ref isn't actually created/moved as part of this release, every doc now points consumers at a ref that won't resolve. That's a correctness/release-process concern for another reviewer, not a cleanliness one.
Nothing else in my lens: the wording changes in the two edited files are clear, consistent with each other, and follow the surrounding comment style.
</details>
<details><summary><b>⚡ Performance</b> — No material issues found</summary>
**VERDICT: No material issues found**
This is a documentation-only change — `README.md` pin guidance and `examples/reusable.yml` comments/ref, swapping `@main` → `@v1`. There is no code, query, loop, allocation, or hot path touched, so there is nothing for the performance lens to evaluate.
- No runtime behavior changes: both files are docs/config-comment edits; the only functional line is the `uses:` workflow ref, which affects *which* image/workflow consumers pin to, not execution efficiency. Verified by reading the full diff — both hunks are comment text and prose.
Nothing in my lane to flag here.
</details>
<details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary>
**VERDICT: No material issues found**
This is a docs-only change — prose in `README.md` and YAML comments plus a single `uses:` ref string (`@main` → `@v1`) in `examples/reusable.yml`. There is no executable code, no control flow, and therefore no error paths, cleanup/rollback, boundary conditions, nil/empty handling, or overflow surface for my lens to evaluate.
I confirmed from the diff that the only non-comment change is the workflow ref tag in the `uses:` line; everything else is comment/prose. Nothing in the error-handling & edge-case lens is materially wrong here.
- Outside my lens: the docs now recommend consumers pin to `review-reusable.yml@v1`. Whether that tag actually exists in the gadfly repo is a real correctness concern (a dangling ref would break every consumer's workflow resolution), but that belongs to the correctness lens, not mine.
</details>
<sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 20s</sub>
I reviewed this through the security (supply-chain) lens, since the only thing a docs-only change to a pin recommendation can affect is what code runs with a consumer's forwarded secrets. I read both edited files in full (examples/reusable.yml:14-54, README.md:313-318) to confirm the diff matches the checked-out state.
What I checked and why it's not a finding:
Recommending a movable @v1 ref over an immutable @<sha> (examples/reusable.yml:52-54, README.md:316-318). This is the one real security-relevant trade-off: @v1 is re-pointed on releases, so whoever controls the gadfly repo can change the code that executes with the consumer's forwarded provider keys / GITEA_TOKEN — exactly the risk the old @<sha>-immutable wording warned about. However, the new text discloses this accurately rather than hiding it: it explains @v1 "moves on releases / deliberate releases," still documents @<sha> as the immutable option, and explicitly discourages the worst case @main ("moves on every push and would change what runs with your forwarded secrets"). This mirrors the project's already-accepted posture for the image :vN tag (also movable). It's an informed, disclosed product trade-off, not an insecure default introduced silently.
Least-privilege secret guidance preserved (examples/reusable.yml:14-20, 55-62). The edit left the "forward ONLY what the reviewer needs / prefer explicit over secrets: inherit" guidance and the commented-out optional secrets intact. No widening of secret exposure.
No injection, authz, SSRF, deserialization, validation, or credential-leak surface is touched — this is comment/prose only and the binary, scripts, and workflows are unchanged.
🎯 Correctness — Minor issues
I've verified both findings. The v1 tag does exist on the remote (refs/tags/v1 → 22aff85), so Finding 1 is contradicted by the actual repo state and must be dropped. Finding 2's factual basis is confirmed — review-reusable.yml lines 9 and 28–29 still reference only @<sha> and don't mention @v1 — though its "contradiction" framing is overstated (the header recommends @<sha>, which the new guidance still endorses, and warns against @main, which it also still endorses).
VERDICT: Minor issues
This is a docs-only change. The factual claims hold up against the code; one surviving consistency gap remains.
Findings (Correctness lens)
.gitea/workflows/review-reusable.yml:28-29 (and the example at :9) still tell consumers only to pin @<sha>, never mentioning the newly-recommended @v1. The PR updated README.md and examples/reusable.yml to recommend review-reusable.yml@v1 (curated release tag) as the primary option for reusable-workflow consumers, but the reusable workflow's own subscription instructions — a place a consumer reads to learn how to pin — still say only "Consumers should likewise pin uses: ...@<sha> (not @main)". This isn't a hard contradiction (@<sha> remains a valid form in the new guidance, and both discourage @main), but it's a missed spot: the now-preferred @v1 option isn't surfaced where consumers look. A one-block update there to mention @v1 would keep the guidance consistent. Confirmed by reading the file; minor docs-consistency item.
🧹 Code cleanliness & maintainability — Minor issues
I verified both findings against the actual repo.
Finding 1 (review-reusable.yml:9, :28): Confirmed. Line 9 still shows ...review-reusable.yml@<sha> as the canonical usage example, and line 28 still reads "Consumers should likewise pin uses: ...@<sha> (not @main)". Neither mentions @v1, while this PR makes @v1 the primary recommendation in README.md and examples/reusable.yml. The inconsistency across the three copies of consumer-facing pin guidance is real.
Finding 2 (@v1 may not resolve): Cannot positively confirm. git tag -l returns no tags in this checkout, but the draft itself flags this as unverified and "likely just unfetched tags," and absence of tags locally does not prove v1 is unpublished. Dropping per the gate rule (keep only what I can confirm).
VERDICT: Minor issues
.gitea/workflows/review-reusable.yml:9 and :28 — Stale/inconsistent pin guidance left behind. This PR updates the @v1 recommendation in README.md and examples/reusable.yml, but the reusable workflow's own header doc comments still say to pin @<sha> and "(not @main)" with no mention of @v1. Line 9's canonical usage example shows ...review-reusable.yml@<sha>, and line 28 says "Consumers should likewise pin uses: ...@<sha> (not @main)". After this change the public pin guidance now disagrees across three copies of the same advice. CLAUDE.md treats consumer-facing docs as "the contract users rely on — stale docs are a bug," so this is a real (if minor) maintainability gap. Fix: update lines 9 and 28 to match the new @v1-primary / @<sha>-immutable / avoid-@main framing (or replace the duplicated prose with a single pointer to the README section so it can't drift again).
The two files actually touched (README.md, examples/reusable.yml) are internally consistent and read cleanly; the wording change is well-scoped and low-churn.
⚡ Performance — No material issues found
VERDICT: No material issues found
This PR changes only README.md (pin-guidance prose) and examples/reusable.yml (comments + the uses: ref @main → @v1). There is no executable code, no data path, no loops, queries, or allocations in the diff — nothing for a performance lens to evaluate.
examples/reusable.yml:55 / README.md:315: the only functional change is the workflow ref consumers pin to; it has zero runtime-performance dimension (it selects which version of the reusable workflow is fetched, not how much work it does).
Nothing in my lens is materially wrong.
🧯 Error handling & edge cases — No material issues found
The change touches only README.md and examples/reusable.yml, and within those only prose and YAML comments — no executable code, no scripts, no entrypoint.sh/Go logic. There are no error paths, no inputs being parsed, no cleanup/rollback, and no edge cases introduced by this diff.
VERDICT: No material issues found
This is a docs-only PR (README pin guidance + example stub comments/uses: ref). Through the error-handling & edge-cases lens there is nothing to scrutinize — no swallowed errors, no nil/empty/zero/overflow/boundary surfaces, no unhappy paths added. Verified by reading the full diff: the only functional line changed is the uses: workflow ref in examples/reusable.yml:54 (@main → @v1), which is consumer-side YAML, not a code path Gadfly executes.
Outside my lens: the PR leans on a @v1 tag existing and being maintained as a "re-moved on releases" pointer; I could not confirm any v* tag exists in this repo (git tag -l returned empty) — but tag/release accuracy is a correctness/docs-validity concern for another lens, not error handling.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 4s
<!-- gadfly-review:ollama:claude-code/opus -->
### 🪰 Gadfly review — `claude-code/opus` (claude-code)
**Verdict: Minor issues** — 5 reviewers: security, correctness, maintainability, performance, error-handling
<details><summary><b>🔒 Security</b> — No material issues found</summary>
**VERDICT: No material issues found**
I reviewed this through the security (supply-chain) lens, since the only thing a docs-only change to a pin recommendation can affect is what code runs with a consumer's forwarded secrets. I read both edited files in full (`examples/reusable.yml:14-54`, `README.md:313-318`) to confirm the diff matches the checked-out state.
What I checked and why it's not a finding:
- **Recommending a movable `@v1` ref over an immutable `@<sha>`** (`examples/reusable.yml:52-54`, `README.md:316-318`). This is the one real security-relevant trade-off: `@v1` is re-pointed on releases, so whoever controls the gadfly repo can change the code that executes with the consumer's forwarded provider keys / `GITEA_TOKEN` — exactly the risk the old `@<sha>`-immutable wording warned about. However, the new text **discloses this accurately** rather than hiding it: it explains `@v1` "moves on releases / deliberate releases," still documents `@<sha>` as the immutable option, and explicitly discourages the worst case `@main` ("moves on every push and would change what runs with your forwarded secrets"). This mirrors the project's already-accepted posture for the image `:vN` tag (also movable). It's an informed, disclosed product trade-off, not an insecure default introduced silently.
- **Least-privilege secret guidance preserved** (`examples/reusable.yml:14-20, 55-62`). The edit left the "forward ONLY what the reviewer needs / prefer explicit over `secrets: inherit`" guidance and the commented-out optional secrets intact. No widening of secret exposure.
No injection, authz, SSRF, deserialization, validation, or credential-leak surface is touched — this is comment/prose only and the binary, scripts, and workflows are unchanged.
</details>
<details><summary><b>🎯 Correctness</b> — Minor issues</summary>
I've verified both findings. The `v1` tag **does exist** on the remote (`refs/tags/v1` → `22aff85`), so Finding 1 is contradicted by the actual repo state and must be dropped. Finding 2's factual basis is confirmed — `review-reusable.yml` lines 9 and 28–29 still reference only `@<sha>` and don't mention `@v1` — though its "contradiction" framing is overstated (the header recommends `@<sha>`, which the new guidance still endorses, and warns against `@main`, which it also still endorses).
## VERDICT: Minor issues
This is a docs-only change. The factual claims hold up against the code; one surviving consistency gap remains.
### Findings (Correctness lens)
- **`.gitea/workflows/review-reusable.yml:28-29` (and the example at `:9`) still tell consumers only to pin `@<sha>`, never mentioning the newly-recommended `@v1`.** The PR updated `README.md` and `examples/reusable.yml` to recommend `review-reusable.yml@v1` (curated release tag) as the primary option for reusable-workflow consumers, but the reusable workflow's own subscription instructions — a place a consumer reads to learn how to pin — still say only *"Consumers should likewise pin `uses: ...@<sha>` (not @main)"*. This isn't a hard contradiction (`@<sha>` remains a valid form in the new guidance, and both discourage `@main`), but it's a missed spot: the now-preferred `@v1` option isn't surfaced where consumers look. A one-block update there to mention `@v1` would keep the guidance consistent. *Confirmed by reading the file; minor docs-consistency item.*
</details>
<details><summary><b>🧹 Code cleanliness & maintainability</b> — Minor issues</summary>
I verified both findings against the actual repo.
**Finding 1** (review-reusable.yml:9, :28): Confirmed. Line 9 still shows `...review-reusable.yml@<sha>` as the canonical usage example, and line 28 still reads "Consumers should likewise pin `uses: ...@<sha>` (not @main)". Neither mentions `@v1`, while this PR makes `@v1` the primary recommendation in `README.md` and `examples/reusable.yml`. The inconsistency across the three copies of consumer-facing pin guidance is real.
**Finding 2** (`@v1` may not resolve): Cannot positively confirm. `git tag -l` returns no tags in this checkout, but the draft itself flags this as unverified and "likely just unfetched tags," and absence of tags locally does not prove `v1` is unpublished. Dropping per the gate rule (keep only what I can confirm).
---
**VERDICT: Minor issues**
- `.gitea/workflows/review-reusable.yml:9` and `:28` — **Stale/inconsistent pin guidance left behind.** This PR updates the `@v1` recommendation in `README.md` and `examples/reusable.yml`, but the reusable workflow's *own* header doc comments still say to pin `@<sha>` and "(not @main)" with no mention of `@v1`. Line 9's canonical usage example shows `...review-reusable.yml@<sha>`, and line 28 says *"Consumers should likewise pin `uses: ...@<sha>` (not @main)"*. After this change the public pin guidance now disagrees across three copies of the same advice. CLAUDE.md treats consumer-facing docs as "the contract users rely on — stale docs are a bug," so this is a real (if minor) maintainability gap. Fix: update lines 9 and 28 to match the new `@v1`-primary / `@<sha>`-immutable / avoid-`@main` framing (or replace the duplicated prose with a single pointer to the README section so it can't drift again).
The two files actually touched (`README.md`, `examples/reusable.yml`) are internally consistent and read cleanly; the wording change is well-scoped and low-churn.
</details>
<details><summary><b>⚡ Performance</b> — No material issues found</summary>
**VERDICT: No material issues found**
This PR changes only `README.md` (pin-guidance prose) and `examples/reusable.yml` (comments + the `uses:` ref `@main` → `@v1`). There is no executable code, no data path, no loops, queries, or allocations in the diff — nothing for a performance lens to evaluate.
- `examples/reusable.yml:55` / `README.md:315`: the only functional change is the workflow ref consumers pin to; it has zero runtime-performance dimension (it selects which version of the reusable workflow is fetched, not how much work it does).
Nothing in my lens is materially wrong.
</details>
<details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary>
The change touches only `README.md` and `examples/reusable.yml`, and within those only prose and YAML comments — no executable code, no scripts, no `entrypoint.sh`/Go logic. There are no error paths, no inputs being parsed, no cleanup/rollback, and no edge cases introduced by this diff.
**VERDICT: No material issues found**
- This is a docs-only PR (README pin guidance + example stub comments/`uses:` ref). Through the error-handling & edge-cases lens there is nothing to scrutinize — no swallowed errors, no nil/empty/zero/overflow/boundary surfaces, no unhappy paths added. Verified by reading the full diff: the only functional line changed is the `uses:` workflow ref in `examples/reusable.yml:54` (`@main` → `@v1`), which is consumer-side YAML, not a code path Gadfly executes.
- *Outside my lens:* the PR leans on a `@v1` tag existing and being maintained as a "re-moved on releases" pointer; I could not confirm any `v*` tag exists in this repo (`git tag -l` returned empty) — but tag/release accuracy is a correctness/docs-validity concern for another lens, not error handling.
</details>
<sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 4s</sub>
Looking at this change through the 🔒 Security lens specifically.
The change is documentation-only — it updates pinning guidance from @main/@<sha> to @v1/@<sha> for reusable-workflow consumers. Security-relevant aspects to check:
Secret forwarding surface — the comment correctly still warns about secrets: inherit handing over every repo secret; explicit forwarding is still recommended. The new guidance doesn't relax this.
Tag mutability (@v1 vs @main vs @<sha>) — this is genuinely the security-relevant tradeoff, and the new comment explicitly:
Discourages @main (moves on every push — could change what runs against forwarded secrets without consumer action).
Offers @v1 as a curated tag "moved on deliberate releases" — less mutable than @main (only moves on tagged releases), but still mutable.
Offers full @<sha> as the immutable option.
From a security perspective, @v1 is strictly better than @main (smaller attack window — attacker needs to land a v* tag push, not any main push) but strictly worse than @<sha> (which the comment also offers). The text is honest about this: "curated pointer moved on deliberate releases" vs "immutable pin." No claim that @v1 equals @<sha>.
Permissions block — permissions: stays at the existing least-privilege (contents: read, issues: write, pull-requests: write); unchanged.
Comment-author gate — issue_comment still gated to your-username; unchanged.
No new injected input, no new deserialization, no new SSRF surface — purely a comment/ref change.
One minor observation: the new @v1 recommendation nudges consumers toward a mutable tag. A security-strict reviewer might prefer the PR to lead with @<sha> and mention @v1 as a convenience option, since silent movement of what runs against forwarded secrets is the exact threat the original @main-warning called out — and @v1 reintroduces a (smaller) version of it. But the comment does flag this honestly ("curated … moved on deliberate releases"), and @<sha> is still offered side-by-side. This is a recommendation/tone call, not a gap; I'll note it but not block on it.
No material security issues. The diff actually improves the security posture of the recommended default (smaller mutation window than @main) while preserving the immutable @<sha> escape hatch and the explicit-secrets warning.
VERDICT: No material issues found
No authn/authz, injection, SSRF, deserialization, or secret-handling regressions in the change.
permissions: block, secrets: explicit-forwarding guidance, and the actor gate on issue_comment are all unchanged.
The new pin guidance (@v1 over @main) reduces — not increases — the window in which an upstream push can silently change what runs against the consumer's forwarded secrets, while still documenting @<sha> as the immutable option. Verified by reading examples/reusable.yml:14–20,52–54 and README.md:313–318.
🎯 Correctness — Blocking issues found
VERDICT: Blocking issues found
examples/reusable.yml:54 / README.md:317 — the advertised @v1 mechanism does not exist in this repo. The PR's whole pitch is that @v1 is "gadfly's curated release tag, re-moved on deliberate releases so central swarm tuning propagates without per-consumer re-pinning." But the only release automation in the repo is .gitea/workflows/build-image.yml, which publishes container image tags (:v1, :latest, :sha-<short>) to gitea.stevedudenhoeffer.com/steve/gadfly — it never touches a git ref. Grep across the repo for any release script, tag-moving workflow, or git push --force ... v1 step returns nothing (scripts/ has only run.sh, status-board.sh, system-prompt.txt; .gitea/workflows/ has only build-image.yml, review-reusable.yml, adversarial-review.yml). So a consumer who follows the new advice and pins uses: steve/gadfly/.gitea/workflows/review-reusable.yml@v1 will get a workflow_call resolve failure unless a human manually git tag v1 <sha> && git push --force origin v1 for every release. Until the PR also adds the release-time automation (or at least an explicit scripts/release.sh + a release workflow that force-moves the git v1 tag on v* tag pushes), the new recommendation is a footgun: the default examples/reusable.yml will not run out of the box. Fix: add the missing automation in the same change (e.g. a scripts/release.sh invoked by a release.yml workflow on push: tags: ['v*'] that force-moves the git v1 ref to the new commit, mirroring how build-image.yml re-tags :latest), or hold this docs change until that exists.
.gitea/workflows/review-reusable.yml:9 and :28 — internal doc is now stale and contradicts the new recommendation. The reusable workflow's own header still tells consumers to pin uses: ...@<sha> (line 9: uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>) and the closing paragraph (line 28) still says "Consumers should likewise pin uses: ...@<sha> (not @main)" — without mentioning the @v1 option the freshly-updated README/reusable.yml now steer consumers toward. CLAUDE.md's own maintenance rule is "the README and examples/ … MUST be reflected … in the same change — stale docs are a bug." Three-doc rule, not two. Verified by reading .gitea/workflows/review-reusable.yml:1-30 and grepping the repo for @<sha> / @v1 / @main (hits in README.md, examples/reusable.yml, and .gitea/workflows/review-reusable.yml only). Fix: update the two @<sha> mentions in this file's header comment to the same @v1 (with @<sha> offered as the alternative) so all consumer-facing docs agree.
🧹 Code cleanliness & maintainability — Minor issues
VERDICT: Minor issues
README.md:315 — "full-stub consumers" is a newly coined compound that's never defined and only used once. examples/reusable.yml:1 calls its stub "SLIM consumer stub" and .gitea/workflows/review-reusable.yml:23 points consumers at "the full stub in adversarial-review.yml", so the established vocabulary is "slim" vs. "full". Hyphenating to "full-stub" reads as a new term and mildly obscures which of the two stubs is meant for the :vN advice. Suggest restructuring the sentence (e.g. "Pin the full stub to a :vN image tag for stability…") rather than introducing "full-stub".
Terminology drift between the two surfaces: README.md:317 calls @v1 "a curated tag moved on releases"; examples/reusable.yml:18 calls it "a curated pointer moved on deliberate releases". Same concept, different label. Pick one — "tag" is more conventional and is also literally what it is (a git tag).
Cross-file doc inconsistency: .gitea/workflows/review-reusable.yml:9 (embedded consumer example) still shows uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>, and line 28 still tells consumers to pin @<sha> and explicitly warns against @main, with no mention of @v1. So the README and examples/reusable.yml now promote @v1 as the primary pin with @<sha> as the immutable option, but the reusable's own header example promotes @<sha> and says nothing about @v1 — the opposite recommendation. The PR updates one consumer-facing surface but not the matching embedded example inside the reusable itself. Suggest: at least add @v1 as the primary recommendation in the embedded stub example (line 9) and update the prose on line 28 to match the new guidance.
Pre-existing comment duplication, not introduced but not addressed: examples/reusable.yml now repeats the same @v1/@<sha>/@main guidance in two places — the header block at lines 17–20 and the inline uses: comment at lines 52–53 — with slightly different wording. The duplication pattern existed before this PR (it duplicated @<sha>/not-@main), so it isn't a regression, but since the PR touches both comments anyway it would have been a low-churn moment to consolidate to a single canonical wording (probably the inline one, since it sits next to the actual uses: field). Not a blocker.
The headline change itself (@main → @v1 with @<sha> preserved as the immutable option) is clean and matches the PR's stated intent. Nothing else in the diff strikes as unclean — no dead code, no leaky abstractions, no naming surprises, no structural churn.
⚡ Performance — No material issues found
VERDICT: No material issues found
This PR is documentation-only: README.md guidance prose plus a workflow uses: ref change (@main → @v1) in examples/reusable.yml. Verified both touched regions:
README.md:313-318 — added the reusable-workflow pinning paragraph alongside the existing image-tag guidance.
Nothing in this diff touches runtime code paths, allocations, queries, loops, or any hot path. There is no efficiency-relevant change to evaluate through the Performance lens.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
This PR is docs/comments-only — it changes two blocks of prose (examples/reusable.yml:14-20, examples/reusable.yml:52-53) and one paragraph (README.md:315-318). No code paths, no error paths, no nil checks, no cleanup, no boundary conditions, no I/O — nothing in the error-handling & edge-cases lens is touched.
I verified by reading examples/reusable.yml:1-70 and README.md:300-330:
The uses: line at examples/reusable.yml:54 is now …@v1; the surrounding secrets:/with:/concurrency: blocks are unchanged.
No new error paths, fallbacks, or input validation are introduced.
The advice is purely advisory ("avoid @main", "curated pointer moved on deliberate releases"); any preconditions about the @v1 tag actually existing belong to the release process, which is out of scope for this diff and out of my lane.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 22s
<!-- gadfly-review:ollama:minimax-m3:cloud -->
### 🪰 Gadfly review — `minimax-m3:cloud` (ollama-cloud)
**Verdict: Blocking issues found** — 5 reviewers: security, correctness, maintainability, performance, error-handling
<details><summary><b>🔒 Security</b> — No material issues found</summary>
Looking at this change through the 🔒 Security lens specifically.
The change is documentation-only — it updates pinning guidance from `@main`/`@<sha>` to `@v1`/`@<sha>` for reusable-workflow consumers. Security-relevant aspects to check:
1. **Secret forwarding surface** — the comment correctly still warns about `secrets: inherit` handing over every repo secret; explicit forwarding is still recommended. The new guidance doesn't relax this.
2. **Tag mutability (`@v1` vs `@main` vs `@<sha>`)** — this is genuinely the security-relevant tradeoff, and the new comment explicitly:
- Discourages `@main` (moves on every push — could change what runs against forwarded secrets without consumer action).
- Offers `@v1` as a curated tag "moved on deliberate releases" — *less* mutable than `@main` (only moves on tagged releases), but still mutable.
- Offers full `@<sha>` as the immutable option.
From a security perspective, `@v1` is strictly better than `@main` (smaller attack window — attacker needs to land a `v*` tag push, not any `main` push) but strictly worse than `@<sha>` (which the comment also offers). The text is honest about this: "curated pointer moved on deliberate releases" vs "immutable pin." No claim that `@v1` equals `@<sha>`.
3. **Permissions block** — `permissions:` stays at the existing least-privilege (`contents: read`, `issues: write`, `pull-requests: write`); unchanged.
4. **Comment-author gate** — `issue_comment` still gated to `your-username`; unchanged.
5. **No new injected input, no new deserialization, no new SSRF surface** — purely a comment/ref change.
One minor observation: the new `@v1` recommendation nudges consumers toward a mutable tag. A security-strict reviewer might prefer the PR to *lead* with `@<sha>` and mention `@v1` as a convenience option, since silent movement of what runs against forwarded secrets is the exact threat the original `@main`-warning called out — and `@v1` reintroduces a (smaller) version of it. But the comment does flag this honestly ("curated … moved on deliberate releases"), and `@<sha>` is still offered side-by-side. This is a recommendation/tone call, not a gap; I'll note it but not block on it.
No material security issues. The diff actually improves the security posture of the recommended default (smaller mutation window than `@main`) while preserving the immutable `@<sha>` escape hatch and the explicit-secrets warning.
**VERDICT: No material issues found**
- No authn/authz, injection, SSRF, deserialization, or secret-handling regressions in the change.
- `permissions:` block, `secrets:` explicit-forwarding guidance, and the actor gate on `issue_comment` are all unchanged.
- The new pin guidance (`@v1` over `@main`) reduces — not increases — the window in which an upstream push can silently change what runs against the consumer's forwarded secrets, while still documenting `@<sha>` as the immutable option. Verified by reading `examples/reusable.yml:14–20,52–54` and `README.md:313–318`.
</details>
<details><summary><b>🎯 Correctness</b> — Blocking issues found</summary>
**VERDICT: Blocking issues found**
- **`examples/reusable.yml:54` / `README.md:317` — the advertised `@v1` mechanism does not exist in this repo.** The PR's whole pitch is that `@v1` is "gadfly's curated release tag, re-moved on deliberate releases so central swarm tuning propagates without per-consumer re-pinning." But the only release automation in the repo is `.gitea/workflows/build-image.yml`, which publishes **container image tags** (`:v1`, `:latest`, `:sha-<short>`) to `gitea.stevedudenhoeffer.com/steve/gadfly` — it never touches a **git ref**. Grep across the repo for any release script, tag-moving workflow, or `git push --force ... v1` step returns nothing (`scripts/` has only `run.sh`, `status-board.sh`, `system-prompt.txt`; `.gitea/workflows/` has only `build-image.yml`, `review-reusable.yml`, `adversarial-review.yml`). So a consumer who follows the new advice and pins `uses: steve/gadfly/.gitea/workflows/review-reusable.yml@v1` will get a `workflow_call` resolve failure unless a human manually `git tag v1 <sha> && git push --force origin v1` for every release. Until the PR also adds the release-time automation (or at least an explicit `scripts/release.sh` + a release workflow that force-moves the git `v1` tag on `v*` tag pushes), the new recommendation is a footgun: the default `examples/reusable.yml` will not run out of the box. **Fix:** add the missing automation in the same change (e.g. a `scripts/release.sh` invoked by a `release.yml` workflow on `push: tags: ['v*']` that force-moves the git `v1` ref to the new commit, mirroring how `build-image.yml` re-tags `:latest`), or hold this docs change until that exists.
- **`.gitea/workflows/review-reusable.yml:9` and `:28` — internal doc is now stale and contradicts the new recommendation.** The reusable workflow's own header still tells consumers to pin `uses: ...@<sha>` (line 9: `uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>`) and the closing paragraph (line 28) still says "Consumers should likewise pin `uses: ...@<sha>` (not @main)" — without mentioning the `@v1` option the freshly-updated README/reusable.yml now steer consumers toward. CLAUDE.md's own maintenance rule is "the README and `examples/` … MUST be reflected … in the same change — stale docs are a bug." Three-doc rule, not two. Verified by reading `.gitea/workflows/review-reusable.yml:1-30` and grepping the repo for `@<sha>` / `@v1` / `@main` (hits in `README.md`, `examples/reusable.yml`, and `.gitea/workflows/review-reusable.yml` only). **Fix:** update the two `@<sha>` mentions in this file's header comment to the same `@v1` (with `@<sha>` offered as the alternative) so all consumer-facing docs agree.
</details>
<details><summary><b>🧹 Code cleanliness & maintainability</b> — Minor issues</summary>
VERDICT: **Minor issues**
- **`README.md:315`** — "full-stub consumers" is a newly coined compound that's never defined and only used once. `examples/reusable.yml:1` calls its stub "SLIM consumer stub" and `.gitea/workflows/review-reusable.yml:23` points consumers at "the full stub in adversarial-review.yml", so the established vocabulary is "slim" vs. "full". Hyphenating to "full-stub" reads as a new term and mildly obscures which of the two stubs is meant for the `:vN` advice. Suggest restructuring the sentence (e.g. "Pin the **full** stub to a `:vN` image tag for stability…") rather than introducing "full-stub".
- **Terminology drift between the two surfaces**: `README.md:317` calls `@v1` "a curated **tag** moved on releases"; `examples/reusable.yml:18` calls it "a curated **pointer** moved on deliberate releases". Same concept, different label. Pick one — "tag" is more conventional and is also literally what it is (a git tag).
- **Cross-file doc inconsistency**: `.gitea/workflows/review-reusable.yml:9` (embedded consumer example) still shows `uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>`, and line 28 still tells consumers to pin `@<sha>` and explicitly warns against `@main`, with no mention of `@v1`. So the README and `examples/reusable.yml` now promote `@v1` as the primary pin with `@<sha>` as the immutable option, but the reusable's own header example promotes `@<sha>` and says nothing about `@v1` — the opposite recommendation. The PR updates one consumer-facing surface but not the matching embedded example inside the reusable itself. Suggest: at least add `@v1` as the primary recommendation in the embedded stub example (line 9) and update the prose on line 28 to match the new guidance.
- **Pre-existing comment duplication, not introduced but not addressed**: `examples/reusable.yml` now repeats the same `@v1`/`@<sha>`/`@main` guidance in two places — the header block at lines 17–20 and the inline `uses:` comment at lines 52–53 — with slightly different wording. The duplication pattern existed before this PR (it duplicated `@<sha>`/not-`@main`), so it isn't a regression, but since the PR touches both comments anyway it would have been a low-churn moment to consolidate to a single canonical wording (probably the inline one, since it sits next to the actual `uses:` field). Not a blocker.
The headline change itself (`@main` → `@v1` with `@<sha>` preserved as the immutable option) is clean and matches the PR's stated intent. Nothing else in the diff strikes as unclean — no dead code, no leaky abstractions, no naming surprises, no structural churn.
</details>
<details><summary><b>⚡ Performance</b> — No material issues found</summary>
**VERDICT: No material issues found**
This PR is documentation-only: README.md guidance prose plus a workflow `uses:` ref change (`@main` → `@v1`) in `examples/reusable.yml`. Verified both touched regions:
- `README.md:313-318` — added the reusable-workflow pinning paragraph alongside the existing image-tag guidance.
- `examples/reusable.yml:52-54` — `uses:` ref updated, comment rewritten.
Nothing in this diff touches runtime code paths, allocations, queries, loops, or any hot path. There is no efficiency-relevant change to evaluate through the Performance lens.
</details>
<details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary>
**VERDICT: No material issues found**
This PR is docs/comments-only — it changes two blocks of prose (`examples/reusable.yml:14-20`, `examples/reusable.yml:52-53`) and one paragraph (`README.md:315-318`). No code paths, no error paths, no nil checks, no cleanup, no boundary conditions, no I/O — nothing in the error-handling & edge-cases lens is touched.
I verified by reading `examples/reusable.yml:1-70` and `README.md:300-330`:
- The `uses:` line at `examples/reusable.yml:54` is now `…@v1`; the surrounding `secrets:`/`with:`/`concurrency:` blocks are unchanged.
- No new error paths, fallbacks, or input validation are introduced.
- The advice is purely advisory ("avoid `@main`", "curated pointer moved on deliberate releases"); any preconditions about the `@v1` tag actually existing belong to the release process, which is out of scope for this diff and out of my lane.
</details>
<sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 22s</sub>
PR #12's own review flagged that the reusable's own header still said pin
@<sha>/@main while the example+README now recommend @v1. Update the header
to recommend @v1 (or @<sha>) consistently.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
steve
merged commit 8f69e71311 into main2026-06-28 04:17:19 +00:00
steve
deleted branch docs/recommend-v12026-06-28 04:17:19 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Makes the public contract match how the fleet now pins. The example stub + README pointed at
@main/@<sha>; update to recommend@v1— gadfly's curated release tag, re-moved on deliberate releases so central swarm tuning propagates without per-consumer re-pinning. A full@<sha>is still offered for an immutable pin;@mainis discouraged (moves on every push).examples/reusable.yml:uses: …@main→@v1+ updated pin comments.README.md: pin guidance now covers the reusable workflow ref (@v1/@<sha>), not just the image:vNtag.Docs-only. Advisory-only invariant unchanged.
🤖 Generated with Claude Code
🪰 Gadfly — live review status
6/6 reviewers finished · updated 2026-06-28 04:14:05Z
claude-code/opus· claude-code — ✅ doneclaude-code/opus:max· claude-code — ✅ doneclaude-code/sonnet· claude-code — ✅ donedeepseek-v4-pro:cloud· ollama-cloud — ✅ doneglm-5.2:cloud· ollama-cloud — ✅ doneminimax-m3:cloud· ollama-cloud — ✅ doneLive status board. Findings are posted in each model's own comment. Advisory only — does not block merge.
🪰 Gadfly review —
deepseek-v4-pro:cloud(ollama-cloud)Verdict: Minor issues — 5 reviewers: security, correctness, maintainability, performance, error-handling
🔒 Security — No material issues found
Verdict: No material issues found
This is a docs-only change that steers consumers from
@main(moves on every push — highest supply-chain risk) toward either@v1(curated release tag, moves only on deliberate releases) or@<sha>(immutable). From a security perspective, this is a net improvement: it reduces the window during which a compromised push tomainwould silently propagate into every consumer's workflow with their forwarded secrets.@v1auto-updates on releases (convenience, central tuning propagates) vs.@<sha>(immutable, no surprise changes). Both are strictly better than@main, which the diff now explicitly discourages.One minor observation (not a security issue, but noted for completeness): the reusable workflow's own doc comment at
.gitea/workflows/review-reusable.yml:28still says "Consumers should likewise pinuses: ...@<sha>(not @main)" without mentioning@v1. That file wasn't in this diff, so it's outside scope, but it's now slightly out of step with the new guidance.🎯 Correctness — Minor issues
Now I have all the information I need. Let me evaluate each finding:
Finding 1 (
@v1tag may not exist): The draft reviewer explicitly labels this as "Unverified" and acknowledges it's a shallow clone where the tag could exist on the remote. I confirmed there is no localv1tag. Since the reviewer themselves cannot confirm it, and I also cannot positively confirm it (the tag's absence in a shallow clone of a feature branch proves nothing), this finding must be dropped per the instructions: "DROP the finding if you cannot confirm it."Finding 2 (docstring drift): I confirmed that
.gitea/workflows/review-reusable.ymlwas not modified in this diff. Its header comment at line 9 still documents the consumer call as@<sha>only, and lines 28-29 still say "Consumers should likewise pinuses: ...@<sha>(not @main)." Meanwhile, the PR updatesexamples/reusable.ymlandREADME.mdto recommend@v1. This is a real inconsistency — the reusable workflow's own docstring contradicts the new guidance. Kept.Verdict: Minor issues
.gitea/workflows/review-reusable.yml:9still documents the consumer call as@<sha>only:uses: ...@<sha>(not @main)." This file is not in the diff, but it's the canonical documentation inside the workflow being referenced. Now the example stub says@v1while the reusable workflow's own docstring says@<sha>with no mention of@v1. A consumer who opens the reusable workflow to understand their pin options will see only the@<sha>recommendation — contradicting the new guidance. Not a runtime bug, but a correctness-of-documentation inconsistency that undermines the PR's purpose.🧹 Code cleanliness & maintainability — Minor issues
Verdict: Minor issues
.gitea/workflows/review-reusable.yml:9,28-29— stale pin guidance in the reusable workflow's own header comment. The PR updates consumer-facing docs (examples/reusable.yml,README.md) to recommend@v1as the primary ref, but the reusable workflow's own docstring still saysuses: ...@<sha>(line 9) and "Consumers should likewise pinuses: ...@<sha>(not @main)" (lines 28-29) with no mention of@v1. A maintainer reading this file gets different guidance than a consumer reading the examples. Over time these two sources of truth will drift further. (Verified by reading the file at lines 1-30.)Fix: Update lines 9 and 28-29 to match the new guidance — e.g.,
@v1(or@<sha>) and mention the curated-tag approach, so the reusable workflow's own documentation stays in sync with the consumer-facing examples.⚡ Performance — No material issues found
Verdict: No material issues found
This is a docs-only change — it updates comments in
examples/reusable.ymland guidance inREADME.mdto recommend@v1(a curated release tag) over@mainfor the reusable workflow ref. There is no code, no logic, no runtime path, and therefore nothing to evaluate through the performance lens. The change has zero impact on allocations, queries, loops, blocking calls, or any other performance characteristic.🧯 Error handling & edge cases — No material issues found
Verdict: No material issues found
This is a docs-only change — it updates comments in
examples/reusable.ymland prose inREADME.md. There are no code paths, no new functions, no error returns, no panics, and no data handling introduced. The error-handling & edge-cases lens (ignored errors, missing cleanup/rollback, panics on bad input, nil/empty/zero/negative/overflow/off-by-one) has nothing to evaluate here.The one thing that brushes against "edge case" territory — whether the
@v1tag actually exists on the repo right now (if it doesn't, consumers following the new guidance would get an immediate workflow-resolution failure) — is a deployment-coordination concern, not an error-handling defect in the diff. I can't verify tag existence with the available file-reading tools, but even if the tag were missing, that's a release-process gap, not something the diff's code/configuration mishandles.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 13s
🪰 Gadfly review —
glm-5.2:cloud(ollama-cloud)Verdict: Minor issues — 5 reviewers: security, correctness, maintainability, performance, error-handling
🔒 Security — No material issues found
VERDICT: No material issues found
Reviewed through the security lens. This is a docs-only change adjusting pin guidance for the reusable-workflow
uses:ref.examples/reusable.yml:54now pins@v1instead of@main, and the comment block (:17-20,:52-53) accurately explains the security trade-off:@v1is a curated tag moved only on deliberate releases (so central tuning propagates),@<sha>is offered for an immutable pin, and@mainis explicitly discouraged because it moves on every push and "would change what runs with your forwarded secrets." The least-privilege secrets-forwarding guidance (:14-16,:58-62) and the comment-trigger actor gate (:49-51,github.actor == 'your-username') are untouched and remain sound.README.md:315-318mirrors the same guidance consistently. No secret leakage, injection, authn/authz, or unsafe-input handling is introduced — the only tainted surface (forwarded secrets to a third-party workflow) is already addressed by the explicitsecrets:block advice, which this PR preserves.The change is a net security improvement (moving the recommended example off the highest-churn mutable ref while still documenting the immutable option). Nothing in my lane to flag.
🎯 Correctness — Minor issues
The finding is confirmed. Lines 9 and 28-29 of
.gitea/workflows/review-reusable.ymlstill recommend@<sha>with no mention of@v1, directly contradicting the updated README andexamples/reusable.ymlguidance.VERDICT: Minor issues
.gitea/workflows/review-reusable.yml:9and:28-29— The PR rewrites the pin guidance inREADME.mdandexamples/reusable.ymlto recommend@v1as the primary ref (with@<sha>as the immutable alternative, avoid@main), but the reusable workflow's own header comments — consumer-facing documentation embedded in the file consumers actually point at — were not updated. Line 9's example still shows...review-reusable.yml@<sha>with no mention of@v1, and lines 28–29 explicitly state "Consumers should likewise pinuses: ...@<sha>(not @main)", framing@<sha>as the recommendation. This now directly contradicts the new README/example guidance (@v1first,@<sha>as the immutable alternative). A consumer reading the workflow file they're subscribing to gets the old, conflicting advice. Suggested fix: update those two comment spots to match the new@v1-first /@<sha>-immutable / avoid-@mainordering. (Note: thev1git tag's existence could not be confirmed with read-only tools; worth verifying it exists before/with merge so the example's@v1ref resolves.)🧹 Code cleanliness & maintainability — No material issues found
No material issues found.
The diff is docs/comment-only and cleanly updates the pin guidance to
@v1consistently across both files. The example file (examples/reusable.yml) and README prose both use the same framing (@v1curated release tag → auto-updating stability;@<sha>→ immutable pin; avoid@main), so the duplicated messaging stays consistent rather than drifting. No dead code, naming, or structural concerns introduced.⚡ Performance — No material issues found
No material issues found.
This is a docs-only change (comments in
examples/reusable.ymland prose inREADME.md) updating recommended pin references (@main→@v1). It touches no runtime code, queries, loops, allocations, or hot paths — there is nothing to evaluate through the performance lens.🧯 Error handling & edge cases — No material issues found
No material issues found
This is a docs-only change: it rewrites comments in
examples/reusable.yml(lines 17-20, 52-54) and prose inREADME.md(lines 315-318) to recommend@v1over@main. No executable code, logic, error-handling, input parsing, or control flow is touched.Through the error-handling / edge-case lens specifically:
uses:ref (@main→@v1), which is a ref string, not logic. A missing/non-existent@v1tag would surface as a Gitea Actions checkout/reusable-resolution failure at job start (same failure mode as any bad ref), not a swallowed error or panic in this repo's code.Nothing in my lane to flag.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 10s
🪰 Gadfly review —
claude-code/sonnet(claude-code)Verdict: Blocking issues found — 5 reviewers: security, correctness, maintainability, performance, error-handling
🔒 Security — Minor issues
The finding is confirmed. Lines 28-29 of
review-reusable.ymlstill saypin uses: ...@<sha> (not @main), which directly contradicts the new guidance inexamples/reusable.ymlthat recommends@v1as the primary recommendation. The second finding (mutable tag trust model) is a design-level observation about the PR's documented intent — the PR description acknowledges the tradeoff — and there is no code to confirm or deny it against; it's a documentation quality concern the draft labels as intentional.Minor issues
review-reusable.ymlstill contradicts the new guidance (review-reusable.yml:28-29):The reusable workflow's own header comment still says:
The updated example stub now defaults to
@v1(mutable tag), but this authoritative comment in the reusable workflow was not updated. A security-aware consumer readingreview-reusable.ymldirectly will get the opposite recommendation from what the example stub models — the two pieces of guidance now contradict each other.Suggested fix: Update
review-reusable.ymllines 28–29 to align with the new guidance (e.g., mention@v1as the recommended starting point and@<sha>for an immutable pin).🎯 Correctness — Blocking issues found
The git repository has no tags at all —
git tag -lreturns empty, andpacked-refscontains only the remote branch ref. The build-image workflow (lines 73–74) confirms it publishes Docker image tags in response to a pushedv*git tag, but it does not create the git tag itself. The diff inexamples/reusable.yml:54changes@mainto@v1, andREADME.mdinstructs consumers to pinreview-reusable.yml@v1. The finding is confirmed.Blocking issues found
@v1tag does not exist —examples/reusable.yml:54/README.md:315No
v1git tag has been pushed to this repository (git tag -lreturns empty;.git/packed-refscontains only the remote branch ref fordocs/recommend-v1). The diff changesuses: …@maintouses: steve/gadfly/.gitea/workflows/review-reusable.yml@v1and updates the README to tell consumers to pinreview-reusable.yml@v1, but in Gitea Actions the@refin auses:directive resolves to a live git ref. A consumer who follows this guidance right now will get a workflow resolution failure — the ref simply doesn't exist.The build-image workflow (
.gitea/workflows/build-image.yml:21,73-74) publishes Docker image tags when av*git tag is pushed; it does not create the git tag itself. Git tags must be pushed separately viagit tag v1 && git push origin v1.Fix: Push a
v1git tag to the repository (or the release cut that creates it) before — or atomically with — merging this PR. Without that tag, any consumer following the updated docs or example stub will have a broken workflow.🧹 Code cleanliness & maintainability — Minor issues
Verdict: Minor issues
README:315 — terminology mismatch. The PR introduces the term "full-stub consumers" in the Release section (line 315), but the README's own intro (lines 40–44) refers to the same
adversarial-review.ymlpath as "the full self-containedadversarial-review.yml". A reader scanning only the Release section encounters "full-stub consumers" without a prior definition tying it toadversarial-review.yml; the intro's "full self-contained" phrasing is the more anchored reference. Fix: match the intro's wording — e.g."Pin full-self-contained-stub consumers…"or append(\adversarial-review.yml`)` inline. Verified against README lines 39–46 and 313–318.Slightly inconsistent phrasing for the same concept across files.
@v1is described three ways:examples/reusable.ymlline 18: "a curated pointer moved on deliberate releases"examples/reusable.ymlline 52: "curated release tag (auto-updates on releases)""Tag" vs "pointer," "moved on releases" vs "moved on deliberate releases" vs "auto-updates on releases" — not a runtime issue, but when the wording drifts across three spots for the same concept, the next editor won't know which phrasing is authoritative and will need to update all three again. Picking one phrasing and using it consistently reduces future churn. Verified by reading both files.
Neither finding is blocking. The docs are broadly coherent and the actual
@v1pin onexamples/reusable.yml:54is correctly placed.⚡ Performance — No material issues found
No material issues found.
This is a docs-only change (README prose and a comment +
uses:ref in an example YAML). There is no executable code, no queries, no allocations, no loops, and no hot paths touched. Nothing to evaluate through a performance lens.🧯 Error handling & edge cases — No material issues found
No material issues found
This is a pure documentation change — updated prose in
README.mdand revised comments plus a singleuses:ref string inexamples/reusable.yml. There are no code paths, error returns, input handling, or runtime logic of any kind introduced or modified. My lens (error handling & edge cases) has nothing to evaluate here.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 30s
🪰 Gadfly review —
claude-code/opus:max(claude-code)Verdict: Minor issues — 5 reviewers: security, correctness, maintainability, performance, error-handling
🔒 Security — No material issues found
VERDICT: No material issues found
This is a docs-only change to supply-chain pinning guidance, which is squarely in scope for the security lens — so I checked it on the merits rather than waving it through.
examples/reusable.yml:54and the surrounding comment (:17-20,:52-53), plusREADME.md:315-318— the change swaps the recommended reusable-workflow ref from@mainto@v1. Verified by reading both files at the PR state. Security-relevant facts:uses:ref is a genuine supply-chain control.@v1is a mutable tag ("re-moved on deliberate releases"), meaning a moved/compromisedv1would execute new code against forwarded secrets.@main, which mutates on every push (strictly larger attack surface).@v1moves only on deliberate releases.@<sha>pin for consumers who want it, and explicitly discourages@main. This mirrors standard practice (actions/checkout@v4).secrets:forwarding oversecrets: inherit) is preserved (:14-16,:55-62).No injection, secret leakage, authz, or untrusted-data handling is introduced or weakened. Nothing material in my lane.
One note, not a finding: a careless copy-paste consumer gets a mutable pin by default — but that's already mitigated by the explicit inline comment recommending
@<sha>, and it's a security upgrade over the previous@maindefault.🎯 Correctness — No material issues found
I've verified the change against the actual repo. My investigation is complete.
VERDICT: No material issues found
This is a docs-only change. Through the Correctness lens, the factual claims hold up against how the system actually works, and the two edited files are internally consistent.
What I verified:
@v1claim is consistent with the release model. README:317 andexamples/reusable.yml:52describe@v1as a curated tag "moved on releases" so swarm tuning propagates. I confirmed the mechanism:review-reusable.yml:93hardcodes the image at:sha-c342bdband its header (:26-27) says that sha is "bumped per Gadfly release." So re-pointing thev1git tag to a newer commit does propagate a newer pinned image — the auto-update story is coherent, not contradictory. A force-movedv*tag also re-triggersbuild-image.yml(:19-21), republishing:v1/:latest, so the image and workflow-ref stories line up.:vNimage vs@v1workflow-ref guidance is accurate.build-image.yml:73-74publishes:${GITHUB_REF_NAME}(+:latest) on av*tag push, matching README:315's:vNadvice.examples/, and CLAUDE.md: every consumer-facing ref now recommends@v1/@<sha>and discourages@main; README:41 uses a neutral@…placeholder. No leftover@mainrecommendation that would contradict the new guidance.steve/gadfly/.gitea/workflows/review-reusable.ymlmatches the registry pathgitea.stevedudenhoeffer.com/steve/gadfly; only the ref suffix changed.One caveat I could not verify (flagging, not asserting as a bug):
v1tag.git tag -lreturns nothing at this checkout, and I was denied network access togit ls-remote, so I cannot confirm av1tag actually exists on the remote yet. If the release process cuts only semver tags (e.g.v1.0.0) and never pushes/moves a barev1, then a consumer copy-pastingexamples/reusable.yml:54(...review-reusable.yml@v1) would hit a workflow-resolution failure, and:v1image pins would also break. This is a release-process/sequencing concern external to the diff text — worth a one-line confirmation from the author that thev1tag is (or will be) published before/with these docs, but it is not a logic defect in the change itself.Outside my lens: none worth raising.
🧹 Code cleanliness & maintainability — Minor issues
Both findings verify against the code.
review-reusable.yml:9still shows…@<sha>and:28still sayspinuses: ...@(not @main)with no mention of@v1, whileREADME.md:317-318andexamples/reusable.ymlnow lead with@v1. Andgit tag -lis empty — nov1tag exists.VERDICT: Minor issues
Finding — stale duplicate of the pin guidance left un-updated (
@<sha>/@main, no@v1).gitea/workflows/review-reusable.yml:9and:28The "how to pin the reusable" advice exists in three consumer-facing places. This PR updated two of them (
README.md:315-318,examples/reusable.yml:17-19,52-54) to recommend@v1, but the third copy — the worked consumer-stub example and pin note in the reusable workflow's own header — still reads:uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>Consumers should likewise pinuses: ...@(not @main)…So the contract now gives inconsistent guidance depending on which file a consumer opens: README/example say "use
@v1, sha is the immutable alternative," whilereview-reusable.yml's header still presents@<sha>as the recommendation and never mentions@v1. CLAUDE.md's maintenance rule ("the example workflows are the contract users rely on — stale docs are a bug") applies directly here.review-reusable.yml:9to…@v1and reword:28to mirror the new phrasing ("pin@v1for auto-updating stability, or@<sha>for an immutable pin; avoid@main"). Keeps the three copies in sync.Note the duplication itself is the root maintainability smell — the same paragraph is now hand-maintained in three spots and has already drifted once. Not worth refactoring docs into a single source here, but the fix above should bring all three back into agreement in this same change.
Outside my lens (flagging because it's potentially blocking):
git tag -lreturns no tags — there is currently nov1tag (or any tag) in the repo. If the curated@v1ref isn't actually created/moved as part of this release, every doc now points consumers at a ref that won't resolve. That's a correctness/release-process concern for another reviewer, not a cleanliness one.Nothing else in my lens: the wording changes in the two edited files are clear, consistent with each other, and follow the surrounding comment style.
⚡ Performance — No material issues found
VERDICT: No material issues found
This is a documentation-only change —
README.mdpin guidance andexamples/reusable.ymlcomments/ref, swapping@main→@v1. There is no code, query, loop, allocation, or hot path touched, so there is nothing for the performance lens to evaluate.uses:workflow ref, which affects which image/workflow consumers pin to, not execution efficiency. Verified by reading the full diff — both hunks are comment text and prose.Nothing in my lane to flag here.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
This is a docs-only change — prose in
README.mdand YAML comments plus a singleuses:ref string (@main→@v1) inexamples/reusable.yml. There is no executable code, no control flow, and therefore no error paths, cleanup/rollback, boundary conditions, nil/empty handling, or overflow surface for my lens to evaluate.I confirmed from the diff that the only non-comment change is the workflow ref tag in the
uses:line; everything else is comment/prose. Nothing in the error-handling & edge-case lens is materially wrong here.review-reusable.yml@v1. Whether that tag actually exists in the gadfly repo is a real correctness concern (a dangling ref would break every consumer's workflow resolution), but that belongs to the correctness lens, not mine.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 20s
🪰 Gadfly review —
claude-code/opus(claude-code)Verdict: Minor issues — 5 reviewers: security, correctness, maintainability, performance, error-handling
🔒 Security — No material issues found
VERDICT: No material issues found
I reviewed this through the security (supply-chain) lens, since the only thing a docs-only change to a pin recommendation can affect is what code runs with a consumer's forwarded secrets. I read both edited files in full (
examples/reusable.yml:14-54,README.md:313-318) to confirm the diff matches the checked-out state.What I checked and why it's not a finding:
Recommending a movable
@v1ref over an immutable@<sha>(examples/reusable.yml:52-54,README.md:316-318). This is the one real security-relevant trade-off:@v1is re-pointed on releases, so whoever controls the gadfly repo can change the code that executes with the consumer's forwarded provider keys /GITEA_TOKEN— exactly the risk the old@<sha>-immutable wording warned about. However, the new text discloses this accurately rather than hiding it: it explains@v1"moves on releases / deliberate releases," still documents@<sha>as the immutable option, and explicitly discourages the worst case@main("moves on every push and would change what runs with your forwarded secrets"). This mirrors the project's already-accepted posture for the image:vNtag (also movable). It's an informed, disclosed product trade-off, not an insecure default introduced silently.Least-privilege secret guidance preserved (
examples/reusable.yml:14-20, 55-62). The edit left the "forward ONLY what the reviewer needs / prefer explicit oversecrets: inherit" guidance and the commented-out optional secrets intact. No widening of secret exposure.No injection, authz, SSRF, deserialization, validation, or credential-leak surface is touched — this is comment/prose only and the binary, scripts, and workflows are unchanged.
🎯 Correctness — Minor issues
I've verified both findings. The
v1tag does exist on the remote (refs/tags/v1→22aff85), so Finding 1 is contradicted by the actual repo state and must be dropped. Finding 2's factual basis is confirmed —review-reusable.ymllines 9 and 28–29 still reference only@<sha>and don't mention@v1— though its "contradiction" framing is overstated (the header recommends@<sha>, which the new guidance still endorses, and warns against@main, which it also still endorses).VERDICT: Minor issues
This is a docs-only change. The factual claims hold up against the code; one surviving consistency gap remains.
Findings (Correctness lens)
.gitea/workflows/review-reusable.yml:28-29(and the example at:9) still tell consumers only to pin@<sha>, never mentioning the newly-recommended@v1. The PR updatedREADME.mdandexamples/reusable.ymlto recommendreview-reusable.yml@v1(curated release tag) as the primary option for reusable-workflow consumers, but the reusable workflow's own subscription instructions — a place a consumer reads to learn how to pin — still say only "Consumers should likewise pinuses: ...@<sha>(not @main)". This isn't a hard contradiction (@<sha>remains a valid form in the new guidance, and both discourage@main), but it's a missed spot: the now-preferred@v1option isn't surfaced where consumers look. A one-block update there to mention@v1would keep the guidance consistent. Confirmed by reading the file; minor docs-consistency item.🧹 Code cleanliness & maintainability — Minor issues
I verified both findings against the actual repo.
Finding 1 (review-reusable.yml:9, :28): Confirmed. Line 9 still shows
...review-reusable.yml@<sha>as the canonical usage example, and line 28 still reads "Consumers should likewise pinuses: ...@<sha>(not @main)". Neither mentions@v1, while this PR makes@v1the primary recommendation inREADME.mdandexamples/reusable.yml. The inconsistency across the three copies of consumer-facing pin guidance is real.Finding 2 (
@v1may not resolve): Cannot positively confirm.git tag -lreturns no tags in this checkout, but the draft itself flags this as unverified and "likely just unfetched tags," and absence of tags locally does not provev1is unpublished. Dropping per the gate rule (keep only what I can confirm).VERDICT: Minor issues
.gitea/workflows/review-reusable.yml:9and:28— Stale/inconsistent pin guidance left behind. This PR updates the@v1recommendation inREADME.mdandexamples/reusable.yml, but the reusable workflow's own header doc comments still say to pin@<sha>and "(not @main)" with no mention of@v1. Line 9's canonical usage example shows...review-reusable.yml@<sha>, and line 28 says "Consumers should likewise pinuses: ...@<sha>(not @main)". After this change the public pin guidance now disagrees across three copies of the same advice. CLAUDE.md treats consumer-facing docs as "the contract users rely on — stale docs are a bug," so this is a real (if minor) maintainability gap. Fix: update lines 9 and 28 to match the new@v1-primary /@<sha>-immutable / avoid-@mainframing (or replace the duplicated prose with a single pointer to the README section so it can't drift again).The two files actually touched (
README.md,examples/reusable.yml) are internally consistent and read cleanly; the wording change is well-scoped and low-churn.⚡ Performance — No material issues found
VERDICT: No material issues found
This PR changes only
README.md(pin-guidance prose) andexamples/reusable.yml(comments + theuses:ref@main→@v1). There is no executable code, no data path, no loops, queries, or allocations in the diff — nothing for a performance lens to evaluate.examples/reusable.yml:55/README.md:315: the only functional change is the workflow ref consumers pin to; it has zero runtime-performance dimension (it selects which version of the reusable workflow is fetched, not how much work it does).Nothing in my lens is materially wrong.
🧯 Error handling & edge cases — No material issues found
The change touches only
README.mdandexamples/reusable.yml, and within those only prose and YAML comments — no executable code, no scripts, noentrypoint.sh/Go logic. There are no error paths, no inputs being parsed, no cleanup/rollback, and no edge cases introduced by this diff.VERDICT: No material issues found
This is a docs-only PR (README pin guidance + example stub comments/
uses:ref). Through the error-handling & edge-cases lens there is nothing to scrutinize — no swallowed errors, no nil/empty/zero/overflow/boundary surfaces, no unhappy paths added. Verified by reading the full diff: the only functional line changed is theuses:workflow ref inexamples/reusable.yml:54(@main→@v1), which is consumer-side YAML, not a code path Gadfly executes.Outside my lens: the PR leans on a
@v1tag existing and being maintained as a "re-moved on releases" pointer; I could not confirm anyv*tag exists in this repo (git tag -lreturned empty) — but tag/release accuracy is a correctness/docs-validity concern for another lens, not error handling.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 4s
🪰 Gadfly review —
minimax-m3:cloud(ollama-cloud)Verdict: Blocking issues found — 5 reviewers: security, correctness, maintainability, performance, error-handling
🔒 Security — No material issues found
Looking at this change through the 🔒 Security lens specifically.
The change is documentation-only — it updates pinning guidance from
@main/@<sha>to@v1/@<sha>for reusable-workflow consumers. Security-relevant aspects to check:Secret forwarding surface — the comment correctly still warns about
secrets: inherithanding over every repo secret; explicit forwarding is still recommended. The new guidance doesn't relax this.Tag mutability (
@v1vs@mainvs@<sha>) — this is genuinely the security-relevant tradeoff, and the new comment explicitly:@main(moves on every push — could change what runs against forwarded secrets without consumer action).@v1as a curated tag "moved on deliberate releases" — less mutable than@main(only moves on tagged releases), but still mutable.@<sha>as the immutable option.From a security perspective,
@v1is strictly better than@main(smaller attack window — attacker needs to land av*tag push, not anymainpush) but strictly worse than@<sha>(which the comment also offers). The text is honest about this: "curated pointer moved on deliberate releases" vs "immutable pin." No claim that@v1equals@<sha>.Permissions block —
permissions:stays at the existing least-privilege (contents: read,issues: write,pull-requests: write); unchanged.Comment-author gate —
issue_commentstill gated toyour-username; unchanged.No new injected input, no new deserialization, no new SSRF surface — purely a comment/ref change.
One minor observation: the new
@v1recommendation nudges consumers toward a mutable tag. A security-strict reviewer might prefer the PR to lead with@<sha>and mention@v1as a convenience option, since silent movement of what runs against forwarded secrets is the exact threat the original@main-warning called out — and@v1reintroduces a (smaller) version of it. But the comment does flag this honestly ("curated … moved on deliberate releases"), and@<sha>is still offered side-by-side. This is a recommendation/tone call, not a gap; I'll note it but not block on it.No material security issues. The diff actually improves the security posture of the recommended default (smaller mutation window than
@main) while preserving the immutable@<sha>escape hatch and the explicit-secrets warning.VERDICT: No material issues found
permissions:block,secrets:explicit-forwarding guidance, and the actor gate onissue_commentare all unchanged.@v1over@main) reduces — not increases — the window in which an upstream push can silently change what runs against the consumer's forwarded secrets, while still documenting@<sha>as the immutable option. Verified by readingexamples/reusable.yml:14–20,52–54andREADME.md:313–318.🎯 Correctness — Blocking issues found
VERDICT: Blocking issues found
examples/reusable.yml:54/README.md:317— the advertised@v1mechanism does not exist in this repo. The PR's whole pitch is that@v1is "gadfly's curated release tag, re-moved on deliberate releases so central swarm tuning propagates without per-consumer re-pinning." But the only release automation in the repo is.gitea/workflows/build-image.yml, which publishes container image tags (:v1,:latest,:sha-<short>) togitea.stevedudenhoeffer.com/steve/gadfly— it never touches a git ref. Grep across the repo for any release script, tag-moving workflow, orgit push --force ... v1step returns nothing (scripts/has onlyrun.sh,status-board.sh,system-prompt.txt;.gitea/workflows/has onlybuild-image.yml,review-reusable.yml,adversarial-review.yml). So a consumer who follows the new advice and pinsuses: steve/gadfly/.gitea/workflows/review-reusable.yml@v1will get aworkflow_callresolve failure unless a human manuallygit tag v1 <sha> && git push --force origin v1for every release. Until the PR also adds the release-time automation (or at least an explicitscripts/release.sh+ a release workflow that force-moves the gitv1tag onv*tag pushes), the new recommendation is a footgun: the defaultexamples/reusable.ymlwill not run out of the box. Fix: add the missing automation in the same change (e.g. ascripts/release.shinvoked by arelease.ymlworkflow onpush: tags: ['v*']that force-moves the gitv1ref to the new commit, mirroring howbuild-image.ymlre-tags:latest), or hold this docs change until that exists..gitea/workflows/review-reusable.yml:9and:28— internal doc is now stale and contradicts the new recommendation. The reusable workflow's own header still tells consumers to pinuses: ...@<sha>(line 9:uses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>) and the closing paragraph (line 28) still says "Consumers should likewise pinuses: ...@<sha>(not @main)" — without mentioning the@v1option the freshly-updated README/reusable.yml now steer consumers toward. CLAUDE.md's own maintenance rule is "the README andexamples/… MUST be reflected … in the same change — stale docs are a bug." Three-doc rule, not two. Verified by reading.gitea/workflows/review-reusable.yml:1-30and grepping the repo for@<sha>/@v1/@main(hits inREADME.md,examples/reusable.yml, and.gitea/workflows/review-reusable.ymlonly). Fix: update the two@<sha>mentions in this file's header comment to the same@v1(with@<sha>offered as the alternative) so all consumer-facing docs agree.🧹 Code cleanliness & maintainability — Minor issues
VERDICT: Minor issues
README.md:315— "full-stub consumers" is a newly coined compound that's never defined and only used once.examples/reusable.yml:1calls its stub "SLIM consumer stub" and.gitea/workflows/review-reusable.yml:23points consumers at "the full stub in adversarial-review.yml", so the established vocabulary is "slim" vs. "full". Hyphenating to "full-stub" reads as a new term and mildly obscures which of the two stubs is meant for the:vNadvice. Suggest restructuring the sentence (e.g. "Pin the full stub to a:vNimage tag for stability…") rather than introducing "full-stub".Terminology drift between the two surfaces:
README.md:317calls@v1"a curated tag moved on releases";examples/reusable.yml:18calls it "a curated pointer moved on deliberate releases". Same concept, different label. Pick one — "tag" is more conventional and is also literally what it is (a git tag).Cross-file doc inconsistency:
.gitea/workflows/review-reusable.yml:9(embedded consumer example) still showsuses: steve/gadfly/.gitea/workflows/review-reusable.yml@<sha>, and line 28 still tells consumers to pin@<sha>and explicitly warns against@main, with no mention of@v1. So the README andexamples/reusable.ymlnow promote@v1as the primary pin with@<sha>as the immutable option, but the reusable's own header example promotes@<sha>and says nothing about@v1— the opposite recommendation. The PR updates one consumer-facing surface but not the matching embedded example inside the reusable itself. Suggest: at least add@v1as the primary recommendation in the embedded stub example (line 9) and update the prose on line 28 to match the new guidance.Pre-existing comment duplication, not introduced but not addressed:
examples/reusable.ymlnow repeats the same@v1/@<sha>/@mainguidance in two places — the header block at lines 17–20 and the inlineuses:comment at lines 52–53 — with slightly different wording. The duplication pattern existed before this PR (it duplicated@<sha>/not-@main), so it isn't a regression, but since the PR touches both comments anyway it would have been a low-churn moment to consolidate to a single canonical wording (probably the inline one, since it sits next to the actualuses:field). Not a blocker.The headline change itself (
@main→@v1with@<sha>preserved as the immutable option) is clean and matches the PR's stated intent. Nothing else in the diff strikes as unclean — no dead code, no leaky abstractions, no naming surprises, no structural churn.⚡ Performance — No material issues found
VERDICT: No material issues found
This PR is documentation-only: README.md guidance prose plus a workflow
uses:ref change (@main→@v1) inexamples/reusable.yml. Verified both touched regions:README.md:313-318— added the reusable-workflow pinning paragraph alongside the existing image-tag guidance.examples/reusable.yml:52-54—uses:ref updated, comment rewritten.Nothing in this diff touches runtime code paths, allocations, queries, loops, or any hot path. There is no efficiency-relevant change to evaluate through the Performance lens.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
This PR is docs/comments-only — it changes two blocks of prose (
examples/reusable.yml:14-20,examples/reusable.yml:52-53) and one paragraph (README.md:315-318). No code paths, no error paths, no nil checks, no cleanup, no boundary conditions, no I/O — nothing in the error-handling & edge-cases lens is touched.I verified by reading
examples/reusable.yml:1-70andREADME.md:300-330:uses:line atexamples/reusable.yml:54is now…@v1; the surroundingsecrets:/with:/concurrency:blocks are unchanged.@main", "curated pointer moved on deliberate releases"); any preconditions about the@v1tag actually existing belong to the release process, which is out of scope for this diff and out of my lane.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 22s