Skip to content

ci(governed-surface-guard): the pull_request leg checks out commits and trees only and installs the toolchain on demand - #26311

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-vqr0lq
Oct 26, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-vqr0lq

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

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 秒)。

风险与代价(含回滚)

席位意见

你要做的
审阅后批准或直接合并。本 PR 改了 .github/workflows/,属 Tier H,落地需要你本人。

What changed

.github/workflows/governed-surface-guard.yml, the pull_request leg only:

  • Checkout. The single checkout step is now two, keyed on the event. merge_group keeps the unchanged step (Checkout repository, fetch-depth: 0, full tree). pull_request gets Checkout repository (commits and trees only): fetch-depth: 0, filter: blob:none, sparse-checkout of scripts and .github.
  • Toolchain on demand. A new step asks the script --toolchain-needed. It runs on the pull_request leg only and appends needed=true|false to $GITHUB_OUTPUT. Every install step is gated on the output being NOT 'false', and so is a git sparse-checkout disable step 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.
  • Unchanged: types: [opened, synchronize, reopened, ready_for_review], the merge_group trigger, the job id governed-surface-guard, the check-run name Governed Surface Queue Guard, permissions, concurrency, timeouts and the judgment step.
  • Header. The ready_for_review note 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. liftGeneratedExceptions now consults the recompute iff it answers true, and the workflow installs iff --toolchain-needed answers true. Membership is still the register's generatedExceptionFor; no path list is restated.
  • readEventDiff(env) is extracted from main() 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 answers false only for a pull_request diff that was read and touches no register path.
  • New self-test battery, 20 cases, roster floor 28 → 29. Its pure half covers the predicate, the lift spy agreeing with it, and the answer per event and read state. Its YAML half covers exactly two checkouts (queue one unchanged; PR one blobless and sparse), the question wired to $GITHUB_OUTPUT on the PR leg only, every install step gated on not-false with no == 'true' spelling anywhere, the restore step ahead of the install, and an unconditional judgment step. installStepAudit gains a stepBodies field 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-needed reads 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

  • Route 2 taken; route 1 not taken. ready_for_review stays in types:, and the header's reason for it stands.
  • The dispatch's framing of route 2 was "no checkout of the full tree, no pnpm install". Measured, both halves needed a qualifier.
    • The pull_request leg 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 keeps fetch-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.
    • The workflow header gives a stated reason for installing on both legs: the pull_request leg 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.
  • Not done: no copy of the script is vendored, and actions/github-script is not used.

Premises (re-measured on be531f685, the branch base)

  • P1 holds. git grep -n 'ready_for_review' on the workflow finds 2 lines: the types: line and one header comment. Control synchronize: 1 line.
  • P2 holds. The check-runs on e7b12fdd, filtered to Governed 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).
  • P3 measured. Tree reads: the event payload, .github/CODEOWNERS, the workflow file and its own sources under scripts/, plus git objects (commits and trees only). API reads: reviews, the pull object, comments and the timeline, all at the existing pull-requests: read. The static and lazy import graph is node: built-ins plus relative scripts/** modules only. Measured by running --self-test on an archive of just scripts/ and .github/ with no node_modules: 373 cases pass at base, exit 0.

Measurements (dev container, 2026-10-26, repository objectstack-ai/objectstack)

  • Clone cost of full history.
    • blobless: 7 s, 105 MiB
    • treeless: 3 s, 64 MiB
    • with contents: 58 s, 956 MiB
  • Sparse checkout of scripts and .github on the blobless clone: 2.7 s.
  • Restoring the full tree (git sparse-checkout disable) for the toolchain case: 26 s. Then pnpm install --frozen-lockfile on a warm store: 13 s.
  • Judgment, PR ci(release): the hotcrm downstream smoke resolves hotcrm's latest release tag at run time #25965 (governed workflow file, no register path): blobless sparse checkout against a full checkout gives byte-identical output, exit 0 on both. --toolchain-needed answers needed=false on pull_request and needed=true on merge_group.
  • Judgment, PR feat(spec,metadata-protocol): a seed dataset column can be written only when its row is created (columns.FIELD.applyOn: 'create') #25813 (two skills/*/references/_index.md files): --toolchain-needed answers needed=true and 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.
  • Frequency. 14 of the 3142 commits reachable from main at be531f685 since 2026-09-26 touched a register path. Counted on a full, non-shallow clone with git rev-list --count --since and a path-limited git log.

Acceptance

  • "Approving and readying a governed PR starts no new guard run" is not met by design. Route 1 is what would meet it, and the dispatch kept ready_for_review (route 2). The ready flip still starts a run, now a short one. This is the card's second acceptance arm.
  • "The pull_request leg'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 Guard remains the check-run name on both legs. The job and its name: are untouched. The self-test's WIRING pin and check:required-contexts both pass.

Tests and gates (final head 8cd23c77, after merging origin/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 no ELIFECYCLE.
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 52 local commands. All 52 exit 0 on 8cd23c77, each exit code captured before any pipe. That set includes check:required-contexts, check-ci-filter-parity, check-step-collectors (658 steps, 40 workflows), check:pm-expected-skips, check:workflow-step-name-quoting and check:nul-bytes.
  • Two runs were added outside the derivation: node scripts/check-required-contexts.mjs --self-test (174 assertions) and node scripts/pm/check-expected-skips.mjs --self-test (173 cases), both exit 0.
  • --ran reconciliation: 51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN. It is a derived zero, because every family recorded an exit code.
  • No ablation: a workflow and a gate script are changed, and their pins are the self-test cases above.

Acceptance notes

  • The skip-changeset label is declared at create. Nothing under .github/workflows/** or scripts/pm/** ships in any package's files[].
  • The rare toolchain case pays about 26 s to restore the tree, in place of about 48 s of full-content checkout. Its wall stays roughly where it was.

Generated by Claude Code

…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>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Reviewed at 2026-10-26T20:34Z — PR #26311 at head 8cd23c77, card #26201. Rendered by an independent contract-review subagent of the seat session, not by the drafting thread.

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 8cd23c77c03c20298464413c312f0380ecd31ce2
Local-runs: none
Scope: .github/workflows/governed-surface-guard.yml, scripts/pm/check-governed-queue-guard.mjs, scripts/pm/dispatch-gates.self-test.mjs + scripts/check-required-contexts.mjs, scripts/pm/check-governed-merges.mjs, .github/CODEOWNERS, scripts/pm/dispatch-gates.mjs, .github/actions/setup-pnpm/action.yml

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 main (3 files, +259/−29); the check-runs on the head, read three times — at 2026-10-26T20:20:55Z 49 runs with 2 in progress (Test Core 1/8, Type Check · consumer gates), at 2026-10-26T20:24:26Z 51 runs, none in progress, and at 2026-10-26T20:31:13Z 51 runs: 34 success, 17 skipped, 0 failure, 0 in progress; the eight required contexts read success (Lint & Repo Gates, TypeScript Type Check, Test Core, Governed Surface Queue Guard) or skipped-by-filter (Build Core, Lint UI, Type Check UI, Build & E2E UI). Job 121820715758 through the jobs endpoint; the two newest merge_group runs of the workflow on main (40393881966 and 40394656414, both success) through their jobs endpoints; the cited files through git show on origin/main (817cb89) and on the head after fetching both refs. main has not moved any of the three PR files since the merge-base 69aa630, so the API diff is the net diff. The row enumeration on this PR's own pull_request range was reproduced with read-only git object queries (merge-base, log, diff-tree) over the fetched objects; no script, gate or build was run.

① Derived judgments

Rules 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 ready_for_review, make the pull_request leg cheap) and the guard's own regime:

  • Added: a second checkout step for the pull_request leg (full history, filter: blob:none, sparse scripts + .github), gated github.event_name == 'pull_request'; the queue checkout gains if: github.event_name != 'pull_request' and nothing else. RIGHT: it drops the install, not the trigger, which is the branch of triage's boundary the order chose, and it leaves the trigger types, the header's ready_for_review rationale, the job id and the check-run name untouched.
  • Added: a question step (id: toolchain, pull_request only, continue-on-error: true) that appends needed=true|false to GITHUB_OUTPUT; a restore step (git sparse-checkout disable, pull_request and needed not equal to 'false'); and if: steps.toolchain.outputs.needed != 'false' on all four install steps. RIGHT, and fail-closed — traced in (b).
  • Added in the script: toolchainNeededFor(rows), readEventDiff(env) (extracted from main()), toolchainNeededAnswer({ eventName, read }), the --toolchain-needed CLI mode, installStepAudit.stepBodies, a 20-case battery and the roster floor 28 → 29. RIGHT as a mechanism (one predicate, register membership, no restated list); a claim-surface breach, judged in (d).
  • Narrowed in the lift: the early return that asked whether some row has a registered path (registered(row).length positive for some row) became if (!toolchainNeededFor(rows)). NOT a narrowing — proved equivalent in (c).
  • Changed pin: dispatch-gates.self-test.mjs LIVE pin, one CI-measured family → exactly the guard's two payload-reading invocations. RIGHT — a true live reading, judged in (e).
  • Removed: nothing. types: [opened, synchronize, reopened, ready_for_review], merge_group:, concurrency, permissions, timeout-minutes: 30, the setup-node step, the self-test step and the judgment step are byte-identical to main.

(a) The refusing leg is untouched — PASS. On merge_group: Checkout repository runs (if: github.event_name != 'pull_request' is true) with the same with: block as main (fetch-depth: 0, no filter, no sparse-checkout, timeout-minutes: 20); the blobless checkout is skipped; the question step is skipped, so steps.toolchain.outputs.needed is the empty string, and the empty string is not equal to 'false', so Setup pnpm, Get pnpm store directory, Setup pnpm cache and Install dependencies all run; the restore step is skipped by its pull_request conjunct; the judgment step carries no if: and runs on both legs. The executed queue-leg sequence is therefore the one the two newest merge_group runs on main show (checkout 44–47 s, setup-node, self-test, setup pnpm, store dir, cache, install, judgment). No path lets a merge_group build skip the install or the full checkout. The job id governed-surface-guard and name: Governed Surface Queue Guard are unchanged; the scripts/check-required-contexts.mjs row (workflow governed-surface-guard.yml, job governed-surface-guard, context Governed Surface Queue Guard) is untouched and check:required-contexts rides the green Lint lanes on the head.

(b) Fail-closed on the cheap leg — PASS. toolchainNeededAnswer returns needed: false only when eventName === 'pull_request' AND read.ok AND toolchainNeededFor(read.rows) is false; a non-pull_request event, an unreadable payload, an unsupported event, a missing sha, an unknown repository, a merge-base or diff-tree failure (all ok: false from readEventDiff) and a register hit each answer true. YAML: the question step's stdout is appended to GITHUB_OUTPUT only after the answer is computed; a crash before the needed= line leaves the output empty, and the four install gates and the restore step read empty as not equal to 'false' and install — the continue-on-error: true on the question step keeps an install decision from reddening a required context and keeps the pre-existing positional pin (every step between the self-test and the judgment degrades instead of reddening) true; a failed restore (also continue-on-error) leads to an install on the sparse tree, whose generator cannot spawn, so the recompute answers "toolchain is not available" and the path stays governed — the same degradation main has on an install outage, a false alarm on the forecast and never a lift. No if: always() anywhere; no == 'true' spelling anywhere. The restore step sits before Setup pnpm and is gated by the same output. Tree reads on the blobless sparse tree: the event payload (runner temp); git object reads only — cat-file -e ^{commit}, merge-base, log --first-parent --format, diff-tree --no-renames --name-only (rename detection is off, so no blob is needed); the self-test reads .github/workflows/governed-surface-guard.yml, .github/CODEOWNERS and its own source, all inside the sparse set; the import graph is node: built-ins plus relative scripts/** modules (static: check-governed-merges.mjs, invoked-as.mjs; lazy: dispatch-gates.mjs, record-recognisers.mjs and what they import under scripts/); runGuard loads the record recognisers only on merge_group (the Tier S record leg is behind event === EVENT_MERGE_GROUP), so the pull_request judgment never reaches .claude/**; the recompute (runSinkGenerator, which needs the full tree and node_modules) runs only after the restore and the install. Root files (package.json, pnpm-lock.yaml, tsconfig.json) are inside a cone-mode sparse checkout, which actions/checkout defaults to; the local ./.github/actions/setup-pnpm action is inside .github. Measured on the head: job 121820715758 ran the self-test and the judgment on the sparse blobless tree with every install step skipped, both success. One note, not a finding: the cone-mode default is not pinned; a later sparse-checkout-cone-mode: false would drop the root files and degrade the needed-true path the fail-closed way described above.

(c) The lift and the predicate — PASS. toolchainNeededFor(rows) asks whether some row has some path with generatedExceptionFor(p) !== null; the old early return asked whether some row's filter of its paths by generatedExceptionFor(p) !== null had positive length. Same predicate, same membership (generatedExceptionFor from the register, no restated list), same loop, same notes, same recompute default, for every row enumerateRows produces (every row carries a paths array). The only textual difference is tolerance for a row without paths or a non-array rows, which no production path produces. On the merge_group leg the toolchain is always installed and the lift is byte-identical to main for every row kind. The self-test spy pins the equivalence from the outside (0 recompute calls without a register hit, 1 with).

(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 pull_request leg of the workflow only, 「stop on breach; explain in the report」. The PR also changes scripts/pm/check-governed-queue-guard.mjs (+196/−21) and scripts/pm/dispatch-gates.self-test.mjs (+5/−2), and the dev did not stop. Judged: the alternatives inside the claimed surface are (i) dropping the install on the pull_request leg unconditionally, which retires the header's forecast-fidelity rationale and prints a false alarm on every register-path diff, or (ii) deciding the install in YAML from a restated path list, which the guard forbids; the Wanted 2 options (a script fetched from the default branch, a vendored copy, github-script) were either forbidden by the order (no vendored copy) or would duplicate the predicate. A new mode in the existing script, sharing the one predicate with the lift, is the minimum route 2 needs with the forecast kept honest. Inside the card's boundary: merge_group semantics untouched (a); every refusal message and exit code on the judgment path is unchanged — readEventDiff carries the same four EXIT_CANNOT_RUN messages, and the merge-base/enumerate failure keeps its "could not read the diff" message and code; the --toolchain-needed mode exits 0 by construction (an install decision, not a verdict). The self-test pin change is forced by a LIVE pin the change made false. Report-shape defect: the os-dev-report carries no files_changed and no deviations key; the JSON template in .claude/agents/os-dev.md (终报消息) lists neither, while that file's prose rules direct deviations into a deviations field — the template and the prose disagree, and the surface widening is named only in summary and the PR body, not as a deviation. Action for the seat: amend the claim's File surface to add the two script files (new --toolchain-needed mode, readEventDiff extraction, battery; the LIVE pin), and file the os-dev.md shape mismatch on its own card.

(e) The dispatch-gates.self-test.mjs pin — PASS, not loosened. Before: liveCiOnly.length === 1 and the single family is the guard. After: the sorted family list must equal exactly scripts/pm/check-governed-queue-guard.mjs and scripts/pm/check-governed-queue-guard.mjs --toolchain-needed — exact in both directions, no extra family admitted, none allowed missing. The classification is true: --toolchain-needed reads the payload through readEventDiff (GITHUB_EVENT_PATH, limb 1 of ciOnlyMeasurement), no root manifest script names the file (limb 2), and dispatch-gates.mjs strips the shell redirection from the argv so the family name is the command without it. Lint · PM dispatch-gates on the head: success.

(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 (merge_group true, unknown event true, unreadable diff true with a one-line reason, read-and-clear false, read-with-hit true naming the path); exactly two checkout steps, the queue one fetch-depth: 0 with no filter and no sparse-checkout, the PR one fetch-depth: 0 + filter: blob:none + sparse scripts and .github; the question step with id: toolchain, pull_request only, appended to GITHUB_OUTPUT; all four install steps gated on not-'false' and no == 'true' spelling in the file; the restore step gated on pull_request and the same output, ordered before the first install step; the judgment step without an if:. The pre-existing wiring pins (install before judgment and after self-test, no --filter, every step between self-test and judgment continue-on-error) still hold over the new block, which is why the question and restore steps carry continue-on-error. Lint · scoped · tooling self-tests on the head: success.

(g) Acceptance. Arm 1 (approve + ready starts no new run) is not met by design — the order chose route 2 and kept ready_for_review. Arm 2 is met on the measured run: job 121820715758 (pull_request, head 8cd23c77) started 2026-10-26T20:12:44Z and completed 2026-10-26T20:13:03Z, 19 s wall. Steps: Set up job 1 s; Checkout repository skipped; Checkout repository (commits and trees only) 10 s; Setup Node.js 3 s; Guard predicate self-test under 1 s; Does this diff need the generator toolchain? under 1 s (success); Restore the full tree, Setup pnpm, Get pnpm store directory, Setup pnpm cache, Install dependencies all skipped; Governed surfaces may not enter the merge queue unreviewed under 1 s (success); Post Setup Node.js 1 s; Post Checkout under 1 s; Complete job under 1 s. Against about 94 s on PR #25965. The margin under the 20 s line is 1 s on this run, so the arm is met by the measured run, not by a bound. The card asks for the figure to be quoted in the PR body, which still reads NOT MEASURED — the seat or the dev's patch round should write it in. Governed Surface Queue Guard remains the check-run name on both legs (the pull_request run on the head and the merge_group runs on main all publish it).

② Semver level

skip-changeset is right: the diff touches .github/workflows/** and scripts/pm/** only; the root package is private with no files[], and no workspace package's files[] names scripts/pm or .github. Clause-②: no and Metadata-protocol: none are line-initial directly after Fixes #26201 (the two lines above them are the relay's attribution). ## 维护者速读(草稿) is present with 席位意见 empty.

③ Boundary flags

  • Dev flag, PR body: acceptance 2 "NOT MEASURED" — now measured by the job quoted in (g); the body should carry the figure.
  • Dev flag, header rewording "Both legs install WHEREVER THE RECOMPUTE CAN CHANGE THE ANSWER": accurate for the pull_request leg (the install is acquired exactly when toolchainNeededFor is true, the same predicate the lift consults); the paragraph says the queue leg always installs, which it does.
  • os-dev-report out_of_scope_findings[0] (class a): verified on the head — enumerateRows is byte-identical to main; it attributes a row by pullNumberFromSubject first and falls back to the event's PR number only when the range holds exactly one commit. This PR leaves the defect in place, neither fixing nor worsening it. Corroboration from this PR's own pull_request range: three first-parent commits (the merge of origin/main, the pin commit, the workflow commit), none carrying a trailing (#N), so every governed row is unattributed on the early warning; and the merge commit's first-parent diff carries 141 paths that main already landed, including the workflow file itself. The seat files the card; nothing here changes a queue verdict, where the squash subject carries (#26311).
  • os-dev-report out_of_scope_findings[1] (carrier: none): right — the toolchain-needing case keeps roughly its old wall (restore plus install in place of a full checkout plus install); it is not cloud-lane work and it is recorded in the PR's Acceptance notes, which is where a carrier-less note goes.
  • PR object: author objectstack-fleet[bot] (type Bot, relay-written); draft; reviewers hotlong and os-zhuang requested; assignee os-warren; labels ci/cd, size/m, skip-changeset; auto-merge not armed; same-repository head. Tier H: the PR stays draft; the maintainer's hand lands it.
  • Report nit: the os-dev-report says 52 commands derived and 51 derived in the --ran line; the head's check-runs are the verdict and are green, so this is a reporting inconsistency only.

Implemented-by: claude/project-thread-vqr0lq
Reviewed-by: session_01LqKsGyMNFwwnbF5FTAqyPn

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · domain:skills#2 · session_01LqKsGyMNFwwnbF5FTAqyPn · 2026-10-26T20:38Z

Seat review of record for #26201 on head 8cd23c77, against GitHub, not the report's own account. Governed PR, Tier H (.github/workflows/governed-surface-guard.yml; check-governed-merges --pr 26311: GOVERNED, H(人合), 288 changed lines under the human-merge threshold; scripts/pm/** off the register): the record that informs the maintainer's hand is the independent ## Contract review at comment 6426695557 (Served-tier: CONTRACT_REVIEW_TIER, head 8cd23c77, VERDICT: PASS, drafted by a reviewer other than the implementer — the card thread). This seat adds the landing read, not a second contract read. ⛔ The seat does not ready, arm or enqueue this PR.

  1. Shape. Draft, base main, mergeable: true, same-repository head claude/project-thread-vqr0lq; body line 1 Fixes #26201, no closing keyword beside any other card; Clause-②: no, Metadata-protocol: none line-initial; ## 维护者速读(草稿) present with 席位意见 empty. Files: .github/workflows/governed-surface-guard.yml (+58/−6), scripts/pm/check-governed-queue-guard.mjs (+196/−21), scripts/pm/dispatch-gates.self-test.mjs (+5/−2). Labels ci/cd, size/m, skip-changeset — right: the root package is private, no workspace files[] names scripts/pm or .github. Reviewers hotlong and os-zhuang requested by the relay; assignee os-warren; auto-merge not armed.
  2. Record, measured. The reviewer proved the merge_group leg byte-identical in effect to main (the question step is skipped there, its output is empty, empty is not 'false', so all four install steps run; the queue checkout keeps fetch-depth: 0 with no filter or sparse set; the judgment step carries no if:; the executed sequence equals the two newest merge_group runs on main, 40393881966 and 40394656414); walked the cheap leg fail-closed (toolchainNeededAnswer is false only for a pull_request diff that was read and touches no register path; a crashed question step leaves the output empty and installs; the restore step precedes Setup pnpm under the same gate; every tree read on the blobless sparse tree is a git object read or a file inside scripts + .github, and the record recognisers load only on merge_group, so .claude/** is never read on the PR leg); proved toolchainNeededFor the same predicate as the lift's old early return (membership from generatedExceptionFor, no restated list), so the queue leg's lift is unchanged for every row kind; judged the self-test LIVE pin tightened to exact set equality, not loosened; read the 20-case battery and found the wiring pinned in both directions. The seat re-read the diff and reads the same.
  3. Gates, pinned to head 8cd23c77. 51 check-runs, 34 success and 17 skipped, none red or pending (read by the reviewer at 2026-10-26T20:31Z and by the seat after). Required set green or skipped-by-filter: Lint & Repo Gates, TypeScript Type Check, Test Core, Governed Surface Queue Guard; Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Check Changeset, Check PR Size and every claim/close guard success.
  4. Acceptance measured. The card's second arm (the pull_request leg under 20 s) is met on this PR's own run, job 121820715758: started 2026-10-26T20:12:44Z, completed 2026-10-26T20:13:03Z, 19 s wall (blobless sparse checkout 10 s, Node 3 s, self-test and question and judgment under 1 s each, every install step skipped), against about 94 s on PR ci(release): the hotcrm downstream smoke resolves hotcrm's latest release tag at run time #25965 and about 90 s on main's merge_group runs. Met by the measured run with a 1 s margin, not by a bound. The first arm (approve + ready starts no new run) is not met by design: the order chose route 2 and kept ready_for_review, whose rationale the header gives. The PR body still reads NOT MEASURED on that arm; the seat has asked the card thread to write the figure in.
  5. 维护者速读. 受管面守卫在 PR 上的那一跑从约 94 秒降到 19 秒:只拉提交历史和目录树、只铺 scripts/ 和 .github/、默认不装依赖;只有当 diff 触到登记表里生成例外路径时才补装(用的是 lift 本来就用的那一个判据,没有抄第二份清单)。合并队列那条真正会拒绝的腿一字未改(复核员逐步证了);检查名、job id、触发类型都没动,翻 ready 仍会重跑(保留了工作流头注释给出的理由)。守卫脚本加了一个 --toolchain-needed 模式和 20 个自测;dispatch-gates 的一条 LIVE 钉子随之改为精确等于两次调用。Tier H:留 draft,等你或 os-zhuang / hotlong 之手;回滚 = revert 两个提交。
  6. Accepted deviations. (a) Claim-surface breach: the claim named the workflow's pull_request leg only; the PR also changes the guard script and one self-test pin, and the dev did not stop. Judged by the reviewer the minimal route 2 with the forecast kept honest (the in-surface alternatives were an unconditional install drop or a path list restated in YAML); no refusal message or exit code on the judgment path changed. The claim is amended in the same round (ci(governed-surface-guard): the pull_request leg re-runs on ready_for_review and spends ~95 s on checkout + install for a 1 s check, so an admin merge tapped right after an approval is refused with "required status check is in progress" #26201 comment 6426749756) and the PR body names both files with evidence. (b) Branch claude/project-thread-vqr0lq (the measured platform exception), named by the claim; claim guards green. (c) The os-dev-report carries no files_changed and no deviations key and names the widening only in summary; the JSON template in .claude/agents/os-dev.md lists neither key while that file's prose directs deviations into deviations — a template/prose mismatch on main, outside this diff. (d) Report nit: 52 commands derived vs 51 in the --ran line; the head's check-runs are the verdict.
  7. Carrier. out_of_scope_findings[0] (class a: the pull_request leg attributes rows by commit subject, reads an issue number's /reviews, 404, and merges origin/main rows into the forecast) → filed as ci(governed-surface-guard): the pull_request leg attributes governed rows by commit subject, so a subject naming an issue reads that issue's /reviews (404) and the early warning misleads #26316 by the seat, verified by the reviewer on the head (enumerateRows byte-identical to main). out_of_scope_findings[1] (carrier: none, the toolchain-needing case keeps roughly its old wall) → recorded in the PR's Acceptance notes, where a carrier-less note goes. Not filed, 收班简报: the os-dev.md template/prose mismatch in 6(c), the cone-mode default not pinned on the sparse checkout (a later sparse-checkout-cone-mode: false would degrade fail-closed, never lift).
  8. Landing. Tier H with a PASS record on the current head and every check green ⇒ the PR stays draft and waits for the maintainer's hand (os-warren, or os-zhuang / hotlong as GOVERNED_APPROVERS: an APPROVED review, or an enqueue by an authorized account, is the review record, after which the owning seat lands it). ⛔ No seat readies, arms or enqueues it before that record.

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 26, 2026 22:46
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit ab4e30a Oct 26, 2026
59 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-vqr0lq branch October 26, 2026 23:05
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

3 participants