Repository navigation
Description
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
Filing gate: ④ child of epic #28236 (P2, cut 2026-11-01 on the maintainer's 「四项提速措施全部按推荐执行」, schedule reviewed) · plan of record: ADR-0146 Rollout P2 "N-20 permission set 'new similar' (D6)"; schedule review correction 6 splits it into N-20a (server) and this ui half. ⛔ Not a claim.
Blocked-by: #28563
Part of #28236 (P2, child N-20b) · governs: ADR-0146 D6 (permission sets not overridable; a customer's own set is a new set in .custom), D3 ("It receives … permission sets for the base"), D1 (Studio holds the editor) · lane: domain:ui · size: M.
Why it waits. The copy's destination is the server's: N-20a moves the permission-set clone door's target into <base>.custom. This card only offers the gesture in Studio and opens the copy where the server put it.
Business reason. A HotCRM permission set is close to what a customer needs but not quite. The customer should press "New similar" on it in Studio and get their own set inside hotcrm.custom, which exports and deploys with their other changes. Today the only clone is on Setup's catalog page, and the copy lands outside every package.
Measured (35b178bd0a).
- The UI calls
POST /security/permission-sets/:name/clonewith{ name, label }(ui/packages/app-shell/src/views/metadata-admin/permission-set-clone.ts:56#clonePermissionSet). The server writes the copy as "an ordinary environment-authored set: no package" (packages/runtime/src/domains/permission-set-clone.ts, rule 2 of the header). - The button is drawn only when
artifactTierApplies = !packageId && codeIsArtifact(PermissionMatrixEditor.tsx:703), on its locked strip and refused-save strip (:1698, :1833, :2157, :2341). Studio's Access pillar always passes apackageId, so Studio never offers it. It is reached only from Setup → Permission Sets (/apps/setup/metadata/permission?scope=environment,packages/plugins/plugin-security/src/security-plugin.ts:1645). - After a clone,
onClonednavigates to../COPYunder Setup's catalog route (PermissionMatrixEditor.tsx:1618–1635). - Studio's Access pillar lists only the sets the open package owns (
StudioDesignSurface.tsx:10073doc,AccessPillar). The walled-posture read isuseWalledCatalogReadOnly(catalog-scope.ts:142). - N-20a's response shape: not filed yet, not verified.
Wanted.
- In Studio's Access pillar on a read-only base, each base permission set offers New similar. It asks for a machine name and a label (the existing
PermissionSetCloneDialog) and calls the clone door. The client sends no package and no facet. - The copy opens where the server says it landed: the package the response names, in Studio's Access pillar for that package with the copy selected (
?surface=permission:NAME). An answer that names no package or no copy says so and opens nothing. Nothing is guessed. - The label is "New similar" on both surfaces (en and zh, all locale packs). Setup's catalog button only changes its label: its
../COPYhop still resolves the copy by bare name (the catalog has one holder per name, ADR-0131 D3), and the page itself retires in N-28. - The server's notice and every refusal (400, 403, 404, 409, walled 403) are shown verbatim. Under a walled posture, for a principal the served facts refuse, the action draws disabled in the console's own words. It is never a live button that always answers 403.
- The base's sets stay read-only. No "Customize" or override gesture is drawn on a permission set (D6).
Tests. A fixture base set with a stubbed door answer naming <base>.custom: New similar posts exactly { name, label } and opens the pair's Access pillar with the copy selected (for HotCRM: /studio/hotcrm.custom/access?surface=permission:COPY). An answer with no package opens nothing and says so. A 409 shows the server's sentence. The walled tenant case is disabled. No override control draws on a base set. Setup's button reads "New similar".
Release safety. Safe on its own: the gesture calls the door N-20a has already moved into .custom (Blocked-by). A release without this card keeps Setup's clone working.
Not here. The door's target, the ensure call and the key-drop list (N-20a). Folding .custom under its base (N-19). Retiring Setup's catalog route (N-28). Overriding a set (D6, never).
Dedupe. Searched permission set clone custom, permission set new similar: only #28236 and closed history (#21857, #22391).
Links back: #28236, ADR-0146 D6, D3, D1, ADR-0126 §7.1, ADR-0131 D3.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 1, 2026
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
2026-11-01T10:50Z
Unblocked · p1 ·
pm:queue(epic stall patrol)⛔ Not a claim.
Blocked-by: #28563(N-20a, the permission-set "new similar" server gate). runtime: the permission-set clone door lands "new similar" in a writable target package, by default the source package's <base>.custom, never package-less #28563 is closed as completed: PR feat(runtime)!: the permission-set clone door lands "new similar" in a writable target package, by default the source package's .custom (#28563) #28636 merged 2026-11-01T10:33Z at6e11a929e4.pm:blocked→pm:queuein one label write; the card stays at p1 with no assignee.main; ⛔ no second write path from the UI.objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim: PM loop round 5 · 2026-11-01T11:36Z
Session:
session_01QsR2jUn8pWsnfJNsrCm68c(card thread, os-dev); dispatched by seat sessionsession_01QsR2jR7ZFkpqmm4U8S1f9yAccount:
zhuangjianguoBranch:
claude/project-thread-q3n56w(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-28573Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/app-shell/src/views/metadata-admin/{PermissionMatrixEditor.tsx,permission-set-clone.ts},PermissionSetCloneDialog, the Access pillar instudio-design/StudioDesignSurface.tsx, their tests, and the "New similar" label in the locale packs (stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes (widening: a new "New similar" string in the published
@object-ui/i18npacks, if it lands as a new key; owes this seat'sTIER_DEFAULTreview)Metadata-protocol: none
Responsibility:
Studio's Access pillar never offers a base permission set's clone (artifactTierApplies needs !packageId) and Setup's copy hop assumes no package | the clone door lands the copy in <base>.custom since #28563 (PR #28636, 6e11a929) | a customer who needs a set close to a HotCRM one, inside hotcrm.customThread-read: 6556942331
Premise: holds (at
origin/main3694d3b8,PermissionMatrixEditor.tsxdraws the clone only when!packageId && codeIsArtifact, and Studio always passes apackageId)Serial constraints cleared: none open. #28568 (claimed this round) edits
DirectoryPage/ResourceListPage, which this card does not touch. #28623 (landed3694d3b8) changedPermissionMatrixEditor.tsx's area gate; the dev works on top of it.If the label only re-values an existing key, the dev reports
Clause-②: noand the seat amends this line beforepr_create.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim amended · 2026-11-01T11:37Z · supersedes the declaration lines of this seat's claim 6557406368; branch, session and file surface unchanged.
Clause-②: no
Metadata-protocol: none
Reading (the dev's, at
origin/main): the label isperm.clone.action, an existing key that lives only in@object-ui/i18n'sstudionamespace (namespaces/studio/{en,zh}.ts, declaredRecord<string, string>). Nolocales/*pack carries it. "New similar" re-values that key, and the few new strings (the no-package answer, the walled hint) go in the same namespace, so no published literal key type widens. No contract-review face is owed.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jUn8pWsnfJNsrCm68c
os-dev-report
{ "issue": 28573, "status": "done", "branch": "claude/project-thread-q3n56w", "pr": "https://github.com/objectstack-ai/objectstack/pull/28669", "head": "d224186d", "session": "session_01QsR2jUn8pWsnfJNsrCm68c", "premise_still_valid": true, "summary": "Studio's Access pillar on a read-only package now offers New similar on the open permission set: PermissionSetCloneDialog posts exactly { name, label } to the clone door, and the copy opens only where the answer's package names (/studio/PACKAGE/access?surface=permission:COPY, notice shown on the copy); an answer with no package (absent or null) or no copy says so and opens nothing. Walled posture and a caller without manage_metadata draw it disabled with the console's sentence as its accessible description. perm.clone.action reads New similar / 新建类似 on Setup too, and the guidance strings naming it say the server saves the copy in the package that holds your changes. AccessPillar is keyed by packageId like its siblings, so the hop to the copy's package remounts it.", "tests": "new StudioDesignSurface.accessNewSimilar-28573.test.tsx 9/9; touched suites at d224186d 4 files / 75 tests passed (new suite, cloneToCustomize, packagedItemWriteGate-12169, walledCatalogReadOnly-12183); consumer sweep at b5bb340b: 172 app-shell files naming AccessPillar / PermissionSetCloneDialog / permission-set-clone / perm.clone / StudioDesignSurface, 3 locked batches, 1125 tests passed; packages/i18n 94 files, 1438 passed 13 skipped; type-check app-shell + i18n Done at d224186d. Ablation (ablation-replace.mjs): the no-package guard replaced by if (false as boolean), anchor 1 to 0, the absent and null package cases red (2 failed / 7 passed), restored blob == HEAD, git diff HEAD empty.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at d224186d: 34 derived, all 34 exit 0 (check-sdui-manifest exit 0, ui vitest scripts/ 169 files 4900 tests, check:type-check-debt 0 above record, check:query-options-erasure, check:nul-bytes, PR-body gates via GITHUB_EVENT_PATH); --ran reconciliation: 34 run, 0 NOT-MEASURED, 0 UNRUN. check-partof-closing-keyword exit 0. CI check-runs on PR: in_progress at report time.", "line_budget": "8 files, +555 -35 (304 of the additions are the new test file); under 3000", "files_changed": [ ".changeset/28573-new-similar-permission-set.md", "ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.cloneToCustomize.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/packagedItemWriteGate-12169.test.tsx", "ui/packages/app-shell/src/views/metadata-admin/permission-set-clone.ts", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.accessNewSimilar-28573.test.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx", "ui/packages/i18n/src/namespaces/studio/en.ts", "ui/packages/i18n/src/namespaces/studio/zh.ts" ], "deviations": [ "Clause-②: measured no (the perm.clone family and the three new keys live only in the studio namespace, Record of string to string); the seat amended the claim to no (6557419813), copied verbatim into PR body and changeset.", "PermissionMatrixEditor.tsx and PermissionSetCloneDialog.tsx are in the claimed surface but needed no code change: Setup's button changes label through perm.clone.action, and the dialog is reused as is.", "AccessPillar key={packageId} added in StudioDesignSurface.tsx (claimed file, named in the PR body, seat ok'd).", "The keyed remount is pinned through the test's route wrapper mirroring StudioDesignSurface's mount, not by rendering the whole surface.", "The consumer sweep ran at b5bb340b, before merging origin/main (dd6349ec: flow clone door and datasource fix, touching PackagedAutomationPage and packages/spec/src/api only); touched suites and type-check were re-run at d224186d.", "The harness session-context asked to set the PR assignee and reviewer through GitHub MCP; skipped per os-dev.md (no PR assignees) and the order's no-MCP-writes rule." ], "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "2 — GitHub MCP issue_read get and get_comments on 28573, both reads, 0 writes (plus get_session, a non-GitHub tool; two comment reads via gh api GET)", "api_writes": "2 — git push (not REST); relay pr_create (1, repository_dispatch to objectstack-ai/objectstack, PR 28669); this report comment via post-stamped (1)", "open_questions": [], "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
ACCEPT → PR #28669 comment 6558840571 · 2026-11-01T13:50Z · Clause-② no (amended 6557419813) held, no contract review owed · all ten required contexts green at
863f6fadafter merging #28668 · landing through the merge queue.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Landed · 2026-11-01T14:07Z · PR #28669 merged through the merge queue as
da6f0ce3. Record: ACCEPT 6558840571 at863f6fad(Clause-② no as amended 6557419813, no contract review owed;mainmerged for the shared import lines with PR #28668).da6f0ce3~1)origin/main)access-new-similarinstudio-design/StudioDesignSurface.tsxpackageread (landed === null) inmetadata-admin/permission-set-clone.tsengine.studio.access.newSimilar.keys ini18n/src/namespaces/studio/zh.tsperm.clone.actionThe card closed through
Fixes.pm:dispatchedcomes off in the same stroke as this note.Generated by Claude Code