Repository navigation
ci(governed-surface-guard): the pull_request leg checks out commits and trees only and installs the toolchain on demand - #26311
Conversation
…nd trees only and installs on demand The early-warning leg re-fires on ready_for_review, which is the moment an approver taps merge; for its whole wall the required context sits in_progress and a direct merge is refused. Its judgment reads commits and trees only, so that leg now checks out full history without blobs on a sparse tree of scripts/ and .github/, and acquires the generator toolchain only when the diff touches a register path the lift recomputes (the new --toolchain-needed answer, the same predicate the lift consults). The merge_group leg, the trigger types and the check-run name are unchanged. Claude-Session: https://claude.ai/code/session_01Cpku5P4EYCqaaEGHuMcxik Co-authored-by: Claude <noreply@anthropic.com>
… is its second CI-measured family The install gate reads the event payload, so the live derivation now classifies two invocations of the one queue guard as CI-measured; the pin names both. Claude-Session: https://claude.ai/code/session_01Cpku5P4EYCqaaEGHuMcxik Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cpku5P4EYCqaaEGHuMcxik Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewReviewed at 2026-10-26T20:34Z — PR #26311 at head Served-tier: Inputs read: card #26201 body and its four comments (triage 6420845946, dispatch order 6425237230, claim 6425299365, os-dev-report 6426304526); the PR object, file list and net diff against ① Derived judgmentsRules the diff adds, narrows or removes, each judged against the maintainer's 「立卡」, triage's 「Drop the redundant trigger or the install. Tier H.」, the order's route choice (route 2 first: keep
(a) The refusing leg is untouched — PASS. On (b) Fail-closed on the cheap leg — PASS. (c) The lift and the predicate — PASS. (d) Scope kept vs the claim — surface breach, accepted as the right minimal route; the seat records it by claim amendment. Claim 6425299365 named the (e) The (f) The battery — PASS. The 20 cases pin: every register row has a sample (a new row without one reds); a register path in any row, including a later row, needs the toolchain; empty or undefined rows do not; a governed diff with no register path does not; the lift spy agrees with the predicate in both directions; the answer per event and read state ( (g) Acceptance. Arm 1 (approve + ready starts no new run) is not met by design — the order chose route 2 and kept ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
席位核对 — ACCEPT ·
|
Requested by Warren · project thread
Fixes #26201
Clause-②: no
Metadata-protocol: none
维护者速读(草稿)
改了什么
受管面守卫(
Governed Surface Queue Guard)在 PR 上的那一跑变轻了:只拉提交历史和目录树(不拉文件内容),工作区只铺开scripts/与.github/两个目录,默认不装依赖。合并队列那一跑(真正会拒绝的那条腿)一字未改;检查名不变;翻 ready 时守卫仍会重跑,这是它的设计初衷,保留。为什么改
在手机上批准受管 PR 后马上点合并,会被「required status check is in progress」拒掉:批准后 PR 被翻成 ready,守卫重跑,那一跑约 95 秒里只有 1 秒在判定,其余是拉代码和装依赖。现在这一跑只做判定需要的事,窗口缩到二十秒以内:本 PR 自己那一跑实测 19 秒(此前约 94 秒)。
风险与代价(含回滚)
columns.FIELD.applyOn: 'create') #25813(带生成型 skills 索引文件)上,新旧两种检出跑出的判定逐字节相同。席位意见
你要做的
审阅后批准或直接合并。本 PR 改了
.github/workflows/,属 Tier H,落地需要你本人。What changed
.github/workflows/governed-surface-guard.yml, thepull_requestleg only:merge_groupkeeps the unchanged step (Checkout repository,fetch-depth: 0, full tree).pull_requestgetsCheckout repository (commits and trees only):fetch-depth: 0,filter: blob:none,sparse-checkoutofscriptsand.github.--toolchain-needed. It runs on thepull_requestleg only and appendsneeded=true|falseto$GITHUB_OUTPUT. Every install step is gated on the output being NOT'false', and so is agit sparse-checkout disablestep that restores the full tree first. A skipped question (the queue leg) or a failed one therefore leaves the output empty and installs, which is the previous behaviour.types: [opened, synchronize, reopened, ready_for_review], themerge_grouptrigger, the job idgoverned-surface-guard, the check-run nameGoverned Surface Queue Guard, permissions, concurrency, timeouts and the judgment step.ready_for_reviewnote gains the reason this leg is kept cheap rather than dropped. The "Both legs install" paragraph now reads "wherever the recompute can change the answer".scripts/pm/check-governed-queue-guard.mjs:toolchainNeededFor(rows)is the one predicate.liftGeneratedExceptionsnow consults the recompute iff it answers true, and the workflow installs iff--toolchain-neededanswers true. Membership is still the register'sgeneratedExceptionFor; no path list is restated.readEventDiff(env)is extracted frommain()so the judgment and the toolchain question read the event and the diff one way. The judgment's messages and exit codes are unchanged.toolchainNeededAnswer({ eventName, read })is pure. It answersfalseonly for apull_requestdiff that was read and touches no register path.$GITHUB_OUTPUTon the PR leg only, every install step gated on not-falsewith no== 'true'spelling anywhere, the restore step ahead of the install, and an unconditional judgment step.installStepAuditgains astepBodiesfield with comment lines dropped.scripts/pm/dispatch-gates.self-test.mjs: the LIVE pin "exactly one family classifies CI-measured" became false because of this change.--toolchain-neededreads the event payload, so the live derivation now sees two CI-measured invocations of the one guard. The pin now names both.Route taken against the dispatch hypotheses
ready_for_reviewstays intypes:, and the header's reason for it stands.pull_requestleg is not API-only. Its judgment reads git history:merge-base,log --first-parent,diff-tree --name-only. Those need commits and trees, not blobs. So the leg keepsfetch-depth: 0(the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 reason holds on this leg too) and drops only the blobs.pull_requestleg forecasts the queue verdict, and without the generator toolchain it forecasts a refusal the queue will not make. So the install is not dropped. It is acquired exactly when the lift would recompute, decided by the same predicate the lift uses.actions/github-scriptis not used.Premises (re-measured on
be531f685, the branch base)git grep -n 'ready_for_review'on the workflow finds 2 lines: thetypes:line and one header comment. Controlsynchronize: 1 line.e7b12fdd, filtered toGoverned Surface Queue Guard, are two runs. Run 121428970465 ran 06:21:40Z → 06:22:56Z, before the ready flip. The ready-fired run 121656663464 ran 15:12:37Z → 15:14:11Z (94 s)..github/CODEOWNERS, the workflow file and its own sources underscripts/, plus git objects (commits and trees only). API reads: reviews, the pull object, comments and the timeline, all at the existingpull-requests: read. The static and lazy import graph isnode:built-ins plus relativescripts/**modules only. Measured by running--self-teston an archive of justscripts/and.github/with nonode_modules: 373 cases pass at base, exit 0.Measurements (dev container, 2026-10-26, repository
objectstack-ai/objectstack)scriptsand.githubon the blobless clone: 2.7 s.git sparse-checkout disable) for the toolchain case: 26 s. Thenpnpm install --frozen-lockfileon a warm store: 13 s.--toolchain-neededanswersneeded=falseonpull_requestandneeded=trueonmerge_group.columns.FIELD.applyOn: 'create') #25813 (twoskills/*/references/_index.mdfiles):--toolchain-neededanswersneeded=trueand names both paths. After the restore step and the install, the judgment is byte-identical to a full checkout with an install, and the same rows LIFTED. Without the toolchain on the sparse tree, every row stays governed: fail-closed, as before.mainatbe531f685since 2026-09-26 touched a register path. Counted on a full, non-shallow clone withgit rev-list --count --sinceand a path-limitedgit log.Acceptance
ready_for_review(route 2). The ready flip still starts a run, now a short one. This is the card's second acceptance arm.pull_requestleg's wall time is under 20 s": met. This PR's own guard run, job 121820715758 (2026-10-26T20:12:44Z → 20:13:03Z), took 19 s wall: blobless sparse checkout 10 s, Node 3 s, install steps skipped. The ready-fired run on PR ci(release): the hotcrm downstream smoke resolves hotcrm's latest release tag at run time #25965 took about 94 s.Governed Surface Queue Guardremains the check-run name on both legs. The job and itsname:are untouched. The self-test's WIRING pin andcheck:required-contextsboth pass.Tests and gates (final head
8cd23c77, after mergingorigin/main)node scripts/pm/check-governed-queue-guard.mjs --self-test: exit 0, 393 cases pass.pnpm check:pm-dispatch-gates: 1899 cases pass (fast tier), 313.4 s. Run detached; the verdict line is quoted and there is noELIFECYCLE.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 52 local commands. All 52 exit 0 on8cd23c77, each exit code captured before any pipe. That set includescheck:required-contexts,check-ci-filter-parity,check-step-collectors(658 steps, 40 workflows),check:pm-expected-skips,check:workflow-step-name-quotingandcheck:nul-bytes.node scripts/check-required-contexts.mjs --self-test(174 assertions) andnode scripts/pm/check-expected-skips.mjs --self-test(173 cases), both exit 0.--ranreconciliation: 51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN. It is a derived zero, because every family recorded an exit code.Acceptance notes
skip-changesetlabel is declared at create. Nothing under.github/workflows/**orscripts/pm/**ships in any package'sfiles[].Generated by Claude Code