From 46a2f1bc88c85aaaaf7a20c5dd2375f180b34d47 Mon Sep 17 00:00:00 2001 From: os-bill Date: Fri, 30 Oct 2026 10:32:21 +0000 Subject: [PATCH 1/4] =?UTF-8?q?docs(adr):=20ADR-0146=20=E2=80=94=20Studio?= =?UTF-8?q?=20designs,=20Setup=20administers;=20one=20editor=20per=20item;?= =?UTF-8?q?=20paired=20customize=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proposed record drafted on the maintainer's instruction in the project decision thread for #27356 rows 12 / 14 / 19. Declares the boundary between Studio (all metadata: design, catalog, source, layers, history, diagnostics) and Setup (administration of the deployment), one editor per metadata item, in-place overlay editing on a read-only package, the operational switches on the item, a browse entry for read-only packages, and a paired `.customize` package shown as one surface with its base. Implements nothing; the rollout is cut as cards after the merge. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Utp6CaRN6wdrRyLKJSCMYH --- ...ditor-per-item-paired-customize-package.md | 250 ++++++++++++++++++ docs/adr/README.md | 7 +- 2 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md diff --git a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md new file mode 100644 index 00000000000..96df3a19a32 --- /dev/null +++ b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md @@ -0,0 +1,250 @@ +# ADR-0146: Studio designs, Setup administers — one editor per metadata item, the whole metadata catalog in Studio, and a paired `.customize` package for every installed base + +**Status**: Proposed (2026-10-30) — drafted on the maintainer's instruction in the project decision thread +「决定 Studio 建议三行的产品取舍」: 「按照这个方案先更新 issue,写adr。等我审核」. Awaiting the maintainer's review and +hand-merge, which is the acceptance act for a governed surface (Prime Directive #14). ⛔ Nothing in this record is in +force until it merges; **this record declares and implements nothing** — the implementation is cut as cards after the +merge ([Rollout](#rollout)). +**Decided by**: the maintainer's rulings in that thread, 2026-10-30T10:04Z–10:28Z, verbatim and untranslated, each +quoted at the decision it fixes. The thread's analysis is kept at +`/mnt/project-files/decisions/27356-Studio与Setup边界-维度分析.md` (project files) and its three-row brief at +`/mnt/project-files/decisions/27356-Studio三行-入口字段表一个设计器-呈批.md`; the rows are +[#27356](https://github.com/objectstack-ai/objectstack/issues/27356) rows 12, 14 and 19 (HotCRM's 18.2.0 browser pass, +hotcrm#2320 Studio report S1 / S3 / S8). +**Builds on**: [ADR-0005](./0005-metadata-customization-overlay.md) (the overlay tier and its five types), +[ADR-0070](./0070-package-first-authoring.md) (every authored item lives in a writable package; D3 "pick or create a +base first"; D5/D6 retire the package-less scope and forbid an org dumping ground), +[ADR-0126](./0126-packaged-metadata-customization-model.md) (three regimes; the activation ledger +`sys_metadata_activation`; §7 flows; §9 what is deliberately not tracked), +[ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D6 (managed install = sealed definitions + +the regimes), [ADR-0010](./0010-metadata-protection-model.md) (the protection envelope a packaged item carries), +[ADR-0029](./0029-kernel-object-ownership-and-platform-objects-decomposition.md) D7 (navigation contributions, the +precedent for "another package's item shown greyed with its source"). +**Governs**: the console's two authoring surfaces in `ui/packages/app-shell` — Studio (`views/studio-design/**`, +`hooks/useStudioDesignGate.ts`, the app → Studio bridge in `layout/`) and Setup (`views/metadata-admin/**`, +`views/setup/**`); the package create door and the flow clone door (`packages/runtime`, `packages/metadata-protocol`); +the QA checklist entries that drive the Setup designer as a door (`docs/qa/platform-checklist/areas/studio-authoring.json` +and neighbours). ⛔ It does not change the metadata type registry, the overlay tier's membership, the activation ledger's +shape or any write door's authority — those are ADR-0005 / ADR-0126 / ADR-0131 and stand. +**Consumers**: `domain:ui` seats (Studio and Setup cards), `domain:server` seats (the two doors in [D3](#d3) and +[D4](#d4)), the QA checklist maintainers, `content/docs` (the "install, then customize in Studio" promise ADR-0126 §1.3 +names). + +--- + +## Context + +Measured on `origin/main` `f8633c7c` (2026-10-30), code read, not run. + +1. **Two editors per item.** Studio is four pillars (Data, Interfaces, Automations, Access) over **7** metadata types + (object, view, page, dashboard, report, flow, permission set), working per package with drafts and a publish review + (ADR-0070). Setup → Metadata ("All Metadata Types", `views/metadata-admin`) lists **all 30** registered types and + opens every item in one generic page (`ResourceEditPage`: schema form, Source JSON, layered code / overlay / + effective diff, history, diagnostics, reset or delete) that saves at once. For the 7 pillar types the same item has + two designers with two save models. HotCRM's browser pass named it (#27356 row 19: "Studio and Setup → Metadata each + open a designer for the same flow or view; only Setup can delete a flow or reset an overlay"). +2. **The registry's tiers** (`DEFAULT_METADATA_TYPE_REGISTRY`, `packages/spec/src/kernel/metadata-plugin.zod.ts`): + 30 types; **5** take an environment overlay (view, dashboard, report, translation, email_template — ADR-0005); + **9** are code-only (`allowRuntimeCreate: false`: field, picklist, job, agent, api, capability, queue, + assignment_rule, sharing_rule); the rest are runtime-creatable into a writable package only. +3. **The gates differ.** Studio's authoring entries read `manage_metadata` (`useCanAuthorMetadata`; the trail + capabilities are `studio.access` and `manage_metadata`, `setup.access` no longer opens them). Setup reads + `setup.access`; delegated administrators reach positions, permission sets and membership through Setup. +4. **The app → Studio bridge skips code packages.** `useStudioDesignGate` draws "Edit {app} in Studio" (app switcher, + app bar pencil) only for a package Studio lists as `writable` (objectui#12615: "Studio opened a read-only package in + its browse-only posture with nothing to edit, so an entry drawn there promised an edit Studio cannot deliver"). On a + deployment whose apps are all code packages the bridge never draws (#27356 row 12). +5. **Operational switches live only in Setup.** ADR-0126 §7.4 placed the packaged-flow toggle (the + `sys_metadata_activation` bit, `POST /api/v1/automation//toggle`) and the clone + (`POST /api/v1/automation//clone`) on Setup › Packaged automation, whose header says "Automation AUTHORING + lives in Studio and stays there. This page is the OPERATIONAL surface". Studio's own Enabled switch is a definition + write (`status`), refused on a read-only package and since #27376 drawn muted with a lock. So an administrator looking + at HotCRM's flow in Studio cannot switch it off or clone it there. +6. **A clone lands package-less.** `packages/runtime/src/flow-clone.ts` drops the package envelope; the copy is "a flow + authored in this deployment" and shows in Studio's package-less "Organization flows" scope (objectui#11553) — the + scope ADR-0070 D5 retires. +7. **Setup's metadata pages carry administration.** Position holders ("Position → Add holder"), permission-set + assignment and queue membership are reached through Setup's metadata list and item pages today (#27356 rows 1, 2, 5, + 9 are about those pages). + +The question the maintainer put was not "which rows to take" but where the line between the two surfaces runs: +「Setup → Metadata 你说的是一个菜单入口吧,这些应该都属于元数据,是否建议都归 studio,是给开发人员用的, setup 时给管理员用的。」 + +## Decision + +### D1 — Studio owns all metadata; Setup owns the deployment's administration {#d1} + +**Studio = the developer's surface: design, catalog, source, layers, history, diagnostics — all 30 types.** The four +pillars stay the designers for the types they cover; an **"All metadata"** area joins them, per package and across +packages, holding what `views/metadata-admin` holds today: the type directory, lists, the generic item page (schema +form, Source JSON, layered code / overlay / effective, history, diagnostics, reset / delete). A pillar type opened from +the directory opens its pillar. + +**Setup = the administrator's surface: people and organization, assignments, runtime configuration, operations.** +Users, organizations and business units, roles, position holders, permission-set assignment, queue membership, +delegated administration; datasources, system settings, app installation and marketplace, licences; deployment-wide +operational overviews (packaged automation, jobs, a diagnostics summary). **Setup carries no metadata editor and no +metadata catalog.** The "Setup → Metadata" routes retire behind redirects into Studio once [D7](#d7) has landed. + +Maintainer, verbatim: 「我认为还是应该在 studio」 (on the catalog, source, layers, history and diagnostics); +「studio 是给开发人员用的, setup 时给管理员用的」. + +Not taken: (a) *Setup keeps the catalog as the "environment view" and Studio keeps the pillars* — the thread's first +proposal; the maintainer ruled the catalog's tools (source, layered diff, history, diagnostics) are a developer's, not an +administrator's, and keeping them in Setup leaves two homes for one item. (b) *Everything metadata-shaped into Studio +including the administration reached through metadata pages* — rejected by [D7](#d7): holders, assignments and +membership are administration and get Setup pages of their own. + +### D2 — One editor per item: an item is edited where it lives {#d2} + +- A **writable package's** item is edited in Studio's pillar (as today). +- A **read-only package's** item of an overlay type (the five of ADR-0005) is edited **in place, on that package, in + Studio**: the pillar opens the item, the draft writes the overlay layer, publish applies it; the item header carries a + "customized in this environment" chip and a **Reset to package default** (the same `DELETE /meta/:type/:name` the + Setup page issues, with the ADR-0126-era honest verb from the layered read's `resettable`). The chip states overlay + presence, a fact the layered read already serves — ⛔ not clone lineage, which ADR-0126 §9 does not track. +- A read-only package's item of any other type is **viewed** in Studio (the browse-only posture) and edited nowhere; + additions go to the paired package ([D3](#d3)). +- No second editor exists for any item: Setup's per-item designer routes for the pillar types stop being editors + ([D1](#d1)); the "Read-only · Customize with an overlay" link that today sends Studio to Setup (#27927, row 13) is + the transitional form and retires with Phase 2. + +Maintainer, verbatim: 「或者直接在只读包上做叠加的覆盖管理」. + +Not taken: a separately selectable **virtual package** standing for "this environment's customization layer" as a +Studio scope — 「代码包只读,覆盖的部分是否建议单独选中一个虚拟包代表自定义层,还是维持 studio 的风格?」. An overlay +is a layer on one item of one package; a scope that collects overlays detaches them from their context and is the +org-level dumping ground ADR-0070 D6 forbids. The word "virtual" survives only as presentation in [D3](#d3). + +### D3 — Every installed base gets a paired customization package, `.customize`; Studio shows the pair as one surface {#d3} + +**Underneath, a real package.** ADR-0070 D1 holds: a new flow, view, page or permission set the customer adds "to +HotCRM" lives in a writable package. That package is **`hotcrm.customize`** — an ordinary writable package that +declares a dependency on `hotcrm`, created on the customer's first addition to the base **without a package prompt** +(ADR-0070 D3's "pick or create a base first" is answered by the pairing convention), one per base, never one per +environment. It receives: new items authored from the base's Studio surface, **clones** of the base's flows +([D4](#d4)), and environment-level permission sets for the base. It is published, reviewed, exported, duplicated and +deleted as any writable package is (ADR-0070 D4); upgrading the base never touches it; ADR-0070 D6 is satisfied (one +per base, not a bucket). + +**On top, one surface.** Studio opens HotCRM and the designer sees **one** HotCRM: the pillar rails list the base's +items (read-only; the overlay types editable in place per [D2](#d2)) and the customize package's items (writable) +**in the same list**, the latter marked with a small "customization" chip and filterable with "only customizations"; +New and Clone land in the customize package without asking; the pending-changes and publish surfaces act on the +customize package; the package switcher folds `hotcrm.customize` under HotCRM instead of giving it a row. Items another +package contributes to the base (flows watching its objects, fields extending its objects, navigation contributions) +are listed greyed with their source package, the ADR-0029 D7 presentation. + +**Upgrade and audit.** "What did we change on HotCRM" is one place: `hotcrm.customize` plus the base's overlays and +switched-off items. Studio's landing carries one line per package ("n customized, m switched off"); Setup carries +nothing per package. + +Maintainer, verbatim: 「假设未来客户安装了很多软件包,对具体软件包的定制岂不是在 软件包中直接看更方便,如果在setup,都 +混在一起了。」; 「流必须住在可写包里(ADR-0070),能否虚拟一个 hotcrm.customize 包,但是设计者看的时候应该在一个[界面]。」 + +Doors this needs (server cards, Phase 2): the package create door accepts the pairing convention (name +`.customize`, dependency on the base, idempotent "create if absent"); the flow clone door takes a target +`packageId` and refuses a package-less target once the convention exists (fixing the Context §6 mismatch with ADR-0070 +D5 on the way). + +### D4 — The operational switches are offered on the item in Studio; Setup keeps the deployment-wide overview {#d4} + +ADR-0126 §7.4 chose Setup as the first surface for the packaged-flow toggle and clone; that was a surface choice +(its Fork D), not one of the §9 walls. This record moves the primitives to where the item is: + +- In Studio, on a **read-only package's flow**, the Enabled switch binds the **activation ledger** + (`GET /api/v1/automation/_status`, `POST /api/v1/automation//toggle`) and reads "off for this deployment"; on a + **writable package's flow** it stays the definition switch ("disabled; publish to apply"). Two switches, two words — + never one control that means different things by package. +- The item's ⋯ menu offers **Clone** (`POST /api/v1/automation//clone`, a new machine name required, the server's + notice shown verbatim with the "switch the original off" offer, objectui#13270's shape); the clone lands in the + paired package ([D3](#d3)). +- Setup › Packaged automation becomes a deployment-wide **operations overview** (which packaged flows are off, which are + "not running here" and why); it stops being the only door. Whether it stays or retires is decided on usage after + Phase 2, not here. +- ADR-0126 §9 stands in full: no lineage from a clone to its source, no diff against the base, no "based on vN" notice, + on either surface. + +Maintainer, verbatim: 「打包自动化开关,这个就很奇怪,正常的操作我应该是在studio中进入 hotcrm app,选中一个流程,点禁用或者 +复制更符合逻辑吧?」 + +### D5 — The app → Studio bridge draws for a read-only package, as a browse entry {#d5} + +objectui#12615's reasoning ("a pencil promised an edit Studio cannot deliver") rules out the **pencil**, not the +**entry**. For a read-only package the app switcher row and the app bar entry draw as "Open {app} in Studio" (an eye, +not a pencil; zh 「在 Studio 中查看 {app}」), for the same principals through the same gate (`useStudioDesignGate` +answers a posture, ⛔ still never a second derivation of `writable`); a writable package keeps "Edit {app} in Studio". +Kernel packages and an unread or failed package list still draw nothing. (#27356 row 12, letter B.) + +Maintainer, verbatim: 「「Edit {app} in Studio」代码包/已安装包一律不画,合理吗?ai写完代码,人类需要进去确认啊」. + +### D6 — Not done, recorded so silence cannot be read as consent {#d6} + +- **No fields table in the object designer** (#27356 row 14, letter **C**, maintainer 2026-10-30T10:07Z). The Records + grid's columns and the Form canvas each enumerate every field and open the one field inspector; objectui#5813 ("a + separate fields tab would ADD a surface, not remove one") and objectui#12450 (seven flat tabs, decision B of + objectui#12446) stand. Maintainer, verbatim: 「Studio 的对象设计器,第一栏数据不就是每一个字段吗?表单对应的不也是每一个 + 字段吗」. +- **No Setup designer for any type**, transitional redirects excepted ([D1](#d1)). +- **No global customization scope** ([D2](#d2), not taken). +- **No change to the overlay tier's membership** (the five types) or to the activation ledger's shape (ADR-0005, + ADR-0126). + +### D7 — Setup pages the move owes {#d7} + +Administration reached through Setup's metadata pages today gets a page of its own under Setup before those routes +retire: **position holders**, **permission-set assignment**, **queue membership**. Each is a people-and-organization +page (the scope of `setup.access` and the delegated-administrator gate), not a metadata page. ⛔ Phase 3 does not +retire a Setup → Metadata route whose administrative action has no Setup home yet. + +## Consequences + +- One editor per item; the HotCRM pass's "two designers, two save models" disappears, and every future type answers + "where is it edited" by rule instead of by card. +- An administrator does not learn Studio for the daily work; a developer does not enter Setup to change a design. The + one recorded crossing: **defining** a permission set (as against assigning one) is design and happens in Studio's + Access pillar, in the paired or the writable package, behind `manage_metadata`. +- The clone's landing moves from the package-less scope to the paired package, which closes the Context §6 gap with + ADR-0070 D5. +- Cost, stated: Setup's item pages for the pillar types stop editing; QA checklist items and e2e specs that drive the + Setup designer as "a sibling door onto the same save" (`studio-authoring.json`, `ux-conventions.json`, the live + `studio-object-designer.spec.ts`) are rewritten to the Studio door or marked transitional; users used to editing a + view in Setup change habit. Translations and email templates lose the Setup form; their simplified form editor is + offered inside Studio's All-metadata area ([Open questions](#open-questions) 3). + +## Rollout + +Cut as cards after this record merges; nothing below binds a seat before that. Each card cites this record. + +1. **Now** (#27356 row 19, letter **A1**, independent of this record): Studio deletes a writable package's flow from + the Automations item menu (confirm; the same `DELETE /meta/:type/:name` door; a pending draft of the item is + discarded first; read-only packages draw nothing). +2. **Phase 2 — customization on the read-only package** (ui + two server doors): (a) in-place overlay editing, the + "customized" chip and Reset on read-only packages ([D2](#d2); views, dashboards, reports first); (b) the ledger + switch and Clone on the item ([D4](#d4)); (c) the clone door's `packageId`; (d) the paired-package create + convention and dependency ([D3](#d3)); (e) the mixed rails, the chip and filter, the folded switcher ([D3](#d3)); + (f) the browse entry ([D5](#d5)) — this one is #27356 row 12 and may land before the record merges, since it reverses + no wall. +3. **Phase 3 — the catalog moves** ([D1](#d1), [D7](#d7)): `views/metadata-admin` directory, lists, item page, + history and diagnostics re-homed under Studio's All-metadata area (per package and across packages); the three Setup + administration pages; Setup → Metadata routes redirect; QA checklist and e2e door rewrites. +4. **Phase 4 — as pulled**: app, action, dataset, translation, email template, documentation and the AI types gain + pillar-grade designers in Studio one card at a time; until then the All-metadata area's generic page is their editor. + +## Open questions (for the maintainer's review of this draft) + +1. Setup › Packaged automation after Phase 2: keep as the operations overview, or retire. +2. The pairing name: `.customize` as the maintainer spelled it, or another suffix; whether the convention is a + registry constant or a server-side default the create door applies. +3. Translations and email templates: keep a simplified **form** editor for their overlays inside Studio's All-metadata + area (the former Setup form, re-homed), so an administrator changing one line of mail copy is not sent to a canvas. + Recommended yes; the rule "one editor per item" still holds because the pillar does not edit these types. + +## Refs + +- [#27356](https://github.com/objectstack-ai/objectstack/issues/27356) rows 12, 13, 14, 19, 20, 21 and their landed + PRs #27376 (read-only flow switch), #27927 (overlay link only where an overlay exists). +- ADR-0126 §7.4 (the Setup surface this record moves from) and §9 (the walls it keeps); ADR-0070 D1, D3, D5, D6; + ADR-0005; ADR-0131 D6. +- objectui#12615 (bridge follows package posture), objectui#5813 and objectui#12450 (the Data pillar's tabs), + objectui#11553 (the package-less scope), objectui#13270 (the clone result's offers). diff --git a/docs/adr/README.md b/docs/adr/README.md index 5bd76f8b610..e52f1f20b70 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -13,12 +13,12 @@ ## Summary -146 records under `docs/adr/` (141 numbers), 11 under `ui/docs/adr/` (listed separately below). +147 records under `docs/adr/` (142 numbers), 11 under `ui/docs/adr/` (listed separately below). | Status | Records | |---|---| | Accepted | 128 | -| Proposed | 4 | +| Proposed | 5 | | Superseded | 4 | | Draft | 3 | | Deferred | 2 | @@ -26,7 +26,7 @@ | Amended | 1 | | Partially implemented | 1 | | Revised | 1 | -| **Total** | **146** | +| **Total** | **147** | ## Shared numbers @@ -213,6 +213,7 @@ A bare `ADR-0006` names the decision; its current text is [0006-project-environm | [ADR-0143](./0143-outbound-connector-auth-is-open-tier.md) | Outbound connector auth is open tier — OAuth2 grants, vendor app-credential exchange and request signing in o… | Accepted — 2026-10-28. Proposed 2026-10-27 (#26833, which also landed the… | 2026-10-28 | — | — | | [ADR-0144](./0144-multi-currency-record-currency-dated-rates-write-time-home-projection.md) | Multi-currency — a record currency in a sibling code field, dated exchange rates, and a home-currency amount… | Accepted — 2026-10-28, ruled on objectstack#27119 (ruling `6465431966`, de… | 2026-10-28 | — | — | | [ADR-0145](./0145-ui-deprecation-tombstones-retire-on-the-spec-window.md) | A `?: never` tombstone on the ui authoring face retires on the spec's own window — one major after the retire… | Accepted — 2026-10-28, #27251 · Amended (2026-10-28, #27291 — one clause e… | 2026-10-28 | — | — | +| [ADR-0146](./0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md) | Studio designs, Setup administers — one editor per metadata item, the whole metadata catalog in Studio, and a… | Proposed — 2026-10-30 — drafted on the maintainer's instruction in the pro… | 2026-10-30 | — | — | ## ObjectUI registry — `ui/docs/adr/` (`ui-` prefix) From 273f7db92be5c81e5499b0bb98527248743e6840 Mon Sep 17 00:00:00 2001 From: os-bill Date: Fri, 30 Oct 2026 12:24:39 +0000 Subject: [PATCH 2/4] =?UTF-8?q?docs(adr):=20ADR-0146=20=E2=80=94=20answer?= =?UTF-8?q?=20contract=20review=206522731250=20(M1,=20S1=E2=80=93S6,=20S8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M1: name the ADR-0126 §9 first-bullet lift (badge, customization list, revert on served facts; diff-vs-base and the upgrade skip-report stay deferred; clone provenance untouched) and stop saying §9 "stands in full". S1: state the ADR-0070 D3 amendment for the paired case. S2: own the greyed-with-source presentation; cite ADR-0029 D7 for the contribution only. S3: correct the Context readings (directory hides field/package and shows the active package's types; dataset has a create dialog, no designer; the charter sentence is the file's doc comment; queue membership has no Setup section at this head, ADR-0142). S4: reachable provenance (ruling record 6520616687; the D1–D3 quotes have no GitHub record), restore the verbatim quote and mark the editorial note. S5: the ledger switch's authority and its disabled shape under a walled posture. S6: cite ADR-0141. S8: export "as ADR-0070 D4 lands". Note #28076 landing D5 ahead of the record. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Utp6CaRN6wdrRyLKJSCMYH --- ...ditor-per-item-paired-customize-package.md | 121 ++++++++++++------ 1 file changed, 83 insertions(+), 38 deletions(-) diff --git a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md index 96df3a19a32..9a8bd005817 100644 --- a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md +++ b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md @@ -6,11 +6,13 @@ hand-merge, which is the acceptance act for a governed surface (Prime Directive force until it merges; **this record declares and implements nothing** — the implementation is cut as cards after the merge ([Rollout](#rollout)). **Decided by**: the maintainer's rulings in that thread, 2026-10-30T10:04Z–10:28Z, verbatim and untranslated, each -quoted at the decision it fixes. The thread's analysis is kept at -`/mnt/project-files/decisions/27356-Studio与Setup边界-维度分析.md` (project files) and its three-row brief at -`/mnt/project-files/decisions/27356-Studio三行-入口字段表一个设计器-呈批.md`; the rows are -[#27356](https://github.com/objectstack-ai/objectstack/issues/27356) rows 12, 14 and 19 (HotCRM's 18.2.0 browser pass, -hotcrm#2320 Studio report S1 / S3 / S8). +quoted at the decision it fixes. **Provenance a repository reader can reach**: the three row rulings (12 B, 14 C, +19 A1) and the D4–D6 quotes are on the card as ruling record +[`6520616687`](https://github.com/objectstack-ai/objectstack/issues/27356#issuecomment-6520616687); the D1–D3 +boundary quotes were spoken in the project thread and have **no GitHub record** — the maintainer's hand-review and +hand-merge of this record is their verification. The thread's full analysis lives in the project's own files, outside +this repository. The rows are [#27356](https://github.com/objectstack-ai/objectstack/issues/27356) rows 12, 14 and 19 +(HotCRM's 18.2.0 browser pass, hotcrm#2320 Studio report S1 / S3 / S8). **Builds on**: [ADR-0005](./0005-metadata-customization-overlay.md) (the overlay tier and its five types), [ADR-0070](./0070-package-first-authoring.md) (every authored item lives in a writable package; D3 "pick or create a base first"; D5/D6 retire the package-less scope and forbid an org dumping ground), @@ -18,8 +20,12 @@ base first"; D5/D6 retire the package-less scope and forbid an org dumping groun `sys_metadata_activation`; §7 flows; §9 what is deliberately not tracked), [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D6 (managed install = sealed definitions + the regimes), [ADR-0010](./0010-metadata-protection-model.md) (the protection envelope a packaged item carries), -[ADR-0029](./0029-kernel-object-ownership-and-platform-objects-decomposition.md) D7 (navigation contributions, the -precedent for "another package's item shown greyed with its source"). +[ADR-0029](./0029-kernel-object-ownership-and-platform-objects-decomposition.md) D7 (navigation contributions — the +*contributed item* this record presents; the greyed-with-source presentation is this record's own, see [D3](#d3)), +[ADR-0141](./0141-inter-app-dependency-declared-checked-before-install.md) (`manifest.dependencies`, checked before +install, the namespace it shares co-owned — the dependency [D3](#d3)'s paired package declares), +[ADR-0142](./0142-ownership-queue-membership-claim-and-assignment-rules.md) D2 (queue membership through the existing +recipient kinds — the queue page [D7](#d7) waits for). **Governs**: the console's two authoring surfaces in `ui/packages/app-shell` — Studio (`views/studio-design/**`, `hooks/useStudioDesignGate.ts`, the app → Studio bridge in `layout/`) and Setup (`views/metadata-admin/**`, `views/setup/**`); the package create door and the flow clone door (`packages/runtime`, `packages/metadata-protocol`); @@ -36,10 +42,12 @@ names). Measured on `origin/main` `f8633c7c` (2026-10-30), code read, not run. -1. **Two editors per item.** Studio is four pillars (Data, Interfaces, Automations, Access) over **7** metadata types - (object, view, page, dashboard, report, flow, permission set), working per package with drafts and a publish review - (ADR-0070). Setup → Metadata ("All Metadata Types", `views/metadata-admin`) lists **all 30** registered types and - opens every item in one generic page (`ResourceEditPage`: schema form, Source JSON, layered code / overlay / +1. **Two editors per item.** Studio is four pillars (Data, Interfaces, Automations, Access) that design **7** metadata + types (object, view, page, dashboard, report, flow, permission set) — plus a create dialog, with no designer, for + `dataset` (`datasetCreate.tsx`, from the report and widget pickers) — working per package with drafts and a publish + review (ADR-0070). Setup → Metadata ("All Metadata Types", `views/metadata-admin`) is the registry's catalog: its + directory shows the types the active package contributes, hiding `field` and `package` (`HIDDEN_TYPES`), and opens + every item in one generic page (`ResourceEditPage`: schema form, Source JSON, layered code / overlay / effective diff, history, diagnostics, reset or delete) that saves at once. For the 7 pillar types the same item has two designers with two save models. HotCRM's browser pass named it (#27356 row 19: "Studio and Setup → Metadata each open a designer for the same flow or view; only Setup can delete a flow or reset an overlay"). @@ -53,19 +61,23 @@ Measured on `origin/main` `f8633c7c` (2026-10-30), code read, not run. 4. **The app → Studio bridge skips code packages.** `useStudioDesignGate` draws "Edit {app} in Studio" (app switcher, app bar pencil) only for a package Studio lists as `writable` (objectui#12615: "Studio opened a read-only package in its browse-only posture with nothing to edit, so an entry drawn there promised an edit Studio cannot deliver"). On a - deployment whose apps are all code packages the bridge never draws (#27356 row 12). + deployment whose apps are all code packages the bridge never draws (#27356 row 12). *Overtaken while this record was + in review*: PR [#28076](https://github.com/objectstack-ai/objectstack/pull/28076) implements [D5](#d5) and was + seat-accepted on 2026-10-30; the reading above is true at `f8633c7c` and false once it merges. 5. **Operational switches live only in Setup.** ADR-0126 §7.4 placed the packaged-flow toggle (the `sys_metadata_activation` bit, `POST /api/v1/automation//toggle`) and the clone - (`POST /api/v1/automation//clone`) on Setup › Packaged automation, whose header says "Automation AUTHORING - lives in Studio and stays there. This page is the OPERATIONAL surface". Studio's own Enabled switch is a definition + (`POST /api/v1/automation//clone`) on Setup › Packaged automation, whose file's doc comment states the charter: "Automation + AUTHORING lives in Studio and stays there. This page is the OPERATIONAL surface". Studio's own Enabled switch is a definition write (`status`), refused on a read-only package and since #27376 drawn muted with a lock. So an administrator looking at HotCRM's flow in Studio cannot switch it off or clone it there. 6. **A clone lands package-less.** `packages/runtime/src/flow-clone.ts` drops the package envelope; the copy is "a flow authored in this deployment" and shows in Studio's package-less "Organization flows" scope (objectui#11553) — the scope ADR-0070 D5 retires. -7. **Setup's metadata pages carry administration.** Position holders ("Position → Add holder"), permission-set - assignment and queue membership are reached through Setup's metadata list and item pages today (#27356 rows 1, 2, 5, - 9 are about those pages). +7. **Setup's metadata pages carry administration.** Two live sections sit inside Setup's metadata item pages today: + position holders (`PositionHoldersSection`, "Position → Add holder") and permission-set assignment + (`AssignedUsersSection`); #27356 rows 1, 2, 5 and 9 are about those pages. Queue membership has **no** Setup page or + section at this head — ADR-0142 D2 (Proposed) defines it through the existing recipient kinds, and its page arrives + with that record's landing. The question the maintainer put was not "which rows to take" but where the line between the two surfaces runs: 「Setup → Metadata 你说的是一个菜单入口吧,这些应该都属于元数据,是否建议都归 studio,是给开发人员用的, setup 时给管理员用的。」 @@ -109,6 +121,17 @@ membership are administration and get Setup pages of their own. ([D1](#d1)); the "Read-only · Customize with an overlay" link that today sends Studio to Setup (#27927, row 13) is the transitional form and retires with Phase 2. +**What this lifts from ADR-0126 §9, stated so the two records cannot be read as disagreeing.** §9's first bullet +deferred "the ServiceNow-style overlay layer (badge / customization list / diff-vs-base / revert / upgrade skip-report) +… **if** customer pull for in-place customization appears". That pull is now on record (HotCRM's pass, #27356 rows 12, +13, 19; the maintainer's 「或者直接在只读包上做叠加的覆盖管理」), and this record charters **three of the five** on facts the +platform already serves, with nothing computed: the **badge** (the "customized" chip = overlay presence in the layered +read; the "customization" chip in [D3](#d3) = the item's package), the **customization list** ([D3](#d3)'s "only +customizations" filter and the landing's per-package count of overlaid and switched-off items — a filter over served +rows and a count of ledger rows) and **revert** (Reset = the existing `DELETE /meta/:type/:name` on the overlay row). +**Diff-vs-base and the upgrade skip-report stay deferred**, and §9's second bullet — no clone provenance, no base-moved +notice — stands untouched. At acceptance, ADR-0126 §9's first bullet takes the pointer to this record. + Maintainer, verbatim: 「或者直接在只读包上做叠加的覆盖管理」. Not taken: a separately selectable **virtual package** standing for "this environment's customization layer" as a @@ -120,27 +143,33 @@ org-level dumping ground ADR-0070 D6 forbids. The word "virtual" survives only a **Underneath, a real package.** ADR-0070 D1 holds: a new flow, view, page or permission set the customer adds "to HotCRM" lives in a writable package. That package is **`hotcrm.customize`** — an ordinary writable package that -declares a dependency on `hotcrm`, created on the customer's first addition to the base **without a package prompt** -(ADR-0070 D3's "pick or create a base first" is answered by the pairing convention), one per base, never one per -environment. It receives: new items authored from the base's Studio surface, **clones** of the base's flows -([D4](#d4)), and environment-level permission sets for the base. It is published, reviewed, exported, duplicated and -deleted as any writable package is (ADR-0070 D4); upgrading the base never touches it; ADR-0070 D6 is satisfied (one -per base, not a bucket). +declares a dependency on `hotcrm` in `manifest.dependencies` (ADR-0141: checked once before install; the paired package +shares the base's namespace by construction and co-owns it under that record's rule), created on the customer's first +addition to the base **without a package prompt**, one per base, never one per environment. **This amends ADR-0070 D3 +for the paired case**: D3 forbade the *silent catch-all* (`com.workspace`, the package-less scope) and left a prompted +one-click auto-provision open (ADR-0070 open question 1); a deterministic, per-base, dependency-declaring target is +neither a catch-all nor silent about where the item went — the item header's chip and the folded switcher say it — so +the prompt is dropped for this one case and stays everywhere else D3 names. It receives: new items authored from the base's Studio surface, **clones** of the base's flows +([D4](#d4)), and environment-level permission sets for the base. It is published, reviewed, duplicated and deleted as any +writable package is today, and exported as ADR-0070 D4 lands (the export door is not on the REST ledger at this head); +upgrading the base never touches it; ADR-0070 D6 is satisfied (one per base, not a bucket). **On top, one surface.** Studio opens HotCRM and the designer sees **one** HotCRM: the pillar rails list the base's items (read-only; the overlay types editable in place per [D2](#d2)) and the customize package's items (writable) **in the same list**, the latter marked with a small "customization" chip and filterable with "only customizations"; New and Clone land in the customize package without asking; the pending-changes and publish surfaces act on the customize package; the package switcher folds `hotcrm.customize` under HotCRM instead of giving it a row. Items another -package contributes to the base (flows watching its objects, fields extending its objects, navigation contributions) -are listed greyed with their source package, the ADR-0029 D7 presentation. +package contributes to the base (flows watching its objects, fields extending its objects, ADR-0029 D7 navigation +contributions) are listed **greyed, with their source package named** — a presentation this record decides (ADR-0029 +D7 defines the contribution, not how a contributed item is drawn; #26889 and #27928 are the row-20 precedent). **Upgrade and audit.** "What did we change on HotCRM" is one place: `hotcrm.customize` plus the base's overlays and switched-off items. Studio's landing carries one line per package ("n customized, m switched off"); Setup carries nothing per package. Maintainer, verbatim: 「假设未来客户安装了很多软件包,对具体软件包的定制岂不是在 软件包中直接看更方便,如果在setup,都 -混在一起了。」; 「流必须住在可写包里(ADR-0070),能否虚拟一个 hotcrm.customize 包,但是设计者看的时候应该在一个[界面]。」 +混在一起了。」; 「流必须住在可写包里(ADR-0070),能否虚拟一个 hotcrm.customize 包,但是设计者看的时候应该在一个及诶慢。」 (verbatim; the last +word is a typing slip for 界面, "one interface" — editorial note, not part of the quote) Doors this needs (server cards, Phase 2): the package create door accepts the pairing convention (name `.customize`, dependency on the base, idempotent "create if absent"); the flow clone door takes a target @@ -156,14 +185,19 @@ ADR-0126 §7.4 chose Setup as the first surface for the packaged-flow toggle and (`GET /api/v1/automation/_status`, `POST /api/v1/automation//toggle`) and reads "off for this deployment"; on a **writable package's flow** it stays the definition switch ("disabled; publish to apply"). Two switches, two words — never one control that means different things by package. +- **Authority is the ledger door's, not Studio's.** The toggle's gate (`packages/runtime/src/domains/activation-gate.ts`) + admits `manage_metadata` in the `single` posture and, under the walled `group` / `isolated` postures, only the + PLATFORM_ADMIN posture rung (ADR-0126 §5); a tenant administrator there is refused with the operator's name. Studio + draws the ledger switch **disabled, with that refusal as its title**, for a principal the gate would refuse — never a + live control that always answers 403 (the shape `useCanReadTrail` already avoids). - The item's ⋯ menu offers **Clone** (`POST /api/v1/automation//clone`, a new machine name required, the server's notice shown verbatim with the "switch the original off" offer, objectui#13270's shape); the clone lands in the paired package ([D3](#d3)). - Setup › Packaged automation becomes a deployment-wide **operations overview** (which packaged flows are off, which are "not running here" and why); it stops being the only door. Whether it stays or retires is decided on usage after Phase 2, not here. -- ADR-0126 §9 stands in full: no lineage from a clone to its source, no diff against the base, no "based on vN" notice, - on either surface. +- ADR-0126 §9's second bullet stands: no lineage from a clone to its source, no diff against the base, no "based on + vN" notice, on either surface. Its first bullet is lifted in part by [D2](#d2), as stated there. Maintainer, verbatim: 「打包自动化开关,这个就很奇怪,正常的操作我应该是在studio中进入 hotcrm app,选中一个流程,点禁用或者 复制更符合逻辑吧?」 @@ -193,9 +227,11 @@ Maintainer, verbatim: 「「Edit {app} in Studio」代码包/已安装包一律 ### D7 — Setup pages the move owes {#d7} Administration reached through Setup's metadata pages today gets a page of its own under Setup before those routes -retire: **position holders**, **permission-set assignment**, **queue membership**. Each is a people-and-organization -page (the scope of `setup.access` and the delegated-administrator gate), not a metadata page. ⛔ Phase 3 does not -retire a Setup → Metadata route whose administrative action has no Setup home yet. +retire: **position holders** (`PositionHoldersSection`) and **permission-set assignment** (`AssignedUsersSection`) are +the two live sections the move re-homes; **queue membership** has no section at this head and arrives as a Setup page +with ADR-0142 D2's landing, never inside a metadata page. Each is a people-and-organization page (the scope of +`setup.access` and the delegated-administrator gate), not a metadata page. ⛔ Phase 3 does not retire a +Setup → Metadata route whose administrative action has no Setup home yet. ## Consequences @@ -210,7 +246,9 @@ retire a Setup → Metadata route whose administrative action has no Setup home Setup designer as "a sibling door onto the same save" (`studio-authoring.json`, `ux-conventions.json`, the live `studio-object-designer.spec.ts`) are rewritten to the Studio door or marked transitional; users used to editing a view in Setup change habit. Translations and email templates lose the Setup form; their simplified form editor is - offered inside Studio's All-metadata area ([Open questions](#open-questions) 3). + offered inside Studio's All-metadata area ([Open questions](#open-questions) 3) — which is the **second** recorded + crossing: an administrator changing one line of mail copy enters Studio, behind `manage_metadata`, as the + permission-set definer does. ## Rollout @@ -223,13 +261,20 @@ Cut as cards after this record merges; nothing below binds a seat before that. E "customized" chip and Reset on read-only packages ([D2](#d2); views, dashboards, reports first); (b) the ledger switch and Clone on the item ([D4](#d4)); (c) the clone door's `packageId`; (d) the paired-package create convention and dependency ([D3](#d3)); (e) the mixed rails, the chip and filter, the folded switcher ([D3](#d3)); - (f) the browse entry ([D5](#d5)) — this one is #27356 row 12 and may land before the record merges, since it reverses - no wall. + (f) the browse entry ([D5](#d5)) — #27356 row 12, PR #28076, seat-accepted 2026-10-30; it reverses no wall and lands + ahead of this record. 3. **Phase 3 — the catalog moves** ([D1](#d1), [D7](#d7)): `views/metadata-admin` directory, lists, item page, history and diagnostics re-homed under Studio's All-metadata area (per package and across packages); the three Setup administration pages; Setup → Metadata routes redirect; QA checklist and e2e door rewrites. -4. **Phase 4 — as pulled**: app, action, dataset, translation, email template, documentation and the AI types gain - pillar-grade designers in Studio one card at a time; until then the All-metadata area's generic page is their editor. +4. **Phase 4 — as pulled**: app, action, dataset (today a create dialog, no designer), translation, email template, + documentation and the AI types gain pillar-grade designers in Studio one card at a time; until then the All-metadata + area's generic page is their editor. + +## At acceptance + +When this record is accepted, the pointers go on the records it amends, in the repository's status-line form +(ADR-0005's is the model): ADR-0126 §7.4 and §9 (first bullet), ADR-0070 D3 (the paired case) and D5 (the clone's +landing), ADR-0029 D7 (the greyed-with-source presentation is this record's). Not owed while Proposed. ## Open questions (for the maintainer's review of this draft) @@ -244,7 +289,7 @@ Cut as cards after this record merges; nothing below binds a seat before that. E - [#27356](https://github.com/objectstack-ai/objectstack/issues/27356) rows 12, 13, 14, 19, 20, 21 and their landed PRs #27376 (read-only flow switch), #27927 (overlay link only where an overlay exists). -- ADR-0126 §7.4 (the Setup surface this record moves from) and §9 (the walls it keeps); ADR-0070 D1, D3, D5, D6; - ADR-0005; ADR-0131 D6. +- ADR-0126 §7.4 (the Setup surface this record moves from) and §9 (first bullet lifted in part by D2; second bullet + kept); ADR-0070 D1, D3 (amended for the paired case by D3), D4, D5, D6; ADR-0005; ADR-0131 D6; ADR-0141; ADR-0142 D2. - objectui#12615 (bridge follows package posture), objectui#5813 and objectui#12450 (the Data pillar's tabs), objectui#11553 (the package-less scope), objectui#13270 (the clone result's offers). From 1330eeb1d8e12dae8c4e2a3a04dfe28aba8ddc37 Mon Sep 17 00:00:00 2001 From: os-bill Date: Fri, 30 Oct 2026 13:14:57 +0000 Subject: [PATCH 3/4] =?UTF-8?q?docs(adr):=20ADR-0146=20=E2=80=94=20answer?= =?UTF-8?q?=20contract=20review=206523690910=20(S9=E2=80=93S12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S9: the paired package is exported, duplicated and deleted as any writable package is; the export door is on the runtime route ledger. S10: the ledger switch's disabled shape reads the two served posture facts the walled catalog doors read; no client copy of the gate's sentence; "naming the platform operator". S11: D4's quote is on the card in part, D5 and D6 in full. S12: #28076 merged; ADR-0141 marked Proposed with its mechanisms on main; "the row-20 cards"; the create door sets the base's namespace explicitly. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Utp6CaRN6wdrRyLKJSCMYH --- ...ditor-per-item-paired-customize-package.md | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md index 9a8bd005817..b486c8048de 100644 --- a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md +++ b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md @@ -7,7 +7,7 @@ force until it merges; **this record declares and implements nothing** — the i merge ([Rollout](#rollout)). **Decided by**: the maintainer's rulings in that thread, 2026-10-30T10:04Z–10:28Z, verbatim and untranslated, each quoted at the decision it fixes. **Provenance a repository reader can reach**: the three row rulings (12 B, 14 C, -19 A1) and the D4–D6 quotes are on the card as ruling record +19 A1) and the quotes under D5 and D6 in full, and under D4 in part, are on the card as ruling record [`6520616687`](https://github.com/objectstack-ai/objectstack/issues/27356#issuecomment-6520616687); the D1–D3 boundary quotes were spoken in the project thread and have **no GitHub record** — the maintainer's hand-review and hand-merge of this record is their verification. The thread's full analysis lives in the project's own files, outside @@ -22,8 +22,9 @@ base first"; D5/D6 retire the package-less scope and forbid an org dumping groun the regimes), [ADR-0010](./0010-metadata-protection-model.md) (the protection envelope a packaged item carries), [ADR-0029](./0029-kernel-object-ownership-and-platform-objects-decomposition.md) D7 (navigation contributions — the *contributed item* this record presents; the greyed-with-source presentation is this record's own, see [D3](#d3)), -[ADR-0141](./0141-inter-app-dependency-declared-checked-before-install.md) (`manifest.dependencies`, checked before -install, the namespace it shares co-owned — the dependency [D3](#d3)'s paired package declares), +[ADR-0141](./0141-inter-app-dependency-declared-checked-before-install.md) (Proposed; its D2 pre-install check and D5 +dependency co-ownership are on `main` — `manifest.dependencies`, checked before install, the namespace it shares +co-owned — the dependency [D3](#d3)'s paired package declares), [ADR-0142](./0142-ownership-queue-membership-claim-and-assignment-rules.md) D2 (queue membership through the existing recipient kinds — the queue page [D7](#d7) waits for). **Governs**: the console's two authoring surfaces in `ui/packages/app-shell` — Studio (`views/studio-design/**`, @@ -62,8 +63,8 @@ Measured on `origin/main` `f8633c7c` (2026-10-30), code read, not run. app bar pencil) only for a package Studio lists as `writable` (objectui#12615: "Studio opened a read-only package in its browse-only posture with nothing to edit, so an entry drawn there promised an edit Studio cannot deliver"). On a deployment whose apps are all code packages the bridge never draws (#27356 row 12). *Overtaken while this record was - in review*: PR [#28076](https://github.com/objectstack-ai/objectstack/pull/28076) implements [D5](#d5) and was - seat-accepted on 2026-10-30; the reading above is true at `f8633c7c` and false once it merges. + in review*: PR [#28076](https://github.com/objectstack-ai/objectstack/pull/28076) implements [D5](#d5) and merged into + `main` on 2026-10-30 (`6b125a7a`); the reading above is true at `f8633c7c` and false on `main` since. 5. **Operational switches live only in Setup.** ADR-0126 §7.4 placed the packaged-flow toggle (the `sys_metadata_activation` bit, `POST /api/v1/automation//toggle`) and the clone (`POST /api/v1/automation//clone`) on Setup › Packaged automation, whose file's doc comment states the charter: "Automation @@ -150,9 +151,9 @@ for the paired case**: D3 forbade the *silent catch-all* (`com.workspace`, the p one-click auto-provision open (ADR-0070 open question 1); a deterministic, per-base, dependency-declaring target is neither a catch-all nor silent about where the item went — the item header's chip and the folded switcher say it — so the prompt is dropped for this one case and stays everywhere else D3 names. It receives: new items authored from the base's Studio surface, **clones** of the base's flows -([D4](#d4)), and environment-level permission sets for the base. It is published, reviewed, duplicated and deleted as any -writable package is today, and exported as ADR-0070 D4 lands (the export door is not on the REST ledger at this head); -upgrading the base never touches it; ADR-0070 D6 is satisfied (one per base, not a bucket). +([D4](#d4)), and environment-level permission sets for the base. It is published, reviewed, exported, duplicated and deleted as any +writable package is (ADR-0070 D4; `GET /packages/:id/export`, `POST /packages/:id/duplicate` and the delete door are on +the runtime route ledger at this head); upgrading the base never touches it; ADR-0070 D6 is satisfied (one per base, not a bucket). **On top, one surface.** Studio opens HotCRM and the designer sees **one** HotCRM: the pillar rails list the base's items (read-only; the overlay types editable in place per [D2](#d2)) and the customize package's items (writable) @@ -161,7 +162,7 @@ New and Clone land in the customize package without asking; the pending-changes customize package; the package switcher folds `hotcrm.customize` under HotCRM instead of giving it a row. Items another package contributes to the base (flows watching its objects, fields extending its objects, ADR-0029 D7 navigation contributions) are listed **greyed, with their source package named** — a presentation this record decides (ADR-0029 -D7 defines the contribution, not how a contributed item is drawn; #26889 and #27928 are the row-20 precedent). +D7 defines the contribution, not how a contributed item is drawn; #26889 and #27928 are the row-20 cards). **Upgrade and audit.** "What did we change on HotCRM" is one place: `hotcrm.customize` plus the base's overlays and switched-off items. Studio's landing carries one line per package ("n customized, m switched off"); Setup carries @@ -172,7 +173,8 @@ Maintainer, verbatim: 「假设未来客户安装了很多软件包,对具体 word is a typing slip for 界面, "one interface" — editorial note, not part of the quote) Doors this needs (server cards, Phase 2): the package create door accepts the pairing convention (name -`.customize`, dependency on the base, idempotent "create if absent"); the flow clone door takes a target +`.customize`, dependency on the base, **`namespace` set to the base's explicitly** — the install primitive +otherwise derives one from the id, which for `hotcrm.customize` would be `customize` — idempotent "create if absent"); the flow clone door takes a target `packageId` and refuses a package-less target once the convention exists (fixing the Context §6 mismatch with ADR-0070 D5 on the way). @@ -187,9 +189,12 @@ ADR-0126 §7.4 chose Setup as the first surface for the packaged-flow toggle and never one control that means different things by package. - **Authority is the ledger door's, not Studio's.** The toggle's gate (`packages/runtime/src/domains/activation-gate.ts`) admits `manage_metadata` in the `single` posture and, under the walled `group` / `isolated` postures, only the - PLATFORM_ADMIN posture rung (ADR-0126 §5); a tenant administrator there is refused with the operator's name. Studio - draws the ledger switch **disabled, with that refusal as its title**, for a principal the gate would refuse — never a - live control that always answers 403 (the shape `useCanReadTrail` already avoids). + PLATFORM_ADMIN posture rung (ADR-0126 §5); a tenant administrator there is refused with a sentence naming the + platform operator. Studio pre-judges that verdict from the two served facts the console already reads for the walled + catalog doors (`features.tenancyPosture` through `useTenancyPosture`, and `user.isPlatformAdmin` on the session — + `views/metadata-admin/catalog-scope.ts`, `walledCatalogReadOnly`): the switch draws **disabled, in the console's own + words**, for a principal those facts refuse, and the server's refusal is shown verbatim after any attempt, as Setup's + page shows it today — never a live control that always answers 403, and never a client copy of the gate's sentence. - The item's ⋯ menu offers **Clone** (`POST /api/v1/automation//clone`, a new machine name required, the server's notice shown verbatim with the "switch the original off" offer, objectui#13270's shape); the clone lands in the paired package ([D3](#d3)). @@ -261,8 +266,8 @@ Cut as cards after this record merges; nothing below binds a seat before that. E "customized" chip and Reset on read-only packages ([D2](#d2); views, dashboards, reports first); (b) the ledger switch and Clone on the item ([D4](#d4)); (c) the clone door's `packageId`; (d) the paired-package create convention and dependency ([D3](#d3)); (e) the mixed rails, the chip and filter, the folded switcher ([D3](#d3)); - (f) the browse entry ([D5](#d5)) — #27356 row 12, PR #28076, seat-accepted 2026-10-30; it reverses no wall and lands - ahead of this record. + (f) the browse entry ([D5](#d5)) — #27356 row 12, PR #28076, merged 2026-10-30; it reversed no wall and landed ahead of + this record. 3. **Phase 3 — the catalog moves** ([D1](#d1), [D7](#d7)): `views/metadata-admin` directory, lists, item page, history and diagnostics re-homed under Studio's All-metadata area (per package and across packages); the three Setup administration pages; Setup → Metadata routes redirect; QA checklist and e2e door rewrites. From 101e337f3b79e0d38e26d626fd3a11e6e778c5d6 Mon Sep 17 00:00:00 2001 From: os-bill Date: Fri, 30 Oct 2026 13:27:18 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs(adr):=20ADR-0146=20=E2=80=94=20Rollout?= =?UTF-8?q?=20and=20Refs=20point=20at=20tracking=20epic=20#28130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maintainer asked for the rollout to have its own epic card (「同意,立专题卡」). #28130 carries the phase 2 and phase 3 child-card plan and is pm:blocked on this record's PR; the Rollout section and Refs now name it. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Utp6CaRN6wdrRyLKJSCMYH --- ...ministers-one-editor-per-item-paired-customize-package.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md index b486c8048de..01b2c4535c5 100644 --- a/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md +++ b/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md @@ -257,7 +257,9 @@ Setup → Metadata route whose administrative action has no Setup home yet. ## Rollout -Cut as cards after this record merges; nothing below binds a seat before that. Each card cites this record. +Tracked by epic [#28130](https://github.com/objectstack-ai/objectstack/issues/28130) (`pm:epic`, `pm:blocked` on +PR #28045), which carries the phase 2 and phase 3 child-card plan. Cut as cards after this record merges; nothing +below binds a seat before that. Each card cites this record and the epic. 1. **Now** (#27356 row 19, letter **A1**, independent of this record): Studio deletes a writable package's flow from the Automations item menu (confirm; the same `DELETE /meta/:type/:name` door; a pending draft of the item is @@ -292,6 +294,7 @@ landing), ADR-0029 D7 (the greyed-with-source presentation is this record's). No ## Refs +- Epic [#28130](https://github.com/objectstack-ai/objectstack/issues/28130) (the rollout's tracking card). - [#27356](https://github.com/objectstack-ai/objectstack/issues/27356) rows 12, 13, 14, 19, 20, 21 and their landed PRs #27376 (read-only flow switch), #27927 (overlay link only where an overlay exists). - ADR-0126 §7.4 (the Setup surface this record moves from) and §9 (first bullet lifted in part by D2; second bullet