-
Notifications
You must be signed in to change notification settings - Fork 0
ops(ci): weekly budget-snapshot-cadence workflow (task #297, follow-up to #287) #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,260 @@ | ||||||||||||||||||
| name: budget-snapshot-cadence | ||||||||||||||||||
|
|
||||||||||||||||||
| # Weekly cadence for evidence-based LFG burn tracking. Runs | ||||||||||||||||||
| # tools/budget/snapshot-burn.sh, captures the resulting JSONL row, | ||||||||||||||||||
| # opens a PR (per the AceHack-first UPSTREAM-RHYTHM rhythm) with the | ||||||||||||||||||
| # snapshot included, and arms auto-merge so the row lands without | ||||||||||||||||||
| # human intervention. Closes task #297 (cadence half of the | ||||||||||||||||||
| # evidence-based-budgeting work; tooling was task #285, baseline | ||||||||||||||||||
| # snapshot was task #287). | ||||||||||||||||||
| # | ||||||||||||||||||
| # Why weekly: docs/budget-history/README.md says "On a cadenced | ||||||||||||||||||
| # schedule (weekly) — catches drift when no PRs are merging." Weekly | ||||||||||||||||||
| # is the right balance for a small project — daily produces too many | ||||||||||||||||||
| # rows for the burn pattern to be informative; monthly is too coarse | ||||||||||||||||||
| # for the Stage-1-blocker decision the snapshots were originally | ||||||||||||||||||
| # designed to gate. | ||||||||||||||||||
| # | ||||||||||||||||||
| # Why off-the-hour: GHA cron thundering-herd avoidance per | ||||||||||||||||||
| # .github/workflows/github-settings-drift.yml convention. Sunday is | ||||||||||||||||||
| # chosen over weekdays so the snapshot isn't competing with PR | ||||||||||||||||||
| # cadence for runner minutes. | ||||||||||||||||||
| # | ||||||||||||||||||
| # Security note (safe-pattern compliance per | ||||||||||||||||||
| # https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/ | ||||||||||||||||||
| # ): this workflow consumes only first-party trusted context — | ||||||||||||||||||
| # secrets.GITHUB_TOKEN, github.repository, github.run_id. Every | ||||||||||||||||||
| # expression value is passed via env: into run blocks and quoted | ||||||||||||||||||
| # there as "$VAR"; no expressions are interpolated directly inside | ||||||||||||||||||
| # run-block scripts. The workflow_dispatch `note` input is also | ||||||||||||||||||
| # routed via env: + quoted to neutralise potentially-malicious | ||||||||||||||||||
| # content if an attacker with dispatch permissions tries injection. | ||||||||||||||||||
| # | ||||||||||||||||||
| # Scope coverage limits per docs/budget-history/README.md: | ||||||||||||||||||
| # snapshot-burn.sh works without admin:org but captures the | ||||||||||||||||||
| # scope_coverage block honestly. If the human maintainer later runs | ||||||||||||||||||
| # `gh auth refresh -s admin:org` the snapshots get richer | ||||||||||||||||||
| # automatically (Actions billing / Packages / shared-storage). | ||||||||||||||||||
| # | ||||||||||||||||||
| # AgencySignature v1 attribution (per the post-ferry-7 convention): | ||||||||||||||||||
| # this workflow's commits identify themselves as the | ||||||||||||||||||
| # budget-cadence-workflow agent running on GitHub Actions. The | ||||||||||||||||||
| # Human-Review-Evidence trailer is "signed-policy" because the | ||||||||||||||||||
| # cadence is authorized by docs/budget-history/README.md + | ||||||||||||||||||
| # the maintainer's 2026-04-22 standing direction for evidence-based | ||||||||||||||||||
| # budgeting. | ||||||||||||||||||
|
AceHack marked this conversation as resolved.
|
||||||||||||||||||
| # | ||||||||||||||||||
| # Auto-merge limitation (Codex review #25 P1): events triggered by | ||||||||||||||||||
| # secrets.GITHUB_TOKEN do not fire downstream workflow runs (GitHub's | ||||||||||||||||||
| # anti-infinite-loop guard). That means a PR opened by this workflow | ||||||||||||||||||
| # would never accumulate the required-status-check runs that | ||||||||||||||||||
| # auto-merge needs to fire on, and `gh pr merge --auto` would sit | ||||||||||||||||||
| # in a dead-end. Until a PAT secret is configured, this workflow | ||||||||||||||||||
| # opens the snapshot PR and leaves it for the next human-or-agent | ||||||||||||||||||
| # pass through the queue to merge — explicit-no-auto-merge over | ||||||||||||||||||
| # silent-stall is the operational call. | ||||||||||||||||||
|
|
||||||||||||||||||
| on: | ||||||||||||||||||
| schedule: | ||||||||||||||||||
| # Weekly Sundays 16:23 UTC — off-the-hour weekend slot to | ||||||||||||||||||
| # avoid GHA cron thundering-herd + PR cadence competition. | ||||||||||||||||||
| - cron: "23 16 * * 0" | ||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||
| inputs: | ||||||||||||||||||
| note: | ||||||||||||||||||
| description: "Optional note to attach to this snapshot row" | ||||||||||||||||||
| required: false | ||||||||||||||||||
| default: "" | ||||||||||||||||||
|
|
||||||||||||||||||
| permissions: | ||||||||||||||||||
| # Need contents:write to push the snapshot branch; pull-requests:write | ||||||||||||||||||
| # to open the auto-merge PR. No other permissions needed. | ||||||||||||||||||
| contents: write | ||||||||||||||||||
| pull-requests: write | ||||||||||||||||||
|
Comment on lines
+71
to
+73
|
||||||||||||||||||
| # to open the auto-merge PR. No other permissions needed. | |
| contents: write | |
| pull-requests: write | |
| # to open the PR; and issues:write because `gh pr create --label ...` | |
| # applies labels via the Issues API. | |
| contents: write | |
| pull-requests: write | |
| issues: write |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pin manual cadence runs to main before creating PR
workflow_dispatch runs can be launched against any ref, but this checkout step uses the triggering ref by default. If someone dispatches from a feature branch, the workflow will create ops/budget-cadence-* from that branch and then open a PR to main, which can unintentionally include unrelated feature-branch commits along with the snapshot row. Because this workflow is meant to produce a snapshot-only PR, force the checkout ref (or guard the job) to main for manual runs.
Useful? React with 👍 / 👎.
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tools/budget/snapshot-burn.sh documents that it needs read:org to fetch Copilot billing data, but this workflow passes secrets.GITHUB_TOKEN as GH_TOKEN. GITHUB_TOKEN is repo-scoped and typically cannot access org-level endpoints like /orgs/<org>/copilot/billing, so scheduled runs may record incomplete/incorrect snapshots (and scope_coverage.has_read_org in the row would be misleading). Consider using a dedicated PAT secret with the required scopes for GH_TOKEN, or adjust the snapshot tooling to accurately detect and report missing org access.
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment cites “Grok ferry-16”, but there doesn’t appear to be any in-repo reference/spec with that identifier, making the rationale non-auditable for future readers. Prefer linking to an actual file in this repo that defines the “Squash-Merge Invariant” (e.g., the AgencySignature v1 spec doc under docs/research/...), or remove the external/opaque reference.
| # Open PR with trailer block in body (Squash-Merge Invariant | |
| # per Amara ferry-7 + Grok ferry-16 — no non-trailer text | |
| # after the trailer block). | |
| # Open PR with trailer block in body. Keep the | |
| # AgencySignature/Human-Review trailers as the final block: | |
| # do not append non-trailer text after them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header comment says this workflow “arms auto-merge so the row lands without human intervention”, but the implementation explicitly does not enable auto-merge (see the “Auto-merge limitation” section and the later comment explaining there is no
gh pr merge --auto). Please reconcile the documentation with the actual behavior (either implement auto-merge with an appropriate token, or update the header/purpose text to match reality).