Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .cursor/BUGBOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
What Bugbot should know before reviewing a diff in THIS repo: the stack, the
conventions that are not enforced by a linter, and the defect classes that
have recurred here. Per-repo by design -- see `.cursor/BUGBOT.md` in
tracebloc/backend for the shape. Presence is asserted by the conformance
(internal ref) for the shape. Presence is asserted by the conformance
audit (repo-inventory.yml `quality_files`); content is yours.
23 changes: 20 additions & 3 deletions .github/workflows/add-to-kanban.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# GENERATED FILE -- DO NOT EDIT BY HAND.
#
# Public-safe copy of `.github/workflows/add-to-kanban.yml` (blob 2a3a432b3d01516575d5c57b9d0a1b2379db299d) for a PUBLIC repo:
# the same workflow, byte for byte, except that its comments are scrubbed as
# described below. Private repos carry the original; the conformance audit
# compares a public repo's copy against THIS file and a private repo's
# against the original.
#
# PUBLIC SURFACE. This file is delivered to a public repo, so its comments carry
# no internal references: each one was replaced with `(internal ref)` by the
# one definition in scripts/public_surface.py (private-repo issue references,
# private repo names, RFC ids, tenant names). A reference anywhere outside a
# comment refuses the render instead of being edited -- it is a defect in the
# source, not a scrub target.
#
# Regenerate: python3 scripts/render-self-contained.py (in tracebloc/org-config)
Comment thread
LukasWodka marked this conversation as resolved.
# Verify: python3 scripts/render-self-contained.py --check (make selftest-self-contained)

name: Add to engineer kanban

on:
Expand All @@ -15,7 +33,7 @@ jobs:
# privilege story covers both credentials in the job rather than just the loud one.
permissions: {}
steps:
# Board writes authenticate as the tracebloc-release-train App (backend#2036),
# Board writes authenticate as the tracebloc-release-train App ((internal ref)),
# not a human's PAT. `owner:` yields an ORG-scoped installation token; a
# repo-scoped one cannot write the org project. No fallback to the PAT: a
# fallback would let a broken App path keep working silently.
Expand Down Expand Up @@ -44,7 +62,7 @@ jobs:
# comment. If it is wrong the failure is LOUD (see below), which is what
# makes trying it cheap.
repositories: ${{ github.event.repository.name }}
# Least privilege (backend#2166): without any `permission-*` the token
# Least privilege ((internal ref)): without any `permission-*` the token
# carries the App's FULL installation grant. actions/add-to-project needs
# THREE scopes, not one: it must RESOLVE the triggering issue/PR node
# before it can add it to the board, so it needs read on both content
Expand Down Expand Up @@ -89,4 +107,3 @@ jobs:
with:
project-url: https://github.com/orgs/tracebloc/projects/2
github-token: ${{ steps.app-token.outputs.token }}

53 changes: 30 additions & 23 deletions .github/workflows/advance-deploy-env.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# GENERATED FILE -- DO NOT EDIT BY HAND (tracebloc/backend#3591).
# GENERATED FILE -- DO NOT EDIT BY HAND.
#
# Self-contained copy of the reusable workflow `.github/workflows/advance-deploy-env.yml`
# (blob 3656a2eaa46555c157af7f713ec7d25f56aa487f) folded with tracebloc/org-config's own caller of it,
Expand All @@ -15,6 +15,13 @@
# read-only App installation token; on a fork PR that token cannot be minted
# (no secrets), so the checkout fails closed rather than running untrusted input.
#
# PUBLIC SURFACE. This file is delivered to a public repo, so its comments carry
# no internal references: each one was replaced with `(internal ref)` by the
# one definition in scripts/public_surface.py (private-repo issue references,
# private repo names, RFC ids, tenant names). A reference anywhere outside a
# comment refuses the render instead of being edited -- it is a defect in the
# source, not a scrub target.
#
# Regenerate: python3 scripts/render-self-contained.py (in tracebloc/org-config)
# Verify: python3 scripts/render-self-contained.py --check (make selftest-self-contained)
#
Expand Down Expand Up @@ -55,7 +62,7 @@
# tracebloc/.github's `scripts/branch_status_map.py` -- read the list there rather
# than from a copy here. The three names this comment used to list were a copy, and
# the table has five.
# A value outside it is REFUSED (backend#2324): the mapper exits non-zero, this
# A value outside it is REFUSED ((internal ref)): the mapper exits non-zero, this
# workflow fails red and the card keeps whatever Status it had. It used to be
# accepted and passed straight to the board write, where it resolves to no option
# id -- and in the closure router that no-write let the project's built-in
Expand All @@ -72,7 +79,7 @@
# not newly shipped. Without this guard, creating a branch (BEFORE = zero
# hash) falls through to the "last 50 commits" range below and mass-advances
# ~50 recent PRs' kanban items — e.g. every time a new `staging` branch is
# cut for a repo (RFC-BACKEND-0008 D8/#1274). Skip create/delete pushes.
# cut for a repo ((internal ref) D8/#1274). Skip create/delete pushes.
if: github.event.created != true && github.event.deleted != true
runs-on: ubuntu-latest
steps:
Expand All @@ -81,7 +88,7 @@
fetch-depth: 0

# The mapping comes from .github, not from a copy in this file: one
# definition of branch -> Status (backend#2243).
# definition of branch -> Status ((internal ref)).
- name: Mint a read-only token for org-config (private; the caller's own token cannot read it)
id: org-config-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
Expand All @@ -107,7 +114,7 @@
# The workflow token, not the App token: this reads `.kanban.yml`
# from the caller's own repo, which is `contents: read` on itself.
GH_TOKEN: ${{ github.token }}
# ONE DEFINITION, SHARED WITH THE CLOSURE ROUTER (backend#2243). This step
# ONE DEFINITION, SHARED WITH THE CLOSURE ROUTER ((internal ref)). This step
# used to hold its own `case` plus its own `yq` read of `.kanban.yml`, and
# the router held two more copies that ignored the override entirely -- so
# with a `.kanban.yml` present the two workflows wrote DIFFERENT statuses
Expand All @@ -123,7 +130,7 @@
run: |
echo "Branch '$BRANCH' is not develop/staging/master/main (and no .kanban.yml override) - nothing to do."

# THIS is the workflow backend#2036 was filed about. On 2026-08-14 at 06:22
# THIS is the workflow (internal ref) was filed about. On 2026-08-14 at 06:22
# UTC, run 31776053792 on client-runtime died with
# gh: API rate limit already exceeded for user ID 54042461
# exit 1 -- because every board caller in the fleet, both crons, the
Expand All @@ -137,7 +144,7 @@
# org ProjectV2.
#
# Minted BEFORE the extract step, because the extract step is its first
# consumer (backend#3447): `/commits/{sha}/pulls` needs `pull-requests: read`,
# consumer ((internal ref)): `/commits/{sha}/pulls` needs `pull-requests: read`,
# and the caller's `github.token` runs under the org default of restricted
# `read` -- contents and packages only -- so under that token the read 403s
# on every PRIVATE repo and succeeds on every public one. From .github#438
Expand All @@ -150,7 +157,7 @@
#
# NO FALLBACK TO THE PAT: a fallback would let a broken App path keep
# working silently, so the migration would look complete while nothing had
# migrated (backend#1680's whole subject).
# migrated ((internal ref)'s whole subject).
- name: Mint an installation token
id: app-token
if: steps.env.outputs.env != ''
Expand All @@ -159,7 +166,7 @@
app-id: ${{ secrets.RELEASE_TRAIN_APP_ID }}
private-key: ${{ secrets.RELEASE_TRAIN_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
# LEAST PRIVILEGE, DERIVED FROM THIS JOB'S OWN CALLS (backend#2157).
# LEAST PRIVILEGE, DERIVED FROM THIS JOB'S OWN CALLS ((internal ref)).
# Without any `permission-*` the token carried the App's FULL installation
# grant -- contents:write included -- across every installed repo. The
# step below makes exactly five kinds of call, and this is the union of
Expand All @@ -179,7 +186,7 @@
#
# `repositories:` STAYS UNNARROWED, but the reason it used to give is gone.
# It cited the closing-issue advancement, which was deliberately cross-repo;
# backend#2722 removed that block, so nothing here reaches outside the
# (internal ref) removed that block, so nothing here reaches outside the
# calling repo any more. `organization-projects` is an ORG-level grant and is
# not narrowed by `owner:` alone either way, so leaving this unnarrowed costs
# nothing measurable -- narrowing it is a plausible tidy-up, but it is a token
Expand All @@ -193,7 +200,7 @@
# branch carrying a PR is the real test; if it reddens, read the failing
# call rather than widening the list back to a full grant.
# `contents: read` IS FOR THE EXTRACT STEP'S CALL SITE, NOT THE MAPPER'S
# (backend#3447). Read this before dropping it again.
# ((internal ref)). Read this before dropping it again.
#
# saadqbal's finding on .github#324 was narrow and is STILL CORRECT, by its
# own test -- check the call site, not the prose. `contents: read` reached
Expand All @@ -212,14 +219,14 @@
# scope is now this token's business, which it was not when #324 was
# written. `fr-gate.yml`'s mint comment ("NOT DERIVED FROM A TEMPLATE")
# records that endpoint as `contents: read + pull-requests: read`, derived
# from its own calls under backend#2157 and running as a required check on
# from its own calls under (internal ref) and running as a required check on
# every promotion since; no workflow in this repo reads that endpoint under
# `pull-requests: read` alone. Granting only PRs read
# would reproduce backend#3447 one scope over, in the same silent shape:
# would reproduce (internal ref) one scope over, in the same silent shape:
# the read 403s, the fail-closed branch refuses the subject fallback, and
# no card moves on any private repo.
#
# `permission-issues` DROPPED (backend#2722). The only issue reads were
# `permission-issues` DROPPED ((internal ref)). The only issue reads were
# `repository.issue(n) {state, projectItems}` in the removed closing-issue
# block; with it gone, nothing in this workflow touches an issue. Re-add it
# only alongside a call that needs it.
Expand All @@ -236,10 +243,10 @@
# The App token minted ABOVE, not `github.token`: `/commits/{sha}/pulls`
# needs `pull-requests: read` + `contents: read`, and the org-default
# restricted workflow token holds only the latter on a private repo
# (backend#3447; the mint step's comment has the derivation).
# ((internal ref); the mint step's comment has the derivation).
GH_TOKEN: ${{ steps.app-token.outputs.token }}
# DERIVE each commit's PR from GitHub, not from its subject text
# (backend#3365). The org convention `type(scope): summary (backend#N)`
# ((internal ref)). The org convention `type(scope): summary (backend#N)`
# puts a ticket in the `(#N)` slot, and an edited squash subject may carry
# no `(#N)` at all -- so the old subject-grep attributed the wrong card or
# none (2/48 on the 2026-09-07 staging hop). The script GETs each commit's
Expand Down Expand Up @@ -339,9 +346,9 @@
# now -- nothing writes this value yet (#1578 does that, in a LATER
# hop). An unknown Status returns "" here, the guard below fails, and
# evaluation falls through to strict equality: the card BLOCKS every
# prod promotion carrying it. That is the backend#1411 shape, and the
# prod promotion carrying it. That is the (internal ref) shape, and the
# column already EXISTS on the board, so this was a live landmine
# waiting for the first card to land in it (#1577, RFC-BACKEND-1552 D5).
# waiting for the first card to land in it (#1577, (internal ref) D5).
"Staging (agent review)") echo 7 ;;
# `Staging (human review)` IS GONE (saadqbal on .github#295). It ranked
# here as a shim so the monotonic guard stayed stable across the #1592
Expand All @@ -363,7 +370,7 @@
# them. Both returned 0 here, which inverted the monotonic guard below
# so the next push carrying an old commit demoted a Done card -- and
# staging->develop back-merges re-carry old commits routinely
# (RFC-BACKEND-1405 D8, backend#1411).
# ((internal ref) D8, (internal ref)).
"Done") echo 11 ;;
"Cancelled") echo 11 ;;
*) echo 0 ;;
Expand All @@ -377,7 +384,7 @@
# items are already skipped above; this is defense-in-depth for any other
# per-item error -- log it, flag the run, but keep processing the rest.
RUN_FAILED=0
# A FAILED LOOKUP IS NOT AN ABSENT CARD (Bugbot, org-config#3). Counted
# A FAILED LOOKUP IS NOT AN ABSENT CARD (Bugbot, (internal ref)). Counted
# separately from RUN_FAILED because it is a different event: a card
# whose state this run could not READ, as opposed to one it read and
# could not write. The loop keeps going either way -- one 403 must not
Expand Down Expand Up @@ -410,7 +417,7 @@
# `... 2>/dev/null) || RESP='{}'`, so a rate limit, a 403 or a network
# error became an empty object, the item lookup below found nothing in
# it, and the card was "not on project - skipping" -- unmoved, behind
# its shipped code, in a run that stayed GREEN (Bugbot, org-config#3).
# its shipped code, in a run that stayed GREEN (Bugbot, (internal ref)).
# A read that failed is a could-not-tell and is recorded as one.
#
# `gh api graphql` exits 1 for a GraphQL-level error too, and ONE of
Expand Down Expand Up @@ -449,7 +456,7 @@
fi

ITEM_ID=$(echo "$RESP" | jq -r --arg n "$PROJECT_NUMBER" '.data.repository.pullRequest.projectItems.nodes[]?
| select(.project.number == ($n | tonumber)) | .id' 2>/dev/null | head -1)

Check warning on line 459 in .github/workflows/advance-deploy-env.yml

View workflow job for this annotation

GitHub Actions / quality / pipefail early-close

pipefail early-close (YAML run blocks)

pipes into an early-closing reader under errexit+pipefail; use a here-string or capture-then-slice: | select(.project.number == ($n | tonumber)) | .id' 2>/dev/null | head -1)

if [ -z "$ITEM_ID" ] || [ "$ITEM_ID" = "null" ]; then
echo "#$prnum not on project (or not a PR) - skipping"
Expand All @@ -461,14 +468,14 @@
# after it in the push below its deploy column. Archived cards are
# intentionally out of the deploy flow, so skip them cleanly.
ARCHIVED=$(echo "$RESP" | jq -r --arg n "$PROJECT_NUMBER" '.data.repository.pullRequest.projectItems.nodes[]?
| select(.project.number == ($n | tonumber)) | .isArchived' 2>/dev/null | head -1)

Check warning on line 471 in .github/workflows/advance-deploy-env.yml

View workflow job for this annotation

GitHub Actions / quality / pipefail early-close

pipefail early-close (YAML run blocks)

pipes into an early-closing reader under errexit+pipefail; use a here-string or capture-then-slice: | select(.project.number == ($n | tonumber)) | .isArchived' 2>/dev/null | head -1)
if [ "$ARCHIVED" = "true" ]; then
echo "::notice::#$prnum project item is archived -- skipping (out of deploy flow)"
continue
fi

CURRENT_STATUS=$(echo "$RESP" | jq -r --arg n "$PROJECT_NUMBER" '.data.repository.pullRequest.projectItems.nodes[]?
| select(.project.number == ($n | tonumber)) | .status.name // ""' 2>/dev/null | head -1)

Check warning on line 478 in .github/workflows/advance-deploy-env.yml

View workflow job for this annotation

GitHub Actions / quality / pipefail early-close

pipefail early-close (YAML run blocks)

pipes into an early-closing reader under errexit+pipefail; use a here-string or capture-then-slice: | select(.project.number == ($n | tonumber)) | .status.name // ""' 2>/dev/null | head -1)
if [ "$TARGET_RANK" -gt 0 ] && [ "$(rank "$CURRENT_STATUS")" -ge "$TARGET_RANK" ]; then
echo "::notice::#$prnum already at '${CURRENT_STATUS:-none}' (>= '$STATUS_NAME') -- not demoting"
continue
Expand All @@ -485,14 +492,14 @@

# NO ISSUE ADVANCEMENT HERE. This workflow advances PRs only.
#
# It used to also advance the issues each promoted PR closes (backend#1600),
# It used to also advance the issues each promoted PR closes ((internal ref)),
# because the closure router parked a PR-closed issue at `On dev` and nothing
# ever moved it when the code shipped -- it drifted permanently (2026-08-06:
# all 20 drifted cards were closed issues, 0 PRs). That was a real problem and
# #1600 was right to fix it; marching the card through the deploy columns was
# the wrong remedy.
#
# backend#2722 sends a completed issue straight to `Done` in
# (internal ref) sends a completed issue straight to `Done` in
# kanban-closure-router.yml instead. `Done` is terminal, so there is nothing
# left to drift, and kanban-archive sweeps it off the board daily -- which
# answers #1600 more completely than advancing ever did. With no issue parked
Expand Down
23 changes: 15 additions & 8 deletions .github/workflows/bugbot-gate.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# GENERATED FILE -- DO NOT EDIT BY HAND (tracebloc/backend#3591).
# GENERATED FILE -- DO NOT EDIT BY HAND.
#
# Self-contained copy of the reusable workflow `.github/workflows/bugbot-gate.yml`
# (blob c526c0a1f25316f429afbadb00ae1eaa4d0807bc) folded with tracebloc/org-config's own caller of it,
Expand All @@ -15,6 +15,13 @@
# read-only App installation token; on a fork PR that token cannot be minted
# (no secrets), so the checkout fails closed rather than running untrusted input.
#
# PUBLIC SURFACE. This file is delivered to a public repo, so its comments carry
# no internal references: each one was replaced with `(internal ref)` by the
# one definition in scripts/public_surface.py (private-repo issue references,
# private repo names, RFC ids, tenant names). A reference anywhere outside a
# comment refuses the render instead of being edited -- it is a defect in the
# source, not a scrub target.
#
# Regenerate: python3 scripts/render-self-contained.py (in tracebloc/org-config)
# Verify: python3 scripts/render-self-contained.py --check (make selftest-self-contained)
#
Expand All @@ -24,7 +31,7 @@
name: Bugbot review gate

# Reusable workflow. Makes Cursor Bugbot's review a GATE instead of advice
# (tracebloc/backend#2284). `scripts/bugbot-gate.py` carries the measurements and
# ((internal ref)). `scripts/bugbot-gate.py` carries the measurements and
# the reasoning; this file is the wiring, and only says what the script cannot.
#
# THE SHORT VERSION OF WHY THIS IS NOT "ADD `Cursor Bugbot` TO THE REQUIRED
Expand All @@ -38,26 +45,26 @@ name: Bugbot review gate
# a finding, because Bugbot re-runs only on a push or an explicit
# `bugbot run`, so resolving a finding can never turn the check green again
# -- and a promotion PR may not be pushed to at all. client#786 and
# frontend-app#863 both merged to `main` on 2026-08-21 carrying exactly that
# (internal ref) both merged to `main` on 2026-08-21 carrying exactly that
# state (`neutral` on the merged head, one resolved Medium beneath).
#
# So the verdict is REPORTED here and the decision is derived from the threads.
#
# ARMING THIS IS THREE STEPS, IN THIS ORDER, AND THE ORDER IS THE POINT.
#
# 1. this file reaches `main`. Every caller in this org pins
# `tracebloc/.github/...@main` (RFC-BACKEND-1405 Q3), so a caller added
# `tracebloc/.github/...@main` ((internal ref) Q3), so a caller added
# before the reusable is ON main references something main does not have and
# dies with a `startup_failure` -- a red check on the very PR introducing a
# gate. code-quality-caller.yml records the identical sequencing for its
# `action-pins` input: the job went to develop in #159 and was armed only
# once `main` carried it. That is why the PR adding THIS file adds no caller.
# 2. a caller is added, starting with tracebloc/.github itself. The gate is
# ADVICE at this point, and saying so plainly is the whole of backend#2284.
# ADVICE at this point, and saying so plainly is the whole of (internal ref).
# 3. the `bugbot / review` context is added to branch protection, once step 2
# has been observed green on real PRs.
#
# Never the reverse. backend#1976's lesson is that a contract claiming a context
# Never the reverse. (internal ref)'s lesson is that a contract claiming a context
# reality lacks is itself a finding; and a required context no workflow reports
# leaves every PR waiting forever (client#665, pii-gate/pii-check). Arm while
# green, then let the contract claim it.
Expand Down Expand Up @@ -91,7 +98,7 @@ name: Bugbot review gate
# The consequence is written into the failure message rather than left to be
# discovered: resolve the thread, then RE-RUN this check. Not "push a commit",
# which is what a stale gate otherwise teaches. Adding the trigger when
# actionlint learns the event is a follow-up on backend#2284.
# actionlint learns the event is a follow-up on (internal ref).
#
# THIS JOB WAITS, on purpose. Its central claim is that Bugbot reviewed the
# CURRENT head, which is false for the first minutes after every push -- so it
Expand Down Expand Up @@ -166,7 +173,7 @@ jobs:
env:
# `github.token`, not `secrets.inherit`: this needs only the scopes
# declared above, and inheriting would hand it every secret the caller
# holds for no gain (RFC-BACKEND-1405 Q5).
# holds for no gain ((internal ref) Q5).
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
Expand Down
Loading
Loading