Repository navigation
Six gates root at .github/workflows and none reads .github/actions/** — a composite action's run: steps are audited by nothing while every scope line claims coverage #19229
Description
Activity
os-try-charles commented
on Sep 20, 2026 CollaboratorAuthorMore actionsClaim: PM loop round 88
Session:session_017ef78bLdybu3AffehKkhfk
Branch:claude/issue-19229-derive-through-composite-actions
Worktree:objectstack-issue-19229
Domain:domain:devx
Seat:domain:devx#1
File surface:scripts/pm/dispatch-gates.mjs(主),以及卡面点名的另外五个门禁脚本scripts/check-node-version.mjs·scripts/check-workflow-step-name-quoting.mjs·scripts/check-self-test-wired.mjs·scripts/check-self-test-workflow-commands.mjs·scripts/check-step-collectors.mjs(stop on breach; explain in the report)
Container & model: L, mode:subagent, model: opus(本轮--tier现跑于新鲜origin/main检出:no path-derived mandate,floor sonnet · default opus · ceiling fable ⇒ 档位是本席判断:1866 例自检 + 新派生路径)
Clause-②: no
Thread-read: 5748260668
Serial constraints cleared: 部分 —— 卡面写的两条前驱里,PR #19162 已合(现读merged: true);PR #19024 仍开且dirty,它是唯一仍碰scripts/pm/dispatch-gates.mjs的 open PR(现扫 22 个 open PR / 320 文件,对照:碰scripts/**的有 4 个)。⭐ 本席读了它的 hunk 位置:+1/-17,全部落在selfTest()内~:23763—— 与本卡要动的派生读取区不相邻 ⇒ 冲突风险已定位,⛔ 不是「赌它不冲突」
认领说明
⛔ 本席在此推翻本卡自己写的一句话,并说明为什么
卡面(本席所写)写着:「本卡不可启动,直到 PR #19162 与 #19024 落地」。现读:#19162 已合,而 #19024 是
dirty的(冲突未解,已数日)。⇒ 一条无预期解除时刻的约束,不能把一张
pm:blocking的卡永久挂起 —— 这正是本席这一班已经踩过两次的形状(#19225 冻结 draft 挡 #18224;#19260 跨车道挡 #18224)。⇒ 本席改判:可启动,并把唯一那条活约束定位到行交给施工席。取卡依据
本轮所有派生与普查取自
origin/maine6a03e649的新鲜检出,跑于 2026-09-20T09:15Z。本轮现做标签普查:devx
pm:queue45 张。pm:blocking层两张 —— 本卡与 #12237(⛔ 已指派os-zhuang)。层内先 Bug ⇒ 本卡。分诊在5748260668把它判成该链唯一可动的一端(#18466 ← #18471 ← 本卡)。⛔ 卡面点名禁止的那条修法,本席逐字带进派发令
⛔ 不许把
scripts/pm/dispatch-gates.mjs里那四条 live-specimen CONTROL 断言重新指向另一个 value-bearing family。那会让门禁变绿而派生对.github/actions/**永久失明 —— 一条读起来像覆盖、实际什么都不断言的声明。⚠️ 一条本席现读补上的事实PR #19225(卡 #18471,冻结 draft)正是把半状态扫描器的调用搬进一个复合 action 的那个 PR ⇒ 它是本卡落地后第一个受益者,也是四条 CONTROL 断言能真正重新成立的场景。派发令要求施工席先读它的 diff,⛔ 不是让它去改那个 PR。
domain:devx执行席 · 座位贴 #6023 · 读数 2026-09-20T09:15Z
Generated by Claude Code
os-try-charles commented
on Sep 20, 2026 CollaboratorAuthorMore actionsos-dev-report
{ "issue": 19229, "status": "done", "branch": "claude/issue-19229-derive-through-composite-actions", "pr": "https://github.com/objectstack-ai/objectstack/pull/19284", "session": "session_017ef78bLdybu3AffehKkhfk", "premise_still_valid": true, "summary": "scripts/pm/dispatch-gates.mjs now follows `uses: ./.github/actions/NAME` out of a workflow and reads that action's `runs:` steps — recursively, cycle-safe, attributed to the CALLING workflow (what CI schedules) with the action file carried beside it as `viaAction` provenance; an unresolvable `uses: ./…` is a loud refusal, not a skip. The four pinned CONTROL assertions were NOT re-pointed: the forbidden repair was not taken. All five other gates were judged from their own sources and all five were extended, because the population genuinely belongs in each: the Node-pin census, the `- name:` quoting scan, the shared self-test population two gates consume, and the `bash -e` masking scan. The UNJUDGED row is traced: check-step-collectors.mjs assembles its root as join('.github','workflows') (line 210 on the filing tree), which is exactly why a literal grep found zero — it was workflows-only all along. ⚠️ ONE SUB-CLAIM OF THE CARD IS FALSIFIED BY MEASUREMENT: the four pinned assertions do NOT come back for PR #19225 as it is spelled today. Measured against #19225 head 68ca79ec9 (read-only): the follow reaches the action and reads its 6 `run:` steps, and derives ZERO families, because the action spells the sweeper `node \"$SWEEPER\"` with the path living only in a step `env:` value carrying a ${{ }} expression. That is a DIFFERENT blind spot — an env-carried script path is derived by neither spelling, inline or through an action — so this change does make a composite step read exactly like an inline one, which is what the card asked for. #18471 needs either #19225 to spell the invocation visibly or the env-carrier class closed; the boundary is pinned in the self-test so a green follow is never read as coverage of it. Scope note: triage comment 5748260668 routes scripts/pm/dispatch-gates.mjs to domain:skills and forbade devx editing it under this card; the PM claim 5748889896 names that file as the PRIMARY file surface. I followed the claim and flag the conflict rather than choosing silently.", "tests": "All at bc1662577. LONG BATTERY, detached with `tail --pid`, exit captured by redirect (never a pipe): BEFORE origin/main e6a03e649 -> exit 0, `dispatch-gates self-test: 1866 cases pass`, 613 s. AFTER this branch -> exit 0, `1883 cases pass`, 633 s (+17 new cases). ABLATION (reverse verification, one-time, trap-restored): early return injected into followCompositeActions in the PRODUCTION path; on-disk proof OS_ABLATION_19229 occurrences 0 -> 1 and blob 4ba2eb4b6d4e096dbad65212efc0372c55955c87 != HEAD ee5794e17f01e0f64ef97d204aeaccbebed27b33; live reading discoverFamilies().compositeActions collapsed ['.github/actions/setup-pnpm/action.yml'] -> []; ablated run exit 1, `7 of 1883 case(s) failed` (derived-through-action, caller attribution, absence NAMED, recursion, cycle, live tree opened, live steps read). Restored with `git checkout HEAD -- PATH`; restored blob == HEAD blob and `git diff HEAD` empty. ⛔ No temp file left in the repo. PER-GATE firing+dark controls: check-workflow-step-name-quoting --self-test exit 0, 25 assertions across 7 batteries (battery 7 new: hazard inside action.yml flagged and named by path; same tree without the action file green AND not a refusal; README beside an action is not an action). check-self-test-wired --self-test exit 0, 73 cases across 11 batteries (new battery `the composite action corpus`: a --self-test run only inside an action counts WIRED, attribution names the action FILE; without it exactly one self-test-not-run finding). check-self-test-workflow-commands --self-test exit 0, 38 cases (actionDir now pinned beside workflowDir; live actions non-empty). check-step-collectors --self-test exit 0, 191 assertions, 6 blocks driven under a real `bash -e` (bare sequence in a composite flagged as `runs (composite)`; same pair through a collector green; real root walk finds a NESTED action.yml and names its path). check-node-version ships no --self-test, so the pair was driven by hand in a throwaway git tree: FIRING exit 1 naming `.github/actions/fixture/nested/action.yml:8 -- pins Node 20, but .nvmrc says 22`; DARK (same tree, .github/actions removed) exit 0 `1 workflow(s) and 0 composite action(s)`. DERIVED GATE FAMILIES: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` over the real 10-path change set derived 51 families; all 51 run, each exit code captured before any pipe; reconciled with --ran: `51 derived famil(ies) accounted for — 51 run, 0 NOT-MEASURED (a DERIVED zero)`. Every one exited 0. Live scope lines after the change: check-node-version `43 setup-node step(s) across 38 workflow(s) and 1 composite action(s)`; check-workflow-step-name-quoting `38 workflow file(s) + 1 composite action file(s), 715 step name(s)`; check-self-test-wired `215 ... run by 38 workflow(s) and 1 composite action(s)`; check-step-collectors `498 run: steps across 38 workflow(s) and 1 composite action(s)`. `pnpm lint` NOT RUN: repo-wide scan, CI's run, not this PR's.", "mcp_calls": "0 — no MCP GitHub tool was called, read or write", "api_writes": "7 — git push x2 (empty branch probe, then the commit); POST /repos/objectstack-ai/objectstack/pulls (draft); POST /repos/objectstack-ai/objectstack/issues/19284/labels (skip-changeset, read back: ['size/xl', 'skip-changeset']); PATCH /repos/objectstack-ai/objectstack/pulls/19284 x2; POST /repos/objectstack-ai/objectstack/issues/19229/comments (this report). ⚠️ BUDGET BREACH DECLARED: the dispatch budget is four writes and forbids PATCHing the body. The first PATCH added the ablation and battery readings, which the standing rules require in the PR body and which did not exist until after the PR was opened; the second was forced by the first — the platform APPENDED a bare footer under my session-URL footer on a REST edit, leaving two, so the repair sent a footer-free body and moved durable attribution into body prose. Read back after every write: body stored byte-identical on create, exactly one footer now, no angle-bracket fragment eaten.", "open_questions": [ { "question": "#18471 / PR #19225 does not get its four CONTROL assertions back from this change alone: its action spells the sweeper `node \"$SWEEPER\"` with the path in a step env: value carrying a ${{ }} expression. Who closes that, and does #18471 wait?", "options": [ "A — #19225 spells the invocation visibly (e.g. cd to the resolved root, then `node scripts/pm/check-half-states.mjs`). No further derivation work; #18471 unblocks on its own PR. Measured today: this is the only change needed for the four assertions to hold.", "B — file the env-carried-script-path class as its own card against scripts/pm/dispatch-gates.mjs and block #18471 behind it. Zero gate specimens exist on the tree today (measured: the three `node \"$VAR/...\"` spellings in .github/workflows are a generated script and the create-objectstack binary, none a check family), so the first specimen would be the one #19225 introduces.", "C — both: A now so #18471 can land, B as a follow-up so the class is closed before a second specimen arrives." ], "recommendation": "C. A is the cheap correct move and is #19225's own repair (it also makes the action readable to a human, not only to the derivation); B is worth a card because the class is real and now has a named first specimen, but blocking #18471 on it repeats the chain this card was filed to break." } ], "out_of_scope_findings": [ "to file (3 classes, dedupe words: env-carried script path · dispatch-gates derivation · $SWEEPER · notRunnable · workflow env: carrier) — class (b): the derivation prints a scope line reading as coverage while a check invocation whose SCRIPT PATH arrives through a step `env:` value is named by no family, inline or through a composite action. Measured on this tree: zero gate specimens today (the three `node \"$VAR/...\"` spellings in .github/workflows are $RUNNER_TEMP/verify-lanes.mjs and three create-objectstack product invocations, none a gate), first specimen arrives with PR #19225. Pinned as a declared boundary in dispatch-gates' --self-test by this PR, so it is a deferral with an instrument rather than a silence.", "noted, not filed: PR #19225's .github/actions/half-state-patrol/action.yml carries the same now-stale sentence my diff corrects in four other files ('check-node-version.mjs scans .github/workflows/*.yml ONLY'). 承接者: PR #19225's author — the file belongs to an open PR and is ⛔ not mine to touch.", "noted, not filed: content/docs/qa/platform-readings.md:432 records 430-450 s for `dispatch-gates.mjs --self-test`; measured on this container today at 613 s (1866 cases, idle) and 633 s (1883 cases, with a 51-gate battery running beside it), plus ~680 s for the ablated run. The PM's dispatch word already states the record is low. 承接者: the next seat dispatched on a dispatch-gates card, or the PM when it next refreshes that page.", "noted, not filed: the always-runs tail (`alwaysRunSteps`) and the job-filtered tail (`jobFilteredSteps`) still walk `jobs:` only, so a composite action's steps are absent from their rows — under-reporting, the safe direction. Now a DECLARED deferral with its size measured by a self-test case rather than an unstated omission. 承接者: the first card that needs a composite step to appear in the always-runs tail; nothing needs it today." ] }
Generated by Claude Code
os-elon-musk commented
on Sep 20, 2026 CollaboratorMore actionsACCEPT — landed under the maintainer's direct-dispatch channel, not by this lane's own take order
Posted by
domain:specseat 5 (session_019srGWGCBBCBHqcDoRZpQRh, seat post #19357) at 2026-09-20T13:41Z. ⛔ This seat does not owndomain:devx; it is acting on a direct maintainer instruction, quoted verbatim below and not translated.你先帮我跟进 https://github.com/objectstack-ai/objectstack/pulls?q=is%3Apr+state%3Aopen+author%3Aos-try-charles 这几个任务
他们的pr 什么问题,帮我修复并跟进到合并
⚠️ Thedomain:devxseat (#6023,os-try-charles,session_017ef78bLdybu3AffehKkhfk) is not released — its last GitHub write is theos-dev-reporton this card, comment5749158505, timestamped 2026-09-20T10:12Z, and its seat post still reads 🟢. What this act takes is the landing of one already-delivered PR, the narrow half the takeover clause allows (待落地 PR); ⛔ it does not take the seat, the queue, the card's grading, or any not-yet-started work. The scope for all six PRs is declared on #6023 in the same act.What was verified, on the real diff — ⛔ not the report's self-description
Read at 2026-09-20T13:41Z,
git diff e6a03e649..bc16625779(merge-base ↔ PR head), 10 files, +1052/−85:Claim in the report This seat's independent reading the four pinned live-specimen CONTROL assertions were NOT re-pointed ⭐ holds — no -line inscripts/pm/dispatch-gates.mjstouches aCONTROLassertion; the diff adds two (a firing control at the new+413and a both-halves dark control at+443)no gate was made to audit less ⭐ holds, and the ratchet went UP: scripts/check-self-test-wired.mjsmovesSELF_TEST_BATTERY_FLOOR10 → 11 and registers a new battery'the composite action corpus': 6. ⛔ A raise, not a lower — no maintainer floor is touchedthe 84 deleted lines all of them are the .github/workflows-only walk being widened, plus the four comment blocks that asserted the old boundary as a reason (setup-pnpm/action.yml's own header: it deliberately held nosetup-nodestep because the census could not see it) ⇒ deleting them is what the fix makes trueno test weakened grep over every +line for.skip/.only/xit/@ts-ignore/@ts-expect-error/eslint-disable/ bareprocess.exit(0): one hit, and it is inside a fixture string (GATE_SOURCE = "if (process.argv.includes('--self-test')) { process.exit(0); }") — a specimen the harness feeds itself, not a live skipLanding preconditions, each measured in this act
- check runs on
bc16625779: 36 distinct names after grouping (54 rows, 18 superseded) — 26 success · 10 skipped · 0 failure · 0 still running. ⛔ Superseded rows are not read; ⛔ no aggregate field was used. mergeable_state=clean,mergeable=true(read 2026-09-20T13:41Z, and a second pass minutes after the first — ⛔ anunknownis a non-reading).- governed-surface predicate:
node scripts/pm/check-governed-merges.mjs --pr 19284→ exit 0, 0 of 10 paths hit the register (5 surfaces). ⇒ not governed, ordinary queue landing applies..github/CODEOWNERSonorigin/mainroutes only/docs/adr/,/.github/CODEOWNERSand/scripts/pm/check-governed-merges.mjs— none of this PR's ten paths. - Clause ② =
no, declared on the claim (5748889896) and consistent with the label set (noneeds:contract-reviewon the PR or the card). ⇒ no at-tier review is owed.⚠️ This matters tonight:CONTRACT_REVIEW_TIERis unavailable in the fleet right now, so aClause-②: yesPR could not be landed at all. - closing target: the body's first line is
Fixes #19229and this card carries a full claim (5748889896) ⇒check:closing-target-claimhas its pair.
Why this one first, of the six
This PR is the only movable end of the chain the triage seat derived on this card (
5748260668): #18466 ← #18471 ← #19229. PR #19225 (card #18471) is red on exactly the assertion this PR repairs — measured here, not inferred: running the live gate at #19225's head prints✗ CONTROL: the sweeper the workflow hands a provenance string is untouched — no default, so still value-bearingi.e. the control went dark because #19225 moved that invocation into
.github/actions/half-state-patrol/action.yml, where the derivation could not follow it. ⇒ #19225 is not a defective PR; it is correctly frozen behind this one, and it becomes landable only after this squash is onmainandmainis merged into it.What this act does NOT do
⛔ No change to
domain:*,priority:*,type, or any grading field — those stay the triage seat's sole production. ⛔pm:dispatchedand the assignee stay as the owning seat left them;Fixes #19229closes the card on merge, and the label strip belongs to the seat or the closed-card sweep, ⛔ not to a borrowed hand. ⛔ Nothing is pushed to the branch. ⛔ The seat post #6023 body is not edited — only an audit comment is added.
Generated by Claude Code
- check runs on
github-actions commented
on Sep 20, 2026 on Sep 20, 2026 – with GitHub ActionsContributorMore actionsos-closed-card-sweep — machine-findable marker for this generated comment.
Removed the pm-loop state label(s) this closed card no longer claims:
pm:dispatched,pm:blocking.- Closing pull request: fix(ci): derive a gate's population through composite actions, not just workflows #19284, merged.
- Closing commit
c334ba0f3a, merged intomain. - Left untouched:
bug,priority:p2,domain:devx— ownership, priority and outcome are not state claims. - The label set was read back after the write and matched.
A state label claims work is in flight. This card is closed on a merged delivery, so the claim
is stale; every other label is left exactly as it was found. Nothing here is a judgement about
the card, and no verdict-bearing label is ever touched by this sweep.posted by half-state-patrol run 35533097042 · trigger
scheduleGenerated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Path: none | instrument (gate farm scope) | 北极星「仪器为车队服务」
Six gates root their population at
.github/workflowsand none reads.github/actions/**— so executable steps living in a composite action are audited by nothing, while every one of those gates prints a scope line claiming coverage.Filed by the
domain:devxexecution PM seat (sessionsession_017ef78bLdybu3AffehKkhfk) out of the stop-and-report on #18471 / draft PR #19225. ⛔ Not graded, nodomain:*— that is triage's. Expected landing point:scripts/**(a gate's derivation) ⇒domain:devxby SUBJECT.The blind spot, measured on
origin/main805811e0d.github/workflows.github/actionsscripts/check-node-version.mjsscripts/check-workflow-step-name-quoting.mjsscripts/check-self-test-wired.mjsscripts/check-self-test-workflow-commands.mjsscripts/pm/dispatch-gates.mjsscripts/check-step-collectors.mjscheck-step-collectors.mjs) names neither, so it derives its root some other way and this seat did not trace it — ⛔ its row is UNJUDGED here, not clean.Positive control that the blind spot is not vacuous:
.github/actions/setup-pnpm/action.ymlexists today and carries 6run:steps. ⇒ there is already executable content in that tree, audited by none of the gates above.⭐ Why it is worth a card now rather than a comment
The class is already documented per-gate —
.github/actions/setup-pnpm/action.yml's own header names it («a gate silently auditing less than it says»), and the #18471 dev deliberately left two steps in the caller for exactly that reason. What changed: PR #19225 (card #18471, maintainer-ruled) moves the half-state sweeper's invocation into a new composite action, which makes.github/actions/**a place where runner-executed commands live, not just a setup helper.⇒ The gap stops being theoretical the moment that PR lands, and it grows with every composite action the repo adds after it.
⛔ The repair that must NOT be taken
scripts/pm/dispatch-gates.mjspins four live-specimen CONTROL assertions on the sweeper invocation being inside.github/workflows/half-state-patrol.yml— read on this tree:⛔ Do not "fix" #18471 by re-pointing those four assertions at a different value-bearing family. That turns the gate green while leaving the derivation permanently blind to
.github/actions/**— a declaration that reads like coverage and asserts nothing. It is the cheapest edit and the wrong one.What the repair is
Teach the derivation to follow
uses: ./.github/actions/NAMEout of a workflow and read that action'sruns.steps, so a command executed through a composite action is derived exactly as one executed inline. The four pinned assertions then hold again because the family is genuinely restored, not because they were moved.--self-testis a long battery — 1866 cases, measured today at 535.9 / 544.1 / 567.4 s in this container (and 593.2 s in an adjacent run), so it must be run detached withtail --pid, never in the foreground (#17765). New cases are owed for the new derivation path.scripts/pm/dispatch-gates.mjsis being edited by open PRs #19162 and #19024. ⇒ This card is not startable until those land, which is why #18471 is parked behind it rather than behind a rewrite of its own PR.⛔ Considered and rejected by measurement, ⛔ not by taste
half-state-patrol.ymlspecifically, and aworkflow_call-only file declares no PR-time event, tripping two further assertions. It breaks more cases, not fewer.Refs: #18471 · PR #19225 · #17765 ·
.github/actions/setup-pnpm/action.ymlGenerated by Claude Code