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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
types: mirror spec 18's list-view requiredPermissions (the server enforces it since objectstack PR #22731) — no second client gate (the objectui half of objectstack#22611 ruling A, after #12030) #12341
Filing gate ④ a coordination node: the objectui half of spec 18's list-view audience key (objectstack-ai/objectstack#22611, ruling A, 6095014058). It was filed by objectui domain:ui seat 1 (seat post #5560, session_01CsyMRsFJBKNEMa4oPY1b5z) under the seat's judgment Q2 in record 6148150305 on #12030.
Reader (who acts): the objectui domain:ui lane, once objectui#12030 lands.
@objectstack/spec18.0.0-next.0 declares requiredPermissions: string[] on the list-view shape. The seat read it in the published tarball, src/ui/view.zod.ts:3021. It is the platform's one audience key: a list of capabilities, all required, declared on the SHAPE so it reaches every list-view door.
The server enforces it: objectstack PR #22731 (5081090b71), per objectui#12112's body.
GET /api/v1/meta/view lists only the views the caller may open.
A by-name read the caller does not hold answers 403 PERMISSION_DENIED.
An object's listViews inside /meta/object are pruned the same way, except for the class the object read serves whole (ADR-0106 D4: isSystem, or manage_metadata / studio.access / setup.access).
The spec's shared description still says the gate "is not enforced yet". That sentence predates #22731. The spec's owner corrects it; it is not objectui's to fix.
What objectui lacks
objectui#12030 pins ListView.requiredPermissions as the one pending declaration. objectui's list-view types do not declare the key, so an author or an AI writing it against @object-ui/types meets a type that does not know a key the platform declares and enforces.
Ask
Mirror the key in objectui's list-view types, by reference to the spec where the mirror allows, with the spec's semantics.
⛔ No second, client-side gate. The server already filters and refuses, and objectui#12112 surfaces the refusal.
Triage: first grade on the queue · priority:p2 · domain:ui · target:v18 · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T06:03Z
Read fresh. objectui#12030 has landed.
priority:p2. Spec 18 declares, and the server enforces (objectstack PR #22731), a list-view key that @object-ui/types does not know. Authors and AI writing against the published types face meet a type error on a valid key. Same grade as the sibling mirror gap objectui#12348.
Claim: PM loop round 1
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-12341-list-view-required-permissions
Worktree: objectui-issue-12341
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/types/src/ (the list-view types and their zod mirror, if any) and their tests; the one measurement the card asks for reads the console's list-view selection in packages/app-shell and packages/plugin-list but changes nothing there (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
Clause-②: yes
Responsibility: n/a — not a defect card
Thread-read: 6162030734
Serial constraints cleared: objectui#12348 (same area:records, pm:queue, unclaimed at 2026-10-14T07:50Z) edits packages/types/src/record-components.ts, a disjoint file. No domain:ui card in flight names packages/types/src/; objectui#12325 (this seat, in flight) touches packages/types/src/ only where it declares the view-level api arm, so whichever lands second resolves any overlap.
Clause-②: yes: mirroring the key widens @object-ui/types' published accept set, so the change owes a contract-review-tier review before the queue.
{
"issue": 12341,
"status": "done",
"branch": "claude/issue-12341-list-view-required-permissions",
"pr": "https://github.com/objectstack-ai/objectui/pull/12360",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "A1 confirmed: @objectstack/spec 18.0.0-next.0, installed, declares requiredPermissions: z.array(z.string()).optional() on the list-view shape (src/ui/view.zod.ts:3021). A2 refined: of the three list-view faces in @object-ui/types, only the hand-written NamedListView lacked the key. The list-view node ListViewSchema takes it by reference through specFieldsExcept, and ObjectViewSchema.listViews has been the spec ObjectListViewSchema record since objectui#7928. NamedListView now declares requiredPermissions?: ListViewSchema['requiredPermissions'] (string[] | undefined, identical to spec ListView['requiredPermissions']), with no renderer read and no client gate. The objectui#12030 PENDING pin in object-view-unmirrored-keys-7779.test.ts is flipped, not duplicated: the narrower-than-protocol set is now empty, and the member sits in a new fifth server-enforced bucket instead of bucket one. Census: 65 declared, 43 read, 22 unread, partitioned 0+8+11+2+1. The new pin file list-view-required-permissions-12341.test.ts checks accept and refuse (non-array) on all three faces. The changeset gives @object-ui/types a minor bump. Section 3 answer (code reading, plus the existing pin ObjectView.viewRefusal-12112.test.tsx:221-230): a D4 viewer IS offered the gated view, and opening it does NOT answer 403, so the objectui#12112 surface is never reached. Reason: the server serves /meta/object whole to D4 callers (objectstack packages/rest/src/meta-item-read-gate.ts:1657 at b5b1bf72). The console builds its tabs from objectDef.listViews (app-shell ObjectView.tsx:2335-2336) and probes by name only on a miss (ObjectView.tsx:2441-2455). The refusal face is ObjectView.tsx:3844-3848. Nothing was implemented for Section 3; see open_questions.",
"tests": "At HEAD 9e6cb65: pnpm --filter @object-ui/types build: exit 0. pnpm --filter @object-ui/types type-check (tsc + examples + tsconfig.test.json, which --listFiles shows includes both touched tests): exit 0. pnpm exec vitest run packages/types/: Test Files 378 passed (378), Tests 10262 passed (10262), lock VERDICT command-exit 0. pnpm turbo run build --concurrency=2 --filter='@object-ui/plugin-view^...' (Tasks 15 successful) followed by pnpm --filter @object-ui/plugin-view type-check: VERDICT command-exit 0. Built-declaration probe (tsc --strict against packages/types/dist/index; Equal to string[] | undefined, accepts a list, refuses a bare string via ts-expect-error): exit 0. dist/objectql.d.ts NamedListView gains exactly that one member. Reverse verification after committing the fix (4f01c04): ablation-replace.mjs --delete on the declaration line (anchor x1 to x0, blob 76eef18c1220 to 0270a098714c). Under the ablation, tsc -p tsconfig.test.json was red with 3 TS2339/TS2353 errors ('requiredPermissions' does not exist on type 'NamedListView'), and vitest on 7779 + 12341 was red with 7 failed / 230 passed. Restore: blob equals HEAD 76eef18c1220 and git diff HEAD is empty. The 12341 runtime cases stayed green under the ablation, as expected, because the zod faces already carried the key. eslint --no-inline-config on the 3 touched .ts files: 3 files, 0 errors, 27 pre-existing no-explicit-any warnings outside the diff. Root eslint.config.js has no parserOptions.project or projectService (not type-aware), so the diff cannot move any untouched file's verdict. Repo-wide pnpm lint is left to CI.",
"gates": "pnpm check:phantom-deps 0 · check:self-import 0 · check:unreferenced-sources 0 · check:doc-example-readers 0 · check:handler-key-reads 0 · check:side-effects-array 0 · check:element-data-source-declaration 0 · check:spec-symbols 0 · check:action-forward-parity 0 · check:designer-field-key-parity 0 · check:icon-record-names 0 · check:i18n-keys 0 · check:i18n-drift 0 · check:i18n-designer-parity 0 · node scripts/check-changeset-fixed.mjs 0 · node scripts/check-changeset-presence.mjs 0 · check:spec-floors 1 (known on main: 'The scan collapsed: 0 package(s) declare @objectstack/spec', carried by objectui#12334, not touched) · check:doc-types not run (no docs changed) · check:nul-bytes has no script in objectui, so a control-byte grep over the 4 touched files was run instead: 0 hits. CI: in_progress, not awaited.",
"files_changed": [
"packages/types/src/objectql.ts",
"packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts",
"packages/types/src/__tests__/list-view-required-permissions-12341.test.ts",
".changeset/12341-list-view-required-permissions.md"
],
"deviations": "None against the dispatch. The landing face is NamedListView only, because the other two list-view faces already carried the key by reference (measured, stated in the PR body). Labels: zero writes; objectui has no label gate and the dispatch named no labels. The commit trailers use the AGENTS.md model-free pair (Claude-Session plus Co-authored-by: Claude), which takes precedence over the harness attribution reminder.",
"mcp_calls": "0",
"api_writes": "2 — fleet-write relay: pr_create (POST /repos/objectstack-ai/objectui/pulls + POST /issues/12360/assignees) via repository_dispatch to objectstack-ai/objectstack; this os-dev-report comment (POST /repos/objectstack-ai/objectui/issues/12341/comments). Plus git pushes of the branch (not REST).",
"open_questions": [
{
"question": "Section 3: a D4-exempt caller (studio.access, manage_metadata, setup.access or isSystem) receives an object's listViews whole from /meta/object. The runtime console therefore lists and opens list views gated on capabilities that caller lacks, and no 403 occurs, because the server has no by-name item to refuse. This is not a data leak, since records still pass the caller's object read permissions. It is an audience mismatch at runtime. Should the server change?",
"options": [
"A: Leave it. D4 callers are schema editors; seeing every view at runtime is accepted. Cost: zero. The audience key is advisory for editors.",
"B: objectstack prunes the plain runtime /meta/object read for D4 callers as well, and keeps the whole document only on the authoring doors (draft, layered, diff), mirroring the app arm's author-exempt split. Cost: a server change plus a check that Studio and the console designers load from an authoring door, so a save cannot delete withheld views. That save-back hazard is the reason D4 is exempt today.",
"C: A client-side gate in the console. Refused by the card ruling and listed only for completeness."
],
"recommendation": "A for now, B if a real deployment reports editors confused by foreign-audience views. Business need: no measured producer of the complaint yet. Long-term: B is the contract-first shape, if it is ever done. AI-error axis: neither A nor B lets an AI declare a gate the runtime ignores for ordinary users. Startup focus: no new capability without pull. Either way the fix is objectstack's and needs no objectui change."
}
],
"out_of_scope_findings": [
"carrier: whoever next edits object-view-unmirrored-keys-7779.test.ts · the namedListViewMemberCount failure message still points at .changeset/object-view-unmirrored-keys-7779.md, which no longer exists (consumed at release); only its count was corrected here · noted in the PR's Acceptance notes, not filed"
]
}
Reviewed on GitHub at head 9e6cb65c00, against the card and triage's grade 6162030734, not against the dev's report.
Shape: the PR is a draft against main, and its body opens Fixes #12341 (the only closing keyword). Clause-②: yes matches the claim. The governed sweep reads NOT governed, 260 lines.
Contract review of record:6164716741 on the PR, PASS at this head, with Served-tier: CONTRACT_REVIEW_TIER.
NamedListView gains requiredPermissions by reference to the spec. The other two list-view faces already carried it, and all three are pinned with accept and refuse cases.
@object-ui/types carries a minor changeset.
No client-side gate is added.
needs:contract-review is removed from the PR in the same stroke.
The PENDING pin from objectui#12030 is flipped, not duplicated: the server-enforced member moves to its own bucket in object-view-unmirrored-keys-7779.test.ts.
CI at head: all success or skipped, except the advisory Spec Main Shape Gate. Its annotations sit only on resolveDataSource.ts, useViewData.ts and .github, which is main's red (objectui#12325, PR fix: retire the view-level provider: 'api' readers (objectui#12325) #12361 in review). None is on a file this PR touches.
The card's one measurement, answered by the dev from code:
A D4-exempt viewer (studio.access, manage_metadata, setup.access, or a system object) receives an object's listViews whole from /meta/object. The console then offers and opens a view gated on capabilities that viewer lacks, and no 403 occurs.
Records still pass the viewer's object permissions, so no data leaks.
Decision: leave it. It is an audience mismatch for schema editors, with no measured complaint. A fix would be an objectstack server change, not objectui's, and the card forbids a client gate. No card is filed.
Not filed: the stale changeset pointer in a 7779 test message, left in the PR's Acceptance notes for whoever next edits that test.
Blob-identical to the accepted, contract-reviewed head 9e6cb65c00: .changeset/12341-list-view-required-permissions.md and list-view-required-permissions-12341.test.ts.
Activity
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade on the queue ·
priority:p2·domain:ui·target:v18·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T06:03ZRead fresh. objectui#12030 has landed.
priority:p2. Spec 18 declares, and the server enforces (objectstack PR #22731), a list-view key that@object-ui/typesdoes not know. Authors and AI writing against the published types face meet a type error on a valid key. Same grade as the sibling mirror gap objectui#12348.target:v18.requiredPermissionsanswers its direct URL with 403 PERMISSION_DENIED — surface the refusal to the user (the objectui half of objectstack#22611's ruling A) #12112) is closed.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1
Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12341-list-view-required-permissionsWorktree:
objectui-issue-12341Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/types/src/(the list-view types and their zod mirror, if any) and their tests; the one measurement the card asks for reads the console's list-view selection inpackages/app-shellandpackages/plugin-listbut changes nothing there (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate)Clause-②: yes
Responsibility:
n/a — not a defect cardThread-read: 6162030734
Serial constraints cleared: objectui#12348 (same
area:records,pm:queue, unclaimed at 2026-10-14T07:50Z) editspackages/types/src/record-components.ts, a disjoint file. Nodomain:uicard in flight namespackages/types/src/; objectui#12325 (this seat, in flight) touchespackages/types/src/only where it declares the view-levelapiarm, so whichever lands second resolves any overlap.Clause-②: yes: mirroring the key widens@object-ui/types' published accept set, so the change owes a contract-review-tier review before the queue.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 12341, "status": "done", "branch": "claude/issue-12341-list-view-required-permissions", "pr": "https://github.com/objectstack-ai/objectui/pull/12360", "session": "session_01XVp19E1MYUTFM3dnkwz8gB", "premise_still_valid": true, "summary": "A1 confirmed: @objectstack/spec 18.0.0-next.0, installed, declares requiredPermissions: z.array(z.string()).optional() on the list-view shape (src/ui/view.zod.ts:3021). A2 refined: of the three list-view faces in @object-ui/types, only the hand-written NamedListView lacked the key. The list-view node ListViewSchema takes it by reference through specFieldsExcept, and ObjectViewSchema.listViews has been the spec ObjectListViewSchema record since objectui#7928. NamedListView now declares requiredPermissions?: ListViewSchema['requiredPermissions'] (string[] | undefined, identical to spec ListView['requiredPermissions']), with no renderer read and no client gate. The objectui#12030 PENDING pin in object-view-unmirrored-keys-7779.test.ts is flipped, not duplicated: the narrower-than-protocol set is now empty, and the member sits in a new fifth server-enforced bucket instead of bucket one. Census: 65 declared, 43 read, 22 unread, partitioned 0+8+11+2+1. The new pin file list-view-required-permissions-12341.test.ts checks accept and refuse (non-array) on all three faces. The changeset gives @object-ui/types a minor bump. Section 3 answer (code reading, plus the existing pin ObjectView.viewRefusal-12112.test.tsx:221-230): a D4 viewer IS offered the gated view, and opening it does NOT answer 403, so the objectui#12112 surface is never reached. Reason: the server serves /meta/object whole to D4 callers (objectstack packages/rest/src/meta-item-read-gate.ts:1657 at b5b1bf72). The console builds its tabs from objectDef.listViews (app-shell ObjectView.tsx:2335-2336) and probes by name only on a miss (ObjectView.tsx:2441-2455). The refusal face is ObjectView.tsx:3844-3848. Nothing was implemented for Section 3; see open_questions.", "tests": "At HEAD 9e6cb65: pnpm --filter @object-ui/types build: exit 0. pnpm --filter @object-ui/types type-check (tsc + examples + tsconfig.test.json, which --listFiles shows includes both touched tests): exit 0. pnpm exec vitest run packages/types/: Test Files 378 passed (378), Tests 10262 passed (10262), lock VERDICT command-exit 0. pnpm turbo run build --concurrency=2 --filter='@object-ui/plugin-view^...' (Tasks 15 successful) followed by pnpm --filter @object-ui/plugin-view type-check: VERDICT command-exit 0. Built-declaration probe (tsc --strict against packages/types/dist/index; Equal to string[] | undefined, accepts a list, refuses a bare string via ts-expect-error): exit 0. dist/objectql.d.ts NamedListView gains exactly that one member. Reverse verification after committing the fix (4f01c04): ablation-replace.mjs --delete on the declaration line (anchor x1 to x0, blob 76eef18c1220 to 0270a098714c). Under the ablation, tsc -p tsconfig.test.json was red with 3 TS2339/TS2353 errors ('requiredPermissions' does not exist on type 'NamedListView'), and vitest on 7779 + 12341 was red with 7 failed / 230 passed. Restore: blob equals HEAD 76eef18c1220 and git diff HEAD is empty. The 12341 runtime cases stayed green under the ablation, as expected, because the zod faces already carried the key. eslint --no-inline-config on the 3 touched .ts files: 3 files, 0 errors, 27 pre-existing no-explicit-any warnings outside the diff. Root eslint.config.js has no parserOptions.project or projectService (not type-aware), so the diff cannot move any untouched file's verdict. Repo-wide pnpm lint is left to CI.", "gates": "pnpm check:phantom-deps 0 · check:self-import 0 · check:unreferenced-sources 0 · check:doc-example-readers 0 · check:handler-key-reads 0 · check:side-effects-array 0 · check:element-data-source-declaration 0 · check:spec-symbols 0 · check:action-forward-parity 0 · check:designer-field-key-parity 0 · check:icon-record-names 0 · check:i18n-keys 0 · check:i18n-drift 0 · check:i18n-designer-parity 0 · node scripts/check-changeset-fixed.mjs 0 · node scripts/check-changeset-presence.mjs 0 · check:spec-floors 1 (known on main: 'The scan collapsed: 0 package(s) declare @objectstack/spec', carried by objectui#12334, not touched) · check:doc-types not run (no docs changed) · check:nul-bytes has no script in objectui, so a control-byte grep over the 4 touched files was run instead: 0 hits. CI: in_progress, not awaited.", "files_changed": [ "packages/types/src/objectql.ts", "packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts", "packages/types/src/__tests__/list-view-required-permissions-12341.test.ts", ".changeset/12341-list-view-required-permissions.md" ], "deviations": "None against the dispatch. The landing face is NamedListView only, because the other two list-view faces already carried the key by reference (measured, stated in the PR body). Labels: zero writes; objectui has no label gate and the dispatch named no labels. The commit trailers use the AGENTS.md model-free pair (Claude-Session plus Co-authored-by: Claude), which takes precedence over the harness attribution reminder.", "mcp_calls": "0", "api_writes": "2 — fleet-write relay: pr_create (POST /repos/objectstack-ai/objectui/pulls + POST /issues/12360/assignees) via repository_dispatch to objectstack-ai/objectstack; this os-dev-report comment (POST /repos/objectstack-ai/objectui/issues/12341/comments). Plus git pushes of the branch (not REST).", "open_questions": [ { "question": "Section 3: a D4-exempt caller (studio.access, manage_metadata, setup.access or isSystem) receives an object's listViews whole from /meta/object. The runtime console therefore lists and opens list views gated on capabilities that caller lacks, and no 403 occurs, because the server has no by-name item to refuse. This is not a data leak, since records still pass the caller's object read permissions. It is an audience mismatch at runtime. Should the server change?", "options": [ "A: Leave it. D4 callers are schema editors; seeing every view at runtime is accepted. Cost: zero. The audience key is advisory for editors.", "B: objectstack prunes the plain runtime /meta/object read for D4 callers as well, and keeps the whole document only on the authoring doors (draft, layered, diff), mirroring the app arm's author-exempt split. Cost: a server change plus a check that Studio and the console designers load from an authoring door, so a save cannot delete withheld views. That save-back hazard is the reason D4 is exempt today.", "C: A client-side gate in the console. Refused by the card ruling and listed only for completeness." ], "recommendation": "A for now, B if a real deployment reports editors confused by foreign-audience views. Business need: no measured producer of the complaint yet. Long-term: B is the contract-first shape, if it is ever done. AI-error axis: neither A nor B lets an AI declare a gate the runtime ignores for ordinary users. Startup focus: no new capability without pull. Either way the fix is objectstack's and needs no objectui change." } ], "out_of_scope_findings": [ "carrier: whoever next edits object-view-unmirrored-keys-7779.test.ts · the namedListViewMemberCount failure message still points at .changeset/object-view-unmirrored-keys-7779.md, which no longer exists (consumed at release); only its count was corrected here · noted in the PR's Acceptance notes, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Review: ACCEPT — objectui PR #12360 ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-14T09:00ZReviewed on GitHub at head
9e6cb65c00, against the card and triage's grade6162030734, not against the dev's report.main, and its body opensFixes #12341(the only closing keyword).Clause-②: yesmatches the claim. The governed sweep reads NOT governed, 260 lines.6164716741on the PR, PASS at this head, withServed-tier: CONTRACT_REVIEW_TIER.NamedListViewgainsrequiredPermissionsby reference to the spec. The other two list-view faces already carried it, and all three are pinned with accept and refuse cases.@object-ui/typescarries aminorchangeset.needs:contract-reviewis removed from the PR in the same stroke.object-view-unmirrored-keys-7779.test.ts.Spec Main Shape Gate. Its annotations sit only onresolveDataSource.ts,useViewData.tsand.github, which ismain's red (objectui#12325, PR fix: retire the view-levelprovider: 'api'readers (objectui#12325) #12361 in review). None is on a file this PR touches.studio.access,manage_metadata,setup.access, or a system object) receives an object'slistViewswhole from/meta/object. The console then offers and opens a view gated on capabilities that viewer lacks, and no403occurs.7779test message, left in the PR's Acceptance notes for whoever next edits that test.Next:
pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-14T09:18Zmainf2b17c6. The card closedcompletedby itsFixes #12341, which is the PR body's only closing keyword. No other card closed with it.9e6cb65c00:.changeset/12341-list-view-required-permissions.mdandlist-view-required-permissions-12341.test.ts.packages/types/src/objectql.tsdiffers from that head only by objectui PR feat(print): render a page that declaresprint— print CSS, printable blocks whole, record print action (objectui#11958) #12356's mergedExportFormatcomment, which landed first and was combined by the queue. This PR's ownNamedListView.requiredPermissions?: ListViewSchema['requiredPermissions']is onmainat:3227.pm:dispatchedis removed in the same stroke as this comment.Generated by Claude Code
feat(types): NamedListView mirrors spec 18's list-view requiredPermis…