fix(metadata): read a view container's own object in the artifact/HMR loader
#3700
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # The PREVENTION half of the governed-surface regime (#11704). The rule, the | |
| # event split, the ruled approval predicate and the exit contract all live in | |
| # `scripts/pm/check-governed-queue-guard.mjs`; that header is authoritative and | |
| # this file is the invocation. Only the wiring decisions are argued here. | |
| # | |
| # Its sibling `check:pm-governed-merges` is the DETECTION half — a report-only | |
| # post-merge audit. Three incidents (#9550, #10580, the #9319 landing) each | |
| # ended with a governed diff enqueued or merged with zero reviews and each was | |
| # caught by ACCIDENT, which is the expected behaviour of a regime whose only | |
| # pre-merge line of defence is seat discipline. This is the missing refusal. | |
| name: Governed Surface Guard | |
| on: | |
| # BOTH legs are load-bearing, and they mean DIFFERENT things — see the script | |
| # header. `merge_group` is the leg that REFUSES: the queue build is the last | |
| # thing between a speculative merge and `main`, and it is the path a seat | |
| # uses. `pull_request` is an EARLY WARNING that deliberately exits 0, because | |
| # a governed PR held as a draft for the maintainer to merge by hand is the | |
| # regime's healthy end state, and a check that reddens on the healthy case is | |
| # the permanently-red gate the 2026-08-18 ruling retired. | |
| pull_request: | |
| branches: | |
| - main | |
| # Naming `types:` REPLACES GitHub's default set rather than extending it, | |
| # so all three defaults are restated here (#8304). `ready_for_review` is | |
| # the addition and it is the point: flipping a governed draft to ready is | |
| # the first move of the exact sequence this guard exists to interrupt, and | |
| # it is not in the default set — without it the warning would not re-fire | |
| # at the one moment a seat most needs to read it. | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| merge_group: | |
| # ⛔ NO `paths:` filter, on either leg, and this is not an oversight. A skipped | |
| # job counts as SUCCESS in branch protection, so a path filter would hand the | |
| # queue a green "Governed Surface Queue Guard" for a PR the filter mis-scoped — | |
| # the #4928 shape, on the one check whose entire job is to refuse. The path | |
| # test belongs INSIDE the script, where "nothing governed" is a verdict that | |
| # says so and costs zero API calls. (`merge_group` has no paths support at all, | |
| # so a filter would also make the two legs disagree about what they cover.) | |
| concurrency: | |
| group: governed-surface-guard-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| # The default read scopes and nothing beyond them. `pull-requests: read` is | |
| # what the review list needs; there is no write scope here, and adding one to | |
| # make this check "fix" anything would be a widening no ruling covers. | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| governed-surface-guard: | |
| # ⚠️ THIS LITERAL IS THE CHECK-RUN NAME branch protection would pin, and it | |
| # is duplicated in `CHECK_CONTEXT_NAME` in the script — deliberately, and | |
| # pinned in both directions: the script's `--self-test` reads THIS FILE and | |
| # fails if the two ever disagree. Renaming a job silently detaches a | |
| # required context (#6865); this is the cheap half of the two-step that | |
| # makes that impossible to do by accident. | |
| # | |
| # ⛔ Making it a required context is NOT this PR's step. Branch protection | |
| # is the maintainer's: it takes a `REQUIRED_CONTEXTS` row in | |
| # `scripts/check-required-contexts.mjs` PLUS the entry in Settings → | |
| # Rulesets, in one sitting (#6865). Either half alone is an outage — a row | |
| # without the setting reads as `direction A — registered here, NOT in the | |
| # live required set`, which is #5617's own defect. | |
| name: Governed Surface Queue Guard | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| with: | |
| # A governed-surface question answered over a truncated history | |
| # answers with SILENCE, and silence reads as compliance (#9902). The | |
| # merge group's base sha can predate a shallow fetch's floor, so the | |
| # whole history is the only depth that cannot under-report. The | |
| # script refuses outright (exit 1) if either sha is missing, rather | |
| # than diffing what it happens to have. | |
| fetch-depth: 0 | |
| # Pinned to the same major and spelling as every other setup-node in this | |
| # repo, and it keeps its literal `node-version` (rather than | |
| # `node-version-file`) for the measured reason the Part-of Closing-Keyword | |
| # Guard records: `actions/setup-node@v5`+ defaults | |
| # `package-manager-cache: true`, which shells out to pnpm and hard-errors | |
| # before any `run:` line when pnpm is not yet on PATH. This job now DOES | |
| # acquire pnpm, but strictly after this step — the same order lint.yml has | |
| # been green on for months — so nothing here may start depending on pnpm | |
| # existing yet. | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '22' | |
| # The self-test runs FIRST and in its own step, because it is the | |
| # precondition for trusting the run after it: this guard's predicates | |
| # decide whether a merge lands, so a rotted predicate must redden here | |
| # rather than quietly wave a governed diff through. `bash -e` aborting the | |
| # step on the first failure is the correct semantics for a | |
| # precondition — the collector idiom next door in lint.yml is for | |
| # INDEPENDENT self-tests, which these are not. | |
| - name: Guard predicate self-test | |
| run: node scripts/pm/check-governed-queue-guard.mjs --self-test | |
| # ── the generator toolchain — the #11705 rows can now actually recompute ─ | |
| # | |
| # The register's `verify` rows (generator-owned files inside `skills/**`) | |
| # recompute by running the tree's OWN generator through `pnpm … exec tsx`. | |
| # Until now this job installed nothing, so that recompute answered "the | |
| # generator toolchain is not available in this environment" on every run | |
| # and the path stayed governed — a spec PR carrying its regenerated | |
| # `references/_index.md` needed a pinned maintainer approval at merge-group | |
| # time even though the seat-side `--test` lifted the same diff in a dev | |
| # container. The script header filed that trade as not taken; the | |
| # maintainer took it (2026-09-01, verbatim): | |
| # | |
| # > 纯生成的指针行(spec 源变更后再生成的 references/_index.md) 不需要我审核吧 | |
| # | |
| # ⭐ NO `--filter` here, deliberately. The set of packages the register's | |
| # recompute needs is `GENERATED_SURFACE_EXCEPTIONS[].verify.pkg`, and a | |
| # filter list in this file would be a SECOND copy of it — one that goes | |
| # stale silently the day a row is added, in the direction that reads as | |
| # compliance (the new row's generator fails to spawn, the path stays | |
| # governed, and nothing says the install was the reason). A full install | |
| # restates nothing, so a register row reaches this job for free — the same | |
| # reason the script imports the predicate instead of reimplementing it. | |
| # The self-test pins that: every `verify.pkg` in the register must be | |
| # covered by the install line below. | |
| # | |
| # ⛔ NO build step, and that is measured rather than assumed: both `verify` | |
| # rows run through `tsx`, which reads the generator's TypeScript sources | |
| # and their relative `./lib/*` imports directly — nothing consults any | |
| # package's `dist/`. Measured on a warm store: install 7s, the skill-refs | |
| # `--check` 1s. A build would be pure cost with nothing depending on it. | |
| # | |
| # ⭐ EVERY step in this block is `continue-on-error` — this is the load- | |
| # bearing half, not defensive decoration. The guard's own promise is that | |
| # "a diff that touches nothing governed is never blocked by an outage", and | |
| # a hard-failing install would newly make EVERY ordinary queue build depend | |
| # on the npm registry and the cache service. With `continue-on-error`, a | |
| # broken install degrades to exactly the behaviour this job had before this | |
| # block existed: the generator cannot spawn, `runSinkGenerator` returns its | |
| # stated "toolchain is not available" reason, and the path stays GOVERNED. | |
| # Fail-closed on the governed path, unaffected on the clear one, and the | |
| # verdict stays inside the script — where the exit contract lives — instead | |
| # of becoming an opaque red step nobody can read a governance answer out of. | |
| # | |
| # Both legs install. The `pull_request` leg is a FORECAST of the queue | |
| # verdict ("the merge-queue run of this same check will REFUSE it"), so a | |
| # leg that cannot recompute forecasts a refusal that will not happen — the | |
| # false-alarm direction, which trains seats to hold PRs that need no | |
| # holding. Same diff, same answer, on both legs and at the seat. | |
| - name: Setup pnpm | |
| uses: ./.github/actions/setup-pnpm | |
| continue-on-error: true | |
| - name: Get pnpm store directory | |
| shell: bash | |
| continue-on-error: true | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| # Deliberately the same key as lint.yml's: one store, one entry, and this | |
| # job is a cache READER in the steady state rather than a second writer. | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v6 | |
| continue-on-error: true | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-v3-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store-v3- | |
| - name: Install dependencies | |
| continue-on-error: true | |
| run: pnpm install --frozen-lockfile | |
| # The live judgment. Everything it reads arrives through `env:` or the | |
| # event payload on disk — no `${{ }}` interpolation into the shell line, | |
| # so no PR-controlled text ever becomes part of a command. | |
| # | |
| # GITHUB_TOKEN is the workflow's own default token at the read scopes | |
| # declared above; it is what makes the review read possible at all, and | |
| # an unreadable review list is a REFUSAL with its own exit code, never a | |
| # pass. ⛔ Fail-open is wrong in this file specifically — it exists | |
| # because every other layer in this chain failed open. | |
| - name: Governed surfaces may not enter the merge queue unreviewed | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: node scripts/pm/check-governed-queue-guard.mjs |