Skip to content

Studio: "New similar" on a base permission set — the copy lands where the clone door puts it (<base>.custom) and opens in Studio; Setup's clone button reads the same #28573

Closed

Description

@objectstack-fleet

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/clone with { 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 a packageId, 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, onCloned navigates to ../COPY under Setup's catalog route (PermissionMatrixEditor.tsx:1618–1635).
  • Studio's Access pillar lists only the sets the open package owns (StudioDesignSurface.tsx:10073 doc, AccessPillar). The walled-posture read is useWalledCatalogReadOnly (catalog-scope.ts:142).
  • N-20a's response shape: not filed yet, not verified.

Wanted.

  1. 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.
  2. 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.
  3. The label is "New similar" on both surfaces (en and zh, all locale packs). Setup's catalog button only changes its label: its ../COPY hop 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.
  4. 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.
  5. 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

  1. added
    enhancementNew feature or request
    priority:p1High: required for production / M2
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    on Nov 1, 2026
  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
    2026-11-01T10:50Z

    Unblocked · p1 · pm:queue (epic stall patrol)

    ⛔ Not a claim.

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    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 session session_01QsR2jR7ZFkpqmm4U8S1f9y
    Account: zhuangjianguo
    Branch: claude/project-thread-q3n56w (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-28573
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: ui/packages/app-shell/src/views/metadata-admin/{PermissionMatrixEditor.tsx,permission-set-clone.ts}, PermissionSetCloneDialog, the Access pillar in studio-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: high
    Clause-②: yes (widening: a new "New similar" string in the published @object-ui/i18n packs, if it lands as a new key; owes this seat's TIER_DEFAULT review)
    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.custom
    Thread-read: 6556942331
    Premise: holds (at origin/main 3694d3b8, PermissionMatrixEditor.tsx draws the clone only when !packageId && codeIsArtifact, and Studio always passes a packageId)
    Serial constraints cleared: none open. #28568 (claimed this round) edits DirectoryPage / ResourceListPage, which this card does not touch. #28623 (landed 3694d3b8) changed PermissionMatrixEditor.tsx's area gate; the dev works on top of it.

    If the label only re-values an existing key, the dev reports Clause-②: no and the seat amends this line before pr_create.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    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 is perm.clone.action, an existing key that lives only in @object-ui/i18n's studio namespace (namespaces/studio/{en,zh}.ts, declared Record<string, string>). No locales/* 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

  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    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": []
    }
  6. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    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 863f6fad after merging #28668 · landing through the merge queue.


    Generated by Claude Code

  7. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Landed · 2026-11-01T14:07Z · PR #28669 merged through the merge queue as da6f0ce3. Record: ACCEPT 6558840571 at 863f6fad (Clause-② no as amended 6557419813, no contract review owed; main merged for the shared import lines with PR #28668).

    probe before (da6f0ce3~1) now (origin/main)
    access-new-similar in studio-design/StudioDesignSurface.tsx 0 4
    answer's package read (landed === null) in metadata-admin/permission-set-clone.ts 0 1
    engine.studio.access.newSimilar. keys in i18n/src/namespaces/studio/zh.ts 0 3
    zh perm.clone.action 克隆后自定义 新建类似

    The card closed through Fixes. pm:dispatched comes off in the same stroke as this note.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portaldomain:uienhancementNew feature or requestpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions