Skip to content

fix(showcase): my-work grid authors filter, the key object-grid reads - #7764

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-7750-my-work-filter-spelling
Aug 11, 2026
Merged

fix(showcase): my-work grid authors filter, the key object-grid reads#7764
os-zhuang merged 2 commits into
mainfrom
claude/issue-7750-my-work-filter-spelling

Conversation

@claude

@claudeclaudeBot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Fixes#7750

What changed

One word in examples/app-showcase/src/ui/pages/my-work.page.ts: the personal work queue's object-grid authored the plural filters:, and now authors filter: — the key the block both publishes and reads.

- filters: [['owner_id', '=', '{current_user_id}']],
+ filter: [['owner_id', '=', '{current_user_id}']],

objectui's renderer reads only schema.filter (plugin-grid/src/ObjectGrid.tsx:472, lowered through toFilterNode) and the legacy schema.defaultFilters (line 655-657). schema.filters has zero read points. So the declared personal scope was accepted at authoring time and then dropped before the wire — no $filter parameter at all, and the queue listed every row.

⚠️ Scope — not an authorization bypass

Carried verbatim from the card so nobody over-escalates it:

Scope, stated precisely: this is not an authorization bypass. The unfiltered read is still RLS-constrained, so the caller sees only rows they may see (admin sees all because admin may see all). The defect is that a declared personal-scope filter silently never applies — and that a typo'd key is accepted without complaint. The second half is the more general problem.

That second, general half — a typo'd key accepted without complaint — is #7751 and is deliberately not touched here. No validation was added to the block schema.

Premise verification

Confirmed against origin/main (8f1851e) before implementing:

  • Line 52 still read filters:.

  • The card's "exactly once in the whole showcase" claim is imprecise, and the correction is worth recording.filters appears at three other authored sites, and all three are legitimate declared plural keys on different surfaces — so the card is correctly scoped, but not for the reason it gives:

    • ui/apps/index.ts:81-83ObjectNavItem.filters, declared plural in packages/spec/src/ui/app.zod.ts:421.
    • ui/pages/renewals-pipeline.page.ts:110,141 — react-tier < ListView filters={…} />, declared plural in packages/spec/src/ui/react-blocks.ts:217.

    Read as "exactly one object-grid block authors the plural", the claim holds and this PR is correctly one line. Read literally, it does not. The underlying reason the typo was easy to make is that the vocabulary genuinely splits by tierListView.filters plural in react, ObjectNavItem.filters plural in nav, object-grid.filter singular in SDUI — which is context for A typo'd key inside a page component's properties is accepted in silence — the props bag is a passthrough record and the SDUI props gate has no schema to dispatch for object-* blocks #7751, not something fixed here.

  • The three sibling object-metric tiles on this same page already spell filter singular (lines 39-41), which is why the grid was the only site that drifted.

Verification bound — stated honestly

End-to-end verification was not performed, and could not be here.

What was checkable, and was checked — the card asked for the pin ancestry, so it was measured rather than assumed:

  • The repo-root pin is .objectui-sha = 6314e87f2d49b1ff3b158c296f1b2a52d14dff68.
  • objectui#4041 (9154d9e) is an ancestor of itGET /repos/objectstack-ai/objectui/compare/9154d9e...6314e87f2 returns status: ahead, behind_by: 0, merge_base == 9154d9e90f9c. The card's claim holds.
  • Read at that exact pin, plugin-grid/src/index.tsx:117 declares { name: 'filter', type: 'array', label: 'Filter' }, ObjectGrid.tsx:472 reads schema.filter, and schema.filters has 0 occurrences in the file.

So the fix lands on the declared, pinned and lowered path — but the proof that it reaches $filter lives in objectui's own pin (gridFilterInputSpelling.test.tsx), not in anything runnable here.

Tests

Added to the existingexamples/app-showcase/test/my-work-visibility.test.ts rather than a new file, deliberately: a new test file can drift a package's TEST_DEBT or the query-options-erasure count. Three pins — the grid authors filter; it authors neither non-canonical spelling (filters, defaultFilters); and it still scopes to {current_user_id}.

Each of those two keys is absent for a DIFFERENT reason, and the test says so per key (corrected in 61022c2 after PM review caught the first version sharing one message across both):

  • filters is dead — zero read points in the renderer, so it is accepted at authoring time and dropped before the wire. That is this defect.
  • defaultFilters is aliveObjectGrid.tsx reads it and lowers it to params.$filter. It is the legacy path object-grid still honors, pinned absent because this page authors the current key, not because the legacy one is inert.

Calling both "dropped" would have reproduced this very defect one level up — a spelling whose real behavior differs from what the surrounding text implies — inside the artifact whose job is to prevent it. Both messages were verified by authoring each key in turn and reading the actual failure text.

The pins assert the authored key against the spelling objectui declares, which is the whole of what is checkable inside this repo. They do not claim to prove $filter reaches the wire, and say so in the file.

Reverse verification, direction predicted before running (ordinary "Red" — the assertions read the authored key directly, so no ??-chain inversion applies): reverting the page to origin/main turned all three new pins red, each naming the real defect, while the four pre-existing tests stayed green.

× authors `filter` (singular) on the work-queue grid
→ expected { objectName: 'showcase_task', …(2) } to have property "filter"
× authors neither non-canonical spelling: `filters`, which is dropped, nor the legacy `defaultFilters`
→ `filters` has no reader in `object-grid` — it is accepted at authoring time
and then dropped before the wire (#7750)
× still scopes the queue to the signed-in user
→ expected undefined to deeply equal [ [ 'owner_id', '=', …(1) ] ]
Test Files 1 failed (1) Tests 3 failed | 4 passed (7)

The per-key messages were each proven separately by authoring that key on the page and reading the failure:

`filters` has no reader in `object-grid` — it is accepted at authoring time and then
dropped before the wire (#7750)
`defaultFilters` is the LEGACY key `object-grid` still reads and lowers to `$filter` —
it works, but it is not the key this page declares

Fix restored, tree clean, suite green again.

Gates run locally

GateResult
example-showcase test20 files / 189 tests passed
example-showcase typecheck (tsc --noEmit)clean
build closure ('@objectstack/example-showcase^...', suffix = upstream deps)70/70 successful
check:type-check-debtOK — none above its recorded number. No ledger raised. The can be lowered lines are pre-existing surplus, untouched.
check:query-options-erasureratchet holds, 67 sites, none new; baseline verified against 8f1851e, no files added
check:nul-bytesOK, 7124 files; plus a targeted control-byte self-scan of both changed files — clean

One eslint finding on the test file (58:3 Definition for rule '@typescript-eslint/no-implied-eval' was not found) is pre-existing and not mine: byte-identical output on the unmodified origin/main copy of the same file, and line 58 sits above every line this PR adds.

Changeset

None — skip-changeset instead.@objectstack/example-showcase is private: true and absent from the fixed group in .changeset/config.json, so a showcase-only change releases nothing. Same call #7568 made earlier today on the same package.


Generated by Claude Code


Generated by Claude Code

…ds (#7750)
The personal work queue authored the plural `filters:` on its `object-grid`.
objectui's renderer reads only `schema.filter` (`plugin-grid/src/ObjectGrid.tsx`,
lowered through `toFilterNode`) and the legacy `schema.defaultFilters`;
`schema.filters` has zero read points on any ref. The declared personal scope
was therefore accepted at authoring time and dropped before the wire — no
`$filter` parameter at all, and the queue listed every row.
objectui#4041 (`9154d9e`) retired the plural from the block's published
vocabulary, so `filter` is now the declared, pinned and lowered spelling. That
commit is an ancestor of this repo's `.objectui-sha` pin `6314e87f2`
(merge_base == `9154d9e`, behind_by 0).
Not an authorization bypass: the unfiltered read is still RLS-constrained, so
the caller only ever saw rows they may see. The defect is that a declared
personal-scope filter silently never applied.
Pins added to the existing `my-work-visibility.test.ts` (no new test file, so no
TEST_DEBT drift): the grid authors `filter`, carries neither dropped spelling,
and still scopes to `{current_user_id}`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BaTeBCjaoTDmDWFVmSY2jL
@vercel

vercelBot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 11, 2026 2:31pm

Request Review

@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 11, 2026
…reason (#7750)
The shared assertion message called both `filters` and `defaultFilters` "dropped
before the wire". That is true of `filters` and FALSE of `defaultFilters`:
`ObjectGrid.tsx` reads it and lowers it to `params.$filter`, so it is the legacy
path object-grid still honors, not a dead key.
Left as written, a future author debugging a filter bug would read the message
and conclude the legacy key is inert — the same defect this card fixes, a
spelling whose real behavior differs from what the surrounding text implies,
reproduced in the artifact whose job is to prevent it.
Both keys stay pinned absent; only the justification changes. `filters` because
nothing reads it, `defaultFilters` because this page authors the current key
rather than the superseded one. Split the shared string into a per-key table and
reworded the `it` so "dropped" attaches only to `filters`.
Text only — no assertion's truth value changed, and the page fix is untouched.
Both messages verified by authoring each key in turn and reading the failure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BaTeBCjaoTDmDWFVmSY2jL
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

showcase my-work: the personal work queue authors filters: (plural) and no $filter ever reaches the wire — the grid lists every row

2 participants

@os-zhuang@claude