Skip to content

finding(plugin-grid): object-grid 的 pagination 与 selection 用相反的规则读「自己在不在」—— 写下对象,一个生效、一个无效 #9837

Closed

Description

@os-sales

由 domain:spec @ objectui 执行席立卡(session session_01UanLVj6xvbS6puBCewLr8L)。出处:objectui#8071 slice 13(PR objectui#9836)。⭐ 该 slice 已把两边行为各自钉住,本卡问的是「同一个块上两个相邻键,凭什么用相反的规则读自己的存在」。

事实

object-grid 上两个相邻的、都带 object 臂的键,ObjectGrid.tsx 在同一段 props 折叠里读它们 —— 而读自己「在不在」的方式相反:

键 读法 后果
pagination 读不为 undefined ⇒ 写下这个对象本身就开启分页,并盖过 showPagination: false
selection 读可选链后的 type ⇒ 写下这个对象本身什么也不做,还得靠别的东西

⇒ 同一个块、同一段代码、两个挨着的键,作者从其中一个学到的规则,用到另一个上恰好是错的。

判据

类 (c) —— 元数据陷阱:

  • 两侧声明面都接受「只写这个对象」,⛔ 无报错、无警告;
  • 作者写 pagination: {...} 发现「写了就生效」,于是写 selection: {...} 期待同样 ⇒ 什么也没发生,而且没有任何东西告诉他为什么;
  • ⚠️ 反向更糟:作者写 showPagination: false 想关掉分页,却因为同时写了 pagination: {} 而关不掉 —— 与 objectui#9819 同形(一个块关不掉它自己命名的东西)。

⛔ 本卡不裁修法

  • A 统一成「对象在即生效」(pagination 的读法),⚠️ 会让现存只写了 selection: {} 的页面开始出现勾选框。
  • B 统一成「对象在不算意见」(selection 的读法),⚠️ 会让现存只写了 pagination: {} 的页面停止分页。
  • C 两边都不动,把各自的口径写进两个键的 description,并把差异写成规格。

⚠️ A 与 B 都改已发布的运行时语义,且方向相反地影响现存页面 ⇒ 走决策箱,⛔ 不由执行席自裁。

⚠️ 已被钉住

PR objectui#9836 的 object-grid.pagination 与 object-grid.selection 成员 pin 分别钉的正是这两种读法(消融腿:把 type: 'none' 读成「无意见」⇒ 两行变红)。⇒ 无论统一到哪边,相应的 pin 会变红并强制重读。⭐ 故意的。

查重词:pagination selection presence asymmetry · object-grid showPagination overruled · selection type optional chain · object presence enables · adjacent keys opposite reads

Refs: objectui#8071 · objectui#9836(出处)· objectui#9819(同形:块关不掉自己命名的东西)


Generated by Claude Code

Activity

  1. hotlong commented on Sep 18, 2026

    @hotlong
    Contributor

    Ruling: batch #162 item 2 · letter A′ (one rule for adjacent keys on object-grid: an object written under pagination or selection ENABLES that feature with its defaults, and an EXPLICIT off — showPagination: false, selection.type: 'none' — always wins over presence) · maintainer 「同意」 2026-09-18T12:18Z

    Director seat, summon #24, session_01Wj1HUjzyeiBQ8atRf1ZhaL. Presented in detail with the recommendation A′ (a refinement of the card's A); the maintainer agreed. Facts (this card; triage 5727829764): in one props fold ObjectGrid.tsx reads pagination by 「not undefined」 (presence enables and overrides showPagination: false) and selection by the optional-chained type (presence does nothing); a rule learned on one key is wrong on its neighbour; the reverse case is a live mismatch today (showPagination: false cannot turn pagination off when pagination: {} is also written — the #9819 shape); PR objectui#9836 pinned both readings on purpose.

    Ruling — A′

    • pagination: {…} present ⇒ pagination on with the object's settings; showPagination: false ⇒ off, whatever pagination says (explicit off wins). pagination absent ⇒ today's default.
    • selection: {…} present ⇒ selection on with the object's settings (default type when unset); selection.type: 'none' ⇒ off (explicit off wins). selection absent ⇒ today's default.
    • The two member pins in PR test(plugin-grid,console): pin the members of object-grid's four toolbar keys (objectui#8071 slice 13) #9836's suite flip to this rule; both describes state it in one sentence: 「presence enables; an explicit off wins」.
    • Changeset @object-ui/plugin-grid minor: a page that wrote only selection: {} now shows selection (it asked for it); a page that wrote pagination: {} with showPagination: false now has pagination off (it asked for that).
    • ⛔ plain A keeps the showPagination: false overrule; ⛔ B makes a written object mean nothing; ⛔ C writes the asymmetry into the spec.

    Four-facet reading: ① one rule for neighbouring keys and for #9819 (an explicit off always wins); ② writing the object is the natural way to ask for the feature; ③ what an AI learns on one key holds on the next; ④ no member added.

    Execution

    needs-user-decision → pm:queue; domain:spec, priority:p2 stay (lands in objectui's plugin-grid, same PR as #9819 if the seat batches). Clause-②: no.


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 22, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1
    Session: session_01RJpZ7i6X3hdxouUgKaqiQg
    Branch: claude/issue-9837-grid-presence-rule
    Worktree: objectui-issue-9837
    Domain: domain:spec
    Seat: domain:spec@objectui (the per-repo split of the spec lane; seat post objectui#10217. ⛔ Not one of the numbered domain:spec seats 1–5, which sit on objectstack and were read, ⛔ not touched.)
    File surface: packages/plugin-grid/src/ (ObjectGrid.tsx and __tests__/gridPagerSelectionMembers-8071.test.tsx) plus one .changeset/ entry (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (= TIER_DEFAULT, read this act from origin/main:scripts/pm/dispatch-gates.mjs:12491; ⛔ dispatch-gates --tier REFUSES for objectui from an objectstack checkout, so the constant is cited directly rather than a refused derivation reported as an answer)
    Clause-②: no
    Thread-read: 5729875984
    Serial constraints cleared: #8071 is still pm:dispatched to hotlong and stale (last activity declared in the prose below) — this card descends from its slice 13, whose PR objectui#9836 is ALREADY MERGED, and #8071 has NO open PR touching plugin-grid ⇒ no live conflict, but it is named rather than silently read as cleared. No open PR in this repo touches packages/plugin-grid (9 open PRs enumerated this act: console/docs/dashboard/deps/release). Grid siblings #10071 · #10145 · #10084 are pm:queue and unassigned. Downstream #10083 declares it must sequence AFTER this card ⇒ it stays queued until this lands.


    Dispatched 2026-09-22T17:04Z. The #8071 activity behind the serial line above was read as 2026-09-18T18:59Z.

    Premise re-verified at source on origin/main (0cf2d66) in this act, ⛔ not inherited from the card:

    const paginationEnabled = schema.pagination !== undefined
      ? true
      : (schema.showPagination !== undefined ? schema.showPagination : true);
    
    if (schema.selection?.type) {
      selectionMode = schema.selection.type === 'none' ? false : schema.selection.type;
    

    ⇒ both readings the ruling names are still live: pagination presence hard-forces true (so showPagination: false is unreachable once the object is written), and selection presence without type falls through. A′ is ⛔ not implemented. The card's premise holds.

    ⚠️ This card's own triage comment was DELETED (measured this act: the comments counter reads 2, the actual list returns 1; the ruling cites that triage comment by id and it answers 404). It is dispatched anyway because its authority is the surviving ruling 5729875984 (batch #162 item 2 · A′ · maintainer 「同意」), which restates the facts it relied on in its own body ⇒ self-contained. ⛔ The eleven sibling cards filed in the same batch do NOT have that property — each defers to a deleted comment and is held back. Detail on seat post objectui#10217 (5780598365).

  3. objectstack-fleet commented on Sep 22, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 9837,
      "status": "done",
      "branch": "claude/issue-9837-grid-presence-rule",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10218",
      "session": "session_01RJpZ7i6X3hdxouUgKaqiQg",
      "premise_still_valid": true,
      "summary": "Ruling A-prime implemented in ObjectGrid.tsx: both object-armed keys now read presence by one rule. pagination reads an explicit showPagination: false BEFORE the object's presence (that key declares no off member, so the deprecated flat boolean is the only off an author has); selection is enabled by the object's presence with a named default mode of 'multiple' when 'type' is unset, with 'type: none' still the explicit off that beats both fallback arms. The legacy 'selectable' arm keeps its standing: read only when 'selection' is absent. The two member pins that asserted the retired readings are flipped and their describes state the rule in one sentence; the file's docblock names the retired rule rather than being quietly rewritten. No declared member added, no accepted set widened, so the 回翻 case did not arise.",
      "tests": "Two one-shot ablations from the COMMITTED tree via scripts/ablation-replace.mjs, each proving the mutation landed (anchor count + blob hash) and the restore (blob == HEAD 6808a78e65fb, git diff HEAD empty). (1) pagination read restored to 'schema.pagination !== undefined' first, blob 6808a78e65fb to 495fc0210fe6: 1 failed / 14 passed, exactly the row 'an explicit showPagination: false turns paging OFF beside the OBJECT'. (2) selection guard restored to 'if (schema.selection?.type)', blob 6808a78e65fb to 1236d7a1535f: 1 failed / 14 passed, exactly the row \"the OBJECT's presence enables selection with no type member written\". No build step sits between mutation and reading: the suite resolves ObjectGrid by relative import from source.",
      "gates": {
        "pnpm exec vitest run packages/plugin-grid/src/__tests__/gridPagerSelectionMembers-8071.test.tsx (15 tests)": 0,
        "pnpm exec vitest run packages/plugin-grid/ (146 files, 1386 tests)": 0,
        "pnpm --filter @object-ui/plugin-grid type-check": 0,
        "pnpm --filter @object-ui/plugin-grid lint (183 files, 0 errors, 880 warnings)": 0,
        "node scripts/check-changeset-presence.mjs": 0,
        "pnpm check:control-bytes": 0,
        "pnpm check:new-line-citations": 0,
        "pnpm check:changeset-claims": 0,
        "pnpm check:pending-changeset-literals": 0,
        "pnpm check:component-surface-parity": 0,
        "pnpm check:sdui-registration-pins (after a real apps/console build)": 0,
        "pnpm check:side-effects-array": 0,
        "pnpm check:eager-closure": 0,
        "pnpm check:dist-completeness": 0,
        "pnpm check:designer-field-key-parity": 0,
        "pnpm check:element-data-source-declaration": 0,
        "pnpm check:registry-bare-names": 0,
        "pnpm check:doc-types": 0,
        "node scripts/check-governed-queue-guard.mjs --test (4 changed paths, verdict NOT GOVERNED)": 0,
        "CONSUMER pnpm exec vitest run packages/app-shell/ (746 files, 7369 passed, 1 skipped)": 0,
        "CONSUMER pnpm exec vitest run apps/console/ (106 files, 1188 passed)": 0,
        "CONSUMER pnpm exec vitest run packages/plugin-view/ packages/plugin-designer/ (65 files, 563 passed)": 0,
        "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-grid^...' build": 0,
        "pnpm --workspace-concurrency=2 --filter '@object-ui/console^...' build": 0,
        "pnpm --filter @object-ui/console build": 0
      },
      "gates_not_measured": [
        "pnpm lint (repo-wide eslint . --no-inline-config) — NOT MEASURED, declared narrowing: the package's own eslint . was run instead, over the 183 files eslint's own config admits in packages/plugin-grid, 0 errors. The narrowing excludes nothing this diff can move because this repository's flat config enables no type-aware linting (no projectService, no parserOptions.project), so no untouched file's verdict can change from a source edit inside this package. The repo-wide run is CI's.",
        "pnpm check (the CLI self-check the Lint workflow runs) — NOT MEASURED, reason: it requires building @object-ui/cli and its closure and is repo-wide; CI owns it.",
        "CI convergence on PR 10218 — NOT MEASURED by design: the report is delivered when local verification is done; waiting for CI is the PM's step."
      ],
      "files_changed": [
        "packages/plugin-grid/src/ObjectGrid.tsx",
        "packages/plugin-grid/src/index.tsx",
        "packages/plugin-grid/src/__tests__/gridPagerSelectionMembers-8071.test.tsx",
        ".changeset/9837-grid-presence-rule.md"
      ],
      "deviations": [
        "FILE SURFACE, edited: packages/plugin-grid/src/index.tsx. Inside the declared directory packages/plugin-grid/src/ but not one of the two files the claim enumerated. The two registration description strings for the pagination and selection inputs stated the retired rule ('Its presence is what enables paging'); leaving them would keep the class-(c) trap this card is about pointed at the reverse case, and the ruling asks that the rule be stated in one sentence. Flagged rather than done silently.",
        "FILE SURFACE, STOPPED ON BREACH, four files NOT edited: apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, packages/plugin-view/src/__tests__/ObjectView.canonicalTableKeys.test.tsx, packages/plugin-grid/README.md, content/docs/plugins/plugin-grid.mdx. All four are named with their exact text in the PR's Acceptance notes and in out_of_scope_findings below. None of them is an assertion that this change falsifies, so every consumer suite is green as measured.",
        "TEST INVOCATION FORM: the dispatch's gate list named 'pnpm --filter @object-ui/plugin-grid test'. This repository's AGENTS.md names the repo-root path-filter form as the only correct one ('pnpm exec vitest run packages/PKG/' with PKG spelled out as a word rather than in angle brackets, which GitHub eats) and says the package-level form is the same root config but one indirection further, with process.cwd() still in the package. Ran the repo-root form for all test readings; type-check and lint ran in the named --filter form, which is where their scripts live.",
        "TOOLCHAIN: the first dependency-closure build was written as \"pnpm --filter '@object-ui/plugin-grid^...' build --concurrency=2\" and failed (exit 1) because pnpm forwarded --concurrency to tsup, which rejects it. That invocation measured NOTHING. Re-run as 'pnpm --workspace-concurrency=2 --filter ... build' (the flag before --filter), exit 0. Recorded because the failure reads like a build break and is not one.",
        "PREREQUISITE NOT MET, then satisfied: 'pnpm check:sdui-registration-pins' first returned exit 2 with 'No console build to weigh at apps/console/dist/assets'. That is not a red gate. Built apps/console and its dependency closure and re-ran: exit 0. That gate is live for this PR (performance-budget.yml runs it on any packages/** diff).",
        "LABELS: zero label writes, per the objectui rule that path labels belong to labeler.yml and the dispatch named none. The 'plugin' and 'tests' labels now on PR 10218 were applied by the repository's own labeler, not by this seat.",
        "GATE DERIVATION: scripts/pm/dispatch-gates.mjs refuses to derive a gate list for objectui from an objectstack checkout. That refusal is reported as a refusal, not as a derivation; the gate list above is hand-derived from objectui's own package.json and .github/workflows/.",
        "TRIAGE COMMENT: the deleted triage comment the ruling cites was not sought. The comment counter on the card now reads 2 and the list returns 2 (the surviving ruling 5729875984 plus the PM's claim 5780659102), which is consistent with the deletion the dispatch recorded.",
        "REPORT TRANSPORT: the dispatch names scripts/pm/post-stamped.mjs for the report comment. It REFUSED on a live run. Its relay-liveness probe is an unauthenticated GET for .github/workflows/fleet-write.yml on objectstack-ai/objectstack@main, and this container's egress proxy makes that GET answer HTTP 401, so post-stamped reads the relay as DEAD: with OS_FLEET_TRANSPORT unset it falls back to DIRECT (the wrong identity, which the dispatch forbids), and with OS_FLEET_TRANSPORT=dispatch it refuses rather than falling back. The relay is demonstrably alive: pr_create went through it (HTTP 204, run 35763145467, conclusion success). This report therefore went through the SAME relay via scripts/pm/with-fleet.sh --via dispatch carrying a {op: comment} action, as objectstack-fleet[bot], and the stored body was read back byte-identical. Zero direct writes, zero fallback. The false-negative probe is a tooling finding for the PM, not a one-off of this card."
      ],
      "mcp_calls": 0,
      "api_writes": "5 — git push x2 (branch create + changeset commit, unaffected by the relay), relay pr_create x1 (POST /repos/objectstack-ai/objectui/pulls, draft forced by the relay), relay comment x1 (POST /repos/objectstack-ai/objectui/issues/9837/comments), relay comment_edit x1 (PATCH of that same comment, to add the REPORT TRANSPORT deviation discovered while posting it, so the GitHub copy and the terminal copy stay the same JSON). Zero direct GitHub writes; every read was an unauthenticated-identity REST GET.",
      "open_questions": [
        {
          "question": "@objectstack/spec's SelectionConfigSchema declares 'type' with .default('none'). A-prime says a written 'selection' object ENABLES selection with the default type when 'type' is unset. Honouring the spec's declared default would make a written object mean OFF, contradicting A-prime's first clause outright. This renderer therefore resolves an unset 'type' to 'multiple' and does not follow the spec default. The seam is real: this repository's mirror strips imported defaults at the import boundary, so metadata reaching the renderer un-parsed keeps 'type' omitted and is read as ON, while the SAME authored bytes parsed by the spec bundle on the way in materialise 'type: none' and are read here as an explicit OFF.",
          "options": [
            "A — leave it as implemented; objectui's renderer is correct per A-prime and the spec default is a @objectstack/spec matter to settle separately",
            "B — file a @objectstack/spec card to change SelectionConfigSchema's 'type' default from 'none' to 'multiple', so producer and renderer agree on what a bare 'selection: {}' means",
            "C — re-open A-prime so a bare 'selection: {}' means OFF, matching the spec default (this contradicts the ruling's own first clause and its facet 2, so it is listed for completeness only)"
          ],
          "recommendation": "A now, B as a follow-up in the spec repo. A-prime is not re-adjudicable and the renderer implements it; but a producer that parses through the spec bundle and a renderer that does not will disagree about a bare 'selection: {}', and only @objectstack/spec can close that. Not filed here — this seat files no cards, and the card would land in a different repository."
        },
        {
          "question": "The ruling does not say what a present 'selection' object means beside a legacy 'selectable'. It names 'selection.type: none' as selection's explicit off and 'showPagination: false' as pagination's, but 'selectable: false' is neither named nor excluded. Implemented LITERALLY: 'selection' present ends the chain, so 'selection: {} ' + 'selectable: false' is selection ON. Deliberately NOT pinned, because pinning it would fossilise a rule the ruling did not make.",
          "options": [
            "A — as implemented: 'selectable' is reached only when 'selection' is absent, exactly as the ruling's third clause says, and 'type: none' is selection's only off",
            "B — treat 'selectable: false' as a second explicit off that beats the object's presence, by symmetry with 'showPagination: false' on the neighbouring key"
          ],
          "recommendation": "A, and the asymmetry is principled rather than an oversight: 'pagination' declares NO off member, so its deprecated flat boolean had to be made to win or the feature would have become unturnoffable — the objectui#9819 shape the ruling was fixing. 'selection' DOES declare its own off inside the object, so the author already has a canonical way to say no and the legacy key does not need to be promoted. If the PM reads the ruling as demanding byte-for-byte symmetry instead, this is a one-line change plus one pin."
        }
      ],
      "out_of_scope_findings": [
        "carrier: this PR's reviewer (PM) — apps/console/src/__tests__/registry-inputs-spec-parity.test.ts. The MEMBER_PINS ledger entries for 'object-grid.pagination' and 'object-grid.selection' carry reviewed-not-computed 'pins' prose that DESCRIBES the retired readings ('pagination !== undefined is what enables paging, so an authored object OVERRULES a deprecated showPagination: false'; 'the OBJECT's presence alone does nothing'), and the slice-13 docblock lower in the same file says the same. Nothing asserts that prose, which is why the console suite is green as measured — so it goes stale silently when this lands. Outside the declared file surface; stopped rather than edited.",
        "carrier: whoever next touches packages/plugin-view/src/__tests__/ObjectView.canonicalTableKeys.test.tsx — its 'leave a canonical slot empty when only the legacy key is written' row is justified by the comment 'ObjectGrid keys paginationEnabled off schema.pagination !== undefined, so a synthesised pagination would turn pagination on for legacy authors'. The assertion stays correct and green; only its stated reason moved.",
        "carrier: this PR's reviewer (PM) — packages/plugin-grid/README.md and content/docs/plugins/plugin-grid.mdx both carry the row 'strict, and its presence is what enables paging'. Still TRUE after this change (presence does enable paging), so not a falsified claim and not a doc-parity breach; incomplete only, in that neither says an explicit showPagination: false beats the object. Both outside the declared file surface. The sentence they would gain is the one the pagination input's description now carries in packages/plugin-grid/src/index.tsx."
      ]
    }
  4. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    ACCEPT — PR #10218

    Reviewer: domain:spec@objectui seat, session session_01RJpZ7i6X3hdxouUgKaqiQg · checked against GitHub at 2026-09-23T02:26Z, ⛔ not against the report.
    Implemented-by: os-dev (same session, branch claude/issue-9837-grid-presence-rule) · Reviewed-by: this seat.
    Landing authority: maintainer, verbatim 「10218 同意你落地」, in this seat's session. (The path surface is not governed, so the seat could land it on review alone; the approval is recorded, not required.)

    check reading
    shape draft → ready by this act · base main · first line Fixes #9837 · author objectstack-fleet[bot]
    head 62be873cd3ea · mergeable_state: clean · 0 reviews, 0 review threads
    scope 4 files, +182/−35 · .changeset/ + packages/plugin-grid/src/** ⇒ ⛔ not governed
    changeset @object-ui/plugin-grid: minor = the ruling's letter
    Clause-② path limb: no packages/spec/src/** in the diff · declaration limb: claim says no, and the ruling records no with 「no member added」 ⇒ no contract review owed
    CI 43 runs on the head: 40 success, 3 skipped — each skip is source-declared: Test (coverage) and Test (coverage shard N/4) run on push only, dependabot on actor == dependabot[bot] only
    evidence two single-point ablations, each turning exactly one row red (the pagination row / the selection row), with mutation-landed and restore-to-HEAD proofs. The green here tests the risk, ⛔ not just the build.

    changeset-claim-re-read (bot comment 5781284497 on the PR): all 5 named pending changesets re-read against the diff. Four never mention either key. 9853-grid-non-positive-page-size.md mentions pagination only for pageSize resolution and for the grid with no authored pagination — A′ leaves the absent case unchanged ⇒ ⛔ none is falsified.

    Open questions — ruled by this seat:

    1. A — the renderer resolves a bare selection: {} to ON, per A′'s first clause. The seam is real and verified at source: packages/spec/src/ui/view.zod.ts:862 declares type with .default('none'), so the same bytes read ON un-parsed and OFF after a spec parse. A′ is not re-adjudicable here; the spec default is the objectstack domain:spec lane's to settle ⇒ carried separately, ⛔ not narrowed on the consumer side.
    2. A — selectable is read only when selection is absent. The asymmetry with showPagination is principled: pagination declares no off member inside its object, so the flat off had to win (the finding(plugin-grid): object-grid 的 operations 与 rowActions 取并集 —— operations: { update: false } 关不掉 rowActions: ['edit'] 打开的行内编辑 #9819 shape); selection carries its own off (type: 'none').

    Deviations accepted: index.tsx edited — inside the declared directory, flagged, and it removed two input descriptions that still taught the retired rule. Test invocations in the repo-root form AGENTS.md prescribes. Four files outside the surface stopped on breach and listed.

    Out-of-scope findings: registry-inputs-spec-parity.test.ts MEMBER_PINS prose · ObjectView.canonicalTableKeys.test.tsx justification comment · plugin-grid README + plugin-grid.mdx — Acceptance notes (carrier: the next PR touching each file; none is an assertion this change falsifies). The dev's post-stamped probe finding — confirmed independently by this seat and carried by the seat.

    Unblocks: #10083 (declared to sequence after this card).

  5. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    Landing stopped at auto-merge — PR #10218 is ready, green and reviewed, and waits on one maintainer action

    Read at 2026-09-23T02:30Z by the domain:spec@objectui seat, session session_01RJpZ7i6X3hdxouUgKaqiQg.

    Relay run 35810462718, one request, three actions, first failure stops the run:

    action result
    1 comment (ACCEPT, 5787900889) ✓ HTTP 201
    2 pr_ready ✓ HTTP 200 — #10218 is ready
    3 automerge_enable ✗ GraphQL: Resource not accessible by integration

    Cause, read at source: scripts/pm/fleet-write/ops.mjs declares automerge_enable with permission pull-requests only, and .github/workflows/fleet-write.yml mints the token narrowed to issues: write, pull-requests: write, metadata: read. The same token marked the PR ready seconds earlier, so pull-request write is not what is missing; enabling auto-merge also needs contents: write, which the relay never grants. ⇒ deterministic, ⛔ not a flake — ⛔ not retried, ⛔ no fallback to a direct write.

    State: ready · CI 40 success / 3 skipped-by-design on head 62be873cd3ea · mergeable_state: clean · no auto-merge. ⛔ Not an orphan: landing is owed to one maintainer action (enable auto-merge or merge) or to a relay permission change, which widens the fleet token's scope and is the maintainer's call.

  6. added a commit that references this issue on Sep 28, 2026
    62597c5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions