Skip to content

The draft status chip sits in the same place in every pillar's item header #12524

Closed

Description

@objectstack-fleet

Source

Measured on objectui main d4bc81eab, 2026-10-15, in a writable package. Data pillar: "Unpublished draft" is the chip right after the api-name chip, beside the title. Automations: the same, beside the title. Interfaces: "Unpublished draft" sits at the far right of the item header, next to the Design / Run toggle. Access: "This package's objects · saved as draft" sits beside the title. Four headers, two positions.

Target

  1. The status chip is the item header's second chip in every pillar: after the api-name or kind chip, before the meta slot.
  2. The right slot holds actions only (Design / Run, the Enabled switch, Explain access, the saved-at meta).
  3. StudioItemHeader takes the chip through chips, so the pillars stop placing it themselves.

File surface

packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (ifHeaderEl and the Access header), StudioItemHeader.tsx, tests beside.

Acceptance

  1. A test renders the four headers with a draft item and asserts the chip's position (the same parent, the same index) in all four.
  2. Screenshots of the four headers at 1280 px, light and dark.
  3. pnpm --filter @object-ui/app-shell test green.

Constraints

Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff from the 2026-10-15 Studio test pass: objectui main d4bc81eab, HotCRM 63db83e2, the vite console on :5180 against objectstack serve --dev on :4001, viewport 1482 × 1119, dark theme with a light-theme check.

Evidence

Screenshots from the test pass, kept on the temporary branch claude/studio-test-pass-evidence-20261015 of objectstack-ai/objectui (commit 72115588c, never merged: the maintainer ruled that screenshots do not enter main, and asked for a temporary branch referenced from the card). The branch's docs/design/studio-redesign/findings/2026-10-15/README.md maps every file to its card. Pane captures, 800 × 604 of a 1482 × 1119 viewport, dark unless named light.

automations header chip left
docs/design/studio-redesign/findings/2026-10-15/12524-automations-header-chip-left.jpg — automations header chip left.

data header chip left
docs/design/studio-redesign/findings/2026-10-15/12524-data-header-chip-left.jpg — data header chip left.

interfaces header chip right
docs/design/studio-redesign/findings/2026-10-15/12524-interfaces-header-chip-right.jpg — interfaces header chip right.

Parent: #12446

Body refreshed 2026-10-15T15:19Z by the epic PM session: an Evidence section with the test-pass screenshots added.

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
    and removed
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    on Oct 15, 2026
  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (domain:ui lane queue; an objectui#12446 test-pass card)
    Session: session_01SJn1GEkrbbBQkhGC26wEDw
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12524-header-status-chip
    Worktree: objectui-issue-12524 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: packages/app-shell/src/views/studio-design/StudioItemHeader.tsx (a status slot and the shared chip), packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (only the chips / actions / status props of the four item headers: ifHeaderEl, the DataPillar and AutomationsPillar headers, accessHeaderEl), metadata-admin/i18n.ts (new keys only, if any), new tests beside them, one .changeset/12524-*.md (stop on breach; explain in the report)
    Container & model: S, mode:cloud, model: opus (cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 5 on 「上限提到 5,提速」, this session's chat, 2026-10-15)
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: none
    Serial constraints cleared: objectui#12522 (the Interfaces header's Design / Run switch, ifHeaderEl) landed as PR objectui#12582 (830eb1f), and objectui#12514 (the Automations and Access empty branches) landed as PR objectui#12581 (f23eb01). The card's coordination with objectui#12455 and objectui#12456 is moot: both landed. Still in flight on StudioDesignSurface.tsx, this seat: objectui#12516 (the DataPillar add-field handler, not its header). Any textual overlap is resolved by merging origin/main.

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12524,
    "status": "done",
    "branch": "claude/issue-12524-header-status-chip",
    "pr": null,
    "session": "session_01GzRy6FiHuy1vpBecH2KRYM — this run's harness-stamped id (Claude-Session trailer on every commit)",
    "premise_still_valid": true,
    "summary": "Measured on f23eb01: the PM's assumption 1 holds. Data and Automations pass the amber 'Unpublished draft' span through chips, and Interfaces (ifHeaderEl) put it first in actions; that header was the only one with the chip in the wrong slot. I chose shape (a): StudioItemHeader takes a typed status prop ({label, title}) and draws the one shared amber chip (StudioStatusChip) after the identity and before the meta. The api-name and kind chips sit in an always-rendered contents wrapper (data-slot identity-chips), so the chip is child index 3 of the title row in all four pillars, whatever identity chips a pillar shows, and the layout does not change. Interfaces' right slot now holds actions only; Access's writable 'saved as draft' note goes through status, and its read-only link stays in actions. Branch head d9376cc, base f23eb01. origin/main has since moved 3 commits (1b3b5b1, daeb77f, 3e09c1e); none touches the header props or StudioItemHeader, and the merge is clean, so I did not merge.",
    "tests": "At HEAD d9376cc. New pin StudioItemHeader.statusPlace-12524.test.tsx: 4 passed (the four real pillars against one server double; with a draft, every chip is a child of the title row at one shared index, after the h1 and the identity-chips wrapper, outside the actions; the Interfaces actions keep their order (canvas-mode-toggle, then if-properties-toggle) with no chip among them; CONTROL with no draft: Data, Automations and Interfaces draw no chip; CONTROL with a read-only package: Access draws no status and its read-only link sits in the ml-auto actions container). Full app-shell suite (the file set of pnpm --filter @object-ui/app-shell test), run as pnpm exec vitest run packages/app-shell/ --shard=K/8 for K = 1 to 8, each under os-verify-lock, all VERDICT command-exit 0: 1420 files passed and 1 skipped (1421); 13538 tests passed and 9 skipped. The unsharded run could not finish inside the 10-minute foreground cap: one attempt was lost when the container restarted, and --shard=1/4 timed out at 590 s with no result, so both read as NOT MEASURED. Shard 1/8 on 81ec63c found 2 real failures in the existing pin StudioDesignSurface.flowCanvasChip-11665: it reads the title's parentElement as the header row, and my first wrapper enclosed the h1. d9376cc fixes this by wrapping only the identity chips, which leaves the h1 a direct child of the row; that pin is green, untouched. Ablation (source path; the test imports ./StudioDesignSurface relatively, so there is no dist step): I moved the Interfaces chip back into actions (mutation landed: grep count 1 for the injected chip, 0 for the removed status line), and the pin went red, 2 failed and 2 passed ('Interfaces: expected … to be …' and 'expected span to be null'); after git checkout HEAD -- StudioDesignSurface.tsx, git diff HEAD is 0 bytes.",
    "gates": "Local, at d9376cc, exit codes captured before any pipe: pnpm --filter @object-ui/app-shell type-check exit 0 (tsc --noEmit and tsc -p tsconfig.test.json; dependency closure built first with turbo run build --filter=@object-ui/app-shell^... --concurrency=2, 28/28 tasks, VERDICT 0); pnpm --filter @object-ui/app-shell build VERDICT 0; eslint on the 3 touched .tsx files exit 0 (0 errors; the 14 warnings are existing react-hooks warnings, none on edited lines); pnpm check:i18n-keys exit 0; pnpm check:i18n-drift exit 0 (0 keys added); node scripts/check-changeset-presence.mjs exit 0; pnpm check:new-line-citations exit 0 (0 new). Not applicable: check:i18n-designer-parity (no keys added), check:i18n-dead-keys (none retired); no new Intl.* call. objectui has no scripts/pm/dispatch-gates.mjs, so there is no --ran reconciliation; the list above is derived by hand from the dispatch. CI: no PR yet, so no check-runs to cite.",
    "mcp_calls": "5 — claude-code-remote add_repo ×2 (objectstack, hotcrm, read; answered read_available, nothing attached); github issue_read ×3 (get #12524, get_comments #12524, get_comments #12446). No write tool.",
    "api_writes": "0 REST writes to GitHub. git push only: claude/issue-12524-header-status-chip (empty branch, then 81ec63c, then d9376cc) and claude/issue-12524-evidence (57d29e5, then 33ef46f). Local backend only (not GitHub): POST /api/v1/packages plus 4 draft PUTs on my own --fresh HotCRM instance on :4123, since stopped.",
    "files_changed": [
    "packages/app-shell/src/views/studio-design/StudioItemHeader.tsx",
    "packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (only the status, chips and actions props of ifHeaderEl, the DataPillar and AutomationsPillar headers, accessHeaderEl, and the accessNoteEl they feed)",
    "packages/app-shell/src/views/studio-design/StudioItemHeader.statusPlace-12524.test.tsx (new)",
    ".changeset/12524-header-status-chip.md (new)"
    ],
    "screenshots": [
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-data-header-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-data-header-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-automations-header-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-automations-header-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-interfaces-header-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-interfaces-header-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-access-header-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-access-header-dark.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-interfaces-full-light.png?raw=true",
    "https://github.com/objectstack-ai/objectui/blob/33ef46f53/docs/design/studio-redesign/findings/12524/12524-interfaces-full-dark.png?raw=true"
    ],
    "deviations": [
    "Target 3 says the header takes the chip 'through chips'. I used a dedicated typed status prop (shape a): the header owns both where the chip sits and how it looks, and a pillar cannot pass markup or a link into it. That is the card's intent ('the pillars stop placing it themselves') with a stricter contract than its wording.",
    "The status chip gained shrink-0 whitespace-nowrap (shared StudioStatusChip). Measured at 1280 px in the Automations header: with main's classes the chip wrapped to two lines (37 px tall) and the title still truncated (117 of 163 px); with the new classes the chip stays on one line (21 px) and the title takes 110 px. The title truncation exists either way; it comes from that pane's width.",
    "Access open-set header (PermissionMatrixEditor.tsx, outside the claimed file surface) is unchanged: there the note still sits at the tab row's right end, as objectui#12456 placed it to stop the title row truncating the set's label. Its markup now comes from the shared StudioStatusChip, through accessNoteEl.",
    "The full app-shell suite was run as 8 shards over the identical file set, not as one pnpm --filter @object-ui/app-shell test invocation, because of the 10-minute foreground cap."
    ],
    "line_budget": "n/a",
    "open_questions": [
    {
    "question": "Status slot shape (PM assumption 2): a dedicated slot (a), or keep it in chips (b)?",
    "options": [
    "A: typed status prop {label, title}, drawn by the header after chips and before meta (built)",
    "B: keep it in chips with one shared chip component"
    ],
    "recommendation": "A, built. Business need: the measured defect was a pillar putting the chip in the wrong slot, and A makes that impossible. Long-term: the header owns position and look (contract-first). AI-error axis: the typed prop refuses JSX or a link, so a mistake is caught at compile time rather than silently tolerated. Startup axis: one optional prop and one component, no new capability."
    },
    {
    "question": "Is Access's 'This package's objects · saved as draft' note target 1's status chip (PM assumption 3)?",
    "options": [
    "A: yes in the writable posture: it goes through status; read-only shows StudioReadOnlyLink, an action, in actions (built)",
    "B: no: it stays a package note in chips, and Access has no status chip"
    ],
    "recommendation": "A, built. Measured: writable shows the amber note (title = engine.studio.access.bannerTitle); read-only shows the link (title = engine.studio.access.bannerTitleReadOnly), unchanged in place. It is the only draft signal the Access pillar shows, the card's Source counts it as Access's chip, and the right slot stays actions only. Caveat: the note is package-level, shown whether or not a draft exists; Access has no per-set draft status (see out_of_scope_findings)."
    },
    {
    "question": "Contract conflict: os-dev.md says to post the report on the card and open the draft PR; this dispatch's degraded channel says not to, because the fleet-write relay answers 403 from this container.",
    "options": [
    "A: follow the degraded channel: pr null, the PR body in pr_body_draft, the PM posts and opens (done)",
    "B: attempt the relay writes"
    ],
    "recommendation": "A. os-dev.md's write path goes through fleet-write, which the dispatch measured as refused here, so the file's step is unexecutable rather than overridden. Two smaller notes: the commit trailers follow objectui AGENTS.md's model-free pair (Co-authored-by: Claude), which takes precedence over the harness reminder; and AGENTS.md names the lock at /home/user/objectstack/scripts/pm/os-verify-lock.sh, while this container's read-only clone has it under /home/user/objectstack-ai/objectstack, which is the path I used."
    }
    ],
    "out_of_scope_findings": [
    "observation (not filed; none of classes a/b/c): permission sets show no item-level draft status. The Access open-set header (PermissionMatrixEditor renderStudio) has no hasDraft state, and its 'saved as draft' note is a constant package note shown with or without a pending draft · reach: read-only inference from the source plus the evidence package · carrier: none · Acceptance notes only · dedupe words: permission set draft status, Unpublished draft Access, matrix draft chip"
    ],
    "pr_title_draft": "feat(app-shell): the draft status chip sits in one place in every Studio item header (objectui#12524)",
    "pr_body_draft": "(elided by the seat: opened verbatim as the body of PR #12589, 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 #12589 from pr_title_draft and pr_body_draft, with assignee os-sales. "pr": null above is the session's own value at report time.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #12589 merged as ae923ec on main · read 2026-10-16T01:19Z

    probe on origin/main ae923ec reading control
    export function StudioStatusChip in StudioItemHeader.tsx 1 the one shared status chip
    status={ in StudioDesignSurface.tsx 5 lines the item headers pass the status as data
    StudioItemHeader.statusPlace-12524.test.tsx, .changeset/12524-header-status-chip.md present —

    State change: the card closed as completed through Fixes #12524, and pm:dispatched is removed in this act. The cloud session session_01GzRy6FiHuy1vpBecH2KRYM is archived. #12590 (objectui#12513), which was queued behind this PR, now merges main and resolves the shared import line in its follow-up round.


    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 requestpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions