Repository navigation
Setup and Studio: suggestions from a full HotCRM browser pass on 18.2.0: user onboarding, packaged automation state, run-now for scheduled flows, admin lists, and Studio entry, field table, flow inspector wording and one designer per item #27356
Description
Suggestions from HotCRM's full browser pass on platform 18.2.0 (hotcrm#2320). The HotCRM maintainer ruled at 2026-10-29T02:08Z that the platform parts go to objectstack as suggestion cards. This card holds Setup and Studio. The console parts are a sibling card.
Each row cites its track report on hotcrm#2320 and the finding id there. Each report's REPORT.md has the steps and screenshots. HotCRM is a read-only code package in Studio throughout.
Setup
| # | Observed on 18.2.0 | Report | Suggestion |
|---|---|---|---|
| 1 | Users → Create User: Permission Set is a free-text box with no picker, and there is no Position field. HotCRM grants access by position. | Setup S1 | A permission-set picker and an optional Position picker. |
| 2 | Position → Add holder lists names only. | Setup S2 | Show the email beside the name. |
| 3 | Packaged Automation: a green On toggle sits beside "Not running here" for five scheduled flows, and the reason names an environment variable. | Setup S3 | A muted toggle, or "On, but scheduled work is off on this deployment" in plain words. |
| 4 | A scheduled flow cannot be run on demand, so an admin cannot check a due-date reminder or a forecast snapshot. | Revenue S14 | A "Run now" action for administrators, recorded as a manual run. |
| 5 | Metadata lists (Positions, Permission Sets): singular titles, the API name is the first column, and at 390 px each row is about 180 px tall. | Setup S4 | Plural titles, the label first with the API name as subtext, compact rows on a phone. |
| 6 | Users row menu: Edit, Ban, Set Password, Impersonate, Set Manager. No Deactivate. | Setup S8 | A Deactivate action named as such. |
| 7 | Approval Requests: the column "Record ID" shows the record's name. | Setup S9 | Call it "Record". |
| 8 | A fallback approver's request looks like any other. It does not say the approver got it because the Sales Director position is empty. | Revenue S20 | Say on the request why it was routed to the fallback. |
| 9 | Permission set → field overrides lists the internal "Search Index (__search)" first. |
Setup S10 | Hide platform-internal fields. |
| 10 | List Display menu holds Export as CSV / XLSX. | Setup S7 | Put Export in the toolbar or the ⋯ menu. |
| 11 | Setup → All reports says "No reports — This app has no reports you can open." | Setup S14 | Hide the entry when empty, or point to the apps' reports. |
Studio
| # | Observed on 18.2.0 | Report | Suggestion |
|---|---|---|---|
| 12 | Studio is reached only from Home → "Build an app". There is no entry in the app switcher, the account menu or an app's top bar. | Studio S1 | An admin-only "Open in Studio" in the app switcher and on the app bar, read-only for a code package. |
| 13 | "Read-only · Customize with an overlay" shows on objects, flows and pages, which take no overlay, and lands on the package's All Metadata Types page. | Studio S2 | Show it only for overlay-able types, landing on that item's designer. |
| 14 | The object designer has no table of fields (API name, type, required, help). | Studio S3 | A Fields tab with those columns. |
| 15 | Flow node help is engine prose (submitter_id, onEmptyApprovers), and a placeholder reads "ADR-0105 D9 — organization…". |
Studio S4 | Business wording, with the detail behind "learn more". |
| 16 | The Create Record node cuts field names to 4–5 characters ("subj", "dueD"). | Studio S5 | Stack field over value, or widen the inspector. |
| 17 | The publish dialog says "Also changed: ~ nodes". | Studio S6 | Name the node and the property changed. |
| 18 | The flow clone notice is a seven-sentence paragraph with code spans; the toast says "Published 1 package-less flow draft". | Studio S7 | One line, plus a "switch the original off" button; name the flow in the toast. |
| 19 | Studio and Setup → Metadata each open a designer for the same flow or view (Setup auto-saves); only Setup can delete a flow or reset an overlay. | Studio S8 | One designer, with delete and reset in Studio. |
| 20 | The navigation tree says "No items in this package" for HotCRM Service and Marketing, while the app shows their contributed entries. | Studio S9 | Show contributed entries greyed, with their package (related: #26889). |
| 21 | A read-only package's flow Enabled switch is drawn on and green, like a live control. | Studio S10 | A muted state with a lock. |
| 22 | At phone width the flow canvas opens at 100% and cuts off branch nodes; an object's record cards show the internal "Account Name (Normalized)". | Studio S11 | Fit to view on open; card lines from highlightFields. |
Acceptance
Each row is either taken, with its own card if it needs one, or answered "will not do", with the reason.
Filed by the repo:hotcrm lane seat (session session_01J8VVAnPkgK6CWrJa6t7Fk5) from the #2320 UX summary, on the maintainer's ruling. Dedupe: read the titles of every open domain:ui card, every domain:ui card closed since 2026-10-26, and the open issue list. #26059 lists other Setup gaps (record scope, delegated admin) and none of these. #26889 is related to row 20 but covers Interfaces listing, not the tree.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p3 kept ·
domain:ui·area:studio· 2026-10-29T02:58Z⛔ Not a claim.
pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT
Dispatch order ·
domain:ui#1·session_01JQwxbZeBv2y91towxasSUT· 2026-10-29T03:26ZYou are the os-dev developer agent for exactly ONE card: #27356, in your own card thread. Your role definition is
.claude/agents/os-dev.mdin the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-rootAGENTS.mdandui/AGENTS.mdbefore your first edit, and pm-dispatchreferences/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/NNNNN" -H "Authorization: Bearer $GH_TOKEN"and/comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with[ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.Identity and branch: the seat's
Claim:comment on this card is your identity; itsBranch:line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWESTClaim:on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Dispatch the ui lane" one message with your branch name and wait. Worktreeobjectstack-issue-27356on that branch from a freshorigin/main;pnpm install(frozen lockfile); push withgit push -u origin <branch>(⛔ no force).Writes: PR only through the relay op
pr_create(node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array[{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=27356 --file=F --jsonrun ONCE with output captured to a file (timestamps only as{{NOW}}/{{WAS:…}}). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and onerun_rerun_failedthrough the relay. Report both counts (api_writeswith endpoints,mcp_callswith tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, then## 维护者速读six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon your diff, run each, record exits before any pipe, reconcile with--ran. Changeset in the root.changeset/when a published package changes. ⛔ui/.github/**and the rootci.ymlare out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.Ruling (cannot be re-ruled)
Triage 6486657637: p3 suggestion card; "one row becomes one card or one PR, each citing its report row, and is regraded on its own"; a row that names a broken capability is regraded up. This order takes three Studio rows, seat 1's area, as three sequential PRs from one thread, each
Part of #27356and citing its row and its hotcrm#2320 report finding. ⛔ Rows 1–11 (Setup) are seat 2's; ⛔ row 20 (Interfaces-adjacent, #26889) is not taken here; rows 12–15, 18, 19, 22 are not in this order.PM mechanism assumptions (measure on
origin/mainafterefdf11ae; disproof welcome)ui/packages/app-shell/src/views/studio-design/(StudioDesignSurface*, the flow status pins*flowStatusTruth-11779*) for where the switch reads the package's read-only flag. Control: an editable package's switch keeps today's look and stays operable.ui/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeConfigField.tsx/FlowKeyValueField(pinsFlowNodeInspector.fieldValueMap-11788,FlowKeyValueField.valueEnvelope). Wanted: the full field label is readable (stack field over value at narrow inspector width, or the inspector's own wrapping); pin with a long field name.ui/packages/app-shell/src/preview/DraftChangesPanel.tsx:~895(preview.changes.detailChangedKeys). Wanted: name what changed (the node and the property) instead of a bare~path; measure what the draft-changes payload carries first. If the payload does not carry node names, say so and stop at the seat for that row (it would be a server door, not a ui PR).Scope
Per PR: the one surface's file(s), its test(s), i18n keys only if new copy is needed (all locales per the parity suite; zh text is real Chinese, other locales fall back as the suite allows), changeset (
@object-ui/app-shell+@object-ui/consolepatch, the repo's pair for app-shell-only fixes). One ablation per PR that reds the new pin. ⛔ No sweep beyond the row; other findings go to the report. Stay under 300 changed lines per PR. Hand back after EACH PR (PR, head, report gist); start the next from a freshorigin/mainafter the previous merges.Tier
Quote
dispatch-gates --tierper diff. Expected none.TIER_DEFAULT, effortmedium.Clause-②: no,Metadata-protocol: none. Each PRPart of #27356; the card closes when every row is taken or answered across seats, not by these PRs.objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT
Claim: PM loop round 27 · 2026-10-29T03:29Z
Session:
session_01JQwxbZeBv2y91towxasSUT(seat; implementation by card thread sessionsession_01JQwxbWuU6sVfBYiy4dY4PA,mode:thread)Account:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-ldfxxi(the card thread's harness push branch, self-reported — the measured platform exception toclaude/issue-N-slug)Worktree:
objectstack-issue-27356in the card thread's cloneDomain:
domain:uiSeat:
domain:ui#1(seat post #25966)File surface: Studio rows only, one PR each, in order — row 21: the read-only package's flow Enabled switch under
ui/packages/app-shell/src/views/studio-design/; row 16: the Create Record node field/value map underui/packages/app-shell/src/views/metadata-admin/inspectors/(FlowNodeConfigField/FlowKeyValueField); row 17:ui/packages/app-shell/src/preview/DraftChangesPanel.tsx; each with its tests, i18n keys if new copy is needed, and the app-shell + console patch changeset. ⛔ Rows 1–11 (Setup, seat 2), row 20, and rows 12–15, 18, 19, 22 (stop on breach; explain in the report)Container & model:
M,mode:thread(the maintainer's word: 3 active card threads per seat, 2026-10-28 10:00Z / 12:11Z),model: TIER_DEFAULT,effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: Studio presentation in this lane's
@object-ui/app-shell| hotcrm#2320 Studio report S10 / S5 / S6 | a read-only switch reads as read-only, a field name is readable, a publish summary names what changedThread-read: 6487063370
Premise: holds as filed (HotCRM's 18.2.0 browser pass); the dev re-measures each row on
origin/mainafterefdf11aebefore its PR, and stops at the seat on row 17 if the draft-changes payload carries no node names.Serial constraints cleared: seat read of every open PR's file list at claim time — none touches
StudioDesignSurface*,FlowNodeConfigField,FlowKeyValueFieldorDraftChangesPanel.Resume-from: none
Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbWuU6sVfBYiy4dY4PA
os-dev-report
{ "issue": 27356, "row": 21, "report_finding": "hotcrm#2320 Studio S10", "status": "done", "branch": "claude/project-thread-ldfxxi", "pr": "https://github.com/objectstack-ai/objectstack/pull/27376", "head": "a24979d2", "session": "session_01JQwxbWuU6sVfBYiy4dY4PA", "premise_still_valid": true, "summary": "Measured on origin/main 28872e68: the Automations pillar's flow switch (flowSwitchEl in StudioDesignSurface.tsx) was already disabled on a read-only package but kept its bg-emerald-500 track at half opacity. Read-only now draws a muted track (on bg-muted-foreground/60, off /25), a hidden Lock icon, no hover fill and no opacity fade; thumb, word and aria-checked unchanged. Writable package unchanged. Part of #27356, row 21 only.", "files_changed": [ ".changeset/27356-studio-readonly-flow-switch.md", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.readOnlyFlowSwitch-27356.test.tsx" ], "line_budget": "224 changed lines (+221 / -3) against the order's 300", "tests": "new file StudioDesignSurface.readOnlyFlowSwitch-27356: 4/4; with the 8 existing switch files: 9 files 76/76 passed; app-shell type-check exit 0; ablation (read-only on-track back to bg-emerald-500 via ablation-replace, anchor 1 to 0): 1 failed / 3 passed, restored blob = HEAD blob 112c2439faa1, git diff HEAD empty", "gates": "dispatch-gates --commands: 34 derived, 34 run, all exit 0; --ran: 34 run, 0 NOT-MEASURED, 0 UNRUN; tier: no path-derived mandate; check:new-line-citations exit 0 (0 new); PR check-runs: in_progress at report time", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0 GitHub MCP calls (subscribe_pr_activity on the claude-code-remote server only)", "api_writes": "2 — fleet-write relay pr_create (#27376); this report via post-stamped (issue comment on #27356)", "deviations": [ "commit 48197f0e (WIP, pushed before the closure build) carries no Claude-Session / Co-authored-by trailer pair; later commits do; history not rewritten, named in the PR body", "PR body follows the order's six-line Chinese block plus the os-dev English sections; template headings What changes / Why / Verification kept" ], "open_questions": [], "out_of_scope_findings": [ "carrier: seat 2 (row 3 of #27356, Setup Packaged Automation toggle has the same green-while-not-running look) · noted, not filed" ] }objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT
Landed (partial, row 21) · seat
domain:ui#1· 2026-10-29T04:35ZPR #27376 merged as
7e200b4a68(seat record 6487871362). Row 21 taken (hotcrm#2320 Studio S10): on a read-only (code) package, Studio's flow Enabled switch now draws a muted track with a lock and no hover, while the thumb, the word andaria-checkedstill say on or off; a writable package's switch is unchanged.Part of #27356, so the card stays open and claimed: rows 16 and 17 follow from the same thread. Row 3's Setup toggle has the same look; that row is seat 2's and was passed to it.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbWuU6sVfBYiy4dY4PA
os-dev-report
{ "issue": 27356, "row": 16, "report_finding": "hotcrm#2320 Studio S5", "status": "done", "branch": "claude/project-thread-ldfxxi", "pr": "https://github.com/objectstack-ai/objectstack/pull/27405", "head": "5ebc5576", "session": "session_01JQwxbWuU6sVfBYiy4dY4PA", "premise_still_valid": true, "summary": "Measured on origin/main 7e200b4a: FlowKeyValueField drew key, value, expression toggle and remove on one line; in the 300 px Studio aside the key box was 104 px, 9 characters visible (Chromium probe). Each row now stacks: key plus remove over value plus toggle; 227 px, 24 characters. FlowNodeConfigField is the only caller, so every key / value map in the flow inspector stacks (one component, declared in the PR body). Stored values unchanged.", "files_changed": [ ".changeset/27356-studio-flow-map-rows-stack.md", "ui/packages/app-shell/src/views/metadata-admin/inspectors/FlowKeyValueField.tsx", "ui/packages/app-shell/src/views/metadata-admin/inspectors/FlowKeyValueField.stackedRows-27356.test.tsx" ], "line_budget": "132 changed lines (+117 / -15) against the order's 300", "tests": "new file FlowKeyValueField.stackedRows-27356: 2/2; the 65 app-shell test files importing FlowNodeInspector / FlowNodeConfigField / FlowKeyValueField: 971/971; app-shell type-check exit 0; ablation (delete the anchor closing the key line and opening the value line): 2/2 failed, restored blob = HEAD blob 9f71951b7644, git diff HEAD empty", "gates": "dispatch-gates --commands: 34 derived, 34 run, all exit 0 (ui scripts family re-run after removing a stale ignored ui/apps/site/node_modules in this worktree: first run 1 failed on quick-reference-commands-4149, rerun 169 passed); --ran: 0 NOT-MEASURED, 0 UNRUN; changeset families re-run on 5ebc5576 exit 0; check:new-line-citations 0 new; PR check-runs in_progress at report time", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0 GitHub MCP calls (subscribe_pr_activity on the claude-code-remote server only)", "api_writes": "2 — fleet-write relay pr_create (#27405); this report via post-stamped (issue comment on #27356)", "deviations": [ "the branch was recreated from origin/main 7e200b4a after #27376 squash-merged and its remote head was deleted; plain push, no force", "first push attempt was refused by check:commit-card-trailers (Part of line in the commit body); amended before publication" ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted in Acceptance notes: the Input primitive's md:text-sm outranks the map's text-xs at desktop width, so key boxes read at 14 px; pre-existing, polish" ] }objectstack-fleet commentedon Oct 29, 2026
domain:ui#2 · os-warren · session_01JQwxbXpF772qWJjojJvRXw
Seat note · Setup rows ·
domain:ui#2· 2026-10-29T05:33Z⛔ Not a claim on the rows marked "not carded".
Seat 2 holds the Setup rows (1–11). Seat 1 holds the Studio rows 16, 17 and 21. Status read on
origin/main9f76037:system+hiddenfields). Dispatched.packages/plugins/plugin-approvals/src/sys-approval-request.object.ts≈L270 (and its generated translations), not a ui string. It belongs to the server lane.UnifiedSidebar.tsx≈L596 says the sidebar reads no report list for it (objectui#12980). "Hide when empty" contradicts that, so the empty-state wording is the open door. It needs a ruling before a card.ListView.tsx≈L6110–6120). Measure which form HotCRM saw first.translateMetadataType, singular), so a plural title needs a plural type label from the registry. Measure before carding.objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT
Landed (partial, row 16) · seat
domain:ui#1· 2026-10-29T05:46ZPR #27405 merged as
b10fd65526(seat record 6488826661). Row 16 taken (hotcrm#2320 Studio): each key/value row in Studio's flow field editor now stacks the key line (with its remove button) above the value line, so neither input is squeezed at narrow inspector widths.Part of #27356, so the card stays open and claimed: row 17 (DraftChangesPanel "Also changed: ~ nodes" names the node and property) follows from the same thread.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbWuU6sVfBYiy4dY4PA
os-dev-report
{ "issue": 27356, "row": 17, "report_finding": "hotcrm#2320 Studio S6", "status": "done", "branch": "claude/project-thread-ldfxxi", "pr": "https://github.com/objectstack-ai/objectstack/pull/27432", "head": "751c7d1b", "session": "session_01JQwxbWuU6sVfBYiy4dY4PA", "premise_still_valid": true, "summary": "Measured on origin/main b10fd655: EntryDetail already reads both full bodies (published + draft) and every flow node carries id and label, so this stays a ui PR (no server door). computeChangeDetail took no type and compared nodes whole, giving the key row ~ nodes. It now takes the entry type; for a flow, diffFlowNodes matches nodes by id and the drill-in shows a row per node added / changed / removed, label first with the id in monospace, a changed node listing differing properties (config one level down). A reorder alone, a list not keyed by id, and non-flow types keep the old key row.", "files_changed": [ ".changeset/27356-studio-publish-flow-node-rows.md", "ui/packages/app-shell/src/preview/DraftChangesPanel.tsx", "ui/packages/app-shell/src/preview/__tests__/DraftChangesPanel.flowNodeRows-27356.test.tsx" ], "line_budget": "290 changed lines (+283 / -7) against the order's 300", "tests": "new file DraftChangesPanel.flowNodeRows-27356: 7/7; every ui test file naming DraftChangesPanel (72 files): 436/436; app-shell type-check exit 0; ablation (flow branch never taken, anchor 1 to 0): 5 failed / 2 passed (the two controls assert the old behaviour), restored blob = HEAD blob 0583bc280d81, git diff HEAD empty", "gates": "dispatch-gates --commands: 34 derived, 34 run, all exit 0; --ran: 0 NOT-MEASURED, 0 UNRUN; check:new-line-citations 0 new; fresh install and closure build before the run; PR check-runs in_progress at report time", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0 GitHub MCP calls (subscribe_pr_activity on the claude-code-remote server only)", "api_writes": "2 — fleet-write relay pr_create (#27432); this report via post-stamped (issue comment on #27356)", "deviations": [ "branch recreated from origin/main b10fd655 after #27405 squash-merged and its remote head was deleted; plain push, no force", "row 17's code was written and its test run against the previous head before #27405 merged, then applied as a patch on the fresh main; every reading above is on 751c7d1b" ], "open_questions": [], "out_of_scope_findings": [] }objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT
Landed (partial, rows 21 / 16 / 17) · seat
domain:ui#1· 2026-10-29T06:58ZPR #27432 merged as
968925c844(seat record 6489956578). Row 17 taken (hotcrm#2320 Studio S6): in the publish review, a flow draft no longer reads "Also changed: ~ nodes"; its steps are compared byidand each step added, changed or removed gets a row led by its label with the id beside it, and a changed step names the properties that differ (configone level down, e.g.config.fields). A reorder alone, or steps without ids, keep thenodesrow;edgesstays a key row.Seat 1's Studio rows of this card are all landed: 21 (#27376, read-only flow switch), 16 (#27405, key/value rows stack), 17 (#27432, this note). The Setup rows (1–11) are seat 2's, so the card stays open; seat 1 releases its claim and returns the card to
pm:queuefor them.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT
Release: session
session_01JQwxbZeBv2y91towxasSUT· cause: seat 1 sign-off (maintainer, 2026-10-29: 「当前任务处理完,合并后就下班」) after its three rows landed · topm:queue(labels and assignee already moved at landing note 6490159654; this line makes the release explicit)Resume-from:
origin/main— seat 1's Studio rows 21 (#27376), 16 (#27405) and 17 (#27432) are merged; no branch carries unmerged work for this card. Remaining rows: Setup rows 1–11 (seat 2's area, one card per row per triage's rule); any Studio row not named above is unclaimed.Generated by Claude Code