You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit d5c5ea3
Browse filesBrowse the repository at this point in the historyBrowse files
feat(platform): fail helper copy lines in check:platform-design
helper-copy fails a hint on an EMCN field (or any hint that spells out
copy), a description on a form Modal, a written SettingsRow or DetailHeader
subtitle, and a non-empty hint in the field data the Platform renders,
including the credential descriptors and catalog generator outside its
tree. disabledReason, error and aria-* stay untouched, as do confirm and
feedback dialog bodies and computed row state.
A line that must stay is named in HELPER_COPY_OWNERS as
<file>#<label, title or field id> with its reason; the design owner's
untouched copy is grouped there for his review. The Platform contract,
the per-job checklist and the UI copy rule say how to fold a line into
the placeholder, label or option instead.
Copy file name to clipboardExpand all lines: .claude/rules/sim-platform-views.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,7 @@ like that" is not one.
19
19
20
20
| Job | Use | Never |
21
21
| --- | --- | --- |
22
+
| Explain a field, dialog or row | Its label, placeholder and options (`Access keys (long-lived)`); `error` for validation, `disabledReason` for a locked control, the dialog's Setup guide for steps | A `hint`, form `Modal``description`, written `SettingsRow`/`DetailHeader` subtitle or data `hint` (`check:platform-design``helper-copy`; a line that must stay is named in `HELPER_COPY_OWNERS`) |
22
23
| First read of a view | Render nothing for data-backed content while pending (static chrome renders at once), `FailureNotice` when the read fails, `EmptyState` when it settles empty. Read the query's `status`, not an empty list. An action's own pending label (`pendingLabel`, a Load action's `Loading…`) is feedback, not loading copy | A skeleton, shimmer, placeholder rows or loading copy (`check:platform-design``loading-copy`); a pending hint, placeholder or detail line; treating empty as loading |
23
24
| Failed read |`FailureNotice`, labelled Retry. `intent='warning'` where the read partly answered | A hand-built retry button or `InlineNotice` + `Button`|
24
25
| Failed background refresh |`FailureNotice` above the content it keeps | Replacing content already on screen |
Copy file name to clipboardExpand all lines: .claude/rules/sim-ui-copy.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ paths:
13
13
14
14
**Do not add subtitles, helper text, or descriptive copy beneath headings, labels, cards, or settings by default.** Prefer one concise, self-explanatory heading or label. Only add supporting copy when the user explicitly asks for it, or when it is necessary to prevent misunderstanding or error — and never use it to restate the heading.
15
15
16
-
This applies to app UI outside the Platform: settings rows, modals, panels, cards, list rows, empty states, form fields, and section headers. Platform views (`app/(product)`, `platform`) follow `apps/sim/platform/AGENTS.md`; marketing surfaces (`app/(landing)`, docs) follow `constitution.md`.
16
+
This applies to app UI outside the Platform: settings rows, modals, panels, cards, list rows, empty states, form fields, and section headers. Platform views (`app/(product)`, `platform`) follow the stricter one-line-per-control rule in `apps/sim/platform/AGENTS.md`, which `check:platform-design` enforces (`helper-copy`); marketing surfaces (`app/(landing)`, docs) follow `constitution.md`.
17
17
18
18
**Carve-out — settings section metadata.**`SettingsNavigationItem.description` in `components/settings/navigation.ts` stays required, and `SettingsPanel` keeps rendering it as the page subtitle. Settings sections are reached through a nav list where the description is the only thing distinguishing adjacent sections, so it earns its place by the "prevents misunderstanding" test. Keep those descriptions verb-first and one line, per `sim-settings-pages.md`. Everything else on a settings page — inline `<p>` blurbs under section headings, field hints, modal bodies, row subtitles — follows the default rule above.
19
19
@@ -32,14 +32,14 @@ This applies to app UI outside the Platform: settings rows, modals, panels, card
32
32
<ChipModalFieldtitle='Workspace name' />
33
33
```
34
34
35
-
If a heading needs a subtitle to be understood, the heading is wrong. Fix the heading — don't append a second line.
35
+
If a heading needs a subtitle to be understood, the heading is wrong. Fix the heading — don't append a second line. For a field, bake the meaning into the line itself first: a format into the placeholder (`us-gov-west-1`), a bound or scope into the label (`Idle timeout (hours, min 1)`), a trade-off into the option (`Access keys (long-lived)`), or point to the dialog's setup guide.
36
36
37
37
## When supporting copy earns its place
38
38
39
39
Keep (or add) a description only when it carries information the label cannot, and its absence would cause a mistake:
40
40
41
41
-**Irreversible or destructive consequences** — "Deleting this workspace removes every workflow and log. This cannot be undone."
42
-
-**A non-obvious format, unit, or bound** — "Comma-separated. Max 50 domains.", "Cost per 1M input tokens."
42
+
-**A non-obvious format, unit, or bound the label, placeholder and options cannot hold** — "Comma-separated. Max 50 domains.", "Cost per 1M input tokens."
43
43
-**A security or access implication** — "This key is shown once and grants full workspace access."
44
44
-**A state the user cannot otherwise see** — "Inherited from your organization's policy."
45
45
-**Instructional copy that advances a flow** — "We sent a 6-digit code to you@example.com."
Copy file name to clipboardExpand all lines: .cursor/rules/sim-platform-views.mdc
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -17,6 +17,7 @@ like that" is not one.
17
17
18
18
| Job | Use | Never |
19
19
| --- | --- | --- |
20
+
| Explain a field, dialog or row | Its label, placeholder and options (`Access keys (long-lived)`); `error` for validation, `disabledReason` for a locked control, the dialog's Setup guide for steps | A `hint`, form `Modal` `description`, written `SettingsRow`/`DetailHeader` subtitle or data `hint` (`check:platform-design` `helper-copy`; a line that must stay is named in `HELPER_COPY_OWNERS`) |
20
21
| First read of a view | Render nothing for data-backed content while pending (static chrome renders at once), `FailureNotice` when the read fails, `EmptyState` when it settles empty. Read the query's `status`, not an empty list. An action's own pending label (`pendingLabel`, a Load action's `Loading…`) is feedback, not loading copy | A skeleton, shimmer, placeholder rows or loading copy (`check:platform-design` `loading-copy`); a pending hint, placeholder or detail line; treating empty as loading |
21
22
| Failed read | `FailureNotice`, labelled Retry. `intent='warning'` where the read partly answered | A hand-built retry button or `InlineNotice` + `Button` |
22
23
| Failed background refresh | `FailureNotice` above the content it keeps | Replacing content already on screen |
**Do not add subtitles, helper text, or descriptive copy beneath headings, labels, cards, or settings by default.** Prefer one concise, self-explanatory heading or label. Only add supporting copy when the user explicitly asks for it, or when it is necessary to prevent misunderstanding or error — and never use it to restate the heading.
11
11
12
-
This applies to app UI outside the Platform: settings rows, modals, panels, cards, list rows, empty states, form fields, and section headers. Platform views (`app/(product)`, `platform`) follow `apps/sim/platform/AGENTS.md`; marketing surfaces (`app/(landing)`, docs) follow `constitution.md`.
12
+
This applies to app UI outside the Platform: settings rows, modals, panels, cards, list rows, empty states, form fields, and section headers. Platform views (`app/(product)`, `platform`) follow the stricter one-line-per-control rule in `apps/sim/platform/AGENTS.md`, which `check:platform-design` enforces (`helper-copy`); marketing surfaces (`app/(landing)`, docs) follow `constitution.md`.
13
13
14
14
**Carve-out — settings section metadata.** `SettingsNavigationItem.description` in `components/settings/navigation.ts` stays required, and `SettingsPanel` keeps rendering it as the page subtitle. Settings sections are reached through a nav list where the description is the only thing distinguishing adjacent sections, so it earns its place by the "prevents misunderstanding" test. Keep those descriptions verb-first and one line, per `sim-settings-pages.md`. Everything else on a settings page — inline `<p>` blurbs under section headings, field hints, modal bodies, row subtitles — follows the default rule above.
15
15
@@ -28,14 +28,14 @@ This applies to app UI outside the Platform: settings rows, modals, panels, card
28
28
<ChipModalField title='Workspace name' />
29
29
```
30
30
31
-
If a heading needs a subtitle to be understood, the heading is wrong. Fix the heading — don't append a second line.
31
+
If a heading needs a subtitle to be understood, the heading is wrong. Fix the heading — don't append a second line. For a field, bake the meaning into the line itself first: a format into the placeholder (`us-gov-west-1`), a bound or scope into the label (`Idle timeout (hours, min 1)`), a trade-off into the option (`Access keys (long-lived)`), or point to the dialog's setup guide.
32
32
33
33
## When supporting copy earns its place
34
34
35
35
Keep (or add) a description only when it carries information the label cannot, and its absence would cause a mistake:
36
36
37
37
- **Irreversible or destructive consequences** — "Deleting this workspace removes every workflow and log. This cannot be undone."
38
-
- **A non-obvious format, unit, or bound** — "Comma-separated. Max 50 domains.", "Cost per 1M input tokens."
38
+
- **A non-obvious format, unit, or bound the label, placeholder and options cannot hold** — "Comma-separated. Max 50 domains.", "Cost per 1M input tokens."
39
39
- **A security or access implication** — "This key is shown once and grants full workspace access."
40
40
- **A state the user cannot otherwise see** — "Inherited from your organization's policy."
41
41
- **Instructional copy that advances a flow** — "We sent a 6-digit code to you@example.com."
Copy file name to clipboardExpand all lines: apps/sim/platform/AGENTS.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,6 +39,8 @@ Use `ActivityRow` for a first-line glyph, avatar or artwork stack, title/detail
39
39
40
40
Inputs and textareas share the neutral field frame, resting border and 8px text inset. Hover changes only the frame border; the fill remains unchanged. Focus alone preserves resting paint. Required placeholders describe the expected input without replacing the label. `viewOnly` supplies native read-only behavior and an always-visible shared copy action in the sidebar’s 24px trailing slot. Textareas place the same action at the top-right. Copy feedback remains visible for four seconds before returning to the copy action. Read-only fields show a not-allowed cursor without dimming, while their copy action remains interactive. TextArea defaultSize selects regular (76px), expanded (112px) or large (240px); skill instruction editors use large. Invite recipient fields share the regular textarea height and insets. Quiet `SearchField` is the explicit focus exception: its subtle underline starts at the typing edge, excluding the leading icon and trailing controls, and appears on hover or focus while the background remains unchanged. Counts inherit adjacent label metrics, use ordinary inline spacing and align on the text baseline. Disabled dropdown triggers and items retain their resting opacity, ink, border and fill with a not-allowed cursor; disabled behavior prevents activation, and hover/press never repaints them. Optional disabledReason descriptions use the shared tooltip and remain available to keyboard users. Supply them for non-obvious restrictions such as inherited access, protected administrators or unavailable prerequisites. Button and Checkbox expose the same optional reason; DataTable forwards selectionDisabledReason from its row metadata. Reuse the actual policy reason rather than a generic disabled message, and keep the control disabled while its explanation is focused. Secret reveal and copy use the same 24px icon action and field inset; text labels belong in their accessible names and tooltips.
41
41
42
+
One line per control. A field, form dialog, settings row or page header carries its meaning in its label, placeholder and options, never in a second line beneath it: no field `hint`, no form `Modal``description`, no written `SettingsRow` or `DetailHeader` subtitle, and no `hint` in the field data a dialog renders. Put a format in the placeholder (`us-gov-west-1`), a bound or scope in the label (`Idle timeout (hours, min 1)`) or an option (`Access keys (long-lived)`), point to the dialog's Setup guide, or delete the line. A validation message is an `error`; a disabled control's reason is its `disabledReason`; a preference's explanation belongs in its existing About tooltip. Only a line nothing else can hold stays (a one-time secret, an irreversible consequence, a security or privacy exposure, a state the viewer cannot otherwise see), named with that reason in `HELPER_COPY_OWNERS`; `check:platform-design` (`helper-copy`) fails any other.
43
+
42
44
Toolbar choices use `ChoiceMenu`, the same compact quiet button and menu as Home's activity period. A toolbar action uses the existing quiet compact Button or IconButton. Page-level actions live in the control bar beneath the title and description; an action for a particular record belongs with that record. `Select` and `SelectField` provide bordered field chrome only for labeled forms, including modal forms. Immediate preferences, row roles and toolbar filters use compact text triggers without borders or chevrons. Searchable, multiple-value and date-range pickers retain their specialized behavior with their text presentation composed from the same compact quiet Button; do not place a full-width field picker in a control bar. Reuse the existing owner for the interaction and compare its actual trigger with Home before accepting it.
43
45
44
46
Button-based field pickers use the owning Base UI Select.Label or Combobox.Label, through FieldFrame’s label slot, so clicking a caption focuses its control without closing and reopening the popup. A calendar popover uses a noninteractive caption explicitly associated with its trigger and displayed value. Text inputs retain native labels. Preserve selected values or counts in accessible names or descriptions alongside field hints and errors.
`${HELPER_COPY_MESSAGES[kind]}: bake it into the placeholder, label or option, or delete it. A line that must stay goes in HELPER_COPY_OWNERS as ${entry} with its reason`
0 commit comments