|
149 | 149 | # place that has to name it. (The adopted objectui copy carries this row |
150 | 150 | # already; upstream is catching up to its own port.) |
151 | 151 | - 'scripts/invoked-as.mjs' |
| 152 | + # The closed-card sweep this workflow also calls (#16005). Same reasoning |
| 153 | + # as the row above, one file along: a step whose script can change without |
| 154 | + # this trigger firing is a step whose PR-time proof is a coincidence. |
| 155 | + - 'scripts/pm/sweep-closed-cards.mjs' |
152 | 156 | - '.github/workflows/half-state-patrol.yml' |
153 | 157 |
|
154 | 158 | # Least privilege: this job reads the repo and writes exactly one issue BODY. |
@@ -248,6 +252,74 @@ jobs: |
248 | 252 | echo "check-half-states exited $code" |
249 | 253 | cat "$RUNNER_TEMP/report.err" >&2 || true |
250 | 254 |
|
| 255 | + - name: Sweep the closed cards |
| 256 | + id: closed-cards |
| 257 | + # #16005 — the pm-loop state labels are CLAIMS that work is in flight, |
| 258 | + # and GitHub leaves every label in place when a merged `Fixes` pull |
| 259 | + # request closes a card. The seat was paying a hand round trip per |
| 260 | + # landing to remove them (eighteen identical ones in one measured |
| 261 | + # shift). This step is that stroke, mechanized; the script's header |
| 262 | + # carries the ruling it obeys and the window that keeps it to |
| 263 | + # close-time hygiene rather than the backfill the 2026-08-31 maintainer |
| 264 | + # ruling refused. |
| 265 | + # |
| 266 | + # ⛔ Gated on the repository NAME, unlike every other step in this file: |
| 267 | + # this one is objectstack-only until a sibling has both its patrol |
| 268 | + # anchor (objectui#5986) and a copy of the script. A verbatim copy of |
| 269 | + # this workflow in a sibling repo therefore SKIPS this step rather than |
| 270 | + # failing on a missing file. |
| 271 | + # |
| 272 | + # ⛔ This step never fails the job, whatever the sweep returns. The |
| 273 | + # anchor write below is the patrol's product and must not be starved by |
| 274 | + # a step that runs before it; the alarm rides an annotation and the run |
| 275 | + # summary instead. Findings are not a failure condition here either — |
| 276 | + # the same posture the sweep step above takes. |
| 277 | + if: github.repository == 'objectstack-ai/objectstack' |
| 278 | + env: |
| 279 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 280 | + # Same wiring, and the same reason, as the live sweep above: the board |
| 281 | + # this run acts on is the repo this workflow is installed in. |
| 282 | + PM_SWEEP_REPO: ${{ github.repository }} |
| 283 | + PROVENANCE: >- |
| 284 | + posted by half-state-patrol [run ${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) |
| 285 | + · trigger `${{ github.event_name }}` |
| 286 | + # A pull_request run PROVES the step — the transport, the flags and |
| 287 | + # the rendering on a real runner — and writes nothing, exactly as the |
| 288 | + # anchor write below is skipped for it. That convention is this file's |
| 289 | + # and it is load-bearing: a PR must never write to the board. |
| 290 | + SWEEP_MODE: ${{ github.event_name == 'pull_request' && '--dry-run' || '--write' }} |
| 291 | + run: | |
| 292 | + set +e |
| 293 | + node scripts/pm/sweep-closed-cards.mjs "$SWEEP_MODE" --provenance="$PROVENANCE" \ |
| 294 | + > "$RUNNER_TEMP/closed-cards.md" 2> "$RUNNER_TEMP/closed-cards.err" |
| 295 | + code=$? |
| 296 | + set -e |
| 297 | + # Captured with NO pipe in between, for the reason the step above |
| 298 | + # states at length: piped, `$?` is the pipe's status and a red run and |
| 299 | + # a green one read the same. |
| 300 | + echo "exit_code=$code" >> "$GITHUB_OUTPUT" |
| 301 | + { |
| 302 | + echo "### Closed-card sweep — exit $code (\`$SWEEP_MODE\`)" |
| 303 | + echo |
| 304 | + echo '```' |
| 305 | + cat "$RUNNER_TEMP/closed-cards.md" 2>/dev/null || echo '(no report produced)' |
| 306 | + echo '```' |
| 307 | + echo |
| 308 | + echo '<details><summary>stderr</summary>' |
| 309 | + echo |
| 310 | + echo '```' |
| 311 | + cat "$RUNNER_TEMP/closed-cards.err" 2>/dev/null || true |
| 312 | + echo '```' |
| 313 | + echo |
| 314 | + echo '</details>' |
| 315 | + } >> "$GITHUB_STEP_SUMMARY" |
| 316 | + cat "$RUNNER_TEMP/closed-cards.err" >&2 || true |
| 317 | + if [ "$code" = "3" ]; then |
| 318 | + echo "::error::closed-card sweep exited 3 — it could NOT read the board, so it says nothing about whether residue is accumulating. See this run's summary." |
| 319 | + elif [ "$code" != "0" ]; then |
| 320 | + echo "::warning::closed-card sweep exited $code — at least one card was left UNJUDGED. An unjudged card is not a clean card; see this run's summary." |
| 321 | + fi |
| 322 | +
|
251 | 323 | - name: Resolve the anchor issue |
252 | 324 | # An install with no anchor configured has nowhere to land its report, |
253 | 325 | # and the ONLY safe behaviour is to say so loudly (#11217). The two |
|
0 commit comments