Repository navigation
Description
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
Filing gate: ① a measured break. Filed on the maintainer's word in direct chat with the epic PM seat, 2026-11-03: 「一个未立卡的小问题,有问题为什么不立卡?」. priority:p1 per the maintainer's standing word on this seat's cards: 「你的相关任务都应该标记为 p1」. ⛔ Not a claim.
Reader: domain:ui (ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx).
Dedupe: perm.badge, provenance badge, shippedByPackage, 包内置. #29729 (in flight) changes the words of perm.badge.custom; it does not touch which badge is chosen, so this is new. The #29674 landing note mentions the symptom and filed nothing.
reach: every permission set authored in a base's .custom pair, whether copied by New similar or created there, as far as the code reads. Only the copy was measured.
type: Bug
Business reason. An administrator who copied a vendor permission set opens their own copy, and its header says it is built into the package. The rail says Added and the page lets them edit it. They cannot tell from the header whose set this is, or whether a package upgrade would own it.
What happens
Measured on main at 601832b1a6, fresh database, showcase app, zh-CN console.
POST /api/v1/security/permission-sets/showcase_contributor/clonewith{name, label}: 200, incom.example.showcase.custom.- Open
/_console/studio/com.example.showcase/access?surface=permission%3Ashowcase_contributor_verify. - The rail row reads 新增. The header chip beside the name reads 包内置. The same page says 位于 com.example.showcase.custom, and it saves edits as drafts.
The #29674 landing note places this badge on the rail. Measured here, it is on the header, and the rail row shows only 新增.
Cause
Read from code, not traced in a run: PermissionMatrixEditor.tsx:727 is const shippedByPackage = !!packageId || codeIsArtifact;, and both perm.badge.package sites (lines 1965 and 2211) read it. Any set opened through a package door therefore reads Package. The pair is a package, so its own additions do too. The comment at that line still describes the two answers from before pairs existed.
Wanted
- A set the pair added or copied does not read as built into the package. The header and the rail tell one story about it.
- A set a read-only package really ships still reads Package.
StudioDesignSurface.accessTabs-12456.test.tsx:121pins that case and stays green. - The rule comes from what already answers this question (
customizationMarks.ts), not a second copy of it. Which word the chip shows follows Studio: one vocabulary for an item's state across the pillars, All metadata and Access #29705's vocabulary as landed.
Tests
A component pin for both cases: a set added in the pair, and a set the base package ships.
Serialize with #29729 if its diff reaches the same badge lines.
Activity
objectstack-fleet commentedon Nov 3, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim: PM loop round 14 · 2026-11-03T05:52Z
Session:
session_01QsR2jQi6dVYD8adyv8MhKt(card thread, os-dev); dispatched by seat sessionsession_01QsR2jR7ZFkpqmm4U8S1f9yAccount:
zhuangjianguoBranch:
claude/project-thread-qs4mew(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-29809Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx(theshippedByPackagerule and its two badge sites), the customization-marks reader it consults (studio-design/customizationMarks.tsor the Access host passing its mark), their tests, and a new changeset; the badge words stay as #29729 lands them (stop on breach; explain in the report)Container & model: S,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: defaultClause-②: no
Metadata-protocol: none
Responsibility:
a permission set the .custom pair added or copied reads 包内置 (Package) on its header while the rail says 新增 | choose the badge from the same customization marks the rail reads, so a pair-added set does not read as built into the package and a set the read-only base ships still does | every administrator copying or creating permission sets on a vendor packageThread-read: none
Premise: holds (measured by the filer on
601832b1a6, showcase, zh-CN: clone of showcase_contributor reads 包内置 on the header, 新增 on the rail)Serial constraints cleared: seat 2 #29729 (p3, in flight; claim names PermissionMatrixEditor legend + OWD prefix only) changes the words of perm.badge.custom in the i18n packs, not which badge is chosen; the second to land merges main
Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jQi6dVYD8adyv8MhKt
os-dev-report
{ "issue": 29809, "status": "done", "branch": "claude/project-thread-qs4mew", "pr": "https://github.com/objectstack-ai/objectstack/pull/29835", "head": "27943c85", "session": "session_01QsR2jQi6dVYD8adyv8MhKt", "premise_still_valid": true, "summary": "Premise held at main 0e4b0fa4: PermissionMatrixEditor's shippedByPackage was !!packageId || codeIsArtifact, and the pair's package door supplies a packageId, so a pair-held set read Package beside the rail's Added. Fix: a new optional page prop customizationMark (CustomizationMarkKind from customizationMarks.ts); the rule is now customizationMark !== 'added' && (!!packageId || codeIsArtifact), read by both badge sites. AccessPillar passes railMarks?.markOf for the open set, the same call its rail row makes. Base sets and customized base sets still read Package; Setup and the metadata admin pass no mark. No badge string touched (#29729's lane).", "files_changed": [ ".changeset/29809-pair-permission-set-badge.md", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.accessPairCopy-29674.test.tsx" ], "line_budget": "86 changed lines (+82 / -4) vs merge base, 4 files, under 3000; source +23 / -3, test +48 / -1, changeset +11", "tests": "New describe in the existing 29674 real-client harness (seat ruling 6583487846): copy in pair -> Custom + rail added; set created in pair (draft only) -> Custom + rail added; CONTROL base set -> Package, no rail mark. With accessTabs-12456: 2 files, 16/16 pass. Ablation 1 (rule back to !!packageId || codeIsArtifact) via ablation-replace.mjs: 2/3 red, control green, restore proven blob == HEAD. Ablation 2 (host passes customizationMark={null}): 2/3 red, control green, restore proven. Neighbours (68 ui test files naming PermissionMatrixEdit, AccessPillar or perm-provenance-badge): 68 files, 474/474 at 26d194d4 and again at the merged head 27943c85 after a closure rebuild (64/64). app-shell type-check exit 0 at both heads; eslint on touched files 0 errors.", "gates": "dispatch-gates --commands at 26d194d4: 35 families, all run, all exit 0 (check-sdui-manifest and its --self-test included); --ran: '35 derived famil(ies) accounted for, 35 run, 0 NOT-MEASURED (a DERIVED zero)'. Main merge (8 commits) touched none of the 4 files; check-sdui-manifest re-run at 27943c85 exit 0. PR body gated before pr_create: changeset-no-major 0, adr-0087-registration 0, closing-keyword-parity binds only #29809, partof-closing-keyword 0. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm", "deviations": [ "the shared checkout was detached so the card branch could be checked out in worktree ../objectstack-issue-29809", "no live dev-server run; the real-client harness is the evidence (named in the PR's Acceptance notes)" ], "mcp_calls": "1, mcp__github__issue_read (get_comments) on #29809; no write tools", "api_writes": "2, pr_create via fleet-write relay (fw-20261103T065253Z-d78eec, PR 29835, body read back identical, assignees none); this os-dev-report comment via post-stamped. Plus git push (not REST).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 3, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
席位核对 · ACCEPT → PR #29835 comment 6597604919 · 2026-11-03T07:07Z · at
27943c85. It lands through the merge queue;Fixes #29809closes this card on merge.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Landed · 2026-11-03T07:42Z · PR #29835 merged through the merge queue as
6fc7872b. Record: ACCEPT 6597604919 at27943c85(Clause-②: no, no contract review owed, 0 governed paths).6fc7872b~1)origin/main)const shippedByPackage = customizationMark !== 'added' && (!!packageId || codeIsArtifact);inui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx(a set the.custompair added no longer reads Package)customizationMark={railMarks?.markOf(inui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(the header chip reads the mark the rail draws)The card closed through
Fixes.pm:dispatchedcomes off with this note. Accepted residue: while the base's customization read is loading or has failed, the header keeps Package for a pair set, and the rail shows no mark, so the two agree. The badge words come from #29729 (seat 2). A pair-added set that still reads Package once the read has answered is a new reading against this fix: file it with the set and the door, not a revert.Generated by Claude Code