Story
As a maintainer,
I want document spam-pr-guard as a canonical fleet standard in petry-projects/.github/standards/ — layers, signals, staged actions, security invariant, config knobs, canary rings, appeal path — so that it ships to every consumer on the next standards/v1-stable cut and consumers have the behavior, tuning knobs, and false-positive appeal path written down and reviewable.
This phase is not "repo-local first" — the fleet standard pattern vendors from petry-projects/.github and promotes to consumers on standards/v1-stable (see standards/standards-versioning.md). The doc rides the same release channel the registry (standards/canary-rings.json) and the stub template (standards/workflows/spam-pr-guard.yml) ride; a single scripts/cut-standards-release.sh cut vX.Y.Z run picks up all three together.
Acceptance Criteria
- Location. The standard lives at
standards/spam-pr-guard.md (dedicated file; prior art: standards/pr-limits.md, standards/persona-standards.md, standards/agent-rate-limits.md). If the maintainer prefers inline, a section in standards/ci-standards.md is also acceptable (prior art: pr-auto-review is documented inline in ci-standards.md § Reusable workflow versioning); pick ONE location, not both.
- Layered defense documented. The doc describes Layer 0 (GitHub-native, Phase 0), Layer 1 (the
spam-pr-guard reusable, Phases 1–3), Layer 2 (the vendored sc_description_missing fix, Phase 1), and Layer 3 (stale backstop + weekly reporting, Phase 6). The signal table (empty template +3, bare-name title +2, …) and the low/medium/high action mapping are given explicitly.
- Security invariant. The doc states the
pull_request_target metadata-only invariant (no PR-code execution, fork-checkout blocked by actions/checkout v7 default) and the fail-closed rule (any unreadable signal escalates to a human; the scorer never scores "not spam" by default).
- Config knobs. Weights, the medium/high thresholds, the burst-limit N, and the security-sensitive path list are documented as config edits in
standards/spam-pr-guard.json, not code changes. The doc states that the config rides standards/v1-stable and reaches consumers on the next cut (no per-config tag).
- Canary rings. The doc links to
standards/canary-rings.json .agents["spam-pr-guard"] and summarises the ring progression (next → ring0 → ring1 → stable), the standard #548 graduated dwell/sample gate, and require_confirmation: true on ring1→stable as the enable-label/close go/no-go gate.
- Caller-stub pin. The doc documents how a consumer repo participates (install the stub via
scripts/seed-repo-template.sh; the stub pins uses: … @spam-pr-guard/v1-stable with the mandatory # NOSONAR(githubactions:S7637) first-party channel ref marker; the stub carries with: { dry_run: true, agent_ref: spam-pr-guard/v1-stable }), and how a consumer flips dry_run: false once comfortable (per-stub override; the fleet default also flips once Phase 5 clears require_confirmation on ring1→stable and the next cut-standards-release.sh cut ships the new default).
- False-positive appeal path. The doc describes the appeal path the Phase 3 reusable's high-action comment points to (how a contributor requests review, reopens, or signals that the close was wrong). The appeal path is the single text source that both the comment and this doc cite — comments reference
standards/spam-pr-guard.md § Appeal path rather than inlining the appeal text, so a change in one place propagates to the other on the next cut.
- Promotion story. The doc states the release model: the standard ships on
standards/v1-stable via scripts/cut-standards-release.sh; consumers that pin a ref consume the published cut (and N-1 remains resolvable per standards-versioning.md § N-1 resolvability). No per-capability spam-pr-guard-prefixed standards tag.
- Cross-links the Phase 3 reusable, the Phase 2 scorer + config, and the section-4 row so the standard describes the real design.
Tasks / Subtasks
Dev Notes
- The fleet pattern treats
standards/ as the single versioned artifact. Promoting a per-capability doc straight into standards/ is the standard shape, not a special case — see standards/pr-limits.md, standards/persona-standards.md, standards/agent-rate-limits.md. The earlier "repo-local first, promote later" phrasing was for pre-standards/v1-stable days and does not apply after the release channel was cut.
- The doc should NOT restate the registry (
standards/canary-rings.json); it links to it. One source of truth per fact.
- Avoid embedding the appeal path in the Phase 3 reusable's comment text — comments reference the doc, so a tuning-time change ships via the next standards cut without touching the workflow.
Project Structure Notes
A documentation story; a new markdown doc in standards/ plus cross-links. No script or workflow behavior changes.
References
Likely target surface
standards/spam-pr-guard.md (or standards/ci-standards.md — pick ONE)
Story prepared by the BMAD Scrum Master (Bob) for epic #1200. Realigned to the vendored-reusable + caller-stub + canary-rings shape — promoted directly to standards/, not repo-local-first. Status: ready-for-dev (blocked_by #1203).
Story
As a maintainer,
I want document
spam-pr-guardas a canonical fleet standard inpetry-projects/.github/standards/— layers, signals, staged actions, security invariant, config knobs, canary rings, appeal path — so that it ships to every consumer on the nextstandards/v1-stablecut and consumers have the behavior, tuning knobs, and false-positive appeal path written down and reviewable.This phase is not "repo-local first" — the fleet standard pattern vendors from
petry-projects/.githuband promotes to consumers onstandards/v1-stable(seestandards/standards-versioning.md). The doc rides the same release channel the registry (standards/canary-rings.json) and the stub template (standards/workflows/spam-pr-guard.yml) ride; a singlescripts/cut-standards-release.sh cut vX.Y.Zrun picks up all three together.Acceptance Criteria
standards/spam-pr-guard.md(dedicated file; prior art:standards/pr-limits.md,standards/persona-standards.md,standards/agent-rate-limits.md). If the maintainer prefers inline, a section instandards/ci-standards.mdis also acceptable (prior art:pr-auto-reviewis documented inline inci-standards.md § Reusable workflow versioning); pick ONE location, not both.spam-pr-guardreusable, Phases 1–3), Layer 2 (the vendoredsc_description_missingfix, Phase 1), and Layer 3 (stale backstop + weekly reporting, Phase 6). The signal table (empty template +3, bare-name title +2, …) and the low/medium/high action mapping are given explicitly.pull_request_targetmetadata-only invariant (no PR-code execution, fork-checkout blocked byactions/checkoutv7 default) and the fail-closed rule (any unreadable signal escalates to a human; the scorer never scores "not spam" by default).standards/spam-pr-guard.json, not code changes. The doc states that the config ridesstandards/v1-stableand reaches consumers on the next cut (no per-config tag).standards/canary-rings.json .agents["spam-pr-guard"]and summarises the ring progression (next → ring0 → ring1 → stable), the standard#548graduated dwell/sample gate, andrequire_confirmation: trueonring1→stableas the enable-label/close go/no-go gate.scripts/seed-repo-template.sh; the stub pinsuses: … @spam-pr-guard/v1-stablewith the mandatory# NOSONAR(githubactions:S7637) first-party channel refmarker; the stub carrieswith: { dry_run: true, agent_ref: spam-pr-guard/v1-stable }), and how a consumer flipsdry_run: falseonce comfortable (per-stub override; the fleet default also flips once Phase 5 clearsrequire_confirmationonring1→stableand the nextcut-standards-release.sh cutships the new default).standards/spam-pr-guard.md § Appeal pathrather than inlining the appeal text, so a change in one place propagates to the other on the next cut.standards/v1-stableviascripts/cut-standards-release.sh; consumers that pin a ref consume the published cut (and N-1 remains resolvable perstandards-versioning.md § N-1 resolvability). No per-capabilityspam-pr-guard-prefixed standards tag.Tasks / Subtasks
standards/spam-pr-guard.md(or new section instandards/ci-standards.md) describing all four layers, the signal table, and the action mapping (AC: Addressing PR comments #1, Add multi-agent isolation strategy using git worktrees #2)require_confirmationgate (AC: Add stacked PR strategy and Epic-level workflow guidance #5)dry_runoverride (AC: feat: add Structured Logging and CQRS standards #6)standards/v1-stablerelease model and N-1 resolvability (AC: Evolve Agentic Development: Integrate Claude Agent Teams with BMAD Workflow #8)Dev Notes
standards/as the single versioned artifact. Promoting a per-capability doc straight intostandards/is the standard shape, not a special case — seestandards/pr-limits.md,standards/persona-standards.md,standards/agent-rate-limits.md. The earlier "repo-local first, promote later" phrasing was for pre-standards/v1-stabledays and does not apply after the release channel was cut.standards/canary-rings.json); it links to it. One source of truth per fact.Project Structure Notes
A documentation story; a new markdown doc in
standards/plus cross-links. No script or workflow behavior changes.References
standards/standards-versioning.md(release channel; AC Add workflow, environment, and orchestration guidance #4, Evolve Agentic Development: Integrate Claude Agent Teams with BMAD Workflow #8)standards/ci-standards.md § Reusable workflow versioning(inline-prior-art for pr-auto-review; AC Addressing PR comments #1)standards/pr-limits.md,standards/persona-standards.md,standards/agent-rate-limits.md(dedicated-file prior art; AC Addressing PR comments #1)standards/canary-rings.json(AC Add stacked PR strategy and Epic-level workflow guidance #5)AGENTS.md § Agentic interaction model,AGENTS.md § Cost reportingdocs/agentic-interaction-model.mdLikely target surface
standards/spam-pr-guard.md(orstandards/ci-standards.md— pick ONE)Story prepared by the BMAD Scrum Master (Bob) for epic #1200. Realigned to the vendored-reusable + caller-stub + canary-rings shape — promoted directly to
standards/, not repo-local-first. Status: ready-for-dev (blocked_by #1203).