Skip to content

Studio read-only posture: a lock in the app chip and one "Read-only · Customize with an overlay" link in the item header replace the banner, the rail footer, the amber badge and the form strips #12453

Closed

Description

@objectstack-fleet

Source

Epic #12446, decision 4. Measured on objectui main a2225f91 with the read-only app.objectstack.hotcrm package open: the Data pillar says read-only in five places at once — the amber "Read-only" badge beside the package name in the shell header, the full-width banner "Read-only package — switch to or create a writable package to edit.", the rail footer "Read-only", the Form tab's "Read-only layout — this package cannot be edited" badge, and the Form canvas strip "Read-only package · click a field to view its properties". The Automations and Access pillars add their own copies of the banner.

Target

Two signals, the same in every pillar:

  1. App chip. After the package name, a 12 px lock glyph and the word "Read-only" at 11 px muted, with a title that carries the current engine.studio.pkg.readonlyHint sentence. This replaces the amber badge.
  2. Item header. At the right of the item header row (object, flow, nav entry, permission set), one amber-tinted link, 28 px, 12 px / 500, with a layers glyph: "Read-only · Customize with an overlay", pointing at the package's metadata directory (/apps/setup/metadata?package=app.objectstack.hotcrm (the package id in the query), the route BuilderLanding already uses). For pillars whose item has no overlay route, the same chip renders without the link half.

Retired: the full-width banner in all pillars, the rail footer, the Form tab's read-only badge and the canvas strip (the Form tab keeps its plain Layout / Preview control; the sentence "click a field to view its properties" survives as the field card's title attribute). Publish drops to the outline disabled variant it already has; the rail's add button hides; "Add record" and record editing stay available because records are not metadata.

The wording ruling of objectui#11781 (StudioDesignSurface.readOnlyWording-11781.test.tsx) is kept: the sentence it pins moves into the chip's title and the link's title rather than disappearing.

File surface

packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (shell header chip, the readOnly banner in each pillar, the Data rail footer, the Form tab badge and strip), ObjectFormDesigner.tsx (the read-only strip), packages/app-shell/src/views/metadata-admin/i18n.ts (new key for the chip label; retired keys for the banner and footer in every locale).

Acceptance

  1. With the read-only package open, the string "Read-only" appears exactly twice in each pillar's DOM: the chip and the header link.
  2. The header link lands on /apps/setup/metadata?package=app.objectstack.hotcrm.
  3. readOnlyWording-11781, interfacesReadOnly-11136, automationsReadOnly-11124, automationsReadOnlySelect-11546, navEditClosesOnReadOnly-11167, ObjectValidationsPanel.readOnlyLook-11781 and ObjectFormDesigner.readOnlyDescription-11924 stay green or are updated in the same PR with the moved sentence, each ablated once.
  4. Before/after screenshots of Data Records and Automations with the read-only package, light and dark.

Constraints

  • Tailwind utilities and theme tokens only.
  • Gates: pnpm --filter @object-ui/app-shell test, lint, build, pnpm check:i18n.
  • Lands after the shell header card (it edits the chip that card introduces).

Reference artboard

docs/design/studio-redesign/data-records-readonly.html on objectui main (landed in #12458); data-records-readonly.png is its 1280 px render. The folder's README carries the shared numbers and what a pull request against this card must show: two screenshots per artboard it touches (light and dark, 1280 px, cropped to the artboard's region), a deviation list with a reason per line, and the card's named tests green or updated. Where this card and the artboard disagree, this card's numbers win and the disagreement is reported here.

Blocked-by: #12459

Body refreshed 2026-10-15T09:53Z by the epic PM session: a Reference artboard section added now that #12458 is on main. Earlier refresh 2026-10-15T08:56Z: the Blocked-by line now names the layout skeleton card #12459, which supersedes #12447, #12448 and #12449.

Parent: #12446

Activity

  1. added
    enhancementNew feature or request
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    on Oct 15, 2026
  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock read 2026-10-15T09:52Z: #12459 landed in #12460 (main cf430cd10e), so the Blocked-by line that names it is satisfied. The reference artboards are on main under docs/design/studio-redesign/ (#12458) and the body now carries a Reference artboard section naming this card's.

    Claimable by the domain:ui lane inside the epic's reservation, as #12450, #12452 and #12454 were claimed by seat domain:ui#4 at 09:35Z; acceptance against the artboard stays with the epic PM.

    Epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff.

  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (epic #12446 subtree)
    Session: session_01SJn1GEkrbbBQkhGC26wEDw
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12453-readonly-posture
    Worktree: objectui-issue-12453 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (the shell header's app chip; the readOnly banner, notes and footers in each pillar; the Data rail footer; the Form tab's read-only caption), ObjectFormDesigner.tsx (the read-only hint and strip), metadata-admin/PermissionMatrixEditor.tsx (only the Access set's read-only note that objectui#12456 placed at the tab row's right), packages/app-shell/src/views/metadata-admin/i18n.ts (the new chip and link keys; retired keys in every locale, engine.studio.designer.hint included), new tests beside them, the screenshots under docs/design/studio-redesign/after/ named 12453-*.png, one .changeset/12453-*.md (stop on breach; explain in the report)
    Container & model: L, mode:cloud, model: opus (cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; batch 5 on 「上限提到 5,提速」, this session's chat, 2026-10-15)
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: 6189329335
    Serial constraints cleared: every pillar card of this epic has landed (objectui#12450, #12451, #12452, #12454, #12455, #12456, #12488). The lane cards in the two regions this card shares landed minutes ago: objectui#12509 (the shell header, PR objectui#12549 a3d14e7) and objectui#12511 (the DataPillar header, PR objectui#12550 5249c24). In flight on StudioDesignSurface.tsx, this seat: objectui#12508 (the client.layered load sites only), which is disjoint. Carried by this card from earlier ACCEPTs: the retirement of engine.studio.designer.hint (no reader since PR objectui#12501), and the placement of the Access set's read-only note (the objectui#12456 dev's finding).

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12453,
    "status": "done",
    "branch": "claude/issue-12453-readonly-posture",
    "pr": null,
    "session": "session_01JeV2fvbxY8QRPVs1wpKue4 (os-dev cloud session; dispatched by seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw)",
    "premise_still_valid": true,
    "summary": "Rework round on head 93f035e, following the seat's review message. (1) Ruling B: BuilderLanding.tsx now exports overlayPath, and StudioReadOnlyLink imports it. The copied route string and the 'twin' note are gone. The function is only a module-level export: no barrel or package export (app-shell index.ts exports { BuilderLanding } by name only), and BuilderLanding is in the same lazy studioBuilder chunk as StudioDesignSurface. (2) The draft footer 'Edits save as drafts. Publish the package to apply them.' is gone on a read-only package from every aside that had it: the Data field aside, the Automations configuration aside, and both Interfaces properties asides (classic and wide-folded layouts). Nothing replaces it. Those four StudioInspector sites are the only readers of engine.studio.inspector.draftFooter, and Access has no such aside. (3) The placement deviation is recorded as ruled (A). Everything from the first round stands: the muted lock chip, one overlay link per pillar, 2 visible 'Read-only' per pillar on HotCRM, and the retired keys. The live re-measure on HotCRM gives 2 visible 'Read-only' in every pillar, light and dark, and no draft footer anywhere.",
    "tests": "HEAD 93f035e (merge of origin/main 5f8ecf6, which touches none of this PR's files). Under os-verify-lock: 54 files / 318 tests passed, VERDICT command-exit 0. That covers the 7 tests the card names, readOnlyPosture-12453, headerActions-12511, narrowHeader-12509, both 12303 read-only-reason tests, walledCatalogReadOnly-12183, packagedItemWriteGate-12169, PermissionMatrixEditor.readonly and .readonlyHeaderBadge, every DataPillar., AutomationsPillar., StudioDesignSurface.access* and StudioDesignSurface.interfaces* file, and BuilderLanding's tests. New pins this round, each a read-only case beside a writable CONTROL: Automations configuration aside (in automationsReadOnly-11124), Interfaces classic properties aside (in interfacesReadOnly-11136), Data field aside (in readOnlyWording-11781). The wide-folded Interfaces aside uses the same expression. Its layout needs an xl matchMedia match, so the classic site pins it, and the live browser check found no footer. Ablations this round used objectstack scripts/ablation-replace.mjs, with anchors that include unique context because the four footer lines are identical. Every mutation went red and every restore was blob == HEAD with git diff HEAD at 0 bytes. B1: Automations footer back, 11124 read-only aside case red. B2: Interfaces classic footer back, 11136 case red. B3: Data field footer back, 11781 read-only case red. B4: overlayPath route changed in BuilderLanding, posture-12453 4/4 pillar cases red. The first-round ablations A1 to A6 stand. Browser on HotCRM (objectstack dev --fresh :4061, console :5261), per pillar, light and dark: Data, Automations, Interfaces and Access each show 2 visible 'Read-only', no draft footer, and a link with href /apps/setup/metadata?package=app.objectstack.hotcrm.",
    "gates": "On 93f035e: pnpm check:i18n-keys exit 0; check:i18n-drift exit 0; check:i18n-designer-parity exit 0; check:i18n-dead-keys exit 0; check:new-line-citations exit 0; node scripts/check-changeset-presence.mjs exit 0 (1 changeset). Under one lock, VERDICT command-exit 0: turbo build of the app-shell dependency closure 28/28, then @object-ui/app-shell type-check, then @object-ui/app-shell build (dist completeness 1104 files). Control-byte grep on the touched files: no hits. eslint --no-inline-config on the 12 touched TS/TSX files: 0 errors, 17 warnings. 16 are pre-existing (same count on base 9231820). 1 is new: react-refresh/only-export-components on the overlayPath export that ruling B asks for. lint.yml deliberately sets no --max-warnings, and other studio-design files already export helpers beside components. check-nul-bytes.mjs does not exist in objectui: NOT MEASURED, the control-byte grep stands in. CI families: NOT MEASURED, because there is no PR yet.",
    "mcp_calls": "This round: ReadNotifications x1 (the seat's review message). Cumulative GitHub MCP: mcp__github__issue_read x4 (reads only). Plus mcp__claude-code-remote__add_repo x2 (read; nothing attached). No write tool.",
    "api_writes": "0 REST writes. git push only, to objectstack-ai/objectui claude/issue-12453-readonly-posture. This round pushed 640dc74, 91fcc6c and 93f035e (earlier: the empty branch, 4507d5b, 4ec7424, db7a1f9, 187ea18). No PR, comment, label or assignee write.",
    "open_questions": [
    {
    "question": "Ruling B leaves one new react-refresh/only-export-components warning: BuilderLanding.tsx now exports a function beside its component. Keep it, or move overlayPath into the non-component module studioScope.ts (which BuilderLanding already imports from), at the cost of widening the surface by one more file?",
    "options": [
    "A. Keep: lint passes with 0 errors, warnings are not gated, and the route lives in one place as ruled.",
    "B. Move overlayPath into studioScope.ts and import it from both files: no warning, one more file in the surface."
    ],
    "recommendation": "A, because ruling B's goal (one route spelling, axis 3) is met and no gate reads warnings (axis 4). B is a cosmetic follow-up the seat can order if it wants a warning-free file."
    }
    ],
    "out_of_scope_findings": [
    "carrier: this PR · the first round's finding (a), the draft footer on read-only asides, was ruled in scope by the seat and is now implemented and pinned here; nothing to file"
    ],
    "pr_title_draft": "feat(app-shell): Studio read-only posture, a lock in the app chip and one overlay link in the item header (objectui#12453)",
    "pr_body_draft": "(elided by the seat: opened verbatim as the body of PR #12565, read back identical)"
    }

    Relayed verbatim by seat domain:ui#4 (session session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final message, the degraded write channel. The seat opened the draft PR #12565 from pr_title_draft and pr_body_draft, with assignee os-sales. "pr": null above is the session's own value at report time. This is the session's second final report, after the seat's review round on 187ea18; the first report (head 187ea18) is superseded and was not relayed.


    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:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtreepriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions