Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

ObjectGrid 用 (schema as any) 读的 4 个键不在 GRID_QUERY_INPUTS 里 —— #4648 要消除的「渲染器读得到、声明面否认」在这些键上仍然存在 #5091

Closed

Description

@yinlianghui

发现于 #5065 的实施(cast 感知读取点普查)。Filed unassigned, not claiming.

现象

GRID_QUERY_INPUTS(packages/plugin-grid/src/index.tsx:145)是 object-grid 发布给
manifest / 设计器 / 生成的 sdui-intrinsics.d.ts 的授权面。该块自己的注释写明了它存在的
理由:

每一个都是 ObjectGrid 今天就读的键,在这份清单落地之前,写了其中任一个的作者会从
sdui-parser 拿到 unknown-prop —— 一个明明有效的键;设计器面板和生成的
sdui-intrinsics.d.ts 却否认它存在。

普查 ObjectGrid.tsx 的 cast 形读取点后,仍有 4 个键处于那个状态 —— 渲染器读、清单不认:

键 读取点 在 GRID_QUERY_INPUTS?
columnState ObjectGrid.tsx:611、:625、:626、:629 ❌
rowActionDefs ObjectGrid.tsx:748(两处)、:984 ❌
maxInlineRowActions ObjectGrid.tsx:2048 ❌
hideRowHeightToggle ObjectGrid.tsx:3150 ❌

对照:同一批 cast 读点里的 bulkActionDefs(:985)与 userActions(:987)已经在清单里,
说明这不是「cast 读的键一律不声明」的约定,而是漏了这 4 个。

四个键全部用 (schema as any).KEY 拼写,所以按普通 schema.KEY 口径做的键面普查也看不见
它们 —— 这正是 #5057 那类误判的来源。

复核方式

grep -nP "\(\s*schema\s+as\s+[^)]*\)\s*\.\s*\w+" packages/plugin-grid/src/ObjectGrid.tsx
sed -n '145,180p' packages/plugin-grid/src/index.tsx     # 声明面全表

逐键对照清单里的 name: 即可。

注意:这几个键要不要声明,不是纯补录

  • columnState 是用户态(列宽 / 列序的持久化载荷),ObjectGrid.tsx:643 的注释说它经
    dataSource.updateViewConfig 回写;把它发布成授权面等于承认它可手写。
  • hideRowHeightToggle / maxInlineRowActions 读起来像宿主/内部开关,不像作者面。
  • rowActionDefs 与已声明的 bulkActionDefs 是对称的一对,只有它没声明,看起来最像单纯漏项。

所以四个键可能分属两类结局:补进清单,或按 ADR-0049 的 enforce-or-remove 判为非授权面并从
schema 读点移走。需要裁定,不是机械补录。

同族

分级

交 PM 分诊。今天的可见症状与 #4648 描述的一致:作者写这些键会被 sdui-parser 判
unknown-prop,而渲染器其实读得到。

Activity

  1. yinlianghui commented on Aug 17, 2026

    @yinlianghui
    ContributorAuthor

    补:正文由 issues 端点存储时会剥掉末尾 footer,故以评论补齐。已读回确认正文完整、无 <+字母被吞。


    Generated by Claude Code

  2. yinlianghui commented on Aug 18, 2026

    @yinlianghui
    ContributorAuthor

    第 5 个键:onNavigate —— 同一状态(渲染器读、GRID_QUERY_INPUTS 不认),发现于 #5087 的实施(PR #5103)。附在本卡而不另立卡:它与既有 4 个键是同一个裁定(补进清单 vs 判为非授权面并从 schema 读点移走),拆开会把一个决定分到两张卡上。

    本卡的普查用的是 cast 形((schema as any).KEY),而 onNavigate 是平读 schema.onNavigate,所以那轮扫描结构上看不见它 —— 与 #5057 的教训方向相反的同一个盲区。

    键 读取点 在 GRID_QUERY_INPUTS? 在 ObjectGridSchema 接口?
    onNavigate ObjectGrid.tsx:1132,传入 useNavigationOverlay ❌ ❌
    // packages/plugin-grid/src/ObjectGrid.tsx:1129
    const navigation = useNavigationOverlay({
      navigation: schema.navigation,
      objectName: schema.objectName,
      onNavigate: schema.onNavigate,
      onRowClick,
    });
    

    同段里 schema.navigation 与 schema.objectName 都在声明面上,只有 onNavigate 不在 —— 与本卡 rowActionDefs / bulkActionDefs 那组「对称的一对只声明了一个」是同一种漏项形状。

    这一个比另外 4 个更该判为非授权面,理由是它函数值:schema 是可序列化文档,装不下函数,所以它不可能经元数据往返。它能被平读到、且 tsc 不报错,纯粹是 BaseSchema 的 [key: string]: any 索引签名(packages/types/src/base.ts)兜住了 —— 也就是说声明面对它结构上无法发出异议。可对照:另外九个回调名(onRowClick / onRowSelect / onCellChange / onRowSave / onBatchSave / onEdit / onDelete / onBulkDelete / onAddRecord)都只存在于 ObjectGridComponentProps,schema.on* 读取点为零 —— 已逐个复核。onNavigate 是这条界线上唯一的破口。

    复核:

    grep -n "schema\.onNavigate" packages/plugin-grid/src/ObjectGrid.tsx   # :1132
    grep -n "onNavigate" packages/plugin-grid/src/index.tsx                # 无命中(不在 GRID_QUERY_INPUTS)
    sed -n '532,760p' packages/types/src/objectql.ts | grep -n onNavigate  # 无命中(不在 ObjectGridSchema)
    

    附带影响,已在 PR #5103 处理:README(#5089)与文档站页面原本都写「the grid … never reads a callback off the schema」。对那九个回调名成立,作为全称判断则被 schema.onNavigate 证伪,故文档站侧已收窄为「never reads any of these nine off the schema」。本卡裁定若把 onNavigate 移出 schema 读点,该句可恢复成全称。


    Generated by Claude Code

  3. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    Contributor

    Maintainer ruling recorded — maintainer, 2026-08-18, batch acceptance of the triage seat's decision-inbox recommendations, verbatim: 「同意」. Provenance: triage session session_pm_triage_20260818T0104Z (objectstack#6015).

    Ruled, per key: rowActionDefs → into GRID_QUERY_INPUTS (the symmetric partner bulkActionDefs is already declared; this is the pure omission). columnState → non-author surface (user-state persistence payload written back via dataSource.updateViewConfig; publishing it would bless hand-authoring it). hideRowHeightToggle / maxInlineRowActions → non-author surface (host/internal switches). The three non-author keys get exemption comments at their read sites naming this ruling, stay out of the manifest and the docs, and the sweep tooling treats them as deliberately unlisted rather than missed.

    Label needs-user-decision → pm:queue in the same stroke.


    Generated by Claude Code

  4. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 6
    Session: session_01RV6yuVCxymHYE16PL9vQkE
    Branch: claude/issue-5091-grid-query-inputs-four-keys
    Worktree: objectui-issue-5091
    Domain: repo:objectui (execution seat)
    File surface: packages/plugin-grid/src/index.tsx (the GRID_QUERY_INPUTS table), packages/plugin-grid/src/ObjectGrid.tsx (exemption comments at the three non-author read sites), plus packages/plugin-grid tests. ⛔ OUT: packages/plugin-view / plugin-list (#5177, PR5231 open), packages/auth + packages/app-shell/src/providers (#5198), packages/cli (#5127), packages/components/src/renderers/form/** (#4259), packages/types (#5186 just merged — rebase, do not re-touch).
    Container & model: M, mode:subagent, model: opus — mechanical per key, but four keys go four different ways and one of them is a trap (below).
    Clause-②: no, and this is a judgement call worth stating. Adding rowActionDefs to GRID_QUERY_INPUTS makes sdui-parser stop emitting unknown-prop for a key the renderer already reads — it removes a false rejection of an already-working key rather than admitting new behaviour. The three non-author keys move nothing at all; they gain comments. No accept/reject boundary moves in the direction that would make this fable-mandatory.
    Serial constraints cleared: packages/plugin-grid is FREE as of this round — #5217 closed with no PR (its premise was falsified; the fix had already landed as PR4670 on 2026-08-15), so the claim that was holding ObjectGrid.tsx is released. #4314's PR5209 and #4538's PR5218 merged earlier. Nothing open touches plugin-grid. Re-verify at your claim.

    Zone 1 — the ruling, verbatim, and it is PER KEY

    Maintainer, 2026-08-18, batch acceptance of the triage seat's decision-inbox recommendations, verbatim: 「同意」. Recorded on this card:

    > Ruled, per key: rowActionDefs → into GRID_QUERY_INPUTS (the symmetric partner bulkActionDefs is already declared; this is the pure omission). columnState → non-author surface (user-state persistence payload written back via dataSource.updateViewConfig; publishing it would bless hand-authoring it). hideRowHeightToggle / maxInlineRowActions → non-author surface (host/internal switches). The three non-author keys get exemption comments at their read sites naming this ruling, stay out of the manifest and the docs, and the sweep tooling treats them as deliberately unlisted rather than missed.

    So: one key in, three keys commented, none removed. ⛔ Do not "tidy" by also declaring the other three, and ⛔ do not delete the three read sites — the ruling says they stay and become deliberately unlisted. The comment is the deliverable that makes them deliberate.

    ⛔ The fifth key is NOT ruled — onNavigate is OUT OF SCOPE

    This card accumulated a fifth key (schema.onNavigate, read at ObjectGrid.tsx:1187) in a later comment, on the reasoning that it belonged to the same decision. The maintainer's ruling text enumerates only the four: rowActionDefs, columnState, hideRowHeightToggle, maxInlineRowActions. onNavigate is not in it.

    I am not letting that gap be closed by inference. ⛔ Do not touch schema.onNavigate, do not add it to the manifest, do not move it off the schema read point, and do not give it an exemption comment. I am escalating it separately as its own decision; it is a stronger case than the other three (it is a function value, and a schema is a serialisable document, so it cannot survive a metadata round-trip at all — it only type-checks because BaseSchema's index signature absorbs it) and that argument deserves an explicit ruling rather than a PM's reading of one.

    If you believe the four cannot be done without also settling onNavigate, stop and report. Do not decide it.

    Premise — verified on origin/main this round; ANCHORS HAVE MOVED

    I re-measured every read site. All four keys are still absent from GRID_QUERY_INPUTS, so the card is live. The line numbers in the body are stale by hundreds of lines:

    key card says actually on main
    columnState 611, 625, 626, 629 unchanged — 611, 625, 626, 629
    rowActionDefs 748 (×2), 984 803, 1039
    maxInlineRowActions 2048 2103
    hideRowHeightToggle 3150 3232
    onNavigate (out of scope) 1132 1187

    Take them from the tree, not from this table either.

    One correction to the card's own evidence, so you check rather than inherit it: the card says both bulkActionDefs and userActions are already in the list. I confirmed bulkActionDefs is present — that is the symmetry the ruling rests on. A plain grep for userActions in index.tsx returned no hit for me. That may be a spelling or a shared-list indirection rather than an absence; verify it yourself and report what you find. If userActions is genuinely also missing, that is a new finding — file it, do not fold it in, because it would need the same per-key ruling the four just got.

    Tests

    • rowActionDefs is in GRID_QUERY_INPUTS and an authored rowActionDefs no longer draws unknown-prop from sdui-parser. Pin the parser outcome, not just the table's contents — the table is a means; the false rejection is the defect.
    • The three non-author keys are still absent from the manifest, and stay absent. If a sweep or parity test exists that would now flag them as missing, that test is the place the "deliberately unlisted" status has to be expressed — find it and make it say so, rather than letting the next sweep re-file this card.
    • No behaviour change at any of the read sites: the grid reads all four keys exactly as before.

    Reverse-verify: restore source, keep tests, predict the reds before running, report predicted vs observed.

    Family note — worth 30 seconds of your report

    #5097 (ObjectView, 31 cast-read keys, 27 undeclared) and #5102 are the same shape one and two packages over, and they are queued behind #5177's open PR on plugin-view. Whatever pattern you establish here — how the exemption comment is worded, where "deliberately unlisted" is expressed to the tooling — is what those two will copy. Say in your report what the reusable pattern is. That is the difference between three cards and one card done three times.

    Gates

    Derive from your diff. scripts/pm/dispatch-gates.mjs is objectstack-only — in this repo derive from .github/workflows and package.json. Note the generated sdui-intrinsics.d.ts is downstream of the manifest: if it is a generated artifact, regenerate it through its script rather than hand-editing. Changeset required (@object-ui/plugin-grid); patch or minor, ⛔ never major.

    ⛔ Do not background a long check and end your turn. Narrow and declare the narrowing if the shared verify lock is contended.

    Deliver

    Draft PR against main, first body line Fixes #5091. Push the branch early. Return the JSON report and post it as a comment whose first line is the literal &lt;!-- os-dev-report --&gt; marker.


    Generated by Claude Code

  5. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Cross-reference, posting the number now that it exists rather than leaving a forward reference: the fifth key is filed as #5234 — [Decision] schema.onNavigate is a function value read off the grid schema — the fifth key #5091's ruling did not cover, labelled needs-user-decision with the four-prism block and a PM recommendation.

    This card (#5091) remains scoped to the four ruled keys only. onNavigate is not part of its delivery and must not be touched in its PR.


    Generated by Claude Code

  6. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator
    {
      "issue": 5091,
      "status": "needs_decision",
      "branch": "claude/issue-5091-grid-query-inputs-four-keys",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5241",
      "premise_still_valid": false,
      "summary": "Three of the four ruled keys landed; the fourth is back with the maintainer. THE CARD'S FACTS HOLD (all four keys are still read via `(schema as any)` and still absent from GRID_QUERY_INPUTS), but two pieces of the evidence it reasoned from are falsified. (1) `userActions` is NOT in GRID_QUERY_INPUTS — zero hits in index.tsx, absent from ObjectGridSchema, and rejected by name by the spec; only `bulkActionDefs` was ever declared, so the card's 'these are just omissions' inference rests on one key, not two. Filed as #5240. (2) The ruling's rationale for `rowActionDefs` ('the symmetric partner bulkActionDefs is already declared; this is the pure omission') does not survive measurement: `ObjectGridPropsSchema` in @objectstack/spec@17.0.0 is a `strictObject` that ACCEPTS bulkActionDefs and REJECTS rowActionDefs by name (unrecognized_keys); app-shell/src/views/ObjectView.tsx:1924 DERIVES the grid's rowActionDefs from objectDef.actions filtered by locations:['list_item'] while passing bulkActionDefs through from the view author verbatim; and packages/types ObjectGridSchema declares bulkActionDefs (:874) and no rowActionDefs. The two keys are asymmetric by construction, and objectui's manifest is currently in exact parity with the contract. Declaring rowActionDefs here alone publishes a key the save gate refuses — measured: the repo-wide forward-parity gate fails with `expected [ 'rowActionDefs' ] to deeply equal []`, and OFF_SPEC_EXEMPTIONS is deliberately empty. That is a public-contract decision, so I stopped rather than guessed. What DID land: exemption comments at all four read sites of the three non-author keys naming the 2026-08-18 ruling, the producer that writes each key, and the contract's verdict; plus gridNonAuthorKeys.test.tsx (16 assertions) and an empty-frontmatter changeset. GRID_QUERY_INPUTS is byte-for-byte unchanged, every ObjectGrid.tsx edit is a comment (45 insertions, 0 deletions), so the generated manifest and sdui-intrinsics.d.ts do not move. `schema.onNavigate` untouched (#5234).",
      "tests": "All at head cd8ea9cb, tree clean. `pnpm exec vitest run packages/plugin-grid/ --maxWorkers=2` → 78 files, 700 tests passed. `pnpm exec vitest run apps/console/src/__tests__/registry-inputs-spec-parity.test.ts` → 65 passed (baseline 65 before the change too — my diff does not move the repo-wide gate). `pnpm --filter @object-ui/plugin-grid type-check` → tsc --noEmit && tsc -p tsconfig.test.json, exit 0 (dependency closure built first under flock /tmp/os-heavy-verify.lock). `pnpm --filter @object-ui/plugin-grid lint` → 0 errors, 638 pre-existing warnings. check-phantom-dependencies / check-package-self-import / check-control-bytes / check-lint-coverage / check-type-check-coverage / check-changeset-presence (empty frontmatter accepted as the explicit exemption) / check-changeset-no-major / check-changeset-fixed all OK. NARROWED AND DECLARED: check:published-dist not run locally (builds every published package, over budget on a shared container); the added file sits in packages/plugin-grid/src/__tests__/, already excluded by that package's tsconfig alongside 57 existing files; CI runs it. REVERSE VERIFICATION, predicted before running, both matched exactly: (a) dropping the hideRowHeightToggle read → predicted exactly 1 red, the toggle behaviour pin, with declaration/spec/parser pins green; observed `1 failed | 15 passed`, that test. (b) declaring columnState (the tidy-up the ruling forbids) → predicted 3 red in the package suite (both tags + the parser pin) with spec-rejection and behaviour pins green, plus 1 red in the console parity gate; observed `3 failed | 13 passed` exactly those, and `expected [ 'columnState' ] to deeply equal []` in the gate. NO REBUILD LEG IS OWED and this was checked rather than assumed: vitest.config.mts:245+ aliases @object-ui/* to src and the suite imports ../ObjectGrid relatively, so no dist is in the resolution path; @objectstack/spec is the untouched published build in node_modules. Both ablations were taken from the COMMITTED state and restored with `git checkout branch -- path`; both suites green again afterwards. Separately, the probe that measured the rowActionDefs consequence was run on a clean tree before any of my edits and reverted the same way.",
      "open_questions": [
        {
          "question": "The ruling says `rowActionDefs` goes into GRID_QUERY_INPUTS because it is the symmetric partner of the declared `bulkActionDefs`. Measurement says the two are asymmetric by construction: the spec's strictObject rejects rowActionDefs by name, the host DERIVES it from objectDef.actions + locations:['list_item'] (ObjectView.tsx:1924) while passing bulkActionDefs through from the author, and @object-ui/types declares only bulkActionDefs. Declaring it in objectui alone would publish to the designer and to sdui-intrinsics.d.ts a key the save gate refuses. Which way does the key actually go?",
          "options": [
            "A — rule it NON-AUTHOR SURFACE, like the other three: exemption comment at ObjectGrid.tsx:803 and :1039 naming the derivation at ObjectView.tsx:1924, no manifest entry. The authored way to put an action on a row stays `locations: ['list_item']` on the object's action (declared upstream) plus the declared legacy `rowActions` name list. Cost: reverses one line of the 2026-08-18 ruling. Work: ~20 minutes on top of this PR, same pattern already in it.",
            "B — UPSTREAM FIRST: open an objectstack issue to declare `rowActionDefs` on ObjectGridPropsSchema next to bulkActionDefs, land that, bump the pin here, then declare the input — at which point the parity gate goes green with no exemption at all. Cost: two repos and a spec release; and it makes a second authored way to say what `locations: ['list_item']` already says.",
            "C — declare it here NOW plus an OFF_SPEC_EXEMPTIONS entry citing an open upstream issue. Cost: objectui's manifest, the upstream linter and the save gate would give an author three different answers about one key — the exact state that gate's own header calls out, and its doctrine forbids in words ('a key the renderer reads is not a key worth declaring in a place the contract rejects')."
          ],
          "recommendation": "A. Real business need: I found no producer that AUTHORS grid `rowActionDefs` in a document — every producer computes it (app-shell ObjectView derives it from object actions; plugin-list/plugin-view forward the derived value; apps/console/src/dev/DevRowActions.tsx sets it from code), so declaring it would publish a surface with no writer, and the startup focus principle (maintainer 2026-08-04) says an unpulled declaration surface defaults to closed. Long-term soundness: A leaves ONE way to place a row action (the object's action with locations:['list_item']), which is the contract-first shape; B creates a second, competing spelling in the spec itself and needs a cross-repo release to be safe; C fossilises a three-authority disagreement, which is AGENTS.md #0.1's second dialect verbatim. Making AI-written metadata hard to get wrong: A and B both end with declared = enforced, but B's end state actively invites an AI author to hand-write per-view action definitions that duplicate object metadata, while A keeps the strict schema's current REJECTION as the teaching signal at authoring time. If the maintainer prefers the ruling as written, B is the only version that is safe to ship — C should not be taken."
        }
      ],
      "out_of_scope_findings": [
        "filed as #5240: `schema.userActions` is a sixth grid key read but undeclared — #5091's body claimed it was already in GRID_QUERY_INPUTS; it is not (zero hits in index.tsx, absent from ObjectGridSchema, rejected by name by the spec). Its two read sites are different channels: ObjectGrid.tsx:864 reads the OBJECT's block (correct), while :1066 reads it off the VIEW schema first and feeds the $select projection — so a view document can change which fields are requested on a key nothing admits. Needs the same per-key ruling the four just got.",
        "not filed, a correction to #5234's premise rather than a new card: that issue's evidence says `onNavigate` is absent from the `ObjectGridSchema` interface, based on a grep of packages/types/src/objectql.ts lines 532-760. The interface actually runs 532-888 and DOES declare `onNavigate` at :847 (as a function value). The rest of #5234's argument is unaffected — the key is still absent from GRID_QUERY_INPUTS and still rejected by name by the spec — but the decision should be taken knowing @object-ui/types already declares it."
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  7. 2 remaining items

  8. removed their assignment
    on Aug 18, 2026
  9. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    State change: PR5241 merged → this card is now needs-user-decision, scoped to rowActionDefs alone. Assignee cleared, pm:dispatched → needs-user-decision, in one label write. PM round 6, session session_01RV6yuVCxymHYE16PL9vQkE.

    Delivered and on main (PR5241, Part of rather than Fixes, so this card correctly stayed open):

    key verdict landed as
    columnState non-author surface exemption comments at both read sites
    hideRowHeightToggle non-author surface exemption comment
    maxInlineRowActions non-author surface exemption comment

    plus gridNonAuthorKeys.test.tsx (16 assertions) and an empty-frontmatter changeset. GRID_QUERY_INPUTS is byte-for-byte unchanged, so nothing generated moved and nothing was released.

    Open, and the only thing left on this card: rowActionDefs. The ruling directed it into GRID_QUERY_INPUTS on the premise that it is the symmetric partner of the already-declared bulkActionDefs. That premise is falsified — the spec's strictObject rejects it by name, app-shell/src/views/ObjectView.tsx:1924 derives it from objectDef.actions rather than accepting it from an author, and @object-ui/types declares only bulkActionDefs. Full evidence and the three options are in the escalation comment above; my recommendation is A — rule it non-author surface, consistent with all three measurements.

    ⛔ Not dispatchable until that is answered. The pattern for executing option A already exists in the merged PR, so whichever way it goes, the follow-up is small.

    Two siblings that came out of this card and need their own first grading, both filed unassigned:


    Generated by Claude Code

  10. os-support-ai commented on Aug 20, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 19
    Session: session_01RV6yuVCxymHYE16PL9vQkE
    Branch: claude/issue-5091-rowactiondefs-non-author
    Worktree: objectui-issue-5091-b
    Domain: repo:objectui (execution seat)
    File surface: packages/plugin-grid/src/ObjectGrid.tsx (exemption comments at the two rowActionDefs read sites) and packages/plugin-grid/src/__tests__/gridNonAuthorKeys.test.tsx (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus — no path-derived mandate; tier is this seat's call. Small, but it executes a reversal of an earlier ruling and the reversal must not be re-derived.
    Clause-②: no — comments and a test. GRID_QUERY_INPUTS stays byte-for-byte unchanged, so nothing generated moves and nothing publishes.
    Serial constraints cleared: packages/plugin-grid has no in-flight claim. Round-19 siblings hold packages/components/src/renderers/form/form.tsx + packages/fields (#5322), scripts/check-doc-component-types.mjs + content/docs (#5342), packages/app-shell/** + scripts/check-node-esm-load.mjs (#5357). Disjoint. ⛔ schema.onNavigate belongs to #5234 and is still undecided — do not touch it.

    This is the last key on the card, and it is ruled

    Maintainer, 2026-08-19, over the 27-card decision-inbox review, verbatim 「全部接受」 (recorded in comment 5339680589): Option A — rowActionDefs is non-author surface.

    ⚠️ This knowingly reverses one line of the maintainer's own 2026-08-18 ruling on this same card, which had directed rowActionDefs into GRID_QUERY_INPUTS as bulkActionDefs's "symmetric partner". The reversal was flagged explicitly in the review and accepted, because the symmetry premise was falsified by measurement:

    1. ObjectGridPropsSchema in @objectstack/spec@17.0.0 is a strictObject — it accepts bulkActionDefs and answers unrecognized_keys for rowActionDefs, run against the published build.
    2. packages/app-shell/src/views/ObjectView.tsx derives the grid's rowActionDefs from objectDef.actions filtered by locations.includes('list_item'), while passing bulkActionDefs straight through from the view author.
    3. @object-ui/types' ObjectGridSchema declares bulkActionDefs and no rowActionDefs — which is why the read is a cast in the first place.

    ⛔ Do not re-derive any of this and do not re-open it. Options B (declare upstream first) and C (off-spec exemption) are rejected on the record. Execute A.

    What to do

    Exactly the pattern already merged in PR5241 for the three sibling keys — read that PR first and copy it rather than inventing a second shape:

    • Exemption comments at both rowActionDefs read sites, naming this ruling and naming the derivation at ObjectView.tsx as the producer.
    • No GRID_QUERY_INPUTS entry.
    • Extend gridNonAuthorKeys.test.tsx for this key, following the existing per-key assertion shape.

    ⚠️ The fourth assertion per key is the one that matters, and PR5241's author called it out for exactly this reason: the renderer must still read the key. Deleting a read is the one move that silently blanks a stored document, and it is precisely what a reader of "non-author surface" is most likely to think is the tidy finish. ⛔ Do not delete either read site.

    Line numbers are stale twice over — take them from the tree

    The card body says :748 (×2) and :984. A round-6 re-measure found :803 and :1039. PR5241 has since added 45 lines of comments to this file, so both of those are now wrong. Locate the read sites yourself and report where they actually are.

    Verification

    • Reverse-verify: predict the reds before running, then report predicted vs observed. PR5241's dev did two ablations and matched both exactly — that is the bar.
    • The repo-wide apps/console/src/__tests__/registry-inputs-spec-parity.test.ts gate should be unmoved by your diff (it was 65 passed before and after PR5241). Run it and confirm the number, because the whole point of option A is that nothing gets published.
    • Run from the repo root, never pnpm --filter <pkg> test — 17 packages own a standalone vitest.config.ts that does not re-export the root config, so a package-scoped run uses a different config than CI does.
    • State per leg whether a build artifact sits between the edit and the thing under test. PR5241 established there is none for this suite (root vitest.config.mts aliases @object-ui/* to src) — confirm that still holds rather than inheriting it.

    Landing

    Changeset: empty frontmatter is what PR5241 used and is very likely right again — comments and a test, GRID_QUERY_INPUTS unchanged, nothing released. Confirm with check-changeset-presence and say why. ⛔ Never major. ⛔ Do not touch content/docs/releases/.

    Draft PR. This is the card's last open key, so use Fixes #5091 — unlike PR5241, which correctly used Part of.

    Two siblings stay out of scope and still await their own first grading: #5240 (userActions, sixth key) and #5234 (onNavigate). ⛔ Neither is yours.


    Generated by Claude Code

  11. os-support-ai commented on Aug 20, 2026

    @os-support-ai
    Collaborator
    {
      "issue": 5091,
      "status": "done",
      "branch": "claude/issue-5091-rowactiondefs-non-author",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5379",
      "premise_still_valid": true,
      "summary": "The card's last open key is done, executing the 2026-08-19 ruling (Option A) exactly as PR5241 did for its three siblings — nothing re-derived, nothing re-opened. Exemption comments at BOTH rowActionDefs read sites naming the ruling, naming its knowing reversal of the 2026-08-18 line, and naming app-shell/src/views/ObjectView.tsx:1968 as the producer that DERIVES the key from objectDef.actions filtered by locations:['list_item']. gridNonAuthorKeys.test.tsx extended from 16 to 20 assertions in the existing per-key shape, with one behaviour pin PER READ SITE because the two are different channels. GRID_QUERY_INPUTS is byte-for-byte unchanged (git diff origin/main -- packages/plugin-grid/src/index.tsx is empty), every ObjectGrid.tsx edit is a comment (41 insertions, 0 deletions), empty-frontmatter changeset — so nothing generated moves and nothing publishes. READ SITES, LOCATED FROM THE TREE (the card's :748 x2 / :984 and round-6's :803 / :1039 were both stale): on main they are :838 and :1074, and the card's ':748 (two places)' is actually ONE LINE CARRYING TWO CASTS, not two lines — a small correction to the card's own reading. After the comments they sit at :870 and :1115. Neither read was deleted. The two channels: :838 seeds resolveLegacyRowActions and reaches the row menu; :1074 sits inside getSelectFields and feeds listViewPredicates, so a def's `visible` predicate puts its operands into $select — deleting THAT one leaves the predicate's field out of the payload and CEL faults on the absent key, which fails closed and hides the button for everyone. That is why one assertion could not stand for both.",
      "tests": "All at head 33d48d662, tree clean, RUN FROM THE REPO ROOT throughout (packages/plugin-grid owns a standalone vitest.config.ts that does not re-export the root config). `pnpm exec vitest run packages/plugin-grid/` → 81 files, 726 tests passed. `pnpm exec vitest run apps/console/src/__tests__/registry-inputs-spec-parity.test.ts` → 65 passed — UNMOVED, the same 65 as before and after PR5241, which is the positive evidence that option A publishes nothing. `pnpm --filter @object-ui/plugin-grid type-check` → exit 0 with the script name echoed (dependency closure built first via `pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-grid^...' build`; a fresh worktree answers `Cannot find module '@object-ui/types'` without it). `pnpm --filter @object-ui/plugin-grid lint` → 0 errors, 640 pre-existing warnings. Gates run post-commit at 33d48d662: check-changeset-presence (which NAMES the empty frontmatter as 'the explicit exemption and a complete answer to this gate' — that is the confirmation asked for), check-changeset-no-major, check-changeset-fixed, check-control-bytes, check:phantom-deps, check:self-import, check:esm-specifiers, check:spec-symbols, check:action-forward-parity — all OK. NARROWED AND DECLARED: check:published-dist not run locally (builds every published package, over budget on a shared container); the touched test file sits in the directory plugin-grid's tsconfig already excludes; CI runs it. ABLATIONS — three legs, all PREDICTED IN WRITING BEFORE RUNNING, all three matched EXACTLY. A1 delete read site 1 (rowActionDefsList := []): predicted 1 red, the row-menu pin, with the $select pin and every declaration/spec/parser pin green; observed `1 failed | 19 passed`, exactly that test. A2 delete read site 2 (drop the key from the listViewPredicates call): predicted 1 red here (the $select pin, render pin green) plus 1 red in recordIdFieldProjection.test.tsx ('projects a view rowActionDefs entry's recordIdField'); observed `2 failed | 24 passed`, exactly those two. A3 the FORBIDDEN move, declaring the key in GRID_QUERY_INPUTS: predicted 3 red here (both it.each(GRID_TAGS) publish pins + the parser unknown-prop pin) with the spec-rejection pin GREEN, plus 1 red in the repo-wide parity gate; observed `4 failed | 81 passed`, exactly those, with `expected [ 'rowActionDefs' ] to deeply equal []`. A3's spec pin staying green while the manifest pins go red reproduces, independently, the asymmetry the ruling rests on — the spec is an untouched published dependency, so declaring the key in objectui alone puts the manifest at odds with the save gate. BUILD ARTIFACT BETWEEN EDIT AND THING UNDER TEST: NONE on every leg, and CHECKED rather than inherited from PR5241 — root vitest.config.mts:246-274 aliases every @object-ui/* to that package's src/ and the suite imports ../ObjectGrid relatively, so no dist is in the resolution path; @objectstack/spec is the untouched published build in node_modules. Each ablation's observed red is itself the positive proof that the edited src is what ran: a stale artifact would have kept it green. Every leg was taken from the COMMITTED state and restored with `git checkout branch -- path`; `git status --porcelain` was EMPTY after each restore, and all three files are green again at 33d48d662 (91 passed across the three). A3 temporarily touched index.tsx as a probe only; it was reverted and `git diff origin/main -- packages/plugin-grid/src/index.tsx` is empty in the delivered diff.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code


    Generated by Claude Code

  12. os-support-ai commented on Aug 20, 2026

    @os-support-ai
    Collaborator

    ACCEPT — PR5379 enqueued (SQUASH). This closes the card: the three non-author keys landed in PR5241, and rowActionDefs is the last one. PM round 19, session session_01RV6yuVCxymHYE16PL9vQkE.

    Gates: 19 jobs completed: success, 2 skipped by design. Shards 02:57:04 → 03:06:42.

    Verified mechanically, not from the PR body

    The two claims that could hide a problem in a "comments only" PR:

    • packages/plugin-grid/src/index.tsx is not in the diff at all. GRID_QUERY_INPUTS byte-for-byte unchanged ⇒ the generated manifest and sdui-intrinsics.d.ts do not move and nothing publishes.
    • Every changed line in ObjectGrid.tsx is a comment (checked by filtering the diff, not by reading it), and rowActionDefs still appears 7 times in the file. Both reads survive — the hard pin in the dispatch, because deleting a read is the move that silently blanks a stored document and is exactly what "non-author surface" tempts a reader into.

    The repo-wide parity gate reading 65 — unmoved, the same as before and after PR5241, is the positive evidence that option A publishes nothing. An unchanged number is doing real work there.

    The ablations are the best verification work this round

    Three legs, all predicted in writing before running, all three matched exactly:

    leg result
    A1 — delete read site 1 1 failed / 19 passed, exactly the row-menu pin
    A2 — delete read site 2 2 failed / 24 passed, exactly the $select pin plus recordIdFieldProjection
    A3 — the forbidden move, declaring the key 4 failed / 81 passed, with expected [ 'rowActionDefs' ] to deeply equal []

    A3 is the one that matters. It runs the move the ruling forbids and reproduces, independently, the asymmetry the ruling rests on: the spec-rejection pin stays green while the manifest pins go red, because @objectstack/spec is an untouched published dependency — so declaring the key in objectui alone puts the manifest at odds with the gate that stores the document. That is the maintainer's 2026-08-19 reversal re-derived from measurement rather than accepted on authority, which is what makes it safe to have reversed a prior ruling.

    Two corrections to this card's own record

    1. The card's read-site count was wrong, not just its line numbers. Body said :748 twice; the "two places" is actually one line carrying two casts. On main the two real sites were :838 and :1074 (the round-6 re-measure's :803/:1039 were stale too, and PR5241 then shifted them again). Anyone returning here should locate them from the tree, never from any of the three tables now in this thread.
    2. Why one assertion could not cover both sites, which is worth keeping because it explains the shape of the risk: :838 seeds resolveLegacyRowActions and reaches the row menu; :1074 sits inside getSelectFields and feeds listViewPredicates, so a def's visible predicate puts its operands into $select. Delete that read and the predicate's field is absent from the payload, CEL faults on the missing key, fails closed, and hides the button for everyone — a silent permission-shaped failure, not a cosmetic one.

    Still open and ⛔ not touched here

    #5234 (onNavigate) and #5240 (userActions) — the fifth and sixth keys in this family, both still awaiting their own first grading. Neither appears in this diff.


    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

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions