Skip to content

ci: publish the platform checklist status pages to the repository wiki on a schedule - #19162

Open
os-steve wants to merge 4 commits into
mainfrom
claude/issue-19157-checklist-status-workflow
Open

os-steve wants to merge 4 commits into
mainfrom
claude/issue-19157-checklist-status-workflow

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes #19157 — the workflow half (scope item 7), and the last half of that card.

Clause-②: yes (widening)

⚠️ Merge order. The ledger half is a separate draft on claude/issue-19157-checklist-planned-status, and it is what adds pnpm gen:checklist-status. Merging this file first leaves a scheduled job that fails until that PR lands — loudly, which is the right direction, but avoidable. Please land the ledger PR first.

This PR is human-merged, and not because anything here is governed: .github/workflows/** is not on the governed register. The seat token that opened it lacks the workflow scope, so it cannot land this file itself. That is why the workflow is alone in its own pull request instead of riding the ledger change.

What this does

A weekly schedule: plus workflow_dispatch runs pnpm gen:checklist-status, publishes its page set to the repository wiki, and mirrors the report into the job summary. The page set is the maintainer's 「一个可以人工阅读确认的入口」 for 「平台真的功能清单,以及实现状态」:

  • one index page Platform-Checklist — a row per area, which is a row per definition item: area, active count, planned count, link;
  • one Checklist-AREA page per area listing every item as id · title · priority · status · personas, with the planned items in their own section first.

Sixteen pages on the tree as it stands (index + 15 areas). The count is a property of the ledger and is asserted nowhere: the generator writes what it reads.

Why the wiki, and not a page in this tree

Three shapes were ruled out on the card before this one, and each rejection is load-bearing in the file's header:

  • a STATUS.md committed here — a third artifact to keep fresh, whose stale copy reads exactly as authoritative as a current one;
  • a check:checklist-status gate pairing that page against the generator — explicitly ruled out: staleness here is tolerated, not gated, the same standing decision that keeps check:platform-checklist out of per-PR CI;
  • a regen-on-edit rule on whoever touches an area JSON — a rule nobody can enforce is a rule that silently stops being followed.

What is left is a schedule. The wiki is one stable URL, outside branch protection and the merge queue, so publishing there costs no review and blocks no pull request. This job writes to the wiki only — never a commit to this repository, never an issue, never a label.

Two refusals rather than quiet passes

  • Fewer than two pages produced fails the run. An empty ledger and a generator that stopped reading it render the same zero, and the second must never be published as the platform's capability list.
  • An unclonable wiki fails naming the remedy, instead of skipping the publish. An uninitialised wiki cannot be cloned, and a job that quietly skipped would report success forever while nothing was ever published — absence must be loud.

A third guard sits last: a generate step that recorded no exit code at all fails the run, because nothing downstream could tell that apart from exit_code=0.

Page ownership is the generator's naming rule and nothing else — the publish step deletes Platform-Checklist.md and Checklist-*.md before copying, so an area dropped from the ledger does not leave its page standing, and a hand-written wiki page is never collateral.

Measured, and one thing deliberately NOT

The generator, its page set and the counts were measured in the sibling PR; what belongs to this file is its own shape:

  • the YAML parses, and every run: block passes bash -n;
  • triggers are exactly schedule (weekly, 37 3 * * 1, minute offset off the hour and off the sibling patrols), workflow_dispatch, and a pull_request paths-filtered to this one file — so it blocks no unrelated pull request, the posture every patrol in this repo keeps. ⛔ No merge_group:, ⛔ no pull_request_target:;
  • permissions: contents: write and nothing else; concurrency keeps one publisher at a time.

NOT MEASURED: a green workflow_dispatch run. A workflow can only be dispatched once it exists on the default branch, so this acceptance item cannot be taken before this PR merges — by construction, not by omission. The pull_request trigger above exists partly to close that gap early: a run on this PR exercises checkout, Node, pnpm, the generator and the summary rendering on a real runner, and publishes nothing. After merge, one manual workflow_dispatch takes the remaining reading: 16 pages on the wiki, index counts equal to the command output.

⚠️ One environment prerequisite the first run will surface: the repository wiki must already exist. If it has never been initialised, the publish step fails and names the remedy (open the Wiki tab, create any first page once); every run after that overwrites the generated pages.

skip-changeset: a workflow file publishes nothing from any released package.


Generated by Claude Code

…i on a schedule

A weekly `schedule:` plus `workflow_dispatch` runs `pnpm gen:checklist-status`
and publishes its page set to the repository wiki — one index
(`Platform-Checklist`, a row per area with its active and planned counts) and
one `Checklist-<area>` page per area, planned items in their own section first
— mirroring the report into the job summary.

The wiki rather than the tree, by ruling: a generated page committed here is a
third artifact to keep fresh whose stale copy reads exactly as authoritative as
a current one, and the paired `check:` that would have kept it honest was
ruled out too — staleness is tolerated, not gated. The wiki is one stable URL
outside branch protection and the merge queue, so publishing costs no review
and blocks no pull request.

Two refusals rather than quiet passes: fewer than two pages produced fails the
run (an empty ledger and a generator that stopped reading it render the same
zero), and an unclonable wiki fails naming the remedy instead of skipping the
publish. A `pull_request` run — paths-filtered to this file alone — proves the
generator on a real runner and writes nothing.

This file is alone in its pull request and lands by a human merge: the seat
token that opened it lacks the `workflow` scope.

Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2
Co-authored-by: Claude <noreply@anthropic.com>
@os-steve os-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 19, 2026 — with Claude
@github-actions github-actions Bot added the ci/cd label Sep 19, 2026
os-steve and others added 3 commits September 19, 2026 13:49
…mily

`scripts/pm/dispatch-gates.mjs` requires every PATHS-FILTERED workflow to
either discover a `check:` family or declare why it has none, and this one is
paths-filtered by its `pull_request:` trigger (filtered to itself, per the
maintainer's amendment). It ran neither: its only working step invokes
`pnpm gen:checklist-status`, a generator, so `extractCheckInvocations` found
nothing and `declaredNoCheckFamiliesReason` read null. One case of 1866 in
`dispatch-gates --self-test`, and it took the required `Lint & Repo Gates`
context with it.

⛔ The fix is the declaration the tool itself prescribes — the marker the
workflow CARRIES, read fresh on every run — and ⛔ not an exemption list in the
script, which is the second copy of a fact that this whole family exists to
retire. Three workflows in the tree already carry it in exactly this form.

The reason is not an apology: the paired `check:checklist-status` was
explicitly ruled out, staleness of this reading entry is tolerated rather than
gated, and publishing on a schedule is what that ruling left. ⛔ Nothing about
the schedule, the wiki publish or the job-summary mirror is touched.

⚠️ The declaration owns ONE line: a comment directly beneath it in the same
form is read as a CUT reason and refused by name, so the paragraph above it
says not to wrap it.

Measured on this head through the tool's own exported predicates: gaps for
this file [] (was ["checklist-status.yml"]), whole-tree gaps [] over 38
workflows of which 16 are paths-filtered, and the reason reads WHOLE.

Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2
Co-authored-by: Claude <noreply@anthropic.com>
…laration beside it

The declaration added to `checklist-status.yml` is the SEVENTH in the tree, and
the live-marker census pins the roster by NAME with an exact match — so adding
one reds it. That is the pin working, and its own comment says why it is a
roster and not a count: "a bare count reddens for a seventh declaration without
saying which six were already read". The maintenance it forces is this commit.

⛔ The two halves are atomically coupled and cannot be split across PRs: the
declaration without this row reds the census, and this row without the
declaration reds it too (the census reads the live files). They land together
or `dispatch-gates --self-test` is red on `main` either way.

Also bumps the companion `liveMarkerCensus.length === 6` guard, which is the
count half of the same reading, and the prose that states it.

Measured on this head: `node scripts/pm/dispatch-gates.mjs --self-test`
EXIT=0, 1866 cases pass (it was EXIT=1, 2 of 1866, with the declaration alone).
The three rows this touches all read green: the paths-filtered guard at
"gaps: none", the census at seven rows, and "every live reason ENDS on its own
marker line (cut: none)".

Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Seat disposition — the shape stays ONE PR, and this PR now awaits a HUMAN merge

Seat domain:spec#4. Head e56de0963252c1e77a7ae9089610c18bf093175e — read back at GET /commits/… → 200, 4 commits, append-only (26cfdf2f88… is an ancestor), mergeable_state: clean.

The question the dev handed up, answered

The # dispatch-gates: no-check-families -- REASON declaration this PR adds is the seventh in the tree, and the live-marker census pins that roster by name with an exact match — so adding one reds it, and the row must be added with it. ⇒ this PR is no longer .github/workflows/** alone; it also touches scripts/pm/dispatch-gates.mjs.

⭐ Ruling: it stays ONE PR. The two halves are atomically coupled — the declaration without the row reds the census, and the row without the declaration reds it too (the census reads live files) — so splitting them would leave --self-test RED on main in between. ⛔ A landing sequence that reds the default branch between two of its own steps is not a shape this seat will order.

⭐ And the census is behaving exactly as designed. Its own comment says the roster is named rather than counted precisely so that 「a bare count reddens for a seventh declaration without saying which six were already read」. ⇒ the maintenance it forced here is the pin working, ⛔ not friction to route around.

⛔ The path surface changed, so the tier was RE-DERIVED rather than carried over

node scripts/pm/check-governed-merges.mjs --pr 19162exit 0: 「0 of 2 path(s) hit the register (6 surfaces, repo-agnostic) · ✅ NOT governed」. ⇒ the tier did not move. ⛔ This is the register's own verdict on the FINAL file list, ⛔ not a reading carried forward from when this PR was one file — the register has grown several times in two days and a stale tier reading is recall, not measurement.

The fix, and why it is a fix rather than a silencing

The mechanism is the one the tool itself prescribes, in the exact one-line form three workflows in the tree already use. Measured through the tool's own exported predicates before the edit — trigger paths 1, extractCheckInvocations [], declaredNoCheckFamiliesReason null ⇒ gap — and after: gaps [] for the file, and [] whole-tree across 38 workflows / 16 paths-filtered.

Nothing suppressed, ⛔ no ignore list, ⛔ the guard not weakened. The workflow still parses to the same 3 triggers, the same cron, the same self-only paths filter and the same 7 steps — the schedule, the wiki publish and the job-summary mirror are untouched.

⭐ Three rows carry it, and the third is the one that matters: 「every live reason … ENDS on its own marker line (cut: none)」 — a cut refusal, so the one-line spelling is confirmed, ⛔ not assumed, with its lit control green beside it.

Readings, each with its reach

reading value
dispatch-gates --self-test on this head EXIT=0, 1866 pass, 0 failures
intermediate — the declaration alone EXIT=1, 2 of 1866 (the census plus its companion)
intermediate — the head before this work EXIT=1, 1 of 1866 (gaps: checklist-status.yml)
PR check runs, read by the seat at 2026-09-19T08:27:31Z 32 runs · 24 success · 8 skipped · 0 not-green; required Lint & Repo Gates success, and step 32 PM dispatch-gates self-test reads success
check-expected-skips --pr 19162 exit 0 — all 8 skips in the roster, each with a named reason

⚠️ Build Core, Temporal Conformance, Dogfood and the rest are skipped by the paths filter on this diff, ⛔ not failures — which is exactly why entry eligibility is 「every check green or an expected skip」 and ⛔ not the required subset.

⛔ This PR is HUMAN-MERGED, and that does not move

The maintainer's Amendment 2 says so. ⭐ It rests on the seat token's missing workflow scope, ⛔ not on the governed register — which has just re-confirmed this PR is not governed. ⚠️ And the seat measured that the token can perform a server-side update-branch on a branch carrying .github/workflows/** (HTTP 202 earlier on this PR). ⇒ ⛔ what the token can do is not a licence; the maintainer's word stands regardless.

⇒ the PR is flipped ready so a person can act on it, and ⛔ it is not enqueued and ⛔ not auto-merged by this seat.

Ordering — ⭐ discharged, and the note in the header is now moot

PR #19161 merged at 2026-09-19T05:12:32Z; this branch carries it (base updated to c229223e93, and scripts/gen-checklist-status.mjs plus the gen:checklist-status script are on main — measured, ⛔ not assumed). ⇒ the workflow header's ordering warning is moot but left untouched: the narrative is the seat's, and the dispatch's scope was the one gap.

Noted, ⛔ not filed

The dev reports that pgrep -f with a name pattern matched its own wrapper shells and another session's wait loop carrying the same pattern, so three waits read 「STILL RUNNING」 for a self-test that had already written its verdict. AGENTS.md §8 already prescribes recording the PID and ⛔ never matching a name. ⇒ ⛔ no new finding — the existing rule biting, and a name-matched kill would have hit another agent.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review September 19, 2026 08:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants