Skip to content

Commit d76facf

Browse files
ci(pm): retire the half-state patrol's schedule — on demand only (#19497) (#19516)
Fixes #19497 Clause-②: no Retires the half-state patrol's schedule under ruling #208 on #19491 (director seat, summon #25), direct-dispatch channel, on the maintainer's verbatim instruction: > 「19491 接受你的建议,并立刻派发处理相关任务。」 R3 of that ruling, verbatim: > **R3** the half-state patrol: ⛔ not frozen, ⛔ not trimmed; its **schedule is retired** (workflow_dispatch only, on demand for the triage seat's daily reconciliation; **#19497**) and the charter's 「锚行未处置 ⛔ 不开新派发」 precondition is deleted (#19496). No line of the 36,717 is edited. and the maintainer's question it answers: 「巡查仪留着却不继续开发,会不会反而不停的报错误的信息」 ## What changed — two files, +89 / −45 **1. `.github/workflows/half-state-patrol.yml`** — the card's change: 1. `on:` drops the `schedule:` block (`37 1,7,13,19 * * *`) and its cadence comment. `workflow_dispatch: {}` and the whole `pull_request:` paths trigger are kept byte-identical, so a PR editing the patrol still proves it on a real runner. 2. The header prose that promised the cadence is rewritten, in seven places, to describe on-demand use and to carry the ⛔ against re-scheduling it on the old argument: the 「why a workflow」 section (kept as history, marked half-superseded), the #13544 correction paragraph, the `Swept` heartbeat paragraph, the new `on:` block prose, the `concurrency` note, the anchor-issue fallback note, and the citation census's HOW OFTEN / WHAT IT COSTS note. 3. ⛔ Not touched, as ruled: `.github/actions/half-state-patrol/action.yml` and `scripts/pm/check-half-states.mjs` — 0 lines of its 36,717. **2. `scripts/pm/dispatch-gates.mjs`** — a forced repair, outside the card's named surface, reported rather than smuggled: Two cases of that tool's self-test read the live `.github/workflows` tree and assert that the specimen workflow declares `schedule`. Retiring the schedule makes both false. Measured before touching them, on the workflow-only commit: `✗ dispatch-gates self-test: 2 of 1883 case(s) failed`, and the two are exactly those. `pnpm check:pm-dispatch-gates` is a required-context gate (`Lint & Repo Gates`) and `scripts/ci/select-gate-families.sh` runs the `pm_dispatch_gates` family for a modified path of class `workflow` (its `*)` arm returns 0), so the red is this PR's, on this PR. The repair is the minimum that makes each case true again, and each keeps the fact it was always about: `'schedule'` drops out of the trigger list one case asserts (it still pins that the specimen is not "a workflow no PR runs"), and `&& isScheduled('half-state-patrol.yml')` drops out of the other (it still pins that the live sweep is withheld by the value-bearing class and nothing else). ⛔ Nothing is added: pinning the ABSENCE of a schedule would be a new ratchet, which ruling #208's R6 does not let this file grow without the maintainer's sentence. A comment above the pair records the ruling so the next reader does not restore the pin. If the director seat would rather this file were not touched at all, the alternative is to land the sibling card first or to leave the PR red by design — flagged in the report's `open_questions`, not decided here. No step, permission, job, timeout or input of the workflow changed. Parsed after the edit: ``` top keys: ['name', True, 'permissions', 'concurrency', 'jobs'] on: {'workflow_dispatch': {}, 'pull_request': {'paths': ['scripts/pm/check-half-states.mjs', 'scripts/invoked-as.mjs', 'scripts/pm/sweep-closed-cards.mjs', 'scripts/check-issue-citations.mjs', '.github/actions/half-state-patrol/**', '.github/workflows/half-state-patrol.yml']}} jobs: ['patrol'] steps: ['Checkout repository', 'Setup Node.js', 'Sweep the board and update the anchor', 'Sweep the closed cards', "Census the repo's issue citations"] ``` ## Census — every other path into the patrol, file by file Population: `git grep -ni 'half.state' -- .github` = 15 files at 2cac363. Dropping comment lines leaves **four** non-comment references outside the patrol's own two files: ``` .github/workflows/board-snapshot.yml:176: - 'scripts/pm/check-half-states.mjs' .github/workflows/lint.yml:1189: - name: PM half-state sweeper self-test .github/workflows/lint.yml:1190: run: pnpm check:pm-half-states .github/workflows/test-nightly-tiers.yml:442: // scripts/pm/check-half-states.mjs. ⛔ Do not re-derive 65,536 from ``` and exactly one `uses:` of the action anywhere in the tree (`half-state-patrol.yml:236`, the local path). | file | runs the patrol? | scheduled? | verdict | |---|---|---|---| | `.github/workflows/half-state-patrol.yml` | **yes** — `uses: ./.github/actions/half-state-patrol` | was `37 1,7,13,19 * * *` | **schedule removed here**; the call stays, `workflow_dispatch` + `pull_request` stay | | `.github/actions/half-state-patrol/action.yml` | it *is* the patrol body | composite action — declares no trigger of its own | untouched by ruling | | `.github/workflows/board-snapshot.yml` | **no** — it runs `scripts/pm/board-snapshot.mjs`; its one non-comment reference is a `pull_request: paths:` entry, because the archiver imports the sweeper's proxy-re-exec plan. Its other three hits are prose (the request budget it shares, and the cron offset it chose against the patrol). | yes, `7 2,8,14,20 * * *` — its own archiver cadence | **keeps its schedule and its call**: it is not a path into the patrol | | `.github/workflows/lint.yml` | **no** — `pnpm check:pm-half-states` is the sweeper's OFFLINE `--self-test` (no network, no token, no board read, no anchor write), which lint.yml's own comment separates from the live sweep at length | yes (hourly full run) | **keeps both**; the self-test's PR-time scoping is the sibling card's, not this one's | | `.github/workflows/test-nightly-tiers.yml` | **no** — one `//` comment citing where a constant comes from | yes | untouched | | `.github/workflows/checklist-status.yml`, `.github/workflows/merged-branch-reaper.yml` | **no** — 0 hits for `half.state`; they were hits on a wider grep only for their own `:37` cron minute | yes (`37 3 * * 1`, `37 4 * * 1`) | untouched | | `closing-target-claim-guard.yml`, `cross-repo-issue-closer.yml`, `cut-rc.yml`, `merge-queue-triage.yml`, `platform-checklist-watchdog.yml`, `release-coverage-patrol.yml`, `required-set-patrol.yml`, `scheduled-full-run-card.yml`, `shard-timings-refresh.yml`, `stale.yml` | **no** — comment text only (`cut-rc.yml` is a false positive: "the doc half states below") | varies | untouched | So: one scheduled invocation of the patrol existed, and it is the one this PR retires. No other workflow loses a call or a schedule. ## H57 — the card's expectation, measured and corrected The card asks this PR to record H57 (「the workflow's latest scheduled run is green and fresh」) as reading the retired schedule as stale on every on-demand run. Measured against `scripts/pm/check-half-states.mjs` at 2cac363, that is not what happens: - `h57Population()` holds a workflow **out** of H57's population when it declares any of `H57_PR_GATING_EVENTS` = `pull_request` / `pull_request_target` / `merge_group`. `half-state-patrol.yml` declares `pull_request` and already did before this PR, so H57 has never judged it (`kind: 'pr-gating'`) and could not report it stale. - After this PR the same workflow is held out one branch earlier, as `kind: 'not-scheduled'`. The only H57-visible change is in its unconditional population clause: one fewer workflow "declares a schedule", one fewer held out as PR-gating. No row is filed either way. **The reading that IS stale, and is deliberately left unrepaired here:** `renderCadenceExpectation()` stamps `expected every 6h (...) · next by …` beside `Swept` in the anchor body on **every** run, computed from the sweeper's own `PATROL_CRON` / `PATROL_CADENCE_HOURS` constants — which this PR may not touch (「No line of the 36,717 is edited」). So the next on-demand run publishes a deadline against a schedule nobody fires. The workflow header now says so in place, and the one-line repair is reported as an out-of-scope finding rather than done here. ## Acceptance ``` $ git grep -n 'cron' .github/workflows/half-state-patrol.yml ; echo "exit=$?" exit=1 # 0 hits (was 1 line on 2cac363) $ git grep -c 'workflow_dispatch' .github/workflows/half-state-patrol.yml 3 # was 2 on 2cac363 ``` The card states the control as `= 1`; measured on `origin/main` the same grep answers **2** (the trigger key plus the citation census's cadence note), and this PR takes it to 3 because two rewritten comments name the dispatch path in prose. The load-bearing readings are the ones that cannot be moved by prose: the trigger key appears exactly once (line 174), and the parsed `on:` mapping above contains `workflow_dispatch` and no `schedule`. ## Gates Every family `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives for this diff was run, each exit code captured before any pipe (`cmd > log 2>&1; code=$?`), then reconciled against a fresh derivation: ``` $ node scripts/pm/dispatch-gates.mjs --ran RANFILE --repo objectstack-ai/objectstack Run reconciliation — 48 derived, 48 run, 0 NOT-MEASURED, 0 UNRUN. ✓ dispatch-gates --ran: 48 derived famil(ies) accounted for — 48 run, 0 NOT-MEASURED (a DERIVED zero — all 48 recorded an exit code and none of them is 3). ``` 47 of the 48 exited 0 in one detached battery. The 48th is `pnpm check:pm-dispatch-gates` — the one its own header says to run detached — and it is also the reverse-verification pair for the repair above, both legs measured from committed states: ``` before (51a65a3, the workflow-only commit): ✗ dispatch-gates self-test: 2 of 1883 case(s) failed. ✗ ⭐ the card's own specimen declares a pull_request trigger beside its schedule — … ✗ the card's specimen is still discovered … — not withheld for being scheduled after (dbeb16d, with the two cases re-pointed): ✓ dispatch-gates self-test: 1883 cases pass. check:pm-dispatch-gates: the battery took 1031.6s on this box. :: exit 0 ``` Also run, as the dispatch asks: ``` $ bash scripts/ci/select-gate-families.selftest.sh :: exit 0 all 40 cases passed (192 checks) ``` `actionlint` is not wired in this repo (0 hits over `.github/workflows/*.yml` and `package.json`); the workflow lint here is the `check:workflow-status-functions` / `check:workflow-step-name-quoting` / `check:node-version` / `check:required-contexts` / `check:ci-filter-parity` / `check:self-test-wired` / `check:stall-guard-*` families, all inside the 48 and all green. Stated rather than implied: the 54 artifact-roster families, the 11 wide-population families, the 14 pending-changeset families and the always-runs tail that the same tool prints OUTSIDE the derived 48 were not run here — CI owns those. The branch carries a merge of `main` at 48c39e0 and CI judges the merged generation. ## Tier Tier S in the card's words — measured on the FINAL file list, the register does not hold either path: ``` $ node scripts/pm/check-governed-merges.mjs --branch claude/issue-19497-patrol-schedule-retired derived from `git diff --name-only --no-renames 48c39e0 dbeb16d` (three-dot): 2 path(s). governed-surface predicate: 0 of 2 path(s) hit the register (6 surfaces, repo-agnostic). ✅ NOT governed — ordinary queue landing applies to a PR with exactly this file list. size: 134 changed line(s) (+89 / −45) ≤ 5000 — under the human-merge threshold ``` `skip-changeset`: one `.github/workflows/**` file and one `scripts/pm/**` file. Nothing under `packages/**`, nothing in any package's `files[]`, nothing published. ## Acceptance notes Noted, not filed — stale cadence prose this PR's change makes inaccurate in files it does not own: - `.github/workflows/lint.yml:4742` ("runs REPORT-ONLY in `half-state-patrol.yml`, four times a day"). Successor: the sibling card's dev, already in flight in that file. - `.github/workflows/board-snapshot.yml:38,140` and `.github/workflows/release-coverage-patrol.yml:102,113` — both cite the patrol's retired cron as the reason their own minute/hour was chosen. The offsets they bought stay correct; only the reason is now historical. Successor: none scheduled. - `scripts/pm/check-half-states.mjs` header prose ("a scheduled caller", four runs a day) — under the same ⛔ as its constants; not touched. --- _Generated by [Claude Code](https://claude.ai/code/session_012GcsUbuqFGBibkEDMRC1eE)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent c736eaa commit d76facf

2 files changed

Lines changed: 89 additions & 45 deletions

File tree

‎.github/workflows/half-state-patrol.yml‎

Lines changed: 80 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ name: Half-State Patrol
88
# NOT repo-agnostic — when it runs, what it may touch, the board's own anchor,
99
# and the one step that writes to this repo's cards.
1010
#
11-
# ## Why a workflow, and not "a seat should run it"
11+
# ## Why a workflow at all — the transport, not the calendar
12+
#
13+
# ⚠️ HALF SUPERSEDED (ruling #208 on objectstack#19491, executed by
14+
# objectstack#19497): this file declares NO schedule. The argument below is kept
15+
# as the history that put the patrol on a runner, not as a promise that anything
16+
# fires it. What survives is the transport reason in the next paragraph; what the
17+
# ruling retired is the calendar.
1218
#
1319
# The sweeper carries thirteen predicates over the dispatch protocol's
1420
# label/assignee/PR invariants, and for most of its life its documented consumer
@@ -17,6 +23,10 @@ name: Half-State Patrol
1723
# claims (H2) and an unenumerated backlog sat on the board. Not one predicate had
1824
# fired. A healing mechanism with no scheduled caller heals only in the
1925
# counterfactual, and an alarm added to a script nobody runs is still silence.
26+
# That reading bought the schedule in #9844 and was true of its day. Ruling #208
27+
# re-measured the same instrument and found the standing caller charging more
28+
# than it healed — see the `on:` block below, which carries the reading and the
29+
# ⛔ that goes with it.
2030
#
2131
# "Some seat should run it" also kept not happening for a MEASURED reason, not a
2232
# discipline one: in every container class measured at the time, the live sweep
@@ -37,12 +47,13 @@ name: Half-State Patrol
3747
# `HTTPS_PROXY`, so the sweeper sent the proxy's placeholder token straight to
3848
# GitHub, earned a 401, and reported that refusal as the container's verdict.
3949
#
40-
# ⛔ That does NOT retire this workflow, and the fix deliberately did not touch
41-
# it. The #9844 reason stands on its own and is not a transport reason: an alarm
42-
# whose only caller is "a seat should remember" is silence, whoever CAN run it.
43-
# The on-demand path is restored BESIDE the schedule — a lane that needs the
44-
# board read right now (the 4x/day body trims its own rows, and says so) can now
45-
# get it — never instead of the schedule.
50+
# ⛔ That did NOT retire this workflow either, and the fix deliberately did not
51+
# touch it: a correction about WHO CAN run the sweep is not a ruling about
52+
# WHETHER it should run by the clock, and this file stayed exactly as it was.
53+
# What the correction bought is the path this workflow now runs on ALONE — a lane
54+
# that needs the board read right now (the body trims its own rows, and says so)
55+
# gets it from its own container or from a `workflow_dispatch` here. Since ruling
56+
# #208 that on-demand read is the only read there is.
4657
#
4758
# ## What lands where
4859
#
@@ -52,11 +63,21 @@ name: Half-State Patrol
5263
# archive this needs. The body is owned end-to-end by the generator, so no run can
5364
# leave half of it stale.
5465
#
55-
# The `Swept` timestamp in that body is the patrol's heartbeat and is deliberately
56-
# refreshed even when the findings are unchanged: a timestamp that stops advancing
57-
# is how a reader learns the standing caller died. That is the whole defect class
58-
# this workflow exists to close, so the run must not "optimize away" the no-op
59-
# edit that proves it is alive.
66+
# The `Swept` timestamp in that body is refreshed even when the findings are
67+
# unchanged, and the run must still not "optimize away" that no-op edit — but
68+
# read it for what it now is. With no schedule behind it, the stamp dates the
69+
# last time a seat ASKED for a reconciliation; it is no longer a heartbeat, and a
70+
# `Swept` that stopped advancing means nobody has dispatched the patrol since,
71+
# ⛔ not that a standing caller died.
72+
#
73+
# ⚠️ KNOWN STALE READING, deliberately not repaired here (objectstack#19497): the
74+
# generator stamps a cadence deadline beside `Swept` from its own `PATROL_CRON` /
75+
# `PATROL_CADENCE_HOURS` constants, so the anchor body will keep stamping an
76+
# "expected every 6h · next by …" deadline computed from the schedule string
77+
# those constants still hold — a deadline against a schedule this file no longer
78+
# declares, and nothing on this board fires. The ruling forbids editing the
79+
# sweeper for it (⛔ not one of its 36,717 lines); the repair is filed as its own
80+
# finding instead.
6081
#
6182
# ## Report-only, and the one thing that is NOT report-only
6283
#
@@ -119,23 +140,39 @@ name: Half-State Patrol
119140
# a healthy block.
120141

121142
on:
122-
schedule:
123-
# Four times a day, six hours apart, at :37 past the hour.
124-
#
125-
# The minute is offset ON PURPOSE. The triage Routine that heals these same
126-
# states fires hourly near the top of the hour, and a patrol landing at the
127-
# same minute would keep reading the board mid-heal — reporting half-states
128-
# the healer is in the middle of pairing, i.e. manufacturing findings that
129-
# clear themselves. :37 puts this sweep in the quiet part of the healer's
130-
# cycle in both directions. Four runs/day rather than hourly: H13's own
131-
# threshold is 2h and the incident it comes from sat ~26h, so six-hourly
132-
# detection is two orders of magnitude better than the status quo (never)
133-
# while staying cheap on the core quota this sweep shares with the loop's
134-
# hot path.
135-
#
136-
# The cadence is per-board and stays in the caller: a sibling with a
137-
# different healer cycle picks its own minute here, not in the action.
138-
- cron: '37 1,7,13,19 * * *'
143+
# ⛔ ON DEMAND ONLY — this workflow declares NO schedule, and re-adding one
144+
# takes the maintainer's sentence, not a reading of the history above.
145+
# Ruling #208 on objectstack#19491, executed by objectstack#19497, maintainer
146+
# 「19491 接受你的建议,并立刻派发处理相关任务。」 The triage seat dispatches this
147+
# workflow when it wants the board reconciled; nothing fires it by the clock.
148+
#
149+
# WHAT THE RETIRED SCHEDULE WAS: `37 1,7,13,19 * * *` — four runs a day, six
150+
# hours apart, the minute deliberately off the top of the hour so the sweep
151+
# never read the board mid-heal while the hourly triage Routine was pairing
152+
# states, and four runs rather than hourly because H13's own threshold is 2h.
153+
# None of that was what the ruling found wrong.
154+
#
155+
# WHY IT WENT: the patrol is REPORT-ONLY (see the section above) while the
156+
# dispatch charter made its anchor rows a precondition for opening a dispatch.
157+
# A row misreading a now-legal state therefore cost every executive seat a
158+
# handling step — four times a day, until a dev repaired the row — and the
159+
# sweeper was taking eight such repairs a day in the fortnight before the
160+
# ruling. On the maintainer's question 「巡查仪留着却不继续开发,会不会反而不停的报
161+
# 错误的信息」 the answer measured yes. The ruling stops the clock, ⛔ not the
162+
# instrument: the script keeps every one of its 36,717 lines and stays runnable
163+
# from here, and the charter's precondition is deleted on the sibling card.
164+
#
165+
# ⛔ Do not re-add a `schedule:` block on the argument the history above makes
166+
# ("an alarm nobody runs is silence"). That argument is answered, not
167+
# forgotten: it was weighed against what the standing caller was charging every
168+
# seat, and it lost. If a month passes with nobody dispatching this, the ruling
169+
# is that the sweeper is deleted whole on its own card — ⛔ never quietly
170+
# re-scheduled.
171+
#
172+
# The cadence was always per-board and stays in the caller: a sibling repo that
173+
# wants a scheduled sweep of ITS board declares `schedule:` in its own copy of
174+
# this caller and picks its own minute against its own healer — never in the
175+
# action, and never by reading a cadence out of this file.
139176
workflow_dispatch: {}
140177
# Changes to the patrol itself get exercised before they merge — the same
141178
# posture as engine-split-metric.yml. On a pull_request run the sweep still
@@ -191,9 +228,10 @@ permissions:
191228
issues: write
192229
pull-requests: read
193230

194-
# One patrol at a time. A scheduled run overlapping a manual dispatch would have
195-
# two runs racing to rewrite the same body, and the loser's findings would vanish
196-
# with no trace but an edit-history entry.
231+
# One patrol at a time. Two dispatches in flight at once — the shape that is left
232+
# now that nothing fires by the clock — would have two runs racing to rewrite the
233+
# same body, and the loser's findings would vanish with no trace but an
234+
# edit-history entry.
197235
concurrency:
198236
group: half-state-patrol
199237
cancel-in-progress: false
@@ -223,8 +261,8 @@ jobs:
223261
# No `pnpm install`: the sweeper imports only `node:` builtins
224262
# (`process`, `child_process`, `fs`, `url`), global `fetch`, and one
225263
# repo-local helper — no npm dependency, so installing the workspace here
226-
# would buy nothing and would give a scheduled patrol a lockfile it could
227-
# fail on.
264+
# would buy nothing and would give this patrol a lockfile it could fail
265+
# on.
228266
#
229267
# `./` — the LOCAL action, deliberately, and this is the one consumer that
230268
# should not pin a sha. A sibling pins one because it wants a reviewed
@@ -246,7 +284,7 @@ jobs:
246284
# travels: the cheapest way to adopt the patrol is still to copy this
247285
# caller, and an unguarded fallback is what would let such a copy
248286
# rewrite some unrelated card in a sibling with this board's findings,
249-
# silently and four times a day. A number is only ever meaningful in
287+
# silently, on every run it is given. A number is only ever meaningful
250288
# the repo it was minted in.
251289
#
252290
# TO ROTATE (here): open a new `tracking`-labeled issue, put its
@@ -418,16 +456,17 @@ jobs:
418456
# `::warning::` carrying the site count. ⛔ NOT the anchor issue — that
419457
# body is owned end-to-end by `check-half-states.mjs`'s generator, and a
420458
# second writer is how half of a generated body goes stale.
421-
# HOW OFTEN: on this workflow's schedule — four times a day, six hours
422-
# apart — plus any `workflow_dispatch`, plus the `pull_request` runs the
423-
# paths filter above admits.
459+
# HOW OFTEN: once per `workflow_dispatch` — this workflow has carried no
460+
# schedule since ruling #208 (objectstack#19497) — plus the
461+
# `pull_request` runs the paths filter above admits.
424462
# WHAT IT COSTS AND WHO PAYS: the census enumerates the whole board once
425463
# (159 requests on this repo at the time of writing, cursor-paginated —
426464
# the alternative is one request per distinct number). It is paid by
427465
# THIS repository's own `secrets.GITHUB_TOKEN` core quota, the same
428-
# 5,000/hour this job already draws the live sweep from: ~636
429-
# requests/day at four runs, under half a percent of a single hour's
430-
# allowance. ⛔ No PAT, no cross-repo credential — the file's own rule.
466+
# 5,000/hour this job already draws the live sweep from: ~159 requests
467+
# per run, ~3% of a single hour's allowance, and no standing daily draw
468+
# at all now that a seat has to ask for each run. ⛔ No PAT, no
469+
# cross-repo credential — the file's own rule.
431470
#
432471
# ⛔ Gated on the repository NAME, for the reason the closed-card sweep
433472
# above states: this script is objectstack-only until a sibling has a

‎scripts/pm/dispatch-gates.mjs‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20667,9 +20667,15 @@ function selfTest() {
2066720667
for (const f of readdirSync(wfDirLive).filter((x) => /\.ya?ml$/.test(x))) {
2066820668
eventsOfWorkflow.set(f, declaredTriggerEvents(readFileSync(nodePath.join(wfDirLive, f), 'utf8')));
2066920669
}
20670+
// ⚠️ The specimen lost its SCHEDULE on 2026-09-21 (ruling #208 on #19491,
20671+
// executed by #19497: the patrol is `workflow_dispatch`-only now, and no line
20672+
// of the sweeper was edited for it). Both cases below are re-pointed at the
20673+
// fact each was always about — the PR-time trigger, and the withholding class
20674+
// — and ⛔ nothing is added: pinning the absence of the schedule would be a
20675+
// new ratchet, which this file may not grow without the maintainer's word.
2067020676
t(
20671-
'⭐ the card\'s own specimen declares a pull_request trigger beside its schedule — half-state-patrol.yml is not a workflow no PR runs',
20672-
['schedule', 'workflow_dispatch', 'pull_request'].every((e) => (eventsOfWorkflow.get('half-state-patrol.yml') ?? []).includes(e)),
20677+
'⭐ the card\'s own specimen declares a pull_request trigger beside its workflow_dispatch — half-state-patrol.yml is not a workflow no PR runs',
20678+
['workflow_dispatch', 'pull_request'].every((e) => (eventsOfWorkflow.get('half-state-patrol.yml') ?? []).includes(e)),
2067320679
);
2067420680
t(
2067520681
'and a genuinely scheduled-only workflow reads as one, so the predicate is not answering `pull_request` to everything (stale.yml)',
@@ -20722,10 +20728,9 @@ function selfTest() {
2072220728
// 3m09s it measured is gone without any scheduled-only rule existing.
2072320729
const sweepEntry = triggerFamilies.find((e) => e.check.startsWith('scripts/pm/check-half-states.mjs'));
2072420730
t(
20725-
'the card\'s specimen is still discovered, still reached only through its patrol, and still classified VALUE-BEARING — not withheld for being scheduled',
20731+
'the card\'s specimen is still discovered, still reached only through its patrol, and still classified VALUE-BEARING — withheld by that class and by nothing else',
2072620732
Boolean(sweepEntry)
2072720733
&& [...sweepEntry.workflows].join('|') === 'half-state-patrol.yml'
20728-
&& isScheduled('half-state-patrol.yml')
2072920734
&& reachesPRTime(sweepEntry.workflows)
2073020735
&& Boolean(sweepEntry.notRunnable)
2073120736
&& !sweepEntry.ciOnly,

0 commit comments

Comments
 (0)