You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
finding(plugin-grid,plugin-list): a directly authored object-grid or list-view node sends the spec context tokens ({current_user_id}, {current_org_id}) in its own filter literally; neither package calls the shared resolver #10607
Filing-gate category: ① a defect with named sites (class a), read from source with a lit control. Runtime reach on a non-ObjectStack backend was not measured by the seat; see the limits below. Reader: triage first (route and grade), then the seat that claims it.
Filed by the domain:ui seat #2 (session_014mXUNuFomfj24w7s1pZzhN) from the objectui#10506 dev report (PR objectui#10577). That PR's contract review confirmed the fact at source and called it "a real defect of the same class … worth a card". ⛔ Not graded here.
Fact (read by the seat on origin/main at ab7751321)
packages/plugin-grid/src and packages/plugin-list/src have 0 production reads of resolveFilterPlaceholders, resolveContextTokens or useFilterScope.
Each sends its own schema.filter straight into its query: ObjectGrid.tsx:~1761 (const schemaFilterSource = schema.filter) and ListView.tsx:~2157 (buildEffectiveFilter(schema.filter, …)).
Lit control: after PR objectui#10577, plugin-view's ObjectView resolves the filters it hands on. The app-shell host, ObjectChart and the four dashboard widgets call the same resolver too.
⇒ A metadata page or app that authors an object-grid or list-view node DIRECTLY, not through object-view, with filter: [['owner', '=', '{current_user_id}']] sends the literal token.
Limits
Against ObjectStack, the server also expands {current_user_id} for a signed-in request (objectql resolveWhereTokens), and refuses the request otherwise: the REST face answers 401 at its auth gate before the filter is read, and where a guest context reaches the engine the resolver answers 400. So on that backend the literal is resolved, or the request refused, before the database sees it. The gap is on the client, and it shows on any backend without such a resolver. Also unmeasured by the seat: date macros ({today}, …) would reach the server as literals, resolved there in the tenant's configured localization.timezone (UTC by default), while the resolving surfaces use browser local time. That is a divergence between surfaces for the same authored filter.
Direction (for triage, not a ruling)
Resolve the node's own authored filter through the ONE shared resolveFilterPlaceholders, with useFilterScope(), as PR objectui#10577 did for object-view. Hold the result by structure so the grid does not refetch on every render (AGENTS.md #10). ⛔ No second resolver. Measure first whether a host that already resolves (e.g. object-view handing a resolved filter down) would double-resolve; resolving twice is idempotent (pinned in objectui#10577).
Dedupe
REST page walk over the 1000 most recently updated objectui items (oldest updated_at 2026-09-18T17:27Z):
object-grid near current_user_id|context token|resolveFilterPlaceholders ⇒ 0.
plugin-grid|plugin-list near resolveFilterPlaceholders ⇒ objectui#10506 and PR objectui#10504, the origin family; neither is this surface.
⚠️ Corrected by the seat on 2026-09-25: the Limits paragraph first said a signed-out request gets a 400 and that the server resolves date macros in UTC. Both came from an earlier review record, and PR objectui#10577's later review (5831522007) corrected them.
Triage: lands in packages/plugin-grid/src/ObjectGrid.tsx and packages/plugin-list/src/ListView.tsx (0 production reads of resolveFilterPlaceholders) ⇒ domain:ui; rationale: a directly authored object-grid or list-view node sends {current_user_id} literally in its own filter — the #10506 class on two more hosts. Against ObjectStack the server resolves or refuses the token, so this is defence in depth ⇒ p3.
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01CRZSc7dU8oDStbTbSwhuZe · 2026-09-25T12:31Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectui origin/main.
Execution note: resolve the node's own filter through the ONE shared resolveFilterPlaceholders with useFilterScope(), as PR objectui#10577 did; hold the result by structure so the grid does not refetch every render.
Claim: PM loop round 5 — domain:ui execution seat 5
Session: session_01KUxVUa7e39aNjhkKi1gsoy
Branch: claude/issue-10607-grid-list-filter-tokens
Worktree: objectui-issue-10607
Domain: domain:ui
Seat: domain:ui#5
File surface: packages/plugin-grid/src/ObjectGrid.tsx (the node's own schema.filter read, ~:1761) and packages/plugin-list/src/ListView.tsx (the three buildEffectiveFilter(schema.filter, …) reads, ~:2190 / :3078 / :4000); pins beside each; and changesets patch for @object-ui/plugin-grid and @object-ui/plugin-list (stop on breach; explain in the report).
Container & model: S, mode:subagent, model: opus (default judgement tier; no path-derived mandate for these objectui paths).
Clause-②: no
Thread-read: 5832409031
Serial constraints cleared: the open-PR file lists were re-read in this act at objectui origin/maine0f8202. Three open PRs share these files, in other regions:
objectui#10627: this seat's PR, in the merge queue; the ListView filter candidates.
objectui#10620: seat 3's PR, a draft; the ListView fetch effect's invalidation nonce.
objectui#10278: a draft for the pm:blocked objectui#9853; the ObjectGrid page size.
This is ordinary concurrency. The branch merges origin/main before pr_create, and the later lander resolves. No live pm:dispatched claim names the schema.filter reads. The shape to follow, PR objectui#10577 (objectui#10506), merged as 6c2f3c5.
Clause-②: no: the documented context tokens ({current_user_id}, {current_org_id}, …) resolve on two more hosts, through the one shared resolver. No schema, export or accept set moves.
Scope
The triage (5832409031): 「resolve the node's own filter through the ONE shared resolveFilterPlaceholders with useFilterScope(), as PR objectui#10577 did; hold the result by structure so the grid does not refetch every render.」
Reproduce first: a directly authored object-grid and a list-view with filter: [['owner', '=', '{current_user_id}']] send the literal token in their query.
Fix: each host resolves its own authored filter once, through @object-ui/core's resolveFilterPlaceholders against useFilterScope(). The result is held by structure, so a re-render with an equal filter does not refetch. ⛔ No second resolver.
Measure the object-view path, which already hands a resolved filter down. Resolving twice is idempotent (pinned in objectui#10577); show it with one fetch.
Pin: the token reaches the query as the scope's user id on both hosts, and the fetch count is stable across an equal-filter re-render. Lit control: a token-free filter goes through unchanged.
os-dev-report
{
"issue": 10607,
"status": "done",
"branch": "claude/issue-10607-grid-list-filter-tokens",
"pr": "#10656",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (mode:subagent, the dispatching seat's id; the Claude-Session trailer on every commit)",
"premise_still_valid": true,
"summary": "H1 confirmed on BASE dddbc27 (the dispatch named e0f8202; main had moved, objectui#10627 merged): git grep of resolveFilterPlaceholders|resolveContextTokens|useFilterScope over packages/plugin-grid/src and packages/plugin-list/src exit 1; control, the same words in plugin-view ObjectView.tsx, 8 hits. ListView carried more raw schema.filter reads than the three named, and every one now reads the held value. Implemented, one resolved value per host through @object-ui/core resolveFilterPlaceholders with useFilterScope(), held in state (the plugin-view useResolvedFilterSegments pattern: authored input compared by structure, plus currentUserId, currentOrgId and onUnresolved each compared on its own, set during render). ObjectGrid: useResolvedGridFilters over filter and the deprecated alias defaultFilters; it feeds schemaFilterSource, the defaultFilters leg of the load effect, and a new load-effect dependency schemaDefaultFilters. ListView: useResolvedAuthoredFilter over schema.filter; it feeds the fetch and its deps, the page-reset signature, selfQueryFilter (3 reads), the child node filter and its memo deps, the export and its deps, and the empty-state test. The only raw schema.filter code read left in either file is the hold input. Files vs merge base 4a3d500: packages/plugin-grid/src/ObjectGrid.tsx +129/-5; packages/plugin-list/src/ListView.tsx +125/-16; new packages/plugin-grid/src/tests/ObjectGrid.filterContextTokens-10607.test.tsx 216 lines (10 cells); new packages/plugin-list/src/tests/ListView.filterContextTokens-10607.test.tsx 215 lines (9 cells); new .changeset/10607-grid-list-filter-context-tokens.md 41 lines (plugin-grid patch, plugin-list patch). resolveFilterPlaceholders (filter-tokens.ts) and useFilterScope.ts are untouched. Head e4aa578 = merge of origin/main 4a3d500. The ListView conflict with objectui#10620 (the react import line, and the fetch-effect deps line) was resolved as a union inside my own hunks. origin/main then gained f99f9cd (plugin-form only, outside both packages' closures), not merged. Draft PR #10656, assignee os-tesla, labels plugin and tests (labeler). Worktree removed without --force. Deviations. (1) isSameAuthoredFilter is a local copy of plugin-view isStructurallyEqual's rules, one in each file: plugin-view depends on plugin-grid, plugin-list depends on neither, and a shared export would move an export set (Clause-2 no). (2) The grid load effect gains the dependency schemaDefaultFilters: base read schema.defaultFilters without keying on it, so a user change carried only by the alias would not re-query. (3) Conflict, flagged rather than silently decided: the pending .changeset/10506-named-view-context-tokens.md says '(A directly authored object-grid or list-view node still does not call it.)', which is false at this head and publishes verbatim. The role file says prose this change makes false is must-fix; the claim declares that file outside the surface (stop on breach). I left it unedited, and my own changeset states the gap is closed. Seat edit before landing: delete that parenthetical, or replace it with '(A directly authored object-grid or list-view node calls it too, since objectui#10607.)'. check:changeset-claims does not flag it (it names the symbols, not the files).",
"tests": "Pins, final (repo root, vitest, via os-verify-lock). Base: each source swapped to its 4a3d500 blob under a trap, restored with both blobs equal to HEAD and git diff HEAD empty. Grid pin: 7 failed, 3 passed, exit 1. List pin: 6 failed, 3 passed, exit 1. The token cells read the literal, e.g. expected [ [ 'owner', '=', '{current_user_id}' ] ] to deeply equal [ [ 'owner', '=', 'usr_42' ] ]. The cells that pass on base are the CONTROL, the same-node count and the already-resolved seam. Head e4aa578, both pins: 19 passed, exit 0. Pre-merge, against BASE dddbc27: grid 7 failed | 3 passed exit 1 (the pin before its COLUMNS constant), list 6 failed | 3 passed exit 1. After the fix: 10 of 10 and 9 of 9, exit 0. H4 ablation (objectstack scripts/ablation-replace.mjs, WRAP mode; anchor hit 1 then 0; blob moved; restored blob == HEAD and git diff HEAD empty; the subject resolves from src/, so there is no dist leg). The hold call was replaced by a per-render resolveFilterPlaceholders. Grid: 5 failed | 5 passed, the 5 hold cells timing out at 15000ms (endless refetch). List: 4 failed | 5 passed, 2 timing out at 15000ms and 2 reading expected 0 to be greater than 0. Expected direction: red. H3, one-time measurement: a temporary plugin-view test (real ObjectView into real ObjectGrid, 2 re-renders), deleted afterwards, git status clean. ObjectGrid.tsx base blob swapped in and restored with a hash check. table.filter: head 1 fetch then 1, base 1 then 1, $filter [["owner","=","usr_42"]] in both. Named grid view (reaches the grid as defaultFilters): head 1 then 1, base 1 then 1, $filter [["owner","equals","usr_42"]] in both. Suites at e4aa578: pnpm exec vitest run packages/plugin-grid/ 157 files, 1497 passed, exit 0; packages/plugin-list/ 99 files, 1156 passed, exit 0; packages/plugin-view/ 49 files, 477 passed, exit 0. Pre-merge: 157/1497, 98/1153, 49/477, all exit 0. Type-check: pnpm turbo run build --filter '@object-ui/plugin-grid^...' --filter '@object-ui/plugin-list^...' --concurrency=2 (13 tasks, exit 0), then pnpm turbo run type-check --filter @object-ui/plugin-grid --filter @object-ui/plugin-list --concurrency=2: pre-merge 16 tasks, exit 0; at e4aa578 16 tasks, exit 0, with deps rebuilt. tsc -p tsconfig.test.json --listFilesOnly lists each pin (1 hit each); direct tsc -p tsconfig.test.json in both packages exit 0. eslint, plain form, on the 4 changed tsx at e4aa578: exit 0, 0 errors. Per-rule warnings vs 4a3d500: ObjectGrid.tsx 207 to 207, ListView.tsx 184 to 184 (0 rules differing); the pins 0 findings. Gates at e4aa578, each exit 0: check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations (0 new), check:changeset-claims (report-only; 12 pending changesets name ObjectGrid.tsx or ListView.tsx, all re-read, none concerns the filter read), check:pending-changeset-literals, node scripts/check-changeset-presence.mjs (4 source files of 2 released packages, 1 changeset), check-changeset-overwrite (1 added, 0 modified), check-changeset-no-major, check-changeset-fixed, check:phantom-deps, check:unreferenced-sources, check:self-import, check:side-effects-array, check-type-check-coverage, check-governed-queue-guard --test on the 5 paths (NOT GOVERNED). The same set was also exit 0 at 7f90de0. NOT MEASURED: check:eager-closure and check:sdui-registration-pins. The latter exited 2 with No console build to weigh (prerequisite not met, not a verdict); both need a full @object-ui/console build, which is CI Bundle Analysis. Also NOT MEASURED: repo-wide pnpm lint and the full test farm (CI-owned). Two lock calls returned 99 queue-timeout (never acquired) and were re-taken with the same slot. CI at e4aa578, one read: 42 check runs, 21 success, 3 skipped, 17 in_progress, 1 queued, 0 failure, so in_progress.",
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "3 — each sent as one POST /repos/objectstack-ai/objectstack/dispatches and executed by the fleet-write relay as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (draft), created #10656, relay run 36149557570; the body was read back byte-identical, 12083 bytes, no differing byte. (2) label-write --assign os-tesla, POST /repos//issues/10656/assignees, relay run 36149671495; read back matching. (3) post-stamped, POST /repos//issues/10607/comments (this os-dev-report). Not REST writes: 4 git pushes of the branch (the empty branch, then 6aac6ac, 7f90de0, e4aa578).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: PR objectui#10656 (the seat, before landing) · the pending .changeset/10506-named-view-context-tokens.md parenthetical '(A directly authored object-grid or list-view node still does not call it.)' is false at e4aa578; the replacement text is in summary deviation (3) · noted, not filed",
"carrier: 承接者:无 · ObjectGrid's load effect keys on schemaFilter from a useMemo (toFilterNodeSafely), an identity dependency AGENTS.md #10 names; pre-existing, unchanged by this PR (it now receives a held input); not reproducible without a forced discard, so not class a · in PR Acceptance notes only, not filed"
]
}
Claim: PM loop round 5 — domain:ui execution seat 5 (amended)
Session: session_01KUxVUa7e39aNjhkKi1gsoy
Branch: claude/issue-10607-grid-list-filter-tokens
Worktree: objectui-issue-10607
Domain: domain:ui
Seat: domain:ui#5
File surface: packages/plugin-grid/src/ObjectGrid.tsx and packages/plugin-list/src/ListView.tsx (the node's own authored filter reads, and the held resolved value that feeds them); pins beside each; the new .changeset/10607-…md; and, added by this amendment, one sentence of the pending .changeset/10506-named-view-context-tokens.md, prose only, with its front matter byte-identical (stop on breach; explain in the report).
Container & model: S, mode:subagent, model: opus (default judgement tier; no path-derived mandate for these objectui paths).
Clause-②: no
Thread-read: 5832409031
Serial constraints cleared: the open-PR file lists were re-read in this act. No open PR touches .changeset/10506-named-view-context-tokens.md. The file belongs to the merged PR objectui#10577 (objectui#10506), and it is still pending on main.
This amends claim 5833014372. Branch, seat and fix are unchanged. One addition: PR objectui#10656 makes a sentence of a pending changeset false, and that changeset publishes verbatim into the CHANGELOG at the next release. .changeset/10506-named-view-context-tokens.md says 「(A directly authored object-grid or list-view node still does not call it.)」. After this PR, both nodes call the shared resolver. The sentence becomes 「(A directly authored object-grid or list-view node calls it too, since objectui#10607.)」. Nothing else in that file changes.
Clause-②: no: the documented context tokens resolve on two more hosts, through the one shared resolver. No schema, export or accept set moves.
os-dev-report
{
"issue": 10607,
"status": "done",
"round": "round 2, prose only, on amended claim 5834409941 (the newest Claim: on the card, naming claude/issue-10607-grid-list-filter-tokens)",
"branch": "claude/issue-10607-grid-list-filter-tokens",
"pr": "#10656",
"head": "80eca8ff1de710f2fa3e8202978dd60aa18c0fd7",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (mode:subagent, the dispatching seat's id)",
"premise_still_valid": true,
"summary": "Commit d325bb2 (prose only), then merge 80eca8f of origin/main f99f9cd (plugin-form only, no conflict). Worktree re-created from the pushed branch at e4aa578, and removed afterwards without --force. PR still draft; not marked ready, not enqueued, no auto-merge. Files changed this round: .changeset/10506-named-view-context-tokens.md +1/-1. The one sentence becomes (A directly authored object-grid or list-view node calls it too, since objectui#10607.). Front matter md5 8212bf42dc2f6ba4025ef7ced79c6d6d before and after; old sentence count 1 to 0, new sentence count 0 to 1; line 22 is 107 chars and nothing was re-wrapped. Also .changeset/10607-grid-list-filter-context-tokens.md +2/-3 (now 40 lines, front matter md5 unchanged a978dc6bfa143307ebb75d6d80f6efdf). Deviation: its sentence 'This closes the gap objectui#10506's entry notes ...' became false once the 10506 entry stopped noting a gap. It is on my file surface, so it now reads 'object-view has done this since objectui#10506; these two nodes, authored directly, had not.' Branch vs main f99f9cd: the 6 files of this PR only. No file under packages/plugin-grid or packages/plugin-list changed between e4aa578 and 80eca8f. Conflict, flagged rather than silently decided: step 3 asks me to PATCH the PR body. My role file says the dev writes the PR body once, at pr_create, never with a PATCH, and hands later edits to the seat; it also says the role file wins over dispatch wording. So I did not PATCH it. The round-2 body is ready at /tmp/claude-0/-home-user/76481b85-cb3e-5e10-aaba-ab350cecd68d/scratchpad/issue-10607/10607-pr-body-round2.md (13152 bytes, md5 deb790552cdf3778f70f6e11b52e57e7, 0 angle brackets, only closing keyword Fixes #10607). It is the stored body with a Round 2 paragraph added and three stale passages corrected: the note that the 10506 sentence was left false, the not-merged-again sentence, and the file table. Seat write: node scripts/pm/post-stamped.mjs --repo=objectstack-ai/objectui --body=10656 --file=THAT_PATH, then read back; AGENTS.md records that a PATCH can turn the session-URL footer into the bare form.",
"files_changed": [
".changeset/10506-named-view-context-tokens.md +1/-1",
".changeset/10607-grid-list-filter-context-tokens.md +2/-3"
],
"tests": "At 80eca8f: pnpm exec vitest run on both pins (os-verify-lock): 19 passed, exit 0; one earlier lock call returned 99 queue-timeout (never acquired) and was re-taken with the same slot. Gates, each exit 0: check:changeset-claims (report-only; both bodies pass the self-contradiction reading), check:pending-changeset-literals, node scripts/check-changeset-presence.mjs (4 source files of 2 released packages, 1 changeset), check-changeset-overwrite (1 added, 1 modified: the 10506 file, declared plugin-view patch and core patch at base and now; the gate's case 2, a deliberate prose correction), check-changeset-no-major, check-changeset-fixed, check:control-bytes, check:new-line-citations (0 new). Suites and type-check were not re-run: round 2 changed no code in either package, and their readings at e4aa578 stand.",
"mcp_calls": "0",
"api_writes": "1 this round — post-stamped: POST /repos//issues/10607/comments (this os-dev-report), sent as one POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay. Not a REST write: 1 git push (e4aa578 to 80eca8f). The PR body was not PATCHed (see summary).",
"open_questions": [],
"out_of_scope_findings": []
}
each host resolves its own authored filter once, through @object-ui/core's resolveFilterPlaceholders with useFilterScope(): ObjectGrid resolves filter and its deprecated alias defaultFilters, and ListView resolves filter. filter-tokens.ts and useFilterScope.ts are untouched. There is no second resolver and no token logic in either host
the hold
plugin-view's useResolvedFilterSegments shape, one per host: held in state, keyed on the authored input (compared by structure) and on currentUserId / currentOrgId / onUnresolved one by one, never on the scope object's identity (AGENTS.md #10). The key is the input, so a date macro cannot churn it. No refetch loop
local comparator
isSameAuthoredFilter is a private copy of plugin-view's structural-equality rules, forced by the dependency graph: plugin-view depends on plugin-grid, plugin-list depends on neither, and a shared export would move an export set. It is not a second resolver
read sites
ObjectGrid: the query, its export and the alias leg. The load effect now keys on the resolved defaultFilters, which it read before without keying on it. ListView: all 10 raw schema.filter reads (fetch and deps, page-reset signature, self-query views, the child node, the export, the empty-state test) now read the held value, and the only raw read left is the hold's input
pending changeset
per the amended claim 5834409941, one sentence of the pending 10506 changeset now reads 「(A directly authored object-grid or list-view node calls it too, since objectui#10607.)」, with the front matter byte-identical. Every other sentence there, and in the 16 other pending changesets naming these files, still reads true
pins
19 cells across two files: the token reaches $filter as the scope's user id on both hosts. An equal inline rebuild does not refetch, and a new user refetches. Lit control: a token-free filter. Negative leg: no user in scope keeps the literal and the resolver warns. The object-view seam: a pre-resolved filter fetches once, unchanged. The token and hold cells fail at the base
contract review
PASS at CONTRACT_REVIEW_TIER on this head, record 5834851784 on the PR. The seat read the reviewer transcript: every turn was at tier
clause ②
no holds: every new symbol is module-private, and no accept set moves
semver
patch for @object-ui/plugin-grid and @object-ui/plugin-list; all 14 changeset sentences read true
governed
NOT GOVERNED (6 paths)
CI
3 skipped, 40 success, 0 red on 80eca8f
closing keywords
the only closing reference in the body is Fixes #10607
The review's out-of-scope reading (a directly authored object-gallery sends its own filter raw) is owed to the filing gate (seat post objectui#10488).
State
ready and auto-merge (squash) go through the relay ops pr_ready + automerge_enable in this act.
Landed: PR objectui#10656 merged as 0c3f70a through the merge queue
domain:ui seat 5, session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T15:34Z. Verified by content on objectui origin/main0c3f70a, not by the sha:
ObjectGrid.tsx and ListView.tsx each read @object-ui/core's resolveFilterPlaceholders with useFilterScope(), through a held resolved value. The grid's schemaFilterSource is authoredFilters.filter (:1880).
Both pins are present: ObjectGrid.filterContextTokens-10607 and ListView.filterContextTokens-10607.
.changeset/10607-grid-list-filter-context-tokens.md is present, and the pending 10506 changeset carries the corrected sentence ("calls it too, since objectui#10607").
The review's out-of-scope reading is filed as objectui#10666 (a directly authored object-gallery sends its own filter raw).
The card closed completed through Fixes #10607. pm:dispatched is removed in the same stroke.
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: business objects, records and views | records-forms.saved-view-management | P2
Triage: first grade —
bug·priority:p3·domain:ui·area:records·pm:queue(findingremoved — graded)Triage: lands in
packages/plugin-grid/src/ObjectGrid.tsxandpackages/plugin-list/src/ListView.tsx(0 production reads ofresolveFilterPlaceholders) ⇒domain:ui; rationale: a directly authoredobject-gridorlist-viewnode sends{current_user_id}literally in its own filter — the #10506 class on two more hosts. Against ObjectStack the server resolves or refuses the token, so this is defence in depth ⇒ p3.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T12:31Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/main.Execution note: resolve the node's own filter through the ONE shared
resolveFilterPlaceholderswithuseFilterScope(), as PR objectui#10577 did; hold the result by structure so the grid does not refetch every render.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 5 —
domain:uiexecution seat 5Session:
session_01KUxVUa7e39aNjhkKi1gsoyBranch:
claude/issue-10607-grid-list-filter-tokensWorktree:
objectui-issue-10607Domain:
domain:uiSeat:
domain:ui#5File surface:
packages/plugin-grid/src/ObjectGrid.tsx(the node's ownschema.filterread, ~:1761) andpackages/plugin-list/src/ListView.tsx(the threebuildEffectiveFilter(schema.filter, …)reads, ~:2190/:3078/:4000); pins beside each; and changesetspatchfor@object-ui/plugin-gridand@object-ui/plugin-list(stop on breach; explain in the report).Container & model:
S,mode:subagent,model: opus(default judgement tier; no path-derived mandate for these objectui paths).Clause-②: no
Thread-read: 5832409031
Serial constraints cleared: the open-PR file lists were re-read in this act at objectui
origin/maine0f8202. Three open PRs share these files, in other regions:ListViewfilter candidates.ListViewfetch effect's invalidation nonce.pm:blockedobjectui#9853; theObjectGridpage size.This is ordinary concurrency. The branch merges
origin/mainbeforepr_create, and the later lander resolves. No livepm:dispatchedclaim names theschema.filterreads. The shape to follow, PR objectui#10577 (objectui#10506), merged as6c2f3c5.Clause-②: no: the documented context tokens ({current_user_id},{current_org_id}, …) resolve on two more hosts, through the one shared resolver. No schema, export or accept set moves.Scope
The triage (
5832409031): 「resolve the node's own filter through the ONE sharedresolveFilterPlaceholderswithuseFilterScope(), as PR objectui#10577 did; hold the result by structure so the grid does not refetch every render.」object-gridand alist-viewwithfilter: [['owner', '=', '{current_user_id}']]send the literal token in their query.filteronce, through@object-ui/core'sresolveFilterPlaceholdersagainstuseFilterScope(). The result is held by structure, so a re-render with an equal filter does not refetch. ⛔ No second resolver.object-viewpath, which already hands a resolved filter down. Resolving twice is idempotent (pinned in objectui#10577); show it with one fetch.⇒
Fixes #10607.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T13:15Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10607,
"status": "done",
"branch": "claude/issue-10607-grid-list-filter-tokens",
"pr": "#10656",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (mode:subagent, the dispatching seat's id; the Claude-Session trailer on every commit)",
"premise_still_valid": true,
"summary": "H1 confirmed on BASE dddbc27 (the dispatch named e0f8202; main had moved, objectui#10627 merged): git grep of resolveFilterPlaceholders|resolveContextTokens|useFilterScope over packages/plugin-grid/src and packages/plugin-list/src exit 1; control, the same words in plugin-view ObjectView.tsx, 8 hits. ListView carried more raw schema.filter reads than the three named, and every one now reads the held value. Implemented, one resolved value per host through @object-ui/core resolveFilterPlaceholders with useFilterScope(), held in state (the plugin-view useResolvedFilterSegments pattern: authored input compared by structure, plus currentUserId, currentOrgId and onUnresolved each compared on its own, set during render). ObjectGrid: useResolvedGridFilters over filter and the deprecated alias defaultFilters; it feeds schemaFilterSource, the defaultFilters leg of the load effect, and a new load-effect dependency schemaDefaultFilters. ListView: useResolvedAuthoredFilter over schema.filter; it feeds the fetch and its deps, the page-reset signature, selfQueryFilter (3 reads), the child node filter and its memo deps, the export and its deps, and the empty-state test. The only raw schema.filter code read left in either file is the hold input. Files vs merge base 4a3d500: packages/plugin-grid/src/ObjectGrid.tsx +129/-5; packages/plugin-list/src/ListView.tsx +125/-16; new packages/plugin-grid/src/tests/ObjectGrid.filterContextTokens-10607.test.tsx 216 lines (10 cells); new packages/plugin-list/src/tests/ListView.filterContextTokens-10607.test.tsx 215 lines (9 cells); new .changeset/10607-grid-list-filter-context-tokens.md 41 lines (plugin-grid patch, plugin-list patch). resolveFilterPlaceholders (filter-tokens.ts) and useFilterScope.ts are untouched. Head e4aa578 = merge of origin/main 4a3d500. The ListView conflict with objectui#10620 (the react import line, and the fetch-effect deps line) was resolved as a union inside my own hunks. origin/main then gained f99f9cd (plugin-form only, outside both packages' closures), not merged. Draft PR #10656, assignee os-tesla, labels plugin and tests (labeler). Worktree removed without --force. Deviations. (1) isSameAuthoredFilter is a local copy of plugin-view isStructurallyEqual's rules, one in each file: plugin-view depends on plugin-grid, plugin-list depends on neither, and a shared export would move an export set (Clause-2 no). (2) The grid load effect gains the dependency schemaDefaultFilters: base read schema.defaultFilters without keying on it, so a user change carried only by the alias would not re-query. (3) Conflict, flagged rather than silently decided: the pending .changeset/10506-named-view-context-tokens.md says '(A directly authored
object-gridorlist-viewnode still does not call it.)', which is false at this head and publishes verbatim. The role file says prose this change makes false is must-fix; the claim declares that file outside the surface (stop on breach). I left it unedited, and my own changeset states the gap is closed. Seat edit before landing: delete that parenthetical, or replace it with '(A directly authoredobject-gridorlist-viewnode calls it too, since objectui#10607.)'. check:changeset-claims does not flag it (it names the symbols, not the files).","tests": "Pins, final (repo root, vitest, via os-verify-lock). Base: each source swapped to its 4a3d500 blob under a trap, restored with both blobs equal to HEAD and git diff HEAD empty. Grid pin: 7 failed, 3 passed, exit 1. List pin: 6 failed, 3 passed, exit 1. The token cells read the literal, e.g. expected [ [ 'owner', '=', '{current_user_id}' ] ] to deeply equal [ [ 'owner', '=', 'usr_42' ] ]. The cells that pass on base are the CONTROL, the same-node count and the already-resolved seam. Head e4aa578, both pins: 19 passed, exit 0. Pre-merge, against BASE dddbc27: grid 7 failed | 3 passed exit 1 (the pin before its COLUMNS constant), list 6 failed | 3 passed exit 1. After the fix: 10 of 10 and 9 of 9, exit 0. H4 ablation (objectstack scripts/ablation-replace.mjs, WRAP mode; anchor hit 1 then 0; blob moved; restored blob == HEAD and git diff HEAD empty; the subject resolves from src/, so there is no dist leg). The hold call was replaced by a per-render resolveFilterPlaceholders. Grid: 5 failed | 5 passed, the 5 hold cells timing out at 15000ms (endless refetch). List: 4 failed | 5 passed, 2 timing out at 15000ms and 2 reading expected 0 to be greater than 0. Expected direction: red. H3, one-time measurement: a temporary plugin-view test (real ObjectView into real ObjectGrid, 2 re-renders), deleted afterwards, git status clean. ObjectGrid.tsx base blob swapped in and restored with a hash check. table.filter: head 1 fetch then 1, base 1 then 1, $filter [["owner","=","usr_42"]] in both. Named grid view (reaches the grid as defaultFilters): head 1 then 1, base 1 then 1, $filter [["owner","equals","usr_42"]] in both. Suites at e4aa578: pnpm exec vitest run packages/plugin-grid/ 157 files, 1497 passed, exit 0; packages/plugin-list/ 99 files, 1156 passed, exit 0; packages/plugin-view/ 49 files, 477 passed, exit 0. Pre-merge: 157/1497, 98/1153, 49/477, all exit 0. Type-check: pnpm turbo run build --filter '@object-ui/plugin-grid^...' --filter '@object-ui/plugin-list^...' --concurrency=2 (13 tasks, exit 0), then pnpm turbo run type-check --filter @object-ui/plugin-grid --filter @object-ui/plugin-list --concurrency=2: pre-merge 16 tasks, exit 0; at e4aa578 16 tasks, exit 0, with deps rebuilt. tsc -p tsconfig.test.json --listFilesOnly lists each pin (1 hit each); direct tsc -p tsconfig.test.json in both packages exit 0. eslint, plain form, on the 4 changed tsx at e4aa578: exit 0, 0 errors. Per-rule warnings vs 4a3d500: ObjectGrid.tsx 207 to 207, ListView.tsx 184 to 184 (0 rules differing); the pins 0 findings. Gates at e4aa578, each exit 0: check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations (0 new), check:changeset-claims (report-only; 12 pending changesets name ObjectGrid.tsx or ListView.tsx, all re-read, none concerns the filter read), check:pending-changeset-literals, node scripts/check-changeset-presence.mjs (4 source files of 2 released packages, 1 changeset), check-changeset-overwrite (1 added, 0 modified), check-changeset-no-major, check-changeset-fixed, check:phantom-deps, check:unreferenced-sources, check:self-import, check:side-effects-array, check-type-check-coverage, check-governed-queue-guard --test on the 5 paths (NOT GOVERNED). The same set was also exit 0 at 7f90de0. NOT MEASURED: check:eager-closure and check:sdui-registration-pins. The latter exited 2 with No console build to weigh (prerequisite not met, not a verdict); both need a full @object-ui/console build, which is CI Bundle Analysis. Also NOT MEASURED: repo-wide pnpm lint and the full test farm (CI-owned). Two lock calls returned 99 queue-timeout (never acquired) and were re-taken with the same slot. CI at e4aa578, one read: 42 check runs, 21 success, 3 skipped, 17 in_progress, 1 queued, 0 failure, so in_progress.",
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "3 — each sent as one POST /repos/objectstack-ai/objectstack/dispatches and executed by the fleet-write relay as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (draft), created #10656, relay run 36149557570; the body was read back byte-identical, 12083 bytes, no differing byte. (2) label-write --assign os-tesla, POST /repos//issues/10656/assignees, relay run 36149671495; read back matching. (3) post-stamped, POST /repos//issues/10607/comments (this os-dev-report). Not REST writes: 4 git pushes of the branch (the empty branch, then 6aac6ac, 7f90de0, e4aa578).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: PR objectui#10656 (the seat, before landing) · the pending .changeset/10506-named-view-context-tokens.md parenthetical '(A directly authored
object-gridorlist-viewnode still does not call it.)' is false at e4aa578; the replacement text is in summary deviation (3) · noted, not filed","carrier: 承接者:无 · ObjectGrid's load effect keys on schemaFilter from a useMemo (toFilterNodeSafely), an identity dependency AGENTS.md #10 names; pre-existing, unchanged by this PR (it now receives a held input); not reproducible without a forced discard, so not class a · in PR Acceptance notes only, not filed"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 5 —
domain:uiexecution seat 5 (amended)Session:
session_01KUxVUa7e39aNjhkKi1gsoyBranch:
claude/issue-10607-grid-list-filter-tokensWorktree:
objectui-issue-10607Domain:
domain:uiSeat:
domain:ui#5File surface:
packages/plugin-grid/src/ObjectGrid.tsxandpackages/plugin-list/src/ListView.tsx(the node's own authoredfilterreads, and the held resolved value that feeds them); pins beside each; the new.changeset/10607-…md; and, added by this amendment, one sentence of the pending.changeset/10506-named-view-context-tokens.md, prose only, with its front matter byte-identical (stop on breach; explain in the report).Container & model:
S,mode:subagent,model: opus(default judgement tier; no path-derived mandate for these objectui paths).Clause-②: no
Thread-read: 5832409031
Serial constraints cleared: the open-PR file lists were re-read in this act. No open PR touches
.changeset/10506-named-view-context-tokens.md. The file belongs to the merged PR objectui#10577 (objectui#10506), and it is still pending onmain.This amends claim
5833014372. Branch, seat and fix are unchanged. One addition: PR objectui#10656 makes a sentence of a pending changeset false, and that changeset publishes verbatim into the CHANGELOG at the next release..changeset/10506-named-view-context-tokens.mdsays 「(A directly authoredobject-gridorlist-viewnode still does not call it.)」. After this PR, both nodes call the shared resolver. The sentence becomes 「(A directly authoredobject-gridorlist-viewnode calls it too, since objectui#10607.)」. Nothing else in that file changes.Clause-②: no: the documented context tokens resolve on two more hosts, through the one shared resolver. No schema, export or accept set moves.⇒
Fixes #10607.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· amended claim · 2026-09-25T14:50Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10607,
"status": "done",
"round": "round 2, prose only, on amended claim 5834409941 (the newest Claim: on the card, naming claude/issue-10607-grid-list-filter-tokens)",
"branch": "claude/issue-10607-grid-list-filter-tokens",
"pr": "#10656",
"head": "80eca8ff1de710f2fa3e8202978dd60aa18c0fd7",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (mode:subagent, the dispatching seat's id)",
"premise_still_valid": true,
"summary": "Commit d325bb2 (prose only), then merge 80eca8f of origin/main f99f9cd (plugin-form only, no conflict). Worktree re-created from the pushed branch at e4aa578, and removed afterwards without --force. PR still draft; not marked ready, not enqueued, no auto-merge. Files changed this round: .changeset/10506-named-view-context-tokens.md +1/-1. The one sentence becomes (A directly authored
object-gridorlist-viewnode calls it too, since objectui#10607.). Front matter md5 8212bf42dc2f6ba4025ef7ced79c6d6d before and after; old sentence count 1 to 0, new sentence count 0 to 1; line 22 is 107 chars and nothing was re-wrapped. Also .changeset/10607-grid-list-filter-context-tokens.md +2/-3 (now 40 lines, front matter md5 unchanged a978dc6bfa143307ebb75d6d80f6efdf). Deviation: its sentence 'This closes the gap objectui#10506's entry notes ...' became false once the 10506 entry stopped noting a gap. It is on my file surface, so it now reads 'object-viewhas done this since objectui#10506; these two nodes, authored directly, had not.' Branch vs main f99f9cd: the 6 files of this PR only. No file under packages/plugin-grid or packages/plugin-list changed between e4aa578 and 80eca8f. Conflict, flagged rather than silently decided: step 3 asks me to PATCH the PR body. My role file says the dev writes the PR body once, at pr_create, never with a PATCH, and hands later edits to the seat; it also says the role file wins over dispatch wording. So I did not PATCH it. The round-2 body is ready at /tmp/claude-0/-home-user/76481b85-cb3e-5e10-aaba-ab350cecd68d/scratchpad/issue-10607/10607-pr-body-round2.md (13152 bytes, md5 deb790552cdf3778f70f6e11b52e57e7, 0 angle brackets, only closing keyword Fixes #10607). It is the stored body with a Round 2 paragraph added and three stale passages corrected: the note that the 10506 sentence was left false, the not-merged-again sentence, and the file table. Seat write: node scripts/pm/post-stamped.mjs --repo=objectstack-ai/objectui --body=10656 --file=THAT_PATH, then read back; AGENTS.md records that a PATCH can turn the session-URL footer into the bare form.","files_changed": [
".changeset/10506-named-view-context-tokens.md +1/-1",
".changeset/10607-grid-list-filter-context-tokens.md +2/-3"
],
"tests": "At 80eca8f: pnpm exec vitest run on both pins (os-verify-lock): 19 passed, exit 0; one earlier lock call returned 99 queue-timeout (never acquired) and was re-taken with the same slot. Gates, each exit 0: check:changeset-claims (report-only; both bodies pass the self-contradiction reading), check:pending-changeset-literals, node scripts/check-changeset-presence.mjs (4 source files of 2 released packages, 1 changeset), check-changeset-overwrite (1 added, 1 modified: the 10506 file, declared plugin-view patch and core patch at base and now; the gate's case 2, a deliberate prose correction), check-changeset-no-major, check-changeset-fixed, check:control-bytes, check:new-line-citations (0 new). Suites and type-check were not re-run: round 2 changed no code in either package, and their readings at e4aa578 stand.",
"mcp_calls": "0",
"api_writes": "1 this round — post-stamped: POST /repos//issues/10607/comments (this os-dev-report), sent as one POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay. Not a REST write: 1 git push (e4aa578 to 80eca8f). The PR body was not PATCHed (see summary).",
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPT: objectui#10656 at
80eca8fdomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T15:20Z. Checked against the diff and CI, not against the report's own account.@object-ui/core'sresolveFilterPlaceholderswithuseFilterScope():ObjectGridresolvesfilterand its deprecated aliasdefaultFilters, andListViewresolvesfilter.filter-tokens.tsanduseFilterScope.tsare untouched. There is no second resolver and no token logic in either hostuseResolvedFilterSegmentsshape, one per host: held in state, keyed on the authored input (compared by structure) and oncurrentUserId/currentOrgId/onUnresolvedone by one, never on the scope object's identity (AGENTS.md #10). The key is the input, so a date macro cannot churn it. No refetch loopisSameAuthoredFilteris a private copy of plugin-view's structural-equality rules, forced by the dependency graph: plugin-view depends on plugin-grid, plugin-list depends on neither, and a shared export would move an export set. It is not a second resolverObjectGrid: the query, its export and the alias leg. The load effect now keys on the resolveddefaultFilters, which it read before without keying on it.ListView: all 10 rawschema.filterreads (fetch and deps, page-reset signature, self-query views, the child node, the export, the empty-state test) now read the held value, and the only raw read left is the hold's input5834409941, one sentence of the pending10506changeset now reads 「(A directly authoredobject-gridorlist-viewnode calls it too, since objectui#10607.)」, with the front matter byte-identical. Every other sentence there, and in the 16 other pending changesets naming these files, still reads true$filteras the scope's user id on both hosts. An equal inline rebuild does not refetch, and a new user refetches. Lit control: a token-free filter. Negative leg: no user in scope keeps the literal and the resolver warns. Theobject-viewseam: a pre-resolved filter fetches once, unchanged. The token and hold cells fail at the baseCONTRACT_REVIEW_TIERon this head, record5834851784on the PR. The seat read the reviewer transcript: every turn was at tiernoholds: every new symbol is module-private, and no accept set movespatchfor@object-ui/plugin-gridand@object-ui/plugin-list; all 14 changeset sentences read true80eca8fFixes #10607The review's out-of-scope reading (a directly authored
object-gallerysends its ownfilterraw) is owed to the filing gate (seat post objectui#10488).State
readyand auto-merge (squash) go through the relay opspr_ready+automerge_enablein this act.objectstack-fleet commentedon Sep 25, 2026
Landed: PR objectui#10656 merged as
0c3f70athrough the merge queuedomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T15:34Z. Verified by content on objectuiorigin/main0c3f70a, not by the sha:ObjectGrid.tsxandListView.tsxeach read@object-ui/core'sresolveFilterPlaceholderswithuseFilterScope(), through a held resolved value. The grid'sschemaFilterSourceisauthoredFilters.filter(:1880).ObjectGrid.filterContextTokens-10607andListView.filterContextTokens-10607..changeset/10607-grid-list-filter-context-tokens.mdis present, and the pending10506changeset carries the corrected sentence ("calls it too, since objectui#10607").The review's out-of-scope reading is filed as objectui#10666 (a directly authored
object-gallerysends its ownfilterraw).The card closed
completedthroughFixes #10607.pm:dispatchedis removed in the same stroke.fix(plugin-grid,plugin-list): resolve context tokens in a directly au…