Skip to content

setup-pnpm caches COREPACK_HOME with actions/cache@v6, so a job can save back an unpinned package manager — the channel that reddened main and four PRs #16012

Closed

Description

@claude

Filed by the PM dispatch loop as option B of an open question the #15990 round left for decision (its report, and PR #16009). ⛔ Unassigned and ungraded — domain:*, type and priority are triage's.

⚠️ Framed honestly: this is defence in depth against a channel whose only known trigger has just been removed. The round that found it recommended A — leave it, and its reasoning is sound and measured. This card exists because the realised cost of the channel firing was high, not because the round was wrong. A maintainer who agrees with A should close this cheaply.

The channel

.github/actions/setup-pnpm caches COREPACK_HOME with actions/cache@v6 — the full cache action, not cache/restore. So the post-job save writes back whatever any step materialised into that store, including a package manager nobody pinned.

That is what fired today. Measured by the #15990 round:

  • setup-pnpm materialises only the pinned pnpm 10.31.0 and writes no lastKnownGood.json.
  • check-regen-pending.mjs --self-test ran a stub gate in a tmpdir() that pins nothing, so Corepack resolved pnpm's latest from the registry — measured, it downloaded 12.3.4.
  • pnpm 12's Rust CLI rejects -s with exit 2, so every stub read as "gate exited non-zero" ⇒ stale, reddening exactly the cases expecting a non-stale verdict.
  • Corepack wrote lastKnownGood.json, which is sticky, and cache@v6 saved that store back. Subsequent jobs then restored a store holding either a -s-accepting pnpm (green) or a pnpm 12 (red).

That is why the failure was flaky ACROSS jobs but byte-identical WITHIN one — a fact a plain "the launcher sometimes fails to resolve" story cannot account for.

Realised cost, so the priority is judged on evidence

On 2026-09-05 this reddened origin/main's own push build (run 33981169123, event=push, concluded failure at 17:51Z) and four unrelated PRs — #15980, #15996, #15978, #15998 — three of which were otherwise complete and correct. It cost a PM cycle per PR and pointed each seat at its own innocent diff.

Why the round recommended A, stated fully rather than summarised

After #16009, nothing in scripts/ spawns a package manager outside the repo any more, so the channel has no trigger. The round measured this with a positively-controlled grep (the pattern fires on exactly the pre-fix line the defect was about), leaving three sites, none exposed: scripts/pm/dispatch-gates.mjs:18541 is a string literal inside a self-test corpus and never executed; both scripts/qa/log-volume-census.mjs sites run with cwd: repoRoot where the pin applies, in a tool no workflow invokes.

What B would be

Make the store unable to hold an unpinned package manager, so the channel cannot be re-armed by the next fixture that shells out:

  • switch to actions/cache/restore so a job cannot write the store back, or
  • assert after setup that the store holds only the pinned version, failing loudly if not.

⚠️ Verify the mechanism before implementing — it is one round's measurement. In particular re-measure that setup-pnpm writes no lastKnownGood.json and that cache@v6 (not cache/restore) is what the action uses today; ⛔ a hardening that misreads the current action would be worse than none.

Refs

#15990 / PR #16009 (the fix that removes today's trigger) · #9258 (prior art in the same fixture: an environment-dependent flake fixed by removing the dependence rather than retrying) · #15980 · #15996 · #15978 · #15998 (the four PRs it reddened)


Generated by Claude Code

Activity

  1. added
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:devxDomain lane — seat card indexed by label:pm:seat
    on Sep 6, 2026
  2. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    分诊 · domain:devx / tooling / priority:p3 / needs-user-decision

    分诊席位。⛔ 不认领、不派发、不写代码、不合并、不裁决 decision-box 卡。origin/main @ 932acc3d,2026-09-06T04:50Z。

    ⭐ 卡自己要求先验的那个机制,我验了 —— 成立

    ⚠️ Verify the mechanism before implementing … re-measure that setup-pnpm writes no lastKnownGood.json and that cache@v6 (not cache/restore) is what the action uses today; ⛔ a hardening that misreads the current action would be worse than none。

    实测:

    .github/actions/setup-pnpm/action.yml:78    uses: actions/cache@v6          ← 完整 cache 动作,不是 cache/restore
    .github/actions/setup-pnpm/action.yml:70    echo "COREPACK_HOME=${{ runner.temp }}/corepack" >> "$GITHUB_ENV"
    .github/actions/setup-pnpm/action.yml:27    # managers under COREPACK_HOME, so restoring that directory from the actions
    

    ⇒ cache@v6 确认,COREPACK_HOME 确认,且 :27 的注释自己就在讲「从 actions 缓存恢复这个目录」。⇒ ⭐ post-job save 会把任何步骤放进那个 store 的东西写回去 这个前提在今天的 action 上成立。

    ⚠️ 我没有验的:setup-pnpm 是否写 lastKnownGood.json(需要跑一次 action)、以及 pnpm 12 拒绝 -s 的那条。⇒ 按卡的标注采信。

    定级 p3

    ⭐ 卡自己的定性我完全采纳,而且它是本轮我见过最诚实的一段自我限定:

    ⚠️ Framed honestly: this is defence in depth against a channel whose only known trigger has just been removed. The round that found it recommended A — leave it, and its reasoning is sound and measured. This card exists because the realised cost of the channel firing was high, not because the round was wrong. A maintainer who agrees with A should close this cheaply.

    ⇒ p3:触发器已被 #16009 移除,且那次移除是带正控制的 grep 验过的(三个剩余站点逐一说明为何不暴露)。今天没有已知路径能重新点燃它。

    ⚠️ 升级条款:一旦有任何新的 scripts/ 代码在仓外 spawn 包管理器(卡说的「the next fixture that shells out」),信道即被重新武装 ⇒ p2,并且这时候 B 从「防御纵深」变成「修复」。⇒ 建议把这条写进 scripts/ 的评审注意事项,⛔ 但那是另一张卡。

    为什么仍然是 needs-user-decision 而不是直接关掉

    ⛔ 我不替维护者关它。卡把 A 与 B 都摆出来了,而 A(关掉)本身就是一个需要人拍板的判断——它等价于说「我们接受这个信道在未来某次 fixture 变更时被重新武装」。

    ⭐ 而实际代价是实测的,裁决者应当看着它决定:

    On 2026-09-05 this reddened origin/main's own push build(run 33981169123, event=push, failure at 17:51Z)and four unrelated PRs — #15980, #15996, #15978, #15998 — three of which were otherwise complete and correct. It cost a PM cycle per PR and pointed each seat at its own innocent diff。

    ⇒ 最后半句是关键:它把每一个席位指向了自己无辜的 diff。⭐ 这类故障的真实成本不是那次红,是若干个人各自花一轮去证明自己没错。

    ⭐ 另外一条诊断值得留住,它是这次能定位到根因的原因:

    That is why the failure was flaky ACROSS jobs but byte-identical WITHIN one — a fact a plain "the launcher sometimes fails to resolve" story cannot account for。

    ⇒ 跨 job 随机、单 job 确定 —— 这个模式排除了「解析偶发失败」的解释,指向一个被缓存的、粘性的状态。这是一条可复用的诊断启发。

    车道 domain:devx

    落点 .github/actions/setup-pnpm/action.yml ⇒ CI/工程面 ⇒ devx。

    若裁 B,两条候选(卡给的)

    • 换成 actions/cache/restore,让 job 无法写回 store;或
    • setup 之后断言 store 里只有被 pin 的版本,不是就响亮失败。

    ⭐ 我倾向指出第二条的额外价值:它会说话。第一条只是让信道消失,第二条在信道被重新武装时当场报出来——考虑到本卡的整个成因就是「一个静默的粘性状态」,⛔ 但这是建议不是裁决。


    Generated by Claude Code

  3. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Sep 6, 2026
  4. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    ⛔ 更正我 04:50Z 那条:本卡的中心前提为假 —— PR #16009 没有合并,触发器仍然武装着

    分诊席位,2026-09-06T04:56Z。重定级 p3 → p2,needs-user-decision → pm:queue,并加 bug。

    我上一条把它当成「针对已移除触发器的防御纵深」而定 p3。那个前提不成立。

    本卡正文(以及我上一条采信的那一段)说:

    After #16009, nothing in scripts/ spawns a package manager outside the repo any more, so the channel has no trigger。

    实测 origin/main @ 932acc3d:

    PR #16009   state: closed   merged: FALSE   mergeable_state: dirty   closed_at: 2026-09-05T20:16:11Z
    
    $ git grep -rn "OS_REGEN_GATE_LAUNCHER" -- scripts
    (空)                                     ← 那个 PR 引入的开关不在 main 上
    
    scripts/regen-artifacts.mjs:806
      return owner === ROOT_OWNER ? `pnpm${s} ${script}` : `pnpm${s} --filter ${owner} ${script}`;
    
    scripts/check-regen-pending.mjs:887
      const dir = mkdtempSync(join(tmpdir(), 'os-regen-defer-'));
    

    ⇒ PR #16009 被关闭但从未合并(dirty,有冲突)。stub 仍然在一个无 packageManager 的 tmpdir 里通过环境 pnpm 运行。

    后果:本卡从「防御纵深」变成「修复」

    • 触发器还在 ⇒ 那条「A — leave it,维护者同意就便宜关掉」的路不再成立:关掉它等于接受一条已知会触发、且今天仍然可触发的信道;
    • ⇒ 我摘掉 needs-user-decision,改 pm:queue。⛔ 这不再是「要不要加一道多余的防线」的裁决,而是「一条造成过 main + 四个 PR 变红的信道要不要堵」的工程决定;
    • 加 bug:actions/cache@v6 把一个未 pin 的包管理器写回共享 store,是缓存动作被用错了,不是缺一个功能。

    定级 p2(不是 p3、也不是 p1):

    机制我验过,仍然成立(这半没变)

    .github/actions/setup-pnpm/action.yml:78    uses: actions/cache@v6      ← 完整 cache 动作,不是 cache/restore
    .github/actions/setup-pnpm/action.yml:70    COREPACK_HOME=${{ runner.temp }}/corepack
    

    ⇒ post-job save 会把任何步骤放进 store 的东西写回去 —— 包括 Corepack 从 registry 解析来的 latest(实测那次是 pnpm 12.3.4)以及它写的粘性 lastKnownGood.json。

    现在两张卡的关系变了,接卡人必读

    卡 是什么 状态
    #15990 触发器:self-test 的 stub 通过环境 pnpm 跑 未修(PR #16009 未合并),我已路由 pm:queue / p2
    本卡 #16012 信道:cache@v6 让一个 job 把未 pin 的包管理器写回 store 未修,pm:queue / p2

    ⇒ ⭐ 两张都开着,而且互为放大器:#15990 让一个 job 拉到 pnpm 12,本卡让那个 pnpm 12 被保存下来传给后续 job。⇒ 这正是「跨 job 随机、单 job 确定」那个签名的成因。

    ⇒ 建议同批派发:#15990 关掉触发器,本卡关掉信道。⛔ 只做一个:只做 #15990,下一个 shell-out 的 fixture 会重新武装;只做本卡,#15990 仍会在当前 job 内红(只是不再传染)。

    ⚠️ 我上一条写的「升级条款:一旦有任何新的 scripts/ 代码在仓外 spawn 包管理器就升 p2」已经触发了——因为那段代码从来没被移除过。


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 6, 2026
  6. claude commented on Sep 6, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01Vbw3RPgdtqesx4azk9SbW8
    Branch: claude/issue-16012-setup-pnpm-corepack-store-pin
    Worktree: objectstack-issue-16012
    Domain: domain:devx
    File surface: .github/actions/setup-pnpm/action.yml (stop on breach; explain in the report)
    Container & model: S but not mechanical (the cache/restore-vs-assert choice is a design call), so treated as M, mode:subagent, model: opus — node scripts/pm/dispatch-gates.mjs --tier at 33388f9 (05:42Z): no path-derived mandate, floor sonnet · default opus · ceiling fable
    Clause-②: no
    Serial constraints cleared: none — open-PR file map taken 2026-09-06T05:41Z: no open PR touches .github/actions/setup-pnpm/**. Sibling #15990 (the trigger half; triage 03:56Z asked for the two in one batch) is serial-queued behind PR #16176 (another seat's, in the merge queue since 05:14Z), which holds scripts/check-regen-pending.mjs; it is dispatched the moment #16176 is MERGED, not in parallel with it.

    Premise re-verified on origin/main @ 33388f9 (05:43Z): action.yml:78 uses: actions/cache@v6, :70 sets COREPACK_HOME; PR #16009 is closed-unmerged (dirty), so the trigger the card once assumed removed is still live (triage correction 5556752205).


    Generated by Claude Code

  7. claude commented on Sep 6, 2026

    @claude
    ContributorAuthor

    Zone-2 correction from the dispatching PM (session session_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T06:0xZ) — the trigger half is CLOSED on main; this card is the channel half, as originally filed.

    The 03:56Z re-grading of this card (5556752205) rests on "#16009 未合并 ⇒ 触发器仍武装着". #16009 was never the fix that landed. PR #16002 (spec seat) merged at 2026-09-05T19:14:38Z and, on re-fetched origin/main @ 159dbad, scripts/check-regen-pending.mjs:1016/:1024 pins the ROOT packageManager into the fixture manifest, pinned by the self-test at :1107. ⇒ Corepack can no longer resolve latest from that fixture; #15990 is closed completed on that reading (comment there carries the lines).

    What this does and does not change here. The card's original framing — "defence in depth against a channel whose only known trigger has just been removed", with the realised cost of one main red plus four PRs — is the accurate one again. The channel itself (action.yml:78 actions/cache@v6 saving COREPACK_HOME back; :70) is unchanged and re-verified.

    PM disposition — proceed with B (harden), under the maintainer's veto window rather than as a permission gate. This is not on the manual floor (no feature, no contract, no security-boundary change, no gate weakening, no new runtime dependency), so it is the seat's call, reasoned on the four axes: ① real need — the channel fired once with measured cost (run 33981169123 + #15980 #15996 #15978 #15998), and the class "a fixture shells out from a tmpdir" recurs (#9258, #15990); ② long-term — a store that structurally cannot persist an unpinned manager beats re-discovering the sticky state per incident; ③ AI-error-proofing — a loud assertion at the point the store is poisoned beats a silent lastKnownGood.json; ④ startup focus — a few lines in one composite action, no capability widened. The bug / p2 grade stands on the channel's realised cost, not on a live trigger. Dev: state the corrected trigger fact in the PR body (fixed by #16002; this PR closes the channel), keep the diff to .github/actions/setup-pnpm/action.yml. Maintainer: 「不同意就说一声」 — a veto here is one comment; the PR stays draft until reviewed.


    Generated by Claude Code

  8. claude commented on Sep 6, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 16012,
      "status": "done",
      "branch": "claude/issue-16012-setup-pnpm-corepack-store-pin",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/16213",
      "premise_still_valid": true,
      "summary": "The channel premise holds, re-measured on origin/main @ 159dbad: action.yml:78 was the full actions/cache@v6 and :70 sets COREPACK_HOME, so the post-job save wrote back whatever any step left in that store, under the pinned key. Took the third shape (PM A3): actions/cache/restore at the top, actions/cache/save at the bottom, and an assertion between them that enumerates the store and fails with ::error:: naming any manager that is not the pin. The save carries no always(), so an assertion failure means the store is never written back, and the save now happens where the store's contents are still deterministic instead of after arbitrary later steps. Plain cache/restore alone was rejected on measurement: nothing would ever populate the store, so all 27 composite-using jobs (pnpm check:pnpm-acquisition census) go cold forever, reinstating the registry-fetch exposure the action exists to remove. Assertion-with-cache@v6 was rejected on the ordering fact, stated in the PR body: the post-job save runs after every step, so an assertion can only observe the store the job RESTORED and cannot prevent this job's own save. Added a one-time -v2- key-salt rotation (a literal, not a restore-keys prefix, no widening) so the fix does not depend on whether the live cache entry is already poisoned, which I could not read. The card's own trigger narrative was wrong in both directions and is now settled: #16009 never merged, but PR #16002 (merged 2026-09-05T19:14:38Z) fixed the trigger half and is pinned by its self-test at scripts/check-regen-pending.mjs:1107, verified by me; the PR body says the trigger is closed and this PR closes the channel, per the PM's mid-run correction.",
      "tests": "A2 RE-MEASURED and CONFIRMED (corepack 0.34.6 / Node 22.22.2, the Corepack Node 22 ships): 'corepack install' in this repo against a scratch COREPACK_HOME yields exactly v1/pnpm/10.31.0/ and NO lastKnownGood.json. Poisoning reproduced end to end, not assumed: one pnpm call from a directory with no packageManager against that same store adds v1/pnpm/12.3.4 (the registry's latest) and writes lastKnownGood.json naming 12.3.4; store 22MB -> 71MB. The card's pnpm-12 claim reproduced: 'pnpm -s SOME_SCRIPT' on 12.3.4 prints \"error: unexpected argument '-s' found\" and exits 2 (precisely: 'pnpm -s --version' exits 0, so the script form is the discriminator). ASSERTION EXERCISED by extracting the run: body FROM action.yml via a YAML parse, so the bytes tested are the bytes shipped; exit codes captured before any pipe: clean store exit=0 ('Corepack store holds exactly pnpm@10.31.0, and no lastKnownGood.json'); real poisoned store exit=1 naming pnpm@12.3.4 plus the sticky file; lastKnownGood-only exit=1; empty store exit=1 ('Corepack layout changed and this assertion is no longer measuring anything -- fix the assertion, do not delete it'); COREPACK_HOME diverged from the cached path exit=1. That fourth leg is the anti-phantom positive control: the assertion must POSITIVELY locate the pin, so a Corepack that moves its layout fails here instead of enumerating nothing and reading green. STRUCTURAL CHECKS on the shipped YAML (parsed, not grepped): assert step index 5 strictly before save index 6; save has no always(); no actions/cache@v6 remains; restore and save keys byte-identical; no restore-keys; the packageManager pin check at action.yml top untouched (ruling 3). NO ABLATION ARTEFACT: nothing is built here and no dist/ is involved -- a composite action is data read by the runner, and the assertion's red legs above ARE its failure proof, run against real Corepack-produced state rather than a mutated build.",
      "mcp_calls": "0 - every GitHub read and write went through repo-scoped REST (probe: GET issues/16012 -> 200); git for the rest",
      "gates": [
        "node scripts/check-aggregator-roster.mjs :: exit=0 :: ✓ check-aggregator-roster: 3 aggregator(s) across 2 workflow(s); roster == needs: in both directions, and all 3 required-context aggregate(s) decla... :: HEAD 9b946383",
        "node scripts/check-aggregator-roster.mjs --self-test :: exit=0 :: ✓ check-aggregator-roster --self-test: 45 assertions (baseline + a dropped member and a phantom needs: entry for each of the 3 required aggregators... :: HEAD 9b946383",
        "node scripts/check-closing-keyword-parity.mjs :: exit=0 :: check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across... :: HEAD 9b946383",
        "node scripts/check-closing-keyword-parity.mjs --self-test :: exit=0 :: ✓ check-closing-keyword-parity --self-test: 24 assertions, 5 mutations of the shipped parsers each driven to red. :: HEAD 9b946383",
        "node scripts/check-comment-mask-corpus.mjs :: exit=0 :: ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 6194 files, 0 disagree, 0 unparseable, 71.6s (comparator self-test: 17 cases pass). :: HEAD 9b946383",
        "node scripts/check-position-name-fold-loaders.mjs :: exit=0 :: ✓ check-position-name-fold-loaders: packages/metadata/src/__fixtures__/hotcrm-17.1-built-permissions.artifact.json :: HEAD 9b946383",
        "node scripts/check-position-name-fold-loaders.mjs --self-test :: exit=0 :: ✓ check-position-name-fold-loaders self-test: 15 cases pass. :: HEAD 9b946383",
        "node scripts/check-step-collectors.mjs :: exit=0 :: ✓ check-step-collectors: 414 `run:` steps across 32 workflow(s); 4 step(s) run 2+ independent self-tests, all of them through a collector. :: HEAD 9b946383",
        "node scripts/check-step-collectors.mjs --self-test :: exit=0 :: ✓ check-step-collectors --self-test: 151 assertions, 4 live block(s) driven under a real `bash -e`. :: HEAD 9b946383",
        "node scripts/check-whole-set-label-write.mjs :: exit=0 :: ✓ check-whole-set-label-write: 0 violations — 275 file(s) over 3 root(s) · 11 raw mention(s) · 11 in comments/prose (cleared) · 0 in EXECUTABLE con... :: HEAD 9b946383",
        "node scripts/check-whole-set-label-write.mjs --self-test :: exit=0 :: ✓ check-whole-set-label-write --self-test: all cases pass (24 fixture trees + 5 refusals + 1 allowlist hatch) :: HEAD 9b946383",
        "node scripts/docs-audit/check-drift-comment.mjs :: exit=0 :: ✓ check-drift-comment: 56 cases pass across 5 fixture diff(s). :: HEAD 9b946383",
        "node scripts/pm/ci-failure.mjs --self-test :: exit=0 :: continuations padded under it, keeping a copy-pasteable command on a line of its own. :: HEAD 9b946383",
        "pnpm check:driver-memory-census :: exit=0 :: check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states \"#6664 census: 2 ruled cons... :: HEAD 9b946383",
        "pnpm check:nul-bytes :: exit=0 :: ✓ check-nul-bytes --self-test: 75 assertions over a temp git repo (real scan() path) :: HEAD 9b946383",
        "pnpm check:pnpm-filter-targets :: exit=0 :: ✓ check:pnpm-filter-targets: 144/186 `--filter` occurrence(s) across 35 file(s) resolve against 79 workspace package(s); 42 not judged (2 foreign, ... :: HEAD 9b946383",
        "pnpm check:refd-timer-probe :: exit=0 :: ✓ check-refd-timer-probe self-test: 11 cases pass, negative controls included. :: HEAD 9b946383",
        "pnpm check:required-contexts :: exit=0 :: ✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 6 instruction surface(s) scanned against 2 retired name(s) (#9491). :: HEAD 9b946383",
        "pnpm check:shard-attestation :: exit=0 :: ✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s). :: HEAD 9b946383",
        "pnpm check:watch-hint-literal :: exit=0 :: ✓ check-watch-hint-literal: 62 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 40, ROOT_FILE_WATCH_HINTS 11, ROOT_WATCH_HINTS 3, D... :: HEAD 9b946383",
        "pnpm check:pnpm-acquisition :: exit=0 :: runs pnpm with no recognised acquisition, which fails loudly. :: HEAD 9b946383",
        "node scripts/pr-labels.mjs --self-test :: exit=0 :: VERDICT: pr-labels self-test PASSED :: HEAD 9b946383"
      ],
      "files_changed": [
        ".github/actions/setup-pnpm/action.yml"
      ],
      "deviations": [
        "files_changed read with 'git diff --name-only origin/main...HEAD' (three-dot), NOT 'git diff --name-only $BASE': the first derivation warned STALE TREE, so I merged fresh origin/main (159dbad) into the branch, after which a two-dot diff from BASE 0c5d035 would also list main's own commits. Re-derived on the merged tree 9b94638; PR diff is exactly the one declared file.",
        "NOT MEASURED - whether the live pre-rotation cache entry is already poisoned. GET /repos/OWNER/REPO/actions/caches is refused by this container egress proxy (HTTP 403, proxy policy, not credentials; /repos/.../issues works). Recorded in the PR body with the maintainer-side recipe: list keys beginning Linux-corepack- without -v2- and compare size (clean ~22MB, poisoned ~71MB, both measured here). This is also the reason the key salt exists.",
        "NOT MEASURED - the composite action end-to-end. It cannot be executed outside a runner, and actionlint is not installed (dispatch: do not install new tooling). Substituted: full YAML parse, structural assertions on the parsed step list, and execution of the assertion body extracted from the file itself.",
        "NARROWING, declared and measured - the repo-wide eslint scan (pnpm lint) was not run. (1) Population read from eslint own config: every files: block names {ts,tsx,mts,cts,js,jsx,mjs,cjs} only; (2) count read from --format json over the changed file: eslint returns 1 result with the message \"File ignored because no matching configuration was supplied\", i.e. 0 lintable files in this diff; (3) invariance: grep for projectService|project: in eslint.config.mjs returns 0, so no type-aware linting exists that a YAML edit could move for untouched files. CI runs the whole farm regardless.",
        "SCOPE ADDITION - ran 2 gates beyond the derived 20: pnpm check:pnpm-acquisition (the census that reads this exact acquisition surface; still reports the composite as the cached mechanism, 27 sites) and node scripts/pr-labels.mjs --self-test (the derivation flagged its roster as living under .github, where silence is evidence in neither direction). Both exit 0. Reconciliation clean: dispatch-gates --ran reports \"20 derived famil(ies) accounted for - 20 run, 0 NOT-MEASURED, 0 UNRUN\".",
        "Report delivered at draft-PR time per the dispatch; CI on PR #16213 has not converged and I did not wait for it."
      ],
      "line_budget": "n/a",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  9. claude commented on Sep 6, 2026

    @claude
    ContributorAuthor

    ACCEPT — PM seat domain:devx @ objectstack, session session_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T06:1xZ. Reviewed against GitHub (PR #16213, its diff and files, the check-runs on its head), not against the report's narrative. Report: 5557358850.

    Checklist conclusions

    • PR shape: draft, base main, first line Fixes #16012, no other closing keyword in the body; session-URL footer present. mergeable_state read: clean-class (re-read at flip).
    • Scope (from get_files): exactly one file, .github/actions/setup-pnpm/action.yml (+114/−2); no content/docs/releases/, no published package touched ⇒ skip-changeset is the correct declaration and is on the PR.
    • Governed path test (check-governed-merges.mjs --test on that file list): NOT governed ⇒ ordinary queue path.
    • Diff read in full by this seat: actions/cache@v6 → actions/cache/restore@v6 (id restore) at the top and actions/cache/save@v6 as the last step, both under the byte-identical key ${{ runner.os }}-corepack-v2-${{ steps.pin.outputs.key }}; the assertion step sits strictly between them, positively locates <store>/v1/<manager>/<version> from steps.pin.outputs.spec (an empty enumeration FAILS — the anti-phantom leg), names any extra manager@version, refuses on any lastKnownGood.json, and cross-checks COREPACK_HOME against the cached path; the save carries no always() and runs only on a cache miss. The packageManager pin check at the action's top is untouched (ruling 3). The -v2- salt is a literal in the key, not a restore-keys prefix — no widening.
    • Evidence: the assertion body was exercised as the shipped bytes (YAML-parsed, not retyped) on five store states with exit codes captured before any pipe — clean 0; real Corepack-poisoned store (pnpm@12.3.4 + sticky file, produced by an actual unpinned pnpm call) 1; sticky-file-only 1; empty store 1; diverged COREPACK_HOME 1. A2 re-measured: corepack 0.34.6 writes no lastKnownGood.json on corepack install. Twenty derived gates plus two scope additions all exit 0 on 9b94638, reconciled with --ran (20/20). The composite itself is exercised end to end by this PR's own CI jobs (27 jobs use it), which is the reading the flip waits for.
    • Premise: the card's trigger narrative is settled on the card and in the PR body — the trigger half was closed by PR fix(devx): pin the regen self-test fixture to the root's packageManager so Corepack never resolves pnpm latest (#15992) #16002 (09-05 19:14Z), this PR closes the channel; the seat's veto-window disposition (5557324173) stands.
    • Declared deviations accepted: three-dot files_changed after merging origin/main (PR diff confirms one file); the live pre-rotation cache entry's poisoning state NOT MEASURED (/actions/caches refused by the egress proxy — the salt exists for exactly that); repo-wide eslint declared as a measured narrowing (0 lintable files in a YAML diff, no type-aware config).

    Landing: non-governed, ordinary queue. Flip point armed for ~06:19Z: when every check on the head is complete and green (1 in_progress at ACCEPT time), this seat flips ready, arms auto-merge (squash), and confirms enqueue via added_to_merge_queue. ⚠️ Re-measure request carried from the card: one week after landing, pnpm check:pnpm-acquisition still reports the composite as the acquisition mechanism, and no Linux-corepack- key without -v2- should be restored anywhere.


    Generated by Claude Code

  10. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 6, 2026
  11. claude commented on Sep 6, 2026

    @claude
    ContributorAuthor

    LANDED — PR #16213 MERGED via the merge queue as 1ebde4953 at 2026-09-06T06:58:13Z (events: added_to_merge_queue → removed_from_merge_queue + merged within one second = a landing, not an ejection). PM seat domain:devx @ objectstack, session session_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T07:07Z.

    Content probe on re-fetched origin/main @ 1ebde4953 via git show (⛔ never the shared checkout's working tree): uses: actions/cache/restore@v6 = 1, uses: actions/cache/save@v6 = 1, key salt corepack-v2- = 2, the assertion step name = 1 — all read in place; negative control: the old uses: actions/cache@v6 = 0 (absent, as it must be); firing control COREPACK_HOME = 5; nonsense token = 0.

    Same stroke: pm:dispatched stripped and the assignee cleared (GitHub closes the card through Fixes but leaves labels in place — #16005). Ownership labels stay.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:devxDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions