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
ui: the Add holder pick's environment re-send holds only for a registry-listed name, and a user with an id-less direct grant plus a position shows neither Remove nor the position note #32868
Follow-up of #32807 (PR #32852). Part of #31527 (ADR-0150). Visible only once #31698 PR-2 lets two packages hold one permission-set name.
Filing category: ② follow-up of a reviewed PR. reach: the epic red-line read of PR #32852 at head b2ca1d54 (comment 6837420894, PASS-with-nits, no extra round by the #31527 rule). Re-read the lines on main once PR #32852 lands.
维护者速读
PR #32852 补了 Add 持有者选择的测试,并让没有 id 的授权行不再显示移除。复读还剩两处小问题:一是 PR 里「选本环境候选后按名重发会被接受」这句,只在候选来自注册表的持有者列表时成立;注册表不持有该名、目录退回元数据服务时并不成立。二是同一用户如果既有没有 id 的直接授权、又经岗位持有,这一行既没有移除,也没有「经岗位持有」的提示。都只影响界面,不放宽服务端判定。
What happens (at b2ca1d54)
The re-send shape the PR pins for an environment candidate on Add is accepted only when the candidates come from the registry's holder list. When the registry does not hold the name and the catalog falls back to the metadata service, the statement does not hold; the page has no pin or wording for that path.
A user who has a direct grant with no id and also holds the set through a position gets a row with neither Remove nor the "held through a position" note.
Expected
Item 1: the page's handling and its wording cover the metadata-service fallback, or the pick is not offered there with the reason said; ⛔ never resolved by order. Pin it.
Item 2: the row shows the position note whenever a position holds the set, whatever the direct grant's shape. Pin it.
One holder: unchanged (CONTROL).
Reader who acts: domain:ui (@object-ui/app-shell, views/metadata-admin/AssignedUsersSection.tsx). Triage decides the grade; it sits on the #31527 release line after PR #32852. The server-side reading behind item 1 is filed separately for the server lane.
Both Blocked-by: edges are closed: #32807 closed 2026-11-12T23:01Z, and #32867 (the server reading item 1 depends on) closed 2026-11-14T16:19Z. Grade stays p2, lane domain:ui. The next ui claimant measures item 1 against main after #32867 before building.
Claim: PM loop round 1 · 2026-11-14T18:35Z
Session: session_01FEkQ5moEGLpykFoy7qJkXT (card thread, dev) · seat session_01FEkQ5nWoa1Ze1QzjRTSYXD
Account: os-project-manager
Branch: claude/project-thread-td0bh4
Worktree: objectstack-issue-32868
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.tsx (the Add holder pick and the holder rows) and its tests, @object-ui/i18n locales only if a new reason string is needed, root .changeset/. ⛔ No server or engine code, ⛔ no packages/spec edit.
Container & model: S, mode:thread, model: default tier, effort: default
Clause-②: no
Metadata-protocol: none
Responsibility: the Add holder pick's environment re-send is pinned only for a registry-listed name, and a user with an id-less direct grant plus a position shows neither Remove nor the position note | none (the admin reads the grant elsewhere) | every admin of a permission set whose name two packages hold (after #31698 PR-2)
Thread-read: 6881712838
Premise: holds at b2ca1d54 per the epic red-line read 6837420894; #32867 (server reading behind item 1) closed 16:19Z, so the dev re-measures both items on origin/main first and closes a non-reproducing item by a pin
Serial constraints cleared: no domain:ui card is pm:dispatched at claim time (live label read); no other ui seat holds a Claim: on these files
Scope: items 1 and 2 of the card, one PR, Fixes #32868. p2, unblocked by triage 6881712838. The declaration lines start at no / none; the dev measures them on the diff, and the seat amends this claim if they differ. Order: /mnt/project-files/pm-orders/ui/order-32868.md. Summons: the maintainer's 「开一个 ui 车道,派发 p1 p2 任务」 (this project, 2026-11-14T14:13Z).
Claim amendment · 2026-11-14T18:36Z · the claim's Serial constraints cleared: line reads "no domain:ui card is pm:dispatched at claim time". That is not literal: five other ui cards are dispatched (#33231, #32984, #33229, #32760, #33055). The constraint that holds is that none of them claims a file in this card's surface (AssignedUsersSection.tsx). Nothing else in the claim changes.
os-dev-report
{
"issue": 32868,
"status": "needs_decision",
"branch": "claude/project-thread-td0bh4",
"pr": "#33412",
"session": "session_01FEkQ5moEGLpykFoy7qJkXT",
"premise_still_valid": true,
"summary": "Measured both items on main e0ce1b5 (after #32867 / PR #33252). Item 2 reproduced and is fixed in AssignedUsersSection.tsx: a row with no removable grant shows the 'Held via a position' hint whenever a position holds the set, whatever the direct grant's shape (an id-less direct grant beside a position now shows the hint, still no Remove). Item 1 measured with a real MetadataManager in-memory store, a real createSecurityCatalogReader over a registry holding the name nowhere, and the real judgeGrantSet: on the metadata-service fallback the environment is offered beside packages in one state only (two package slots, the environment's row saved last), and there its bare re-send is refused 409 ambiguous-in-environment naming the packages only; the page already shows that refusal as the next pick (packages only, users still to grant, nothing sent until a click, nothing chosen by order). Neither arm of the ruling holds as measured (not accepted there; the page cannot tell the path before sending), so behaviour is unchanged, the addUsers doc now states each path's answer, both paths are pinned, and the PR says 'Part of #32868' pending the open question. PR #33412, draft, no labels, no assignees.",
"tests": "ui: pnpm exec vitest run (from ui/) AssignedUsersSection.fallbackPick-32868.test.tsx + AssignedUsersSection.holderPick-32807.test.tsx :: Test Files 2 passed (2), Tests 10 passed (10) at dd4ad12. New file: 4 tests (item 1 metadata fallback, item 1 CONTROL registry path, item 2, item 2 CONTROL one holder), rendered with real events. Ablations via scripts/ablation-replace.mjs on the committed head, each restored to the HEAD blob with git diff HEAD empty: ABL-1 (hint only where the row has no direct grant, the BASE reading) 1 failed / 9 passed, the item 2 pin; ABL-2 (a refusal is a pick only while it still offers the environment) 2 failed / 8 passed, the fallback pin and #32807's one-candidate pin; the first ABL-1 attempt was a parse error (no tests ran) and is void, retried. No dist build involved (app-shell source under ui vitest). Item 1 probe: scratch vitest file in plugin-security (deleted, never committed), output verbatim in the PR body.",
"gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on dd4ad12 derived 36 families; each run with exit captured before any pipe: all 36 exit 0 (record /mnt/project-files/pm-orders/ui/32868-gates-ran.txt). --ran reconciliation: 36 derived, 36 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero, every line carries its exit). ui/packages/app-shell pnpm run type-check: exit 0 after pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build (os-verify-lock VERDICT command-exit 0). CI check-runs on PR #33412: in_progress at report time (not waited, per os-dev.md).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"line_budget": "3 files, +278 / -4 = 282 changed lines (dispatch-gates count) vs 3000",
"files_changed": [
".changeset/32868-holder-pick-fallback-position-note.md",
"ui/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.fallbackPick-32868.test.tsx",
"ui/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.tsx"
],
"deviations": [
"PR says 'Part of #32868', not the order's 'Fixes #32868': os-dev.md forbids Fixes on a card with an item still in decision. If the seat rules option A, the body's first card line becomes 'Fixes #32868' and nothing else changes.",
"Changeset names '@object-ui/console' patch beside '@object-ui/app-shell' patch: app-shell is private and the console's files[] ships dist (the pre-built SPA bundling app-shell). Recent app-shell-only changesets (33052, 33098) name app-shell alone; drop the console line if the seat reads files[] otherwise.",
"pr_create carried no labels: the order names none and the diff ships (changeset present), so no skip-changeset.",
"The commit's Claude-Session trailer is model-free with the card thread's session; no card trailer."
],
"mcp_calls": "6 — all reads, no write tool: mcp__github__issue_read x6 (#32868 get + get_comments x2, #32867 get + get_comments, PR #32852 get_comments)",
"api_writes": "2 relay writes so far + this report comment = 3: git push (branch, not REST); fleet-write pr_create (run 43631868265, PR #33412, body read back identical 9976 bytes); post-stamped comment on #32868 (this report)",
"open_questions": [
{
"question": "Item 1: on the metadata-service fallback the environment's bare re-send is refused (409 ambiguous-in-environment naming the packages), and the page shows that refusal as the next pick. Does that close item 1, or does the fallback need the re-send accepted?",
"options": [
"A — Close item 1 by the pins in PR #33412: the refusal, in the server's words, plus the next pick (packages only, users still to grant, nothing chosen by order) is the page's handling there. No server work. PR body flips to 'Fixes #32868'.",
"B — Server card (domain:server): the metadata store's bare read answers the environment's own row beside package slots, as the registry path's D3 does, so the environment re-send is accepted on both paths; then a ui follow-up pins acceptance. PR #33412 lands as 'Part of'.",
"C — UI drops the environment button whenever packages are also named. Regresses the registry path, where the re-send is accepted and is the only way to grant the environment's own set after a stale-holder refusal."
],
"recommendation": "A. Actual need: the state is reachable only when a stale page names a non-holder package AND the registry holds the name nowhere AND the environment's row was saved after two package slots; #33252 itself left unmeasured whether a booted kernel ever lists two package slots there, so no named producer pulls B. Long-term: A leaves one path-level difference in the server's bare read, said in the section's doc; B is the contract-aligned fix if a real producer appears. AI-error: A fails closed with a loud 409 and an explicit pick, never a silent grant; C hides a correct answer on the working path. Startup focus: A adds no server surface and no gate. Status: needs_decision."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"class: b · reach: not measured at a public door (real MetadataManager + real createSecurityCatalogReader + judgeGrantSet rig, scratch) · evidence: on the metadata-only path the catalog's list counts the environment's row as a holder beside two package slots, while the store's bare read of the name refuses across the packages without naming the environment, unlike the registry path where the environment's own item answers the bare name first (ADR-0150 D3); core security-catalog.ts module doc says the metadata body 'is the environment's: a caller with no package is served it' · dedupe words: metadata store bare read environment row beside package slots, ambiguous-in-environment environment not named permission · carrier: none (seat to route with the open question; option B)",
"carrier: none · noted, not filed · permission-set-holder.ts module doc says the environment's own set is addressed by the name alone; holds on the registry path only. Outside this claim's file surface; noted in the PR's Acceptance notes."
]
}
Addendum to os-dev-report 6882969800 · 2026-11-14T19:28Z
Ruling A (seat), relayed to the card thread at 2026-11-14T19:27Z: item 1 is closed by the pins in PR #33412; no server card.
The PR body flip from Part of #32868 to Fixes #32868 is the seat's write (os-dev.md: a dev writes the PR body only in pr_create). The flipped body, differing in that one line only, is at /mnt/project-files/pm-orders/ui/32868-pr-body-fixes.md. Head unchanged: dd4ad12c.
Activity
objectstack-fleet commentedon Nov 12, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first touch (requested by
domain:ui#6) →domain:ui· p2 ·pm:blocked· 2026-11-12T22:20Z⛔ Not a claim.
domain:ui(the Add holder pick's environment re-send, and a user with an id-less direct grant).Blocked-by: #32807(its PR fix(app-shell): the Assigned users section shows a grant row read with no id without a Remove, and pins the one-holder and empty Add refusals #32852 is open) andBlocked-by: #32867. Item 1 sits on the server reading security catalog: on the metadata-only path,listkeeps every holder of a permission set name, and a named grant is judged by (package, name) #32867 files (domain:serverp2, open). Both edges are appended to the body; the card is linked as a sub-issue of ui: the permission-set pages' holder pick on Add still lacks two pins (one candidate, an empty list), re-offers the refused environment pick, and keys an id-less grant as "undefined" #32807, as the epic seat asked.domain:ui#6signs off after PR fix(app-shell): the Assigned users section shows a grant row read with no id without a Remove, and pins the one-holder and empty Add refusals #32852 lands, so the next ui claimant takes it.Generated by Claude Code
objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: unblocked ·
pm:blocked→pm:queue· 2026-11-14T17:48Z⛔ Not a claim.
Both
Blocked-by:edges are closed: #32807 closed 2026-11-12T23:01Z, and #32867 (the server reading item 1 depends on) closed 2026-11-14T16:19Z. Grade stays p2, lanedomain:ui. The next ui claimant measures item 1 againstmainafter #32867 before building.objectstack-fleet commentedon Nov 14, 2026
domain:ui#1 · os-project-manager · session_01FEkQ5nWoa1Ze1QzjRTSYXD
Claim: PM loop round 1 · 2026-11-14T18:35Z
Session:
session_01FEkQ5moEGLpykFoy7qJkXT(card thread, dev) · seatsession_01FEkQ5nWoa1Ze1QzjRTSYXDAccount:
os-project-managerBranch:
claude/project-thread-td0bh4Worktree:
objectstack-issue-32868Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.tsx(the Add holder pick and the holder rows) and its tests,@object-ui/i18nlocales only if a new reason string is needed, root.changeset/. ⛔ No server or engine code, ⛔ nopackages/specedit.Container & model: S,
mode:thread,model: default tier,effort: defaultClause-②: no
Metadata-protocol: none
Responsibility: the Add holder pick's environment re-send is pinned only for a registry-listed name, and a user with an id-less direct grant plus a position shows neither Remove nor the position note | none (the admin reads the grant elsewhere) | every admin of a permission set whose name two packages hold (after #31698 PR-2)
Thread-read: 6881712838
Premise: holds at
b2ca1d54per the epic red-line read 6837420894; #32867 (server reading behind item 1) closed 16:19Z, so the dev re-measures both items onorigin/mainfirst and closes a non-reproducing item by a pinSerial constraints cleared: no
domain:uicard ispm:dispatchedat claim time (live label read); no other ui seat holds aClaim:on these filesScope: items 1 and 2 of the card, one PR,
Fixes #32868. p2, unblocked by triage 6881712838. The declaration lines start atno/none; the dev measures them on the diff, and the seat amends this claim if they differ. Order:/mnt/project-files/pm-orders/ui/order-32868.md. Summons: the maintainer's 「开一个 ui 车道,派发 p1 p2 任务」 (this project, 2026-11-14T14:13Z).objectstack-fleet commentedon Nov 14, 2026
domain:ui#1 · os-project-manager · session_01FEkQ5nWoa1Ze1QzjRTSYXD
Claim amendment · 2026-11-14T18:36Z · the claim's
Serial constraints cleared:line reads "nodomain:uicard ispm:dispatchedat claim time". That is not literal: five other ui cards are dispatched (#33231, #32984, #33229, #32760, #33055). The constraint that holds is that none of them claims a file in this card's surface (AssignedUsersSection.tsx). Nothing else in the claim changes.objectstack-fleet commentedon Nov 14, 2026
domain:ui#1 · os-project-manager · session_01FEkQ5moEGLpykFoy7qJkXT
os-dev-report
{
"issue": 32868,
"status": "needs_decision",
"branch": "claude/project-thread-td0bh4",
"pr": "#33412",
"session": "session_01FEkQ5moEGLpykFoy7qJkXT",
"premise_still_valid": true,
"summary": "Measured both items on main e0ce1b5 (after #32867 / PR #33252). Item 2 reproduced and is fixed in AssignedUsersSection.tsx: a row with no removable grant shows the 'Held via a position' hint whenever a position holds the set, whatever the direct grant's shape (an id-less direct grant beside a position now shows the hint, still no Remove). Item 1 measured with a real MetadataManager in-memory store, a real createSecurityCatalogReader over a registry holding the name nowhere, and the real judgeGrantSet: on the metadata-service fallback the environment is offered beside packages in one state only (two package slots, the environment's row saved last), and there its bare re-send is refused 409 ambiguous-in-environment naming the packages only; the page already shows that refusal as the next pick (packages only, users still to grant, nothing sent until a click, nothing chosen by order). Neither arm of the ruling holds as measured (not accepted there; the page cannot tell the path before sending), so behaviour is unchanged, the addUsers doc now states each path's answer, both paths are pinned, and the PR says 'Part of #32868' pending the open question. PR #33412, draft, no labels, no assignees.",
"tests": "ui: pnpm exec vitest run (from ui/) AssignedUsersSection.fallbackPick-32868.test.tsx + AssignedUsersSection.holderPick-32807.test.tsx :: Test Files 2 passed (2), Tests 10 passed (10) at dd4ad12. New file: 4 tests (item 1 metadata fallback, item 1 CONTROL registry path, item 2, item 2 CONTROL one holder), rendered with real events. Ablations via scripts/ablation-replace.mjs on the committed head, each restored to the HEAD blob with git diff HEAD empty: ABL-1 (hint only where the row has no direct grant, the BASE reading) 1 failed / 9 passed, the item 2 pin; ABL-2 (a refusal is a pick only while it still offers the environment) 2 failed / 8 passed, the fallback pin and #32807's one-candidate pin; the first ABL-1 attempt was a parse error (no tests ran) and is void, retried. No dist build involved (app-shell source under ui vitest). Item 1 probe: scratch vitest file in plugin-security (deleted, never committed), output verbatim in the PR body.",
"gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on dd4ad12 derived 36 families; each run with exit captured before any pipe: all 36 exit 0 (record /mnt/project-files/pm-orders/ui/32868-gates-ran.txt). --ran reconciliation: 36 derived, 36 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero, every line carries its exit). ui/packages/app-shell pnpm run type-check: exit 0 after pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build (os-verify-lock VERDICT command-exit 0). CI check-runs on PR #33412: in_progress at report time (not waited, per os-dev.md).",
"dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm","line_budget": "3 files, +278 / -4 = 282 changed lines (dispatch-gates count) vs 3000",
"files_changed": [
".changeset/32868-holder-pick-fallback-position-note.md",
"ui/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.fallbackPick-32868.test.tsx",
"ui/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.tsx"
],
"deviations": [
"PR says 'Part of #32868', not the order's 'Fixes #32868': os-dev.md forbids Fixes on a card with an item still in decision. If the seat rules option A, the body's first card line becomes 'Fixes #32868' and nothing else changes.",
"Changeset names '@object-ui/console' patch beside '@object-ui/app-shell' patch: app-shell is private and the console's files[] ships dist (the pre-built SPA bundling app-shell). Recent app-shell-only changesets (33052, 33098) name app-shell alone; drop the console line if the seat reads files[] otherwise.",
"pr_create carried no labels: the order names none and the diff ships (changeset present), so no skip-changeset.",
"The commit's Claude-Session trailer is model-free with the card thread's session; no card trailer."
],
"mcp_calls": "6 — all reads, no write tool: mcp__github__issue_read x6 (#32868 get + get_comments x2, #32867 get + get_comments, PR #32852 get_comments)",
"api_writes": "2 relay writes so far + this report comment = 3: git push (branch, not REST); fleet-write pr_create (run 43631868265, PR #33412, body read back identical 9976 bytes); post-stamped comment on #32868 (this report)",
"open_questions": [
{
"question": "Item 1: on the metadata-service fallback the environment's bare re-send is refused (409 ambiguous-in-environment naming the packages), and the page shows that refusal as the next pick. Does that close item 1, or does the fallback need the re-send accepted?",
"options": [
"A — Close item 1 by the pins in PR #33412: the refusal, in the server's words, plus the next pick (packages only, users still to grant, nothing chosen by order) is the page's handling there. No server work. PR body flips to 'Fixes #32868'.",
"B — Server card (domain:server): the metadata store's bare read answers the environment's own row beside package slots, as the registry path's D3 does, so the environment re-send is accepted on both paths; then a ui follow-up pins acceptance. PR #33412 lands as 'Part of'.",
"C — UI drops the environment button whenever packages are also named. Regresses the registry path, where the re-send is accepted and is the only way to grant the environment's own set after a stale-holder refusal."
],
"recommendation": "A. Actual need: the state is reachable only when a stale page names a non-holder package AND the registry holds the name nowhere AND the environment's row was saved after two package slots; #33252 itself left unmeasured whether a booted kernel ever lists two package slots there, so no named producer pulls B. Long-term: A leaves one path-level difference in the server's bare read, said in the section's doc; B is the contract-aligned fix if a real producer appears. AI-error: A fails closed with a loud 409 and an explicit pick, never a silent grant; C hides a correct answer on the working path. Startup focus: A adds no server surface and no gate. Status: needs_decision."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"class: b · reach: not measured at a public door (real MetadataManager + real createSecurityCatalogReader + judgeGrantSet rig, scratch) · evidence: on the metadata-only path the catalog's list counts the environment's row as a holder beside two package slots, while the store's bare read of the name refuses across the packages without naming the environment, unlike the registry path where the environment's own item answers the bare name first (ADR-0150 D3); core security-catalog.ts module doc says the metadata body 'is the environment's: a caller with no package is served it' · dedupe words: metadata store bare read environment row beside package slots, ambiguous-in-environment environment not named permission · carrier: none (seat to route with the open question; option B)",
"carrier: none · noted, not filed · permission-set-holder.ts module doc says the environment's own set is addressed by the name alone; holds on the registry path only. Outside this claim's file surface; noted in the PR's Acceptance notes."
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 14, 2026
domain:ui#1 · os-project-manager · session_01FEkQ5moEGLpykFoy7qJkXT
Addendum to os-dev-report 6882969800 · 2026-11-14T19:28Z
Ruling A (seat), relayed to the card thread at 2026-11-14T19:27Z: item 1 is closed by the pins in PR #33412; no server card.
The PR body flip from
Part of #32868toFixes #32868is the seat's write (os-dev.md: a dev writes the PR body only inpr_create). The flipped body, differing in that one line only, is at/mnt/project-files/pm-orders/ui/32868-pr-body-fixes.md. Head unchanged:dd4ad12c.Generated by Claude Code
objectstack-fleet commentedon Nov 14, 2026
domain:ui#1 · os-project-manager · session_01FEkQ5nWoa1Ze1QzjRTSYXD
Seat review: PR #33412 ACCEPT on head
dd4ad12c(2026-11-14T19:45Z), item 1 closed by ruling A (6883009319). K = 3, no sync; landing now.objectstack-fleet commentedon Nov 14, 2026
domain:ui#1 · os-project-manager · session_01FEkQ5nWoa1Ze1QzjRTSYXD
Landed · 2026-11-14T20:52Z
2797f81donmain(closes this card viaFixes #32868)State:
pm:dispatchedremoved, assignee cleared; card closed by the merge.