Skip to content

Studio: name where a customization is saved on the surface that made it, and stop listing the .custom pair as its own landing card #29691

Closed

Description

@objectstack-fleet

epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848

Filing gate: ② filed on the maintainer's word in direct chat with the epic PM seat, 2026-11-03: 「同意立卡」, agreeing the four UX proposals with the direction written here. Priority on 「相关卡 p1, 让车道处理」. ⛔ Not a claim.
Reader: domain:ui.
Governs: ADR-0146 D3: "the package switcher folds hotcrm.custom under HotCRM instead of giving it a row".
Dedupe: landing custom pair card. New.
type: enhancement

Business reason. A person customizing a vendor's package cannot tell what happened to their edit. The header keeps saying read-only, while a package they never made appears on the landing.

What happens

Measured on main at 3482f3d8d2, on the showcase, zh-CN.

  1. Customize an item of read-only com.example.showcase, or add a field. The header still reads 只读, and the switcher still names the base.
  2. The sheet and toast say 已发布本软件包的 1 项; the sheet groups the change under object_extension.
  3. /_console/studio lists a separate 可写 card for com.example.showcase.custom under 我的软件包. BuilderLanding.tsx:120 takes every writable package, and :308 draws them, with no pair filter.

Direction (agreed)

  • The landing does not give a pair its own card. The base's card keeps its "n customized" line and its link.
  • The item header and the pending-changes sheet carry one sentence, the same in both: 保存到 ObjectStack Showcase 的定制.

Check before removing: the pair's export and delete must stay reachable (D3 tells the administrator to export or delete .custom before uninstalling the base). Name where they live now. A review reports that the pair card's link returns to the base; that is unverified.

Links back: #28236, ADR-0146 D3.

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 3, 2026
  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p1 kept · domain:ui kept · pm:queue kept · 2026-11-03T01:56Z

    ⛔ Not a claim.

    • Read fresh. The .custom pair stops getting its own landing card, and the header and the pending-changes sheet name where a customization is saved (ADR-0146 D3).
    • p1 on the maintainer's word 「相关卡 p1, 让车道处理」.
    • The card's own check stands: the pair's export and delete must stay reachable before the card goes.

    Generated by Claude Code

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim: PM loop round 19 · 2026-11-03T01:58Z
    Session: session_01QsR2jTWKHRdA5msPPhwmw4 (card thread, os-dev); dispatched by seat session session_01QsR2jUJ19MstFvFhjgiYTu
    Account: zhuangjianguo
    Branch: claude/project-thread-pkn482 (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-29691
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: PR 1 (Part of #29691): ui/packages/app-shell/src/views/studio-design/BuilderLanding.tsx (the writable list folds pairs with the existing foldCustomizationPairs: a pair whose base is listed draws no card, an orphan pair keeps its card) and BuilderLanding.customizationCounts-28566.test.tsx (its pair case updated), ui/packages/app-shell/src/views/studio-design/preview/DraftChangesPanel.tsx (an optional base-label prop drawing the new key) and preview/__tests__/DraftChangesPanel.test.tsx, ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (one prop at the DraftChangesPanel call, set only when pairId is; no header call site) and StudioDesignSurface.customizePublish-28562.test.tsx (its stub draws the prop), the new key preview.changes.savedToCustomization in all ten packs under ui/packages/i18n/src/locales/, and a root .changeset (app-shell + i18n patch). The item-header sentence (PR 2, reusing the key) waits for seat 4's #29693 and is declared by a claim amendment before code. Any other file is declared by a claim amendment before code (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: yes (widening): one new i18n key in the published locale packs, nothing removed or narrowed
    Metadata-protocol: none
    Responsibility: the landing pair card and the pending-changes sheet sentence (PR 1); the item-header sentence after seat 4 #29693 (PR 2); toast unchanged
    Thread-read: 6593426427
    Premise: holds (at origin/main 3d5933a9: the landing draws every writable package with no pair filter (BuilderLanding ~120/~308); the pair card opens /studio/PAIR/data which redirects to the base; the pair export and delete live on the Packages page detail sheet, not the landing card, and stay reachable)
    Serial constraints cleared: PR 2 (item header) waits for seat 4 #29693, which reworks the StudioItemHeader row, and is cleared with seat 4 before code. No open PR touches BuilderLanding.tsx, DraftChangesPanel.tsx or StudioDesignSurface.tsx at claim time. Seats 2, 3 and 5 yielded this card (coordinator ruling 01:54Z).

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jTWKHRdA5msPPhwmw4
    os-dev-report

    {
      "issue": 29691,
      "status": "done",
      "branch": "claude/project-thread-pkn482",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29723",
      "session": "session_01QsR2jTWKHRdA5msPPhwmw4",
      "premise_still_valid": true,
      "summary": "PR 1 of 2 (Part of #29691). The Studio landing folds each BASE.custom pair under its listed base with the switcher's foldCustomizationPairs, in both sections; the base card keeps its customized line and pair link, and an orphan pair keeps its card. DraftChangesPanel takes an optional customizationOf (the base label) and says under its title 'Saved to BASE's customizations' / 保存到 BASE 的定制 through one exported helper, savedToCustomizationText, for PR 2's header to reuse. StudioDesignSurface passes the base label only when pairId is set. New key preview.changes.savedToCustomization in all ten locale packs. Toast unchanged. Item header waits for #29693 (PR 2).",
      "tests": "Red on main: the 3 touched test files with 1c1a5d40's BuilderLanding.tsx, DraftChangesPanel.tsx and StudioDesignSurface.tsx (blob-identical, restored, git diff HEAD empty): 7 failed / 24 passed, the 7 being the new pins, CONTROLs green. Branch: 3 files, 31 passed on d47495aa and on 62ad4a49. Sweep on d47495aa, locked, maxWorkers=2: 254 ui test files naming BuilderLanding or DraftChangesPanel or reading the locale packs, 6 batches all green (2810 tests); packages/i18n/ 95 files, 1443 passed, 13 skipped. turbo type-check app-shell + i18n 66/66. eslint: 0 errors. Ablation = main's BuilderLanding (no fold): red as above. Live, fresh showcase on d47495aa: ensure-customization 201 (com.example.showcase.custom, writable, source authored, listed as its own row); GET /packages/PAIR/export 200 with the pair manifest; DELETE /packages/PAIR 200, list then holds only the base.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at d47495aa: 35 commands, every one exit 0 (incl. check-sdui-manifest, check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity against the body, check-partof-closing-keyword, pnpm --dir ui exec vitest run scripts/ 170 passed 2 skipped). Merge of main (62ad4a49) brought no ui/ file. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "9 — issue_read x4 (29691 get/comments x2, 29693 get+comments), get_session x1 (claude-code-remote), plus ToolSearch loads; no GitHub MCP write",
      "api_writes": "3 — git push x2 (branch, merge of main); pr_create via fleet-write dispatch.mjs (PR #29723); plus this os-dev-report comment via post-stamped",
      "deviations": [
        "The claim's file surface spells the sheet as ui/packages/app-shell/src/views/studio-design/preview/DraftChangesPanel.tsx; the file is ui/packages/app-shell/src/preview/DraftChangesPanel.tsx (and its test preview/__tests__/DraftChangesPanel.test.tsx). Only those real paths were edited.",
        "DraftChangesPanel.test.tsx stubs useObjectTranslation for the whole file; the new describe switches the stub to the real hook through a hoisted flag (i18nMode.real) so it can read the shipped zh and en packs. The file's other cases keep the stub.",
        "PR not assigned and no reviewer requested (seat common rules), although the session's harness asked for it."
      ],
      "line_budget": "+186 / -13 across 17 files (source 41, tests 134, i18n 11, changeset 13)",
      "files_changed": [
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.tsx",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.customizationCounts-28566.test.tsx",
        "ui/packages/app-shell/src/preview/DraftChangesPanel.tsx",
        "ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
        "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.customizePublish-28562.test.tsx",
        "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts",
        ".changeset/29691-landing-pair-card.md"
      ],
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: the publish toast still reads 已发布本软件包的 N 项 for a pair's publish (card's What-happens item 2); the agreed direction names only the header and the sheet, so it is left unchanged here."
      ]
    }
  5. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
    2026-11-03T02:52Z

    Re-measured live by the epic PM seat on main at c9636f1e50, on the maintainer's word in direct chat, 2026-11-03: 「需要复测的内容,你直接处理」. This updates the card body where it differs. ⛔ Not a claim.

    Confirmed. With the pair installed, /_console/studio:

    • The pair's card under 我的软件包 reads "ObjectStack Showcase (custom)", com.example.showcase.custom, 可写. Clicking it lands on /_console/studio/com.example.showcase/data, with the chip reading 只读. So the card promises a writable package and opens a read-only one.
    • The base's line links to /_console/studio/com.example.showcase.custom/data (studio-landing-customizations-pair). Its destination was not clicked here; from the card's behaviour, expect the same landing.
    • With every customization restored and the pair still installed, the base's card reads 已定制 0 项,已停用 0 项. The counts item says a package with nothing customized draws nothing. Please make it draw nothing.

    Still open for the seat: where the pair's export and delete live once the card goes.

  6. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Landed (partial, PR 1 of 2) · 2026-11-03T03:29Z · PR #29723 merged through the merge queue as 7f328cda at 2026-11-03T03:28Z (GitHub's clock). ACCEPT 6594418645 at head 62ad4a49.

    probe before (7f328cda~1) now (origin/main)
    foldCustomizationPairs(pkgs) in ui/packages/app-shell/src/views/studio-design/BuilderLanding.tsx 0 1
    export function savedToCustomizationText in ui/packages/app-shell/src/preview/DraftChangesPanel.tsx 0 1

    The landing no longer gives a .custom pair its own card, and the pending-changes sheet names where a pair's drafts are saved. The card stays open and pm:dispatched for PR 2: the item-header sentence, reusing savedToCustomizationText, after seat 4's #29693 lands.

  7. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim amended · 2026-11-03T05:35Z · PR 2 (Fixes #29691) file surface declared before code, as claim 6593455602 reserved. Branch (claude/project-thread-pkn482), session, size, container and Metadata-protocol: none are unchanged.

    Serial cleared: seat 4's #29693 landed as PR #29765 (05:16Z), and the card thread merged main into the branch at 1a47f9b2. At origin/main 339f63da, none of the 37 open PRs touches a file below. Seat 4 agreed earlier that PR 2 adds the header slot.

    File surface (PR 2):

    • ui/packages/app-shell/src/views/studio-design/StudioItemHeader.tsx: a new optional note?: React.ReactNode slot, rendered as its own line (data-slot="item-note") between the title-row div and the tabs nav, outside titleRowRef, so the feat(app-shell): a Studio item header keeps the item name readable; chips, tools and labels give way first #29765 fold never measures it. Absent, the header renders exactly as before.
    • ui/packages/app-shell/src/views/studio-design/preview/DraftChangesPanel.tsx: a new exported SavedToCustomizationNote({ baseLabel }) that renders savedToCustomizationText through useObjectTranslation. The sheet line is unchanged.
    • ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx: note passed at three item-header call sites (Interfaces, Data, Automations), only when that item's edits go to the pair. Access stays as it is, because its status chip already names the base (Studio Access: a New similar copy of a permission set reads "0 objects granted" in its pair, though the server holds its grants #29674).
    • Tests: a new describe in StudioItemHeader.titleRowFold-12897.test.tsx (the note sits outside the measured row; CONTROL: no note, no line); pins in StudioDesignSurface.customizePublish-28562.test.tsx, DataPillar.baseObjectExtension-28575.test.tsx and AutomationsPillar.customizeFlow-28570.test.tsx (after Customize plus an edit the header names the base; CONTROL: before Customize, no line).
    • .changeset/29691-item-header-saved-to.md (@object-ui/app-shell patch).

    No new i18n key: PR 2 reuses preview.changes.savedToCustomization.

    Clause-②: yes (widening), now also covering the optional StudioItemHeader prop note and the exported SavedToCustomizationNote in published @object-ui/app-shell. Nothing narrows. Any other file is declared by a further amendment before code.

  8. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jTWKHRdA5msPPhwmw4
    os-dev-report
    {
    "issue": 29691,
    "status": "done",
    "branch": "claude/project-thread-pkn482",
    "pr": "#29843",
    "session": "session_01QsR2jTWKHRdA5msPPhwmw4",
    "premise_still_valid": true,
    "summary": "PR 2 of 2 (Fixes #29691, draft). StudioItemHeader takes an optional note, drawn as one line after the title row and before the tabs, outside the row the #29693 fold measures. The header says the sheet's sentence ('Saved to BASE's customizations' / 保存到 BASE 的定制, key preview.changes.savedToCustomization, no new key) through SavedToCustomizationNote on Interfaces (item added in the pair, overridden, or unlocked by Customize), Data (object added in the pair, or a base object whose pair extension is published, drafted or dirty; label from customization.baseLabel because packageId names the pair for a pair's object) and Automations (flow added, overridden or unlocked). Access unchanged. Changeset app-shell patch, Clause-② yes (widening), Metadata-protocol none.",
    "tests": "Red on main: the 4 touched test files with 339f63d's StudioItemHeader.tsx, DraftChangesPanel.tsx and StudioDesignSurface.tsx (new helper module kept, HEAD restored): 6 failed / 52 passed. The 6 are the three surface pins (Interfaces 1, Data 2, Automations 2) and the header own-line pin; every CONTROL is green on main. Branch: 58 passed. Ablation of the outside-titleRowRef placement (note moved to the row's last child): the fold describe reds 3 of 4 (own line; a 400 px note folds nothing at 632 px; folds at 330 and unfolds at 480 with the note), CONTROL green, restored. Same-text pin is in customizePublish-28562: the harness stubs DraftChangesPanel, so the stub draws its line with the real savedToCustomizationText from the label the host hands it, and the pin compares that with the real header note after the first edit opens the pair. The real sheet line stays pinned by PR 1's DraftChangesPanel.test.tsx. Sweep, locked, maxWorkers=2: 284 ui test files naming StudioItemHeader, DraftChangesPanel, StudioDesignSurface, DataPillar, AutomationsPillar, InterfacesPillar or savedToCustomization, plus src/preview/ whole, in 6 batches on a3d4ffd, all green (3551 tests). turbo type-check app-shell 65/65. eslint: 0 errors, no warning on a changed line except react-refresh only-export-components on savedToCustomizationText in the new module (the same warning it carried in DraftChangesPanel).",
    "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on a3d4ffd: 35 commands, each exit 0 (incl. check-sdui-manifest, check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity with GITHUB_EVENT_PATH on this body, pnpm --dir ui exec vitest run scripts/). e2d07e0 rewords the changeset only; check-changeset-no-major, check-empty-changeset and check:changeset-gate-self-tests exit 0 there. Body gates before pr_create: check-partof-closing-keyword 0, check-closing-keyword-parity 0 (its --body mode exits 2 listing the intended Fixes #29691).",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "2 since PR 1: subscribe_pr_activity (#29843) and ToolSearch loads; no GitHub MCP write",
    "api_writes": "4 — git push x3 (6e6a5f3, a3d4ffd, e2d07e0); pr_create via fleet-write dispatch.mjs (PR #29843, body read back byte-identical, no assignees); plus this os-dev-report comment via post-stamped",
    "deviations": [
    "One file beyond the amended claim: ui/packages/app-shell/src/preview/savedToCustomization.tsx (new, 30 lines). The first sweep on 6e6a5f3 found 7 crashes in StudioDesignSurface.oneSurface-28572 and kernelReadOnly-29567: both vi.mock the whole DraftChangesPanel module, and 'No SavedToCustomizationNote export is defined on the mock'. About 57 Studio test files mock that module whole. Rather than edit two unclaimed test files, savedToCustomizationText and SavedToCustomizationNote moved to their own module, which DraftChangesPanel imports and re-exports, so PR 1's export is unchanged. If you'd rather patch the two mocks instead, say so and I'll swap it.",
    "customizePublish-28562's DraftChangesPanel stub now also renders a sheet-saved-to line from the real helper (for the same-text pin); the mock stays a plain factory."
    ],
    "line_budget": "+288 / -14 across 9 files (source 74, tests 202, changeset 12)",
    "files_changed": [
    ".changeset/29691-item-header-saved-to.md",
    "ui/packages/app-shell/src/preview/DraftChangesPanel.tsx",
    "ui/packages/app-shell/src/preview/savedToCustomization.tsx",
    "ui/packages/app-shell/src/views/studio-design/StudioItemHeader.tsx",
    "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
    "ui/packages/app-shell/src/views/studio-design/StudioItemHeader.titleRowFold-12897.test.tsx",
    "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.customizePublish-28562.test.tsx",
    "ui/packages/app-shell/src/views/studio-design/DataPillar.baseObjectExtension-28575.test.tsx",
    "ui/packages/app-shell/src/views/studio-design/AutomationsPillar.customizeFlow-28570.test.tsx"
    ],
    "open_questions": [
    "Keep the new savedToCustomization module, or patch the two whole-module mocks instead?"
    ],
    "security_findings": "none",
    "out_of_scope_findings": [
    "carrier: none · noted, not filed: no live browser pass on this PR; the sentence's live text on showcase is 'Saved to ObjectStack Showcase’s customizations' by PR 1's measured base label."
    ]
    }

  9. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim amended · 2026-11-03T07:08Z · PR 2 (#29843) file surface widened by one file, after code. The dev reported this deviation openly in report 6597610452, and the seat accepts it here. This adds to amendment 6596316060. Branch, session, size and the declaration lines are unchanged.

    Added: ui/packages/app-shell/src/preview/savedToCustomization.tsx (new, 30 lines). It holds savedToCustomizationText and the new SavedToCustomizationNote. DraftChangesPanel.tsx imports and re-exports savedToCustomizationText, so PR 1's export is unchanged. Why: StudioDesignSurface.oneSurface-28572 and kernelReadOnly-29567 replace the whole DraftChangesPanel module with a stub that lacks the new export, and 7 of their cases crashed. Moving the sentence to its own module keeps the header independent of that stub. Patching both mocks would have widened the claim by two unclaimed test files, so the seat prefers the module.

    Path correction: amendment 6596316060 wrote views/studio-design/preview/DraftChangesPanel.tsx. The file is ui/packages/app-shell/src/preview/DraftChangesPanel.tsx, the same one PR 1 touched.

    Clause-②: yes (widening) still holds: an optional note prop and a new SavedToCustomizationNote export, with nothing removed or narrowed.

  10. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Landed · 2026-11-03T07:40Z · PR 2 #29843 merged through the merge queue as 97f8f6f6 at 2026-11-03T07:40Z (GitHub's clock). ACCEPT 6597855402 and contract review 6597647521 (PASS) at head e2d07e05. PR 1 #29723 had landed as 7f328cda.

    probe before (97f8f6f6~1) now (origin/main)
    data-slot="item-note" in ui/packages/app-shell/src/views/studio-design/StudioItemHeader.tsx 0 1
    <SavedToCustomizationNote call sites in ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx 0 3

    Fixes #29691 closed this card, and both of its PRs are landed. pm:dispatched comes off in the same stroke as this note. There is no follow-up. Access was left unchanged on purpose, because its status chip already names the base (#29674).

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