Repository navigation
ci(pm): retire the half-state patrol's schedule — on demand only; every scheduled invocation of the patrol action stops (ruling #208 on #19491) #19497
Description
Activity
- addedpriority:p1High: required for production / M2High: required for production / M2
on Sep 21, 2026 os-project-manager commented
on Sep 21, 2026 CollaboratorAuthorMore actionsClaim: objectstack#19497 — director seat, summon #25,
session_012GcsUbuqFGBibkEDMRC1eE, 2026-09-21T04:12Z
Branch:claude/issue-19497-patrol-schedule-retired
Seat: director
Mode: subagent
Clause-②: noDirect dispatch under the maintainer's verbatim 「19491 接受你的建议,并立刻派发处理相关任务。」 (ruling #208 on #19491). File surface declared for the in-flight intersection check: .github/workflows/half-state-patrol.yml (schedule block + header prose) and any other workflow that runs the patrol action on a schedule. Concurrency: three maintainer-directed tooling devs in flight at once for this ruling (#19496, #19497, #19498), disjoint file surfaces; the ≤1 tooling dev rule of ruling #202 B yields to the maintainer's 「立刻派发」 for this batch only. Review: at-tier, diff-scoped, CI read from check-runs (R5's shape, applied to these PRs first).
Generated by Claude Code
os-project-manager commented
on Sep 21, 2026 CollaboratorAuthorMore actionsos-dev-report
Reported 2026-09-21T05:01Z - draft PR #19516, head dbeb16d, branch
claude/issue-19497-patrol-schedule-retired{
"issue": 19497,
"status": "done",
"branch": "claude/issue-19497-patrol-schedule-retired",
"pr": "#19516",
"head": "dbeb16ddbb1032dfd15d69445969ff61fdc5e69a",
"session": "session_012GcsUbuqFGBibkEDMRC1eE",
"premise_still_valid": true,
"summary": "The patrol workflow'sschedule:block (37 1,7,13,19 * * *) is gone;workflow_dispatch: {}and thepull_request:paths trigger are byte-identical, and the header prose that promised the four-times-a-day cadence is rewritten in seven places for on-demand use, carrying the maintainer's sentence and the forbidding of a silent re-schedule. The action file andscripts/pm/check-half-states.mjsare untouched (0 of its 36,717 lines). The census found exactly one scheduled invocation of the patrol in the whole tree — this workflow — so no other file loses a call or a schedule; board-snapshot.yml, lint.yml, checklist-status.yml, merged-branch-reaper.yml and ten prose-only files keep everything they had, listed file by file in the PR body. ONE FILE OUTSIDE THE CARD'S SURFACE WAS TOUCHED AND IS FLAGGED: retiring the schedule falsified two cases ofscripts/pm/dispatch-gates.mjs's self-test that read the live workflows tree and assert the specimen declaresschedule(measured red first: 2 of 1883, and no others);check:pm-dispatch-gatesis a required context and the CI family selector runs it for aworkflow-class path, so the pin was repaired in the same change that made it false, minimally, adding nothing.",
"tests": "48 of 48 derived families run and reconciled:node scripts/pm/dispatch-gates.mjs --ran RANFILE --repo objectstack-ai/objectstack-> 'Run reconciliation - 48 derived, 48 run, 0 NOT-MEASURED, 0 UNRUN' and 'a DERIVED zero - all 48 recorded an exit code and none of them is 3'. 47 exited 0 in one detached battery (exit code captured before any pipe: cmd > log 2>&1; code=$?). The 48th,pnpm check:pm-dispatch-gates, is the reverse-verification pair for the repair, both legs from committed states: BEFORE (51a65a3, workflow-only) '✗ dispatch-gates self-test: 2 of 1883 case(s) failed' naming exactly the two schedule pins; AFTER (dbeb16d) '✓ dispatch-gates self-test: 1883 cases pass' + 'the battery took 1031.6s on this box', exit 0. Alsobash scripts/ci/select-gate-families.selftest.shexit 0, 'all 40 cases passed (192 checks)'. Acceptance greps:git grep -n 'cron' .github/workflows/half-state-patrol.yml= 0 hits (exit 1), was 1 line on the base tree; controlgit grep -c 'workflow_dispatch'= 3 (was 2 - the trigger key plus two rewritten prose mentions; the trigger key itself is exactly one, line 174) and the parsedon:mapping reads {'workflow_dispatch': {}, 'pull_request': {...}} with no schedule.node scripts/pm/check-governed-merges.mjs --branch claude/issue-19497-patrol-schedule-retiredon the final file list: '0 of 2 path(s) hit the register ... NOT governed', 134 changed lines. actionlint is not wired in this repo (0 hits in .github/workflows/*.yml and package.json). NOT MEASURED: the 54 artifact-roster families, 11 wide-population families, 14 pending-changeset families and the always-runs tail the same tool prints outside the derived 48 - CI owns those.",
"mcp_calls": "0 - no MCP tool was called, GitHub or otherwise",
"api_writes": "2 - POST /repos/objectstack-ai/objectstack/pulls (draft PR 19516), POST /repos//issues/19497/comments (this report, via scripts/pm/post-stamped.mjs). No labels, no assignee, no ready flip, no PATCH of any body, no issue created. Four git pushes to the feature branch are outside the REST budget.",
"open_questions": [
{
"question": "scripts/pm/dispatch-gates.mjsis ruled 'kept frozen' by R6, yet this PR edits two of its self-test cases because retiring the schedule makes them false and the gate is a required context. Is the forced pin repair inside the freeze or outside it?",
"options": [
"A - keep it here: the repair is the smallest thing that makes a required gate true again, adds no assertion, and is the same PR that falsified the pin",
"B - split it into its own PR so the card's diff stays inside its named surface, and land that one first",
"C - revert the repair and let the PR sit red until the sibling card's work lands, on the argument that the freeze binds absolutely"
],
"recommendation": "A, because the pin is false only because of this change, and a PR that knowingly leaves a required context red onmainis the expensive option; B costs a second round and lands the same two lines; C leaves a false pin onmainfor as long as it takes."
}
],
"out_of_scope_findings": [
"to file (3 classes, dedupe words: PATROL_CRON, renderCadenceExpectation, anchor cadence deadline, half-state heartbeat, retired schedule) - class (a):renderCadenceExpectation()in scripts/pm/check-half-states.mjs stamps 'expected every 6h (...) - next by ...' besideSweptin the anchor body on EVERY run, computed fromPATROL_CRON/PATROL_CADENCE_HOURS, so from this PR onward the pinned anchor publishes a deadline against a schedule nothing fires. One-line shape: render the cadence clause only when the caller passes a schedule, i.e. make the constants optional rather than assumed. Blocked by the ruling's 'no line of the 36,717 is edited' - a seat must file it and a later card must land it.",
"noted, not filed: the card's item-3 expectation about H57 is falsified and the PR body carries the measurement -h57Population()holds any workflow declaringpull_requestout of H57's population (H57_PR_GATING_EVENTS), and half-state-patrol.yml declaredpull_requestbefore this PR, so H57 never judged it and could not have read the retired schedule as stale. After this PR it is held out one branch earlier, asnot-scheduled. The only visible change is the population summary line: one fewer 'declares a schedule', one fewer held out as PR-gating.",
"noted, not filed: stale cadence prose in files this PR 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 cite the retired cron as the reason their own minute/hour was chosen (the offsets stay correct, only the reason is now historical), successor: none scheduled; scripts/pm/check-half-states.mjs header prose ('a scheduled caller'), under the same forbidding as its constants."
]
}
Generated by Claude Code
os-project-manager commented
on Sep 21, 2026 CollaboratorAuthorMore actionsLanding record — director seat, summon #25 (
session_012GcsUbuqFGBibkEDMRC1eE), 2026-09-21T06:09Z. PR #19516 merged through the queue (d76facf22a5daa6c8c642ff595cd0ae681d381ad, 2026-09-21T06:08Z), verified on fetchedorigin/main:.github/workflows/half-state-patrol.ymldeclaresworkflow_dispatchand the pre-existingpull_requestpaths trigger and noschedule(grep on main);.github/actions/half-state-patrol/action.ymlandscripts/pm/check-half-states.mjsuntouched; the twodispatch-gates.mjsself-test pins repaired in the same change. Contract review of record 5755780744 (PASS on headdbeb16dd), provenance 5755791129. Ruling #208 R3's workflow half is thereby in force: the half-state patrol runs on demand only (the triage seat's daily full reconciliation may dispatch it;sweep-closed-cards.mjs's 72-hour default window means at least every three days or a wider--window); the charter half (the anchor is no longer a dispatch precondition) lands with PR #19513. GitHub closed this card on theFixeskeyword;pm:dispatchedremoved in this stroke so the close is whole.
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Path: none | tooling | maintainer-directed (ruling #208 on #19491) — dispatched at filing, never queued
Filed and dispatched by the director seat, summon #25 (
session_012GcsUbuqFGBibkEDMRC1eE), under the maintainer's verbatim direct-dispatch instruction: Ruling #208 on #19491 — maintainer 「19491 接受你的建议,并立刻派发处理相关任务。」 (2026-09-21, chat, on the director seat's 档 2 package R1–R7). Direct-dispatch channel (SKILL.md 〈多仓协调〉规则 4 「维护者直派通道」): the audit quote above is the authorization; ⛔ not a triage grading, ⛔ never queued. The full analysis and measured table are the ruling record on #19491.Why (measured, 2026-09-21T03:43Z,
origin/main4045781)scripts/pm/check-half-states.mjsis 36,717 lines / 2.48 MB with 68Hrows, changed 52 times in 14 days (8 times on 2026-09-20, every one a misread repair). It blocks no branch, but the charter made its anchor rows a dispatch precondition, so a row that misreads a now-legal state costs every executive seat a handling step, four times a day, until a dev repairs the row — the loop the maintainer asked to stop (「留着却不继续开发,会不会反而不停的报错误的信息」 — yes, and this card is the answer). Ruled: retire the schedule, keep the script runnable on demand, delete no line of it; the charter half (the anchor is no longer a precondition) is the sibling charter card filed with this one.The change (
.github/**— not on the governed register: Tier S, the director seat lands it after an at-tier read).github/workflows/half-state-patrol.yml: remove theschedule:block (todaycron: '37 1,7,13,19 * * *'); keepworkflow_dispatch: {}exactly. Rewrite the header prose that explains the four-times-a-day cadence and the:37offset so it describes on-demand use, citing this ruling (objectstack#19491, ruling 🔗 Broken links detected in documentation #208) — the file's own comments must not promise a schedule that no longer exists.git grep -n 'half-state-patrol' .github(PR ci(pm): make the half-state patrol callable instead of copied #19225 made the patrol a callable action,.github/actions/half-state-patrol/action.yml;board-snapshot.yml,checklist-status.yml,merged-branch-reaper.ymlwere hits on a wider grep). Any workflow that runs the patrol action on a schedule loses that call or that schedule in this PR (say which, per file); a workflow that calls it only onworkflow_dispatchor as part of a maintainer-run job stays. ⛔ Do not touch the action file or the script.vars.HALF_STATE_ANCHOR_ISSUE) keeps its last body; the triage seat may run the workflow by hand for its daily full reconciliation. Row H57 (「the workflow's latest scheduled run is green and fresh」) will read the retired schedule as stale on every on-demand run: state this in the PR body as a known, unread reading; ⛔ do not editcheck-half-states.mjsfor it — if a one-line fix exists, put it inout_of_scope_findings.Acceptance
git grep -n 'cron' .github/workflows/half-state-patrol.yml= 0 with controlgit grep -n 'workflow_dispatch' .github/workflows/half-state-patrol.yml= 1; the census of item 2 listed file by file with the verdict per file.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives for a.github/workflows/**diff (workflow lint / self-test-wired / gate-population families), exit codes captured before any pipe;bash scripts/ci/select-gate-families.selftest.shstill passes (it reads lint.yml, untouched here).skip-changeset(nothing underpackages/**).Out of scope
The charter's anchor-precondition lines (sibling card); the self-test scoping in
lint.yml(sibling card); any trimming of the 68 rows (⛔ ruled not now — a PR on a 36,717-line file is its own risk; if the script stays unused for a month it is deleted whole, on its own card).Generated by Claude Code