Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
aed01ec
feat: implement issue #1729 — [Phase 3] Collapse the first repo's Cla…
don-petry Oct 10, 2026
e9a8ffd
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
7a6948b
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
0c8121e
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
5c5ee59
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
928c42c
fix(bot): simplify concurrency group expression by removing redundant…
don-petry Oct 10, 2026
abf13c4
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
9bea00c
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
221bac6
docs(bot): clarify why agent-ingress canonical registration is premature
don-petry Oct 10, 2026
35e61c3
fix(reviews): restore verbatim markets ingress fixture; correct regis…
don-petry Oct 10, 2026
8bd6b88
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
d74ace1
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
1d8fac8
fix(bot): update stale canonical ingress template comments
don-petry Oct 10, 2026
3536ea3
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
a8a4caf
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
de7cf8d
Merge branch 'main' into dev-lead/issue-1729-20261010-1002
don-petry Oct 10, 2026
ab9d636
fix(fleet): restore the canonical-pending registry comment (revert 1d…
claude Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
tests/test_rate_limit_samples.bats \
tests/fleet_stub_drift.bats \
tests/fleet_stub_remediate.bats \
tests/fleet_stub_registry.bats \
tests/fleet_remediate_gate.bats \
tests/template_stub_drift.bats \
tests/canary_rollout.bats \
Expand Down Expand Up @@ -334,7 +335,7 @@
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# NOTE: persist-credentials is intentionally left at the default (true) —

Check warning on line 338 in .github/workflows/lint.yml

View workflow job for this annotation

GitHub Actions / Lint

338:9 [comments-indentation] comment not indented like content
# vci_resolve_reusable needs `git fetch origin` to authenticate against this
# private repo when resolving same-repo channel tags. Setting
# persist-credentials: false would silently push every such caller into the
Expand Down
18 changes: 18 additions & 0 deletions scripts/fleet_monitor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ CANONICAL_STUB_REPO="${CANONICAL_STUB_REPO:-petry-projects/.github}"
STUB_REGISTRY=(
$'initiative-planner\tInitiative-planner\t.github/workflows/initiative-planner.yml\tstandards/workflows/initiative-planner.yml\t\t\t'
$'initiative-driver\tInitiative-driver\t.github/workflows/initiative-driver.yml\tstandards/workflows/initiative-driver.yml\t\t\t'
# Collapsed agent-ingress.yml roles (#1729 AC11): one row per job in the
# petry-projects/markets ingress. These entries register for future drift
# coverage once the canonical standards/workflows/agent-ingress.yml is
# published to petry-projects/.github (#1729 AC11). Until then, a canonical
# 404 gracefully skips these rows with a warning, leaving them without
# coverage. The monitor and remediation helpers handle this degradation
# automatically (see the @test "fleet_monitor: a 404 canonical
# agent-ingress skips every role row with a warning and stays green" in
# tests/fleet_stub_registry.bats).
# legacy_canonical_path is empty for pr-review and ci-failure-analyst because
# petry-projects/.github publishes no standards/workflows/<role>.yml for them
# (checked 2026-10-10), so a repo that has not collapsed classifies MISSING
# for those two roles.
$'dev-lead\tDev-lead\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tdev-lead\t.github/workflows/dev-lead.yml\tstandards/workflows/dev-lead.yml'
$'pr-auto-review\tPr-auto-review\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tpr-auto-review\t.github/workflows/pr-auto-review.yml\tstandards/workflows/pr-auto-review.yml'
$'pr-review\tPr-review\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tpr-review\t.github/workflows/pr-review.yml\t'
$'pr-review-mention\tPr-review-mention\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tpr-review-mention\t.github/workflows/pr-review-mention.yml\tstandards/workflows/pr-review-mention.yml'
$'ci-failure-analyst\tCi-failure-analyst\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tci-failure-analyst\t.github/workflows/ci-failure-analyst.yml\t'
Comment thread
don-petry marked this conversation as resolved.
)

# fetch_raw_content <repo> <path> — emit a file's raw contents on stdout. Returns
Expand Down
4 changes: 4 additions & 0 deletions scripts/fleet_stub_drift.sh
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,15 @@ patch_job_block() {
# back to the legacy file, which would mask/resurrect a removed stub).
# • otherwise (no ingress file — a legacy repo mid-rollout): classify on the
# legacy whole-file SHAs, exactly as before (backward compatibility, AC #4).
# With no legacy canonical SHA (the role has no published per-role template)
# the legacy file cannot be compared, so it is MISSING, never DRIFTED (#1729).
classify_role_drift() {
local ingress_present="${1:-}" canon_block="${2:-}" ingress_block="${3:-}"
local legacy_canon="${4:-}" legacy_repo="${5:-}"
if [ "$ingress_present" = "yes" ]; then
classify_stub_drift "$canon_block" "$ingress_block"
elif [ -z "$legacy_canon" ]; then
echo "MISSING"
else
classify_stub_drift "$legacy_canon" "$legacy_repo"
fi
Expand Down
18 changes: 18 additions & 0 deletions scripts/fleet_stub_remediate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ CANONICAL_STUB_REPO="${CANONICAL_STUB_REPO:-petry-projects/.github}"
STUB_REGISTRY=(
$'initiative-planner\tInitiative-planner\t.github/workflows/initiative-planner.yml\tstandards/workflows/initiative-planner.yml\t\t\t'
$'initiative-driver\tInitiative-driver\t.github/workflows/initiative-driver.yml\tstandards/workflows/initiative-driver.yml\t\t\t'
# Collapsed agent-ingress.yml roles (#1729 AC11): one row per job in the
# petry-projects/markets ingress. These entries register for future drift
# coverage once the canonical standards/workflows/agent-ingress.yml is
# published to petry-projects/.github (#1729 AC11). Until then, a canonical
# 404 gracefully skips these rows with a warning, leaving them without
# coverage. The monitor and remediation helpers handle this degradation
# automatically (see the @test "fleet_monitor: a 404 canonical
# agent-ingress skips every role row with a warning and stays green" in
# tests/fleet_stub_registry.bats).
# legacy_canonical_path is empty for pr-review and ci-failure-analyst because
# petry-projects/.github publishes no standards/workflows/<role>.yml for them
# (checked 2026-10-10), so a repo that has not collapsed classifies MISSING
# for those two roles.
$'dev-lead\tDev-lead\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tdev-lead\t.github/workflows/dev-lead.yml\tstandards/workflows/dev-lead.yml'
$'pr-auto-review\tPr-auto-review\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tpr-auto-review\t.github/workflows/pr-auto-review.yml\tstandards/workflows/pr-auto-review.yml'
$'pr-review\tPr-review\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tpr-review\t.github/workflows/pr-review.yml\t'
$'pr-review-mention\tPr-review-mention\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tpr-review-mention\t.github/workflows/pr-review-mention.yml\tstandards/workflows/pr-review-mention.yml'
$'ci-failure-analyst\tCi-failure-analyst\t.github/workflows/agent-ingress.yml\tstandards/workflows/agent-ingress.yml\tci-failure-analyst\t.github/workflows/ci-failure-analyst.yml\t'
)

# ── Never-overwrite allowlist (AC #3) ─────────────────────────────────────────
Expand Down
184 changes: 184 additions & 0 deletions tests/fixtures/agent-ingress/markets-agent-ingress.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# ─────────────────────────────────────────────────────────────────────────────
# Agent Ingress — petry-projects/markets (ADR-0007, epic #1723, story #1729)
#
# ONE ingress for this repo's eligible Class-1 event-driven agentic roles. The
# on: block is the UNION of the collapsed roles' triggers; each job below is ONE
# role, guarded by a PURE event-filter if: that reconstructs that role's original
# subscription. pull_request_target roles (add-to-project, dependabot-automerge,
# dependabot-rebase), repo-local (auto-rebase), Class-3 (feature-ideation,
# initiative-driver), and required-check gates (agent-shield, dependency-audit)
# keep their own stubs — see docs/initiatives/agent-ingress-collapse-markets.md.
# ─────────────────────────────────────────────────────────────────────────────

name: Agent Ingress

on:
pull_request:
# opened/reopened/synchronize ← dev-lead(base=main), pr-auto-review, pr-review;
# ready_for_review ← pr-auto-review, pr-review; review_requested ← pr-review-mention.
types: [opened, reopened, synchronize, ready_for_review, review_requested]
pull_request_review:
# submitted ← dev-lead, pr-auto-review, pr-review; dismissed ← pr-auto-review, pr-review.
types: [submitted, dismissed]
pull_request_review_comment:
types: [created]
issue_comment:
types: [created]
issues:
types: [labeled]
check_run:
types: [completed]
check_suite:
types: [completed]
workflow_run:
workflows: ["CI"]
types: [completed]
workflow_dispatch:
inputs:
pr_url:
description: "Optional: review a single PR URL instead of enumerating"
required: false
type: string
dry_run:
description: "If true, never submit reviews or comments"
required: false
default: "false"
type: string
force_review:
description: "If true, bypass idempotency and re-review at the same head SHA"
required: false
default: "false"
type: string
repository_dispatch:
types: [dev-lead-ci-failure, dev-lead-reviews-retry, dev-lead-issue-retry, pr-review-mention]

permissions: {}

jobs:
# ── dev-lead ────────────────────────────────────────────────────────────────
dev-lead:
if: >-
(github.event_name == 'pull_request'
&& contains(fromJSON('["opened","reopened","synchronize"]'), github.event.action)
&& github.event.pull_request.base.ref == 'main')
|| (github.event_name == 'pull_request_review' && github.event.action == 'submitted')
|| github.event_name == 'pull_request_review_comment'
|| github.event_name == 'issue_comment'
|| github.event_name == 'issues'
|| github.event_name == 'check_run'
|| (github.event_name == 'repository_dispatch'
&& contains(fromJSON('["dev-lead-ci-failure","dev-lead-reviews-retry","dev-lead-issue-retry"]'), github.event.action))
uses: petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@dev-lead/v139-stable # NOSONAR(githubactions:S7637) first-party channel ref
with:
agent_ref: dev-lead/v139-stable
secrets: inherit # NOSONAR(githubactions:S7635) first-party trusted reusable
permissions:
contents: write
pull-requests: write
issues: write
actions: read
checks: read
statuses: read

# ── pr-auto-review ──────────────────────────────────────────────────────────
pr-auto-review:
if: >-
(github.event_name == 'pull_request'
&& contains(fromJSON('["opened","reopened","synchronize","ready_for_review"]'), github.event.action))
|| (github.event_name == 'pull_request_review'
&& contains(fromJSON('["submitted","dismissed"]'), github.event.action))
|| github.event_name == 'check_suite'
|| github.event_name == 'workflow_run'
# Workflow-level concurrency in the source stub → job-level here, bounded per
# ADR-0010: literal role prefix, payload parts only (no run_id), literal bool.
# PR events keep their per-PR slot; check_suite / workflow_run use their own
# event ids so runs on a shared commit never cancel another PR's review (§4b).
concurrency:
group: >-
pr-auto-review-${{
github.event.pull_request.number
|| github.event.check_suite.id
|| github.event.workflow_run.id
|| 'none'
}}
cancel-in-progress: true
permissions:
pull-requests: read
checks: read
actions: read
uses: petry-projects/.github/.github/workflows/pr-auto-review-reusable.yml@pr-auto-review/v1-stable # NOSONAR(githubactions:S7637) first-party channel ref
secrets:
GH_PAT_WORKFLOWS: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}

# ── pr-review ─────────────────────────────────────────────────────────────────
pr-review:
# Subscription filter AND the source stub's check_suite-with-no-PR skip, both
# pure event predicates over the delivered payload.
if: >-
(
(github.event_name == 'pull_request'
&& contains(fromJSON('["ready_for_review","reopened","synchronize"]'), github.event.action))
|| (github.event_name == 'pull_request_review'
&& contains(fromJSON('["submitted","dismissed"]'), github.event.action))
|| github.event_name == 'check_suite'
|| github.event_name == 'workflow_dispatch'
|| (github.event_name == 'repository_dispatch' && github.event.action == 'pr-review-mention')
)
&& (github.event_name != 'check_suite' || github.event.check_suite.pull_requests[0] != null)
# Job-level concurrency, bounded per ADR-0010: payload parts only (no inputs.*,
# no run_id). A sweep with no PR shares the 'enumerate' slot. The fallback is
# NOT 'batch', because the pinned reusable declares pr-review-batch (§4b).
concurrency:
group: >-
pr-review-${{
(github.event.pull_request && github.event.pull_request.number)
|| (github.event.check_suite && github.event.check_suite.pull_requests[0] && github.event.check_suite.pull_requests[0].number)
|| github.event.inputs.pr_url
|| (github.event.client_payload && github.event.client_payload.pr_url)
|| 'enumerate'
}}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
checks: read
uses: petry-projects/.github-private/.github/workflows/pr-review.yml@pr-review/stable # NOSONAR(githubactions:S7637) first-party channel ref # DEFECTIVE PIN — see §5
with:
agent_ref: pr-review/stable
pr_url: ${{ inputs.pr_url || '' }}
dry_run: ${{ inputs.dry_run || '' }}
force_review: ${{ inputs.force_review || '' }}
secrets: inherit # NOSONAR(githubactions:S7635) first-party trusted reusable

# ── pr-review-mention ──────────────────────────────────────────────────────────
pr-review-mention:
if: >-
(
(github.event_name == 'pull_request' && github.event.action == 'review_requested')
|| github.event_name == 'issue_comment'
|| github.event_name == 'pull_request_review_comment'
)
&& github.event.sender.type != 'Bot'
permissions:
pull-requests: write
uses: petry-projects/.github/.github/workflows/pr-review-mention-reusable.yml@pr-review-mention/v2-stable # NOSONAR(githubactions:S7637) first-party channel ref
secrets: inherit # NOSONAR(githubactions:S7635) first-party trusted reusable

# ── ci-failure-analyst ─────────────────────────────────────────────────────────
ci-failure-analyst:
if: >-
github.event_name == 'check_run'
&& github.event.check_run.conclusion == 'failure'
&& !startsWith(github.event.check_run.name, 'CI Failure Analyst')
concurrency:
group: "ci-failure-analyst-${{ github.event.check_run.head_sha }}"
cancel-in-progress: false
permissions:
pull-requests: write
issues: write
actions: read
contents: read
checks: read
uses: petry-projects/.github-private/.github/workflows/ci-failure-analyst-reusable.yml@b58510275dd1cbbd13c0733c15265d51fd63b992 # DEFECTIVE PIN — bare SHA, see §5
secrets:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
7 changes: 7 additions & 0 deletions tests/fleet_stub_drift.bats
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,13 @@ INGRESS_NO_DEVLEAD="${BATS_TEST_DIRNAME}/fixtures/agent-ingress/collapsed-no-dev
[ "$output" = "MISSING" ]
}

# A role with no published per-role canonical (#1729: pr-review,
# ci-failure-analyst) cannot compare a legacy file, so it is MISSING, not DRIFTED.
@test "classify_role_drift: no ingress and no legacy canonical is MISSING, never DRIFTED" {
run classify_role_drift "no" "irrelevant-block-sha" "" "" "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
[ "$output" = "MISSING" ]
}

# ---------------------------------------------------------------------------
# stub_drift_row_role — role rows flow through the SAME 4-field TSV shape as
# whole-file rows, so the report/alert path is shared. The emitted SHAs are the
Expand Down
Loading
Loading