Skip to content

Commit 3fcafcd

Browse files
ci: fold the four daily patrols into one fleet-patrols.yml workflow (1 of 3) (#26512)
<!-- claude-projects-attribution: {"github_login":"os-warren"} --> _Requested by **Warren** · [project thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Bh55CNSFH3iN1HNN1Gog95)_ Part of #26071 Clause-②: no Metadata-protocol: none Ruling-ref: `Ruling: batch #397 item 2 · letter A · maintainer 「同意」` — comment 6416984681 on #26071 (director seat, 2026-10-26T13:18Z). This PR is (ii) of letter A, the first of three serial PRs from one card thread: (ii) the four daily patrols → one workflow (this), then (iii) the four PR-body guards → one workflow, then (i) the `lint.yml` schedule skip. The card closes with the last one. Head branch `claude/project-thread-31axox` is the card thread's harness push branch (the measured platform exception to `claude/issue-N-slug`; the next two PRs use `-2` and `-3`). ## 维护者速读 - **改了什么**:四个日巡逻 workflow(required-set-patrol、platform-checklist-watchdog、release-coverage-patrol、board-snapshot)合为一个 `.github/workflows/fleet-patrols.yml`,四个 job 各守自己原来的 cron;每个 job 的 steps、permissions、concurrency、env 与原文件解析后逐项相同(脚本比对,见 Tests)。读这些文件名的两个门禁(`check-required-contexts` 的 `PATROL_WORKFLOW`、watchdog 静态 pin 的文件名与 `pull_request` 路径白名单)、锚点渲染器发布的文案、归档器的 adopt 清单、两份 checklist 文档改指新文件。 - **为什么改**:裁决 A(批 #397 第 2 项,「同意」)的 (ii):四个文件各自 checkout + setup、各占一个 workflow;合为一文件四 job 省文件不省信号 —— 失败信号、最小权限、并发组都留在 job 级,没有一项上提到 workflow 级。 - **风险与回滚**:纯搬运,不改任何判定逻辑。风险两处:① 每个 job 的 `if:` 必须命中自己的 cron —— `github.event.schedule` 与 `on.schedule` 里的字符串是同一事实写两遍,文件头注已标 ⛔ 同改;② `pull_request` 触发是四个原过滤器的并集,所以改 `scripts/pm/board-snapshot.mjs` 之类的 PR 现在也跑 watchdog job(不阻塞:它不是 required context,checklist 红也不红 job)。回滚 = revert 本 PR,四个原文件原样回来。 - **先看**:① `fleet-patrols.yml` 四个 job 的 `if:`(各 job `name:` 下方三行)与 `on.schedule` 的四条 cron;② `scripts/check-platform-checklist-watchdog.mjs` 的 `PR_TRIGGER_ALLOWED_PATHS`(冻结的并集)与 clause 4 文案;③ `scripts/check-required-contexts.mjs` 的 `PATROL_WORKFLOW`。 - **两分钟验证**:`node scripts/check-platform-checklist-watchdog.mjs --self-test && node scripts/check-platform-checklist-watchdog.mjs && pnpm check:required-contexts` —— 三条 OK 行;落地后在 Actions 页对「Fleet Patrols」点 Run workflow,`patrol` 选 `required-set-patrol`,应只跑那一个 job,其余三个 skipped。 - **需要你做的**:Approve(Tier H,`.github/workflows/**`);席位随后落地。 ## What changes File by file, against the retired workflow(s). ### `.github/workflows/fleet-patrols.yml` (new) ← `required-set-patrol.yml`, `platform-checklist-watchdog.yml`, `release-coverage-patrol.yml`, `board-snapshot.yml` (deleted) - **`on.schedule`** — the four crons, each under the retired file's own cron comment, re-read on this tree and equal to the card's measurement: `23 4,16 * * *` (required-set), `51 2 * * *` (watchdog), `19 4 * * *` (release-coverage), `7 2,8,14,20 * * *` (board-snapshot). - **`on.workflow_dispatch`** — one `patrol` choice input (`all` by default, or a job id) so a manual fire or smoke test can target one patrol, as each retired file allowed, without spending the archiver's 800-request budget to smoke-test the watchdog. - **`on.pull_request.paths`** — the union of the four retired filters, each retired file's own path replaced by the new file: `.github/workflows/fleet-patrols.yml`, `scripts/check-required-contexts.mjs`, `scripts/check-release-section-coverage.mjs`, `scripts/pm/board-snapshot.mjs`, `scripts/pm/check-half-states.mjs`, `scripts/invoked-as.mjs`. A matching pull request runs all four jobs; none writes anything on a `pull_request` event (every board write keeps its `github.event_name != 'pull_request'` guard, which the watchdog pin judges across every job of the file). - **No workflow-level `permissions:`, `concurrency:` or `env:`.** Each job carries the retired file's blocks at job level, unchanged: - `required-set-patrol` (display name `Live required-set sweep`, was job `sweep`): `permissions: {contents: read}`, concurrency group `required-set-patrol-${{ github.event.pull_request.number || github.ref }}`, `timeout-minutes: 10`, 5 steps. - `platform-checklist-watchdog` (`Platform checklist gate sweep`, was `watchdog`): `{contents: read, issues: write}`, group `platform-checklist-watchdog`, `env` ANCHOR_IDENTITY_LABEL / ANCHOR_TITLE / ANCHOR_MARKER / ANCHOR_ROUTING_LABELS / PATROL_SCHEDULE, `timeout-minutes: 15`, 5 steps. - `release-coverage-patrol` (`Release section-coverage sweep`, was `patrol`): `{contents: read, issues: write}`, group `release-coverage-patrol`, `env.ANCHOR_ISSUE` (the folded scalar, same relative indentation), `timeout-minutes: 10`, 8 steps. - `board-snapshot` (`Snapshot the board to the archive branch`, was `archive`): `{contents: write, issues: read, pull-requests: read}`, group `board-snapshot`, `timeout-minutes: 15`, 9 steps. - **One addition per job, a job-level `if:`** — `(github.event_name != 'schedule' || github.event.schedule == 'ITS CRON') && (github.event_name != 'workflow_dispatch' || inputs.patrol == 'all' || inputs.patrol == 'ITS JOB ID')`. A scheduled run executes exactly one job (the other three read as skipped); a dispatch runs the one the input names; a pull_request run exercises every job. Job ids are the retired file stems; the job display names — the check-run names — are unchanged, so the Checks tab reads as before. - **Comments** — each retired file's header is carried whole as the comment block above its job (headed `formerly .github/workflows/FILE`), and a new file header explains the four clocks, the dispatch input, the union filter and where the retired runs' history is. Four comment edits beyond transport, each because the sentence described the retired file-level shape: (watchdog) "this file carries … `paths`-filtered to THIS FILE AND NOTHING ELSE" → the union, frozen in the pin; (watchdog) "fires only on a pull request editing this workflow" → "… or a sibling patrol's own script", with why that blocks nothing; (board-snapshot) the adopt list's "this file" → "the `board-snapshot` job of it; a repo that wants only the archiver deletes the three sibling jobs and their crons"; (release-coverage) one blank comment line between the carried "Nightly…" and "Two readers, one fact" paragraphs. - **History of the retired files** (hypothesis 4): GitHub keeps a deleted workflow's runs — the Actions sidebar keeps listing each retired workflow by name while runs of it exist, and `GET /actions/workflows/FILE.yml` answers with `state: deleted`. New history lands under "Fleet Patrols", one job per patrol; open a run and read its job list, or filter the run list by job name, to follow one patrol. ### `scripts/check-required-contexts.mjs` - `PATROL_WORKFLOW`: `'required-set-patrol.yml'` → `'fleet-patrols.yml'`; the header sentence that names the standing caller names the job. The wiring battery of `--self-test` now reads the new file: no other workflow wires `--verify-required-set`, the file declares no `merge_group`, no `REQUIRED_CONTEXTS` row names it, and the drift annotation keys on the `✅` clean mark — all green. `REQUIRED_CONTEXTS` itself is untouched (`ci.yml`, `lint.yml`, `governed-surface-guard.yml` only). ### `scripts/check-platform-checklist-watchdog.mjs` - `WORKFLOW_REL` → `.github/workflows/fleet-patrols.yml`. - Clause 4's allowed list `PR_TRIGGER_ALLOWED_PATHS` is the six-entry frozen union above, still compared as a SET, so widening the workflow's filter by one path without the same reviewed edit here reds exactly as before. The refusal text, the `--list` / OK lines and the header say so, and a new header section ("Why the allowed list is more than one entry") records the reason and what the clause keeps. The `GOOD` fixture and `PR_BLOCK` carry the six entries; the widened-by-one and swapped-for-another-file cases still fire, and one case is added — the list minus one sibling input fires on the missing half (clause 4 battery: floor 10, 11 cases; 43 assertions across 8 batteries). - One stale header sentence ("The watchdog carries no `pull_request:` trigger, by clause 3") corrected to clause 4's reality — it contradicted the clause it sat under since the 2026-09-06 ruling. ### `scripts/render-release-coverage-anchor.mjs` - The anchor body's published preamble named `.github/workflows/release-coverage-patrol.yml` as the writer; it names the `release-coverage-patrol` job of `fleet-patrols.yml`. Two comments likewise. **Declared: a file the order's surface did not name.** The string is published to the anchor issue every night, and this rename made it false; os-dev's rule that a change must fix the published text it falsifies applies. Its `--self-test` pins no file name (17 assertions, green). ### `scripts/pm/board-snapshot.mjs` - The adopt list's workflow entry: `.github/workflows/board-snapshot.yml` → `fleet-patrols.yml` (its `board-snapshot` job). **Declared on the same ground**: a comment-only line, but it is the adopt instruction whose own text forbids shortening it from memory. `--self-test` green (169 cases). ### `docs/qa/platform-checklist/README.md`, `docs/qa/platform-checklist/RUNNER.md` - The three lines that name the retired watchdog file name the job of the new file; nothing else. **Not touched, by the order's surface:** `half-state-patrol.yml` and `governed-surface-guard.yml` (not named by the ruling); `REQUIRED_CONTEXTS`; `lint.yml`; `scripts/pm/check-expected-skips.mjs` — its roster names only `pr-automation.yml`, `pack-smoke-optin.yml`, `upgrade-harness-optin.yml` and `ci.yml` rows, no patrol job, so there is nothing to re-point (hypothesis 2 measured). ## Why The ruling (letter A, (ii)): one file per concern, four jobs on their existing crons, each keeping its own failure signal and minimal permissions. This PR is the transport and nothing else — no judgement logic, no cadence, no grant changes. ## Tests **Transport proof** — a scratchpad script parsed `fleet-patrols.yml` and each retired file at `git show d0a7e74:.github/workflows/FILE` with the `yaml` package and deep-compared them: every job's `steps`, `permissions`, `concurrency`, `env`, `name`, `runs-on` and `timeout-minutes` equal the retired file's; `on.pull_request.paths` equals the union of the four retired filters with each file's own path renamed; four crons, 4 of 4; workflow-level `permissions` absent; triggers `schedule, workflow_dispatch, pull_request`; jobs `required-set-patrol, platform-checklist-watchdog, release-coverage-patrol, board-snapshot`. Verdict line: `TRANSPORT CHECK OK`. - `node scripts/check-platform-checklist-watchdog.mjs --self-test` → exit 0 — `OK check-platform-checklist-watchdog self-test: 43 assertions across 8 floored batteries, every clause driven by a fixture that makes it fire.` - `node scripts/check-platform-checklist-watchdog.mjs` → exit 0 — `OK .github/workflows/fleet-patrols.yml: schedule + workflow_dispatch present, pull_request_target / merge_group absent, any pull_request trigger paths-filtered to this file and the sibling patrol jobs' own inputs alone, no board write reachable from a pull_request run, invoked through pnpm check:platform-checklist.` - **Reverse verification of the pin against the live file** (fix committed first; restore by `git checkout HEAD -- FILE`, proven by `git hash-object` equality and an empty `git diff HEAD`): with `docs/qa/platform-checklist/**` injected after `scripts/invoked-as.mjs` in `on.pull_request.paths` (on disk: 1 injected line; a parse shows 7 entries) the gate exits 1 — `… whose paths: filter also names docs/qa/platform-checklist/**.`; restored, exit 0. A first attempt appended the line at the end of the file, which YAML read as a seventh step of the last job rather than a path, so the gate stayed 0: that reading was a no-op and is discarded; the anchored injection is the measurement. - `pnpm check:required-contexts` → exit 0 — the self-test's wiring battery reads `fleet-patrols.yml`: the only wirer of `--verify-required-set`, no `merge_group`, no `REQUIRED_CONTEXTS` row names it, the drift annotation keys on `✅`. - `node scripts/render-release-coverage-anchor.mjs --self-test` → exit 0 (`17 assertions pass`); `node scripts/pm/board-snapshot.mjs --self-test` → exit 0 (`169 cases pass across 13 batteries`). - Not owed: no package `test` / `typecheck` (the diff touches no package source, so ① and ② are empty); `test:repo`, `pnpm lint` and the whole-tree scans are CI's. Dogfood battery: n/a — no `!` in the title and no `(narrowing)` arm. No ablation: no tested behaviour changes; the workflow and the two gate scripts are proven by their self-tests and the reverse verification above. ## Acceptance notes - **The one behaviour change of the transport, stated:** a workflow has one `pull_request:` trigger, so the watchdog job now also runs on pull requests that edit a sibling patrol's script (`scripts/check-required-contexts.mjs`, `scripts/check-release-section-coverage.mjs`, `scripts/pm/board-snapshot.mjs`, `scripts/pm/check-half-states.mjs`, `scripts/invoked-as.mjs`), where before its filter named its own file alone. Those are patrol-tooling pull requests, a few a month; the job publishes no required context and never reds on checklist drift (it reds only when the gate recorded no exit code), so the standing decision's purpose — no unrelated PR blocked by checklist drift — holds. The letter is kept by the pin: the path list is frozen as a set in `PR_TRIGGER_ALLOWED_PATHS`. The alternative — a fifth routing job (`dorny/paths-filter`) with `needs:` + `always()` on every patrol job — was not taken: the ruling says four jobs, and the `if:` subtlety it adds is the transport risk the card names. - **Stale mentions left in place** (comment-only, outside the order's surface; carrier: none — a docs-only sweep if the seat wants one): `.github/workflows/lint.yml:2505` (the checklist NOTE names `platform-checklist-watchdog.yml` as the channel), `merged-branch-reaper.yml:238`, `shard-timings-refresh.yml:217`, `test-nightly-tiers.yml:44`, `scripts/check-platform-checklist.mjs:88,488`, `scripts/check-stall-guard-budget.mjs:457` (a measured job-id-reuse reading: `patrol` was reused across `half-state-patrol.yml` and `release-coverage-patrol.yml`; after this PR it is not), `scripts/ci/board-snapshot-r2-upload.sh:4`, `scripts/import-prerequisite.mjs:235`, `scripts/sync-release-index-currency.mjs:50`, `scripts/pm/dispatch-gates.mjs:329,1840-1842` and `dispatch-gates.self-test.mjs:672,1044` (measurement narratives naming the files as measured). `docs/audits/gate-census-2026-09.md` names the retired files with line numbers as a dated census and is left as the reading it was. `ui/content/docs/guide/ci-cd-pipeline.md` and `ui/scripts/dependabot-merge-gate.mjs` describe objectui's own `board-snapshot.yml`, not this repo's. - **`actionlint`** is not wired in this repository (no reference under `.github/`, `package.json` or `scripts/`); the workflow was parsed with the `yaml` package by the transport check and by the two pins. - **Seat: claim amendment** — the file surface widens by `scripts/render-release-coverage-anchor.mjs` and `scripts/pm/board-snapshot.mjs` (one line each), both declared above. ## Verification Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on head b33a799 (11 paths vs merge base d0a7e74; 2,905 changed lines, under the 3,000 human-merge threshold): 62 families. Each ran in this worktree with the exit code captured before any pipe (`bash -c "$cmd" > log 2>&1; st=$?`), then reconciled: - `node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack` → exit 0 — `✓ dispatch-gates --ran: 62 derived famil(ies) accounted for — 62 run, 0 NOT-MEASURED (a DERIVED zero — all 62 recorded an exit code and none of them is 3).` - `pnpm check:pm-dispatch-gates` → exit 0 — fast tier, 1935 cases, 352 s on this box (`check:pm-dispatch-gates: the battery (the fast tier) took 352.0s on this box.`). - `pnpm --filter @objectstack/lint run check:doc-formula-expressions` first refused (exit 3: `@objectstack/formula` and `@objectstack/lint` not built); after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under `scripts/pm/os-verify-lock.sh` (slot `issue-26071`: `VERDICT command-exit 0 · held the lock 97s`) it exits 0, and the ran list records that re-run. - `actionlint`: not wired in this repository. - `REQUIRED_CONTEXTS` untouched: `scripts/check-required-contexts.mjs` still names only `ci.yml`, `lint.yml` and `governed-surface-guard.yml`. - CI on the PR is not waited for (the order forbids it); the seat reads the check-runs. Every reading above was taken on head b33a799; no commit followed. <details><summary>All 62 derived families, exit 0 each (wall seconds shown where ≥ 10 s)</summary> - `node scripts/check-adr-links.mjs` → exit 0 - `node scripts/check-adr-links.mjs --self-test` → exit 0 - `node scripts/check-aggregator-roster.mjs` → exit 0 - `node scripts/check-aggregator-roster.mjs --self-test` → exit 0 - `node scripts/check-ci-filter-parity.mjs` → exit 0 - `node scripts/check-closing-keyword-parity.mjs` → exit 0 - `node scripts/check-closing-keyword-parity.mjs --self-test` → exit 0 - `node scripts/check-comment-mask-corpus.mjs` → exit 0 (154 s) - `node scripts/check-declaration-mirrors.mjs` → exit 0 - `node scripts/check-declaration-mirrors.mjs --self-test` → exit 0 - `node scripts/check-platform-checklist-watchdog.mjs` → exit 0 - `node scripts/check-platform-checklist-watchdog.mjs --self-test` → exit 0 - `node scripts/check-release-section-coverage.mjs` → exit 0 - `node scripts/check-release-section-coverage.mjs --strict` → exit 0 - `node scripts/check-scripts-symbol-anchors.mjs` → exit 0 - `node scripts/check-scripts-symbol-anchors.mjs --self-test` → exit 0 - `node scripts/check-self-test-wired.mjs` → exit 0 - `node scripts/check-self-test-wired.mjs --self-test` → exit 0 - `node scripts/check-self-test-workflow-commands.mjs` → exit 0 (106 s) - `node scripts/check-self-test-workflow-commands.mjs --self-test` → exit 0 - `node scripts/check-step-collectors.mjs` → exit 0 - `node scripts/check-step-collectors.mjs --self-test` → exit 0 - `node scripts/check-whole-set-label-write.mjs` → exit 0 - `node scripts/check-whole-set-label-write.mjs --self-test` → exit 0 - `node scripts/ci/plan-test-core-shards.mjs --self-test` → exit 0 - `node scripts/docs-audit/check-drift-comment.mjs` → exit 0 - `node scripts/pm/bare-root-worklist.mjs --self-test` → exit 0 (28 s) - `node scripts/pm/board-snapshot.mjs --self-test` → exit 0 - `node scripts/pm/ci-failure.mjs --self-test` → exit 0 - `node scripts/render-release-coverage-anchor.mjs --self-test` → exit 0 - `pnpm --filter @objectstack/lint run check:doc-formula-expressions` → exit 0 (re-run after the formula/lint build; first run exit 3) - `pnpm check:agent-test-spelling` → exit 0 - `pnpm check:bash32-floor` → exit 0 - `pnpm check:cli-command-ids` → exit 0 (16 s) - `pnpm check:cross-package-test-inputs` → exit 0 (35 s) - `pnpm check:declared-population-live` → exit 0 (34 s) - `pnpm check:doc-authoring` → exit 0 - `pnpm check:driver-memory-census` → exit 0 - `pnpm check:entry-guard` → exit 0 (39 s) - `pnpm check:gitlink-declared` → exit 0 - `pnpm check:node-version` → exit 0 - `pnpm check:nul-bytes` → exit 0 - `pnpm check:parse-guard` → exit 0 - `pnpm check:platform-checklist` → exit 0 (28 s) - `pnpm check:pm-board-snapshot` → exit 0 - `pnpm check:pm-dispatch-gates` → exit 0 (354 s) - `pnpm check:pm-expected-skips` → exit 0 - `pnpm check:pm-governed-merges` → exit 0 - `pnpm check:pm-post-stamped` → exit 0 - `pnpm check:pm-record-recognisers` → exit 0 - `pnpm check:pnpm-acquisition` → exit 0 - `pnpm check:pnpm-filter-targets` → exit 0 - `pnpm check:pnpm-flag-spellings` → exit 0 - `pnpm check:ratchet-remedy-authority` → exit 0 - `pnpm check:refd-timer-probe` → exit 0 (21 s) - `pnpm check:required-contexts` → exit 0 - `pnpm check:shard-attestation` → exit 0 - `pnpm check:stall-guard-budget` → exit 0 - `pnpm check:stall-guard-headroom` → exit 0 - `pnpm check:watch-hint-literal` → exit 0 - `pnpm check:workflow-status-functions` → exit 0 - `pnpm check:workflow-step-name-quoting` → exit 0 </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01JQwxbW8nFvKeVjgKv8RTwH)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent c3fb185 commit 3fcafcd

11 files changed

Lines changed: 1499 additions & 1406 deletions

‎.github/workflows/board-snapshot.yml‎

Lines changed: 0 additions & 429 deletions
This file was deleted.

‎.github/workflows/fleet-patrols.yml‎

Lines changed: 1427 additions & 0 deletions
Large diffs are not rendered by default.

‎.github/workflows/platform-checklist-watchdog.yml‎

Lines changed: 0 additions & 427 deletions
This file was deleted.

‎.github/workflows/release-coverage-patrol.yml‎

Lines changed: 0 additions & 308 deletions
This file was deleted.

‎.github/workflows/required-set-patrol.yml‎

Lines changed: 0 additions & 207 deletions
This file was deleted.

‎docs/qa/platform-checklist/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ Why this shape:
211211
census and not a verdict). Adding anchors never reds; ⛔ lowering a floor is
212212
MAINTAINER-ONLY. ⚠️ Note what a red here reaches: `check:platform-checklist` is not
213213
CI-wired (see "Operating cadence"), so it reaches whoever runs the gate — **not every
214-
PR** — plus the daily `platform-checklist-watchdog` workflow, which files or refreshes
214+
PR** — plus the daily `platform-checklist-watchdog` job of `fleet-patrols.yml`, which files or refreshes
215215
one issue when the gate is red.
216216
- **`why` is the debt marker.** A recipe exists because stock fixtures cannot demonstrate
217217
something — the same discipline as a coverage waiver. Landing the fixture in the
@@ -433,7 +433,7 @@ checklist drift. It runs on a **manual / periodic cadence** instead. Run
433433
- **alongside a `checklist-author`** (find gaps) **or `checklist-test`** (execute items).
434434

435435
A red gate does have a reporting channel, and it is not this cadence:
436-
[`.github/workflows/platform-checklist-watchdog.yml`](../../../.github/workflows/platform-checklist-watchdog.yml)
436+
the `platform-checklist-watchdog` job of [`.github/workflows/fleet-patrols.yml`](../../../.github/workflows/fleet-patrols.yml)
437437
runs `pnpm check:platform-checklist` on `main` daily and files or refreshes one issue when
438438
it is red (⛔ and does nothing when it is green). That closes the visibility half only —
439439
the cadence above is still how the gate gets run *before* a red can matter.

‎docs/qa/platform-checklist/RUNNER.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ contract.
1414
**Who sees a red gate.** `pnpm check:platform-checklist` is not wired into per-PR CI (a
1515
standing maintainer decision — see the README's "Operating cadence"), so the channel that
1616
sees its red is
17-
[`.github/workflows/platform-checklist-watchdog.yml`](../../../.github/workflows/platform-checklist-watchdog.yml):
17+
the `platform-checklist-watchdog` job of [`.github/workflows/fleet-patrols.yml`](../../../.github/workflows/fleet-patrols.yml):
1818
it runs the gate on `main` daily, files or refreshes exactly one issue when the gate is red,
1919
and does nothing at all when it is green.
2020

0 commit comments

Comments
 (0)