Repository navigation
feat(pm/fleet-write): the relay token carries workflows write on every stroke, spent by automerge_enable on a pull that changes a workflow file - #22827
Conversation
…y stroke, spent by automerge_enable on a pull that changes a workflow file Ruling A on the card (comment 6104822731, maintainer 「22708 A」): the `automerge_enable` row gains `alsoSpends: ['workflows']`, `PERMISSIONS` gains `workflows: 'write'` between `contents` and `metadata`, the mint step declares the literal `permission-workflows: write`, and the validate self-test pins the grant: the alsoSpends pin names both rows, the map pin and the token-grants pin carry the fifth grant, and two new refused-by-construction cases pin that `workflows` is spent by `automerge_enable` alone and that `PERMISSIONS` is nothing wider than the union of every row's spends. The `ops.mjs` header and the landing-operations reference record the lowered human floor beside the grant, citing the ruling, so a later reader does not take the wider token for a drift. No new gate. `STROKE_SCOPED_PERMISSIONS` is unchanged: the grant is literal, not per stroke. Red-before: with only `PERMISSIONS` widened, `validate.mjs --self-test` reds 3 of 128 cases; with the pins, 130 pass. execute 111, dispatch 216. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011u73oxZ5X95qrARPTeoU6v
Contract reviewServed-tier: Reviewed by the skills seat 2 in seat ( ① Derived judgments
② Semver levelNo published package touched; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)· PR #22827 · #22708席位 2( 改了什么:车队中继铸出的 App 令牌在每一笔写上常驻 为什么改:你裁了 A(「22708 A」):以后改 CI 工作流文件的 PR 由席位中继入队,不再每张等人点。本 PR 自己也改了工作流文件,所以它是最后一张要人点入队的。 风险与代价(含回滚):最大风险在 App 侧:铸币会在每一笔申请 席位意见:ACCEPT。61 条派生门禁全跑、对账 61/61;CI 全绿(两项 path-skip 与昨天 #22796 相同); 你要做的:两步。① 先到 objectstack-fleet App 设置确认 Repository permissions → Workflows = Read and write,且 objectstack-ai 组织安装已接受;② 再对本 PR 点一次 ready + auto-merge(或入队)。合并后第一笔中继写失败即 revert。 Generated by Claude Code |
Fixes #22708
Clause-②: no
Ruling A on the card (comment 6104822731; maintainer 「22708 A」): the fleet relay's App token carries
workflows: writeon every stroke, so a seat may enqueue a pull that changes.github/workflows/**. This PR is that change, and it is itself the last workflow-file pull a human enqueues: it changesfleet-write.yml, so the token it widens cannot land it.Who wrote it, and under which rule. The PM seat itself (skills seat 2,
session_011u73oxZ5X95qrARPTeoU6v), not an os-dev, under the PM red line's one exception: a maintainer's explicit per-PR authorization of an internal-tooling PR. The authorization, verbatim, from the maintainer in this seat's session chat at 2026-10-11T10:52Z: 「22708 你可以处理:执行 #22708 裁决 A:按该卡开发报告(评论 6106463015)里 deviations D1、D2 的说明,修改 scripts/pm/fleet-write/ops.mjs、.github/workflows/fleet-write.yml、scripts/pm/fleet-write/validate.mjs。跑 validate.mjs、execute.mjs、dispatch.mjs 的 --self-test 和相关 gates,然后开 draft PR。」 The first dev's attempt (report 6106463015) was stopped by the session's permission classifier at thevalidate.mjspins; its measured premises and its preparedops.mjs+fleet-write.ymlpatch are used here unchanged.What changed
scripts/pm/fleet-write/ops.mjs:PERMISSIONSgainsworkflows: 'write'betweencontentsandmetadata(the order the mint's literal list and the pins compare); theautomerge_enablerow gainsalsoSpends: Object.freeze(['workflows']); the header's permission paragraph, thePERMISSIONSJSDoc, thealsoSpendsfield doc and the transfer section's "one widening" sentence are updated, and the lowered human floor is recorded beside the grant with the ruling's comment id.STROKE_SCOPED_PERMISSIONSis unchanged: the grant is literal, not per stroke..github/workflows/fleet-write.yml: the mint step declares the literalpermission-workflows: writeafterpermission-contents, with a ONE-consumer comment; the header's grant list and the two "four grants" sentences read five.scripts/pm/fleet-write/validate.mjs: the alsoSpends pin expects[['pr_create', ['issues']], ['automerge_enable', ['workflows']]]; the map pin and the token-grants pin carry the fifth grant; two new cases in the refused-by-construction battery (floor 20 to 22):workflowsis spent byautomerge_enablealone asalsoSpendsand is no row'spermission;PERMISSIONSminusmetadataequals the union of every row'spermissionandalsoSpends, both exactlyactions / contents / issues / pull-requests / workflows. ThetokenPermissionsOfdoc comment says five..claude/skills/pm-dispatch/references/landing-operations.md:67(Tier S; one line for one line, 117 bytes; the file stays 101/101): diagnostic step ③ now reads the token as carryingworkflows: writeby the ruling, so a refusal there is a grant drift (the App's accepted permissions), not a missing grant..claude/skills/pm-dispatch/SKILL.md:263(the human-floor sentence) is untouched.Verification (head
db16cfc7d; baseb7cd1af9d,origin/mainwhen the worktree was cut)PERMISSIONSwidened and the pins at base,node scripts/pm/fleet-write/validate.mjs --self-testexits 1, "3 of 128 case(s) failed" (the alsoSpends pin, the map pin, the token-grants pin). After the pins: 130 cases pass across 10 batteries.execute.mjs --self-test111 cases anddispatch.mjs --self-test216 cases, exit 0;pnpm check:pm-fleet-write-validate,-execute,-dispatchexit 0.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree with no paths derived 61 commands atb7cd1af9d; every one ran alone with its exit captured before any pipe (the tool's documented idiom); the reconciliation line:✓ dispatch-gates --ran: 61 derived famil(ies) accounted for — 61 run, 0 NOT-MEASURED (a DERIVED zero — all 61 recorded an exit code and none of them is 3).pnpm --filter @objectstack/lint run check:doc-formula-expressionsfirst answered exit 3 (PREREQUISITE NOT MET:@objectstack/formulaand@objectstack/lintunbuilt); the@objectstack/lint...closure was built under the verify lock (VERDICT command-exit 0, 141 s) and the rerun exits 0.pnpm check:pm-dispatch-gates(the long battery) exit 0.check-skill-line-ratchet:landing-operations.md is 101 lines (ceiling 101; headroom 0).check:pm-skill-id-lint,check:nul-bytes,check:pm-governed-merges,check:pm-governed-prose,check:skill-frame-sync,check:required-contexts,check-self-test-wired,check-self-test-workflow-commands,check-whole-set-label-write,check-scripts-symbol-anchors,check-ci-filter-parityexit 0 (all in the 61).scripts/pm/**,.github/**and.claude/**ship in no package'sfiles[], so the PR takesskip-changeset.Premises (report 6106463015, re-read on this base)
actions/create-github-app-token@v3declares thepermission-workflowsinput (action.yml:143, read at the tag ref; the sha read was refused by the proxy).execute.mjshas no token-grant surface (PERMISSIONSimported at:164, used nowhere), so the pin lives invalidate.mjs.REFUSED_PATH_FAMILIEScarries/\/git\//and/\/contents\//, so the wider token reaches no file write through any row; the refused-by-construction battery pins that over every path every op can spell.Risk the maintainer checks before this merges (NOT MEASURED from the seat)
The mint step requests
permission-workflows: writeon EVERY relay stroke. If the objectstack-fleet App's registration, or the organization installation's accepted permissions, lacks Workflows: Read and write,actions/create-github-app-tokenfails on every stroke: every relay write stops, not only this class of pull./app/**is unreachable from seat egress, so this cannot be read here. Check: the App's Repository permissions show Workflows = Read and write, and the installation onobjectstack-aihas accepted that change. The first relay stroke after the merge is the measurement; if the mint fails, revert this PR.Acceptance notes
workflows: writeso seats can enqueue pulls that change.github/workflows/**, or stay a human-queue item? #22708 after the merge: the first pull the widened token enqueues.pr_update_branchon a pull whose base brought workflow-file changes may also needworkflows(the platform's merge commit changes workflow files on the head); the literal grant covers it either way, so noalsoSpendsbeyond the ruling's row.scripts/pm/fleet-write/execute.mjs:164importsPERMISSIONSand never uses it (a dead import; noted, not filed).维护者速读(草稿)
改了什么:车队中继(fleet-write)铸出的 App 令牌在每一笔写上常驻
workflows: write;automerge_enable行登记它花费这项授权(改.github/workflows/**的 PR 入队需要);validate 自测钉死:授权集与 workflow 字面输入一致、workflows只由该行花费、授权集不比各行所花更宽。另把landing-operations.md里「token 缺 workflows 权限」那条诊断改成「令牌常驻该权限,仍拒即授权漂移」。不加门禁。为什么改:你裁了 A(「22708 A」):以后改 CI 工作流文件的 PR 由席位中继入队,不再每张等人点一下。本 PR 自己也改了工作流文件,所以它是最后一张需要人点入队的。
风险与代价(含回滚):最大风险在 App 侧:铸币会在每一笔申请
permission-workflows: write;若 App 注册或组织安装没接受 Workflows 读写权限,每一笔中继写都在铸币处失败,整个中继停摆,不只这一类 PR。席位测不了这项(到不了/app/**)。回滚 = revert 本 PR。代价:令牌权限面永久多一项(可改写工作流文件的能力),安全/权限边界的人工地板为这一项降低,出处已写在代码旁。席位意见:(席位在评论里定稿)
你要做的:两步。① 先确认 objectstack-fleet App 的 Repository permissions 里 Workflows 为 Read and write,且组织安装已接受;② 然后点一次 ready + auto-merge(或入队)。合并后第一笔中继写就是实测,失败即 revert。
Generated by Claude Code