Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/workflows/add-to-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# • This file is a THIN CALLER STUB. All noise-gate / reconcile logic lives
# in the reusable workflow above.
# • You MAY change: nothing in normal use. The `uses:` ref and `agent_ref`
# are pinned to the `add-to-project/v1-stable` channel and move with it — do
# are pinned to the `add-to-project/v1-ring1` channel and move with it — do
# not change them to `@main` or a SHA (see ci-standards.md → Reusable
# workflow versioning).
# • You MUST NOT change: trigger events, the concurrency group, or the
Expand Down Expand Up @@ -47,11 +47,11 @@ jobs:
add-to-project:
permissions:
contents: read
uses: petry-projects/.github/.github/workflows/add-to-project-reusable.yml@add-to-project/v1-stable # NOSONAR(githubactions:S7637) first-party channel ref
uses: petry-projects/.github/.github/workflows/add-to-project-reusable.yml@add-to-project/v1-ring1 # NOSONAR(githubactions:S7637) first-party channel ref
Comment thread
don-petry marked this conversation as resolved.
Resolved
with:
project_id: PVT_kwDOD2inqs4BZq3-
project_url: https://github.com/orgs/petry-projects/projects/1
agent_ref: add-to-project/v1-stable
agent_ref: add-to-project/v1-ring1
# Pass only the secrets the reusable declares (least privilege; avoids
# `secrets: inherit` handing the reusable every org secret).
secrets:
Expand Down
101 changes: 95 additions & 6 deletions .github/workflows/initiative-driver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,32 @@
# sub-issues to dev-lead — so the central driver does not have to watch every
# enrolled repo's events.
#
# Rate-limit gate (#640): before dispatching, this stub asks the source-side
# agent-rate-limit gate (petry-projects/.github/scripts/agent-rate-limit-gate.sh)
# whether `initiative-driver` may dispatch right now. initiative-driver is the
# canary that ENFORCES: the gate derives concurrency / cooldown / daily-budget /
# consecutive-failure counters from this stub's own run history (no state
# backend) and reads every threshold from standards/agent-rate-limits.json.
# It throttles dispatches that DO start (cooldown / daily budget / breaker); it
# does NOT pre-empt the cancel-in-progress concurrency group below — that group
# cancels a superseded run before any step (gate included) executes (#443/#402).
# A `defer` simply skips the dispatch step — never a cancel, never a job failure.
#
# Gate tooling is fetched at a pinned commit SHA of petry-projects/.github (not
# a moving tag — the PAT is handed to that code). If the tooling is unavailable
# or the gate errors, the gate step FAILS LOUDLY (::error:: annotation + step
# summary, step marked failed) but the dispatch still runs (fail-open — an
# outage of the gate must never stop the fleet; standards/agent-rate-limits.md).
#
# To adopt:
# 1. Copy this file verbatim to .github/workflows/initiative-driver.yml in your repo.
# 2. Ensure the `initiative:auto` label exists on the repo.
# 3. Confirm the org-level secret GH_PAT_WORKFLOWS is accessible **and its
# owner has write access to petry-projects/.github-private** (to dispatch
# the central workflow) **and to this repo** (the central driver applies the
# `dev-lead` label cross-repo with that PAT; a label applied with
# GITHUB_TOKEN would not trigger dev-lead).
# 3. Confirm the org-level secret GH_PAT_DON_PETRY (or the legacy fallback
# GH_PAT_WORKFLOWS) is accessible **and its owner has write access to
# petry-projects/.github-private** (to dispatch the central workflow) **and
# to this repo** (the central driver applies the `dev-lead` label
# cross-repo with that PAT; a label applied with GITHUB_TOKEN would not
# trigger dev-lead).
#
# Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md
name: Initiative Driver — Dispatch Central
Expand Down Expand Up @@ -76,11 +94,82 @@ jobs:
GH_TOKEN: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}
run: |
if [ -z "${GH_TOKEN}" ]; then
echo "::error::GH_PAT_WORKFLOWS is required — a workflow_dispatch fired with GITHUB_TOKEN never starts a run."
echo "::error::GH_PAT_DON_PETRY (or legacy GH_PAT_WORKFLOWS) is required — a workflow_dispatch fired with GITHUB_TOKEN never starts a run."
exit 1
fi

- name: Checkout agent-rate-limit gate tooling
# Phase-4 wiring (#640): the gate library + orchestrator live in
# petry-projects/.github; an enrolled caller stub does not carry them, so
# fetch them read-only into a scratch path. Uses the same PAT as the
# dispatch — the workflow's GITHUB_TOKEN cannot read another repo — so the
# stub's `permissions:` block is unchanged.
# continue-on-error: a tooling-checkout outage must not stop the fleet —
# the gate step then finds no script, reports an ::error:: (fail loudly),
# emits no decision, and the dispatch step's `!= 'defer'` guard falls
# through to dispatching (fail-open).
# ref: pinned to an immutable commit SHA of petry-projects/.github (#1232)
# — a moving tag silently lagged the gate script (v1 predates it) and
# would hand the PAT to whatever the tag next points at. Bump it in a
# reviewed PR (see standards/agent-rate-limits.md §3.1).
continue-on-error: true
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new PAT-bearing checkout and fail-open gate are not covered by CI; no guard tests this workflow’s security-sensitive dispatch contract. Add a fixture-driven test with negative cases for the private checkout/pin, missing-tooling fail-open behavior, and explicit defer suppression, then invoke it from workflow-tests.

(Based on your team's feedback about guarding reliability- and security-sensitive workflow invariants).

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/initiative-driver.yml, line 116:

<comment>The new PAT-bearing checkout and fail-open gate are not covered by CI; no guard tests this workflow’s security-sensitive dispatch contract. Add a fixture-driven test with negative cases for the private checkout/pin, missing-tooling fail-open behavior, and explicit `defer` suppression, then invoke it from `workflow-tests`.

(Based on your team's feedback about guarding reliability- and security-sensitive workflow invariants). </comment>

<file context>
@@ -76,11 +94,82 @@ jobs:
+        # would hand the PAT to whatever the tag next points at. Bump it in a
+        # reviewed PR (see standards/agent-rate-limits.md §3.1).
+        continue-on-error: true
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+        with:
+          repository: petry-projects/.github
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This finding requires adding CI fixture-driven tests for the security-sensitive PAT checkout and fail-open gate behavior. These test fixtures would need to be added to the workflow-tests job and scripts/test-initiative-driver-workflow.sh, which is outside the scope of syncing workflow stub changes from the upstream template. This would be a follow-up task in the test infrastructure.

with:
repository: petry-projects/.github
ref: cd0b16751454d2eb3486ec04477d7ee9cc96c425 # main @ 2026-10-02 (#1232)
path: .arl-gate-tooling
fetch-depth: 1
persist-credentials: false
token: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}

- name: Agent rate-limit admission gate (enforcing)
# initiative-driver is the ONE canary agent type that ENFORCES (pure bash,
# no model spend, the direct #443 target — AC #5). Reads run history with
# the PAT (independent of the `permissions:` block) and emits
# decision=allow|defer to $GITHUB_OUTPUT; a defer is honoured by the `if:`
# on the dispatch step below. Fail loud, fail open: a missing gate script
# or a gate error marks THIS step failed with an ::error:: (visible in the
# run), but continue-on-error keeps the job — and the dispatch — going.
continue-on-error: true
id: arl_gate
env:
GH_TOKEN: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}
ARL_ACTOR: ${{ github.actor }}
ARL_TRACKING_REPO: ${{ github.repository }}
# For issue events use the event's issue number; for schedule/workflow_dispatch
# fall back to a configured repo variable so argate_escalate can post the
# breaker marker and apply the needs-human-review label (both are skipped when
# tracking_issue is empty). Set INITIATIVE_DRIVER_TRACKING_ISSUE to the epic
# or operations issue number for this repo to enable escalation on non-issue runs.
ARL_TRACKING_ISSUE: ${{ github.event.issue.number || vars.INITIATIVE_DRIVER_TRACKING_ISSUE || '' }}
run: |
set -euo pipefail
ARL_GATE_SCRIPT=.arl-gate-tooling/scripts/agent-rate-limit-gate.sh
if ! [ -f "$ARL_GATE_SCRIPT" ]; then
msg="Agent rate-limit gate NOT ENFORCED: ${ARL_GATE_SCRIPT} is missing (tooling checkout failed or the pinned ref lacks the script). Dispatching ungated (fail-open)."
echo "::error::${msg}"
echo "### :warning: ${msg}" >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
bash "$ARL_GATE_SCRIPT" initiative-driver \
--repo "$ARL_TRACKING_REPO" \
--mode enforce \
--workflow initiative-driver.yml \
--actor "$ARL_ACTOR" \
--tracking-repo "$ARL_TRACKING_REPO" \
--tracking-issue "$ARL_TRACKING_ISSUE" || {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
rc=$?
echo "::error::Agent rate-limit gate errored (exit ${rc}) — dispatching ungated (fail-open)."
echo "### :warning: Agent rate-limit gate errored (exit ${rc}) — dispatching ungated (fail-open)." >> "$GITHUB_STEP_SUMMARY"
exit "$rc"
}

- name: Dispatch central initiative-driver
# Skipped (clean no-op) ONLY on an explicit `defer` — never a cancel, never
# a job failure (#640, AC #1/#2). Fail-OPEN: an empty/missing decision (the
# gate step or its tooling checkout failed) still dispatches, because an
# outage of the gate must never stop the fleet (ADR §7 fail-safe direction).
if: steps.arl_gate.outputs.decision != 'defer'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Exclude deferred runs from both history counters. Each deferred attempt still runs this workflow, so it can reset the cooldown and consume the daily budget without dispatching.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/initiative-driver.yml, line 172:

<comment>Exclude deferred runs from both history counters. Each deferred attempt still runs this workflow, so it can reset the cooldown and consume the daily budget without dispatching.</comment>

<file context>
@@ -76,11 +94,82 @@ jobs:
+        # a job failure (#640, AC #1/#2). Fail-OPEN: an empty/missing decision (the
+        # gate step or its tooling checkout failed) still dispatches, because an
+        # outage of the gate must never stop the fleet (ADR §7 fail-safe direction).
+        if: steps.arl_gate.outputs.decision != 'defer'
         env:
           GH_TOKEN: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excluding deferred runs from history counters requires changes to the gate script logic in petry-projects/.github/scripts/agent-rate-limit-gate.sh, not changes to this caller stub. The gate script is the authority for how runs are counted and how decisions are made. This is an upstream issue to be addressed in the central gate tooling, not in individual caller stubs.

env:
GH_TOKEN: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}
run: |
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/persona-mention.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# ─────────────────────────────────────────────────────────────────────────────
# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/persona-mention.yml
# Standard: petry-projects/.github/standards/persona-standards.md (§4.1)
# Reusable: petry-projects/.github/.github/workflows/persona-mention-reusable.yml
#
# AGENTS — READ BEFORE EDITING:
# • This file is a THIN CALLER STUB. All routing logic lives in the reusable
# workflow above, and every per-persona decision lives in that persona's
# manifest — not here and not in the reusable.
# • You MUST NOT change: the `uses:` ref — it is pinned to the
# `persona-mention/v1-ring1` channel, a moving tag advanced centrally.
# Never repoint it to `@main`, a SHA, or a frozen `@vX.Y.Z` (see
# ci-standards.md → Reusable workflow versioning). Also do not change the
# trigger events or the job-level `permissions:` block — reusable workflows
# can be granted no more permissions than the calling job, so removing the
# stanza breaks the reusable's gh API calls.
# • Do NOT add a per-persona stub. ONE router serves every persona (§4.1);
# a stub per agent is the drift the manifest exists to prevent.
# • If you need different behaviour, open a PR against the reusable in the
# central repo. A new release is rolled out by moving the channel tag
# centrally — never by editing callers, so no fanout PR is needed.
# ─────────────────────────────────────────────────────────────────────────────
#
# Persona Mention Router — thin caller for the org-level reusable.
#
# Adopting this file makes every persona that enables the `mention` surface
# addressable in this repo as `@petry-projects/<role>` — e.g.
#
# @petry-projects/qa-lead please assess test risk on this PR
#
# The handle is an org TEAM, never a user account: '@qa-lead' is a real GitHub
# account owned by an unrelated person (§4.1).
#
# To adopt: copy this file to .github/workflows/persona-mention.yml in your repo.
# Requires: GH_PAT_WORKFLOWS org secret (already present in petry-projects org).
name: Persona — Mention Router

on:
# issue_comment covers BOTH issues and PR conversation comments.
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
# Discussions cannot run an agent inline (#571) — but this router only parses
# and dispatches, and the agent itself runs on the resulting
# repository_dispatch, which is exactly the bridge the manifest declares.
discussion_comment:
types: [created]
# NOTE: reviewer assignment (pull_request/review_requested) is NOT subscribed
# here yet, even though §4 says "Reviewer-assignment counts here too". The
# router has no path for it, and a trigger that fires into a router which
# ignores it is a dead trigger that only burns runs. Tracked as finding 10 in
# petry-projects/.github#755; the trigger lands with the routing, not before.

permissions: {}

jobs:
persona-mention:
permissions:
contents: read # the reusable checks out its tooling repo — required,
# or the call fails at startup (a reusable is granted
# no more than the caller; persona-standards.md §5)
issues: read
pull-requests: read
# NOSONAR(githubactions:S7637) first-party channel ref
uses: petry-projects/.github/.github/workflows/persona-mention-reusable.yml@persona-mention/v1-ring1
# NOSONAR(githubactions:S7635) org secrets are scoped to first-party reusables
secrets: inherit
28 changes: 23 additions & 5 deletions .github/workflows/pr-auto-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# reusable workflow above.
# • You MAY change: the workflow name(s) in `workflow_run.workflows` to match
# your repository's CI workflow name(s).
# • You MUST NOT change: the `@pr-auto-review/v1-stable` channel in the `uses:`
# • You MUST NOT change: the `@pr-auto-review/v1-ring1` channel in the `uses:`
# line — this reusable is on the org-wide moving-channel model (rollout and
# rollback are a single central tag move; a frozen `@vN`/`@<sha>` pin is
# rejected by the compliance audit). Nor the trigger event types or the
Expand All @@ -28,9 +28,7 @@
# workflow_run fires when a named GitHub Actions workflow completes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This PR introduces a multi-event concurrency/cancel invariant (per-trigger group selection with conditional cancel-in-progress) that no regression guard covers. The repo's own 'Workflow regression guards' job (ci.yml workflow-tests) fixture-protects sibling concurrency invariants — e.g. scripts/test-pr-review-workflow.sh asserts a head-SHA-keyed group and cancel-in-progress: false with negative cases in the companion .test.sh — but nothing guards pr-auto-review.yml. A future standards re-sync could silently regress this expression while YAML still parses. Wire a negative-case guard (e.g. scripts/test-pr-auto-review-workflow.sh + .test.sh) into the workflow-tests job.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/pr-auto-review.yml, line 60:

<comment>This PR introduces a multi-event concurrency/cancel invariant (per-trigger group selection with conditional `cancel-in-progress`) that no regression guard covers. The repo's own 'Workflow regression guards' job (ci.yml `workflow-tests`) fixture-protects sibling concurrency invariants — e.g. `scripts/test-pr-review-workflow.sh` asserts a head-SHA-keyed group and `cancel-in-progress: false` with negative cases in the companion `.test.sh` — but nothing guards `pr-auto-review.yml`. A future standards re-sync could silently regress this expression while YAML still parses. Wire a negative-case guard (e.g. `scripts/test-pr-auto-review-workflow.sh` + `.test.sh`) into the `workflow-tests` job.</comment>

<file context>
@@ -46,13 +44,36 @@ on:
+# A default-branch trigger with no associated PR (fork / no PR) also falls back to
+# the unique-per-run group so unrelated PRs never collapse into one group.
+concurrency:
+  group: >-
+    ${{
+    (github.event_name == 'check_suite' && github.event.check_suite.pull_requests[0].number)
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This finding requires adding test fixtures to guard the concurrency/cancel invariants. The regression guard infrastructure (workflow-tests job + fixture scripts) lives in the CI configuration, not in the workflow stubs themselves. This is outside the scope of syncing workflow stubs from the upstream template. Creating test fixtures for this would be a follow-up task in the test/CI infrastructure, not part of this sync.

Comment thread
don-petry marked this conversation as resolved.
Resolved
# check_suite does NOT trigger for GitHub Actions runs, so this is required
# to catch CI turning green on a PR.
# Set to this repository's CI workflow name(s). TalkTerm's CI workflow is
# named "CI" (see .github/workflows/ci.yml `name: CI`), so the value below is
# already correct for this repo.
# TODO: replace "CI" with your repository's CI workflow name(s).

Check warning on line 31 in .github/workflows/pr-auto-review.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=petry-projects_TalkTerm&issues=AaED-f_sFFJY36NUFMzZ&open=AaED-f_sFFJY36NUFMzZ&pullRequest=529
workflow_run:
workflows: ["CI"]
types: [completed]
Expand All @@ -46,13 +44,33 @@

permissions: {}

# The concurrency group depends on the event context (issue #1126):
# • pull_request / pull_request_review — share one group per PR number and never
# cancel an in-progress run, because these run on the PR head and a cancelled
# run would leave a cancelled `pr-auto-review / check-and-dispatch` check there.
# • check_suite / workflow_run — use a unique group per github.run_id, so separate
# runs never collide. `cancel-in-progress` is enabled for them, but it only
# affects another attempt of the same run (reruns keep the same run ID).
# check_suite and workflow_run events may have multiple associated PRs
# (pull_requests[]), so no array indexing is used; events without a single PR
# context fall back to the unique-per-run group to avoid cross-PR interference
# (petry-projects/.github#1342).
concurrency:
group: >-
${{
(github.event_name == 'pull_request' || github.event_name == 'pull_request_review')
&& format('pr-auto-review-ready-check-pr-{0}', github.event.pull_request.number)
|| format('pr-auto-review-ready-check-unique-{0}', github.run_id)
}}
cancel-in-progress: ${{ github.event_name == 'check_suite' || github.event_name == 'workflow_run' }}

jobs:
pr-auto-review:
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
uses: petry-projects/.github/.github/workflows/pr-auto-review-reusable.yml@pr-auto-review/v1-ring1 # NOSONAR(githubactions:S7637) first-party channel ref
secrets:
# Canonical-first fallback (.github-private#1326). The reusable resolves this
# secret BY NAME, so only the VALUE changes — the passed key stays named
Expand Down
Loading