Skip to content

Commit c2f3eaa

Browse files
committed
fix(audits): close guardrail detector gaps and correct guidance from release review
1 parent d00a1d8 commit c2f3eaa

18 files changed

Lines changed: 91 additions & 49 deletions

‎.agents/skills/add-block-preview/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ To pull an already-GA block from discovery surfaces on hosted (incident, depreca
5353
- **Clone-not-remove:** gated blocks stay in `getAllBlocks()` output as clones with `hideFromToolbar: true` — `.find`-by-type consumers rely on this. Never filter them out.
5454
- **Keys are registry block types.** Never `custom_block_*` (parse drops them — custom blocks have their own enabled/disabled lifecycle).
5555
- **The shared hidden-predicate is `isHiddenUnder`** (`apps/sim/blocks/visibility/context.ts`). Never restate the preview/disabled rule inline at a new consumer.
56-
- **Process-global caches stay ungated.** Shared builders such as `getExposedIntegrationTools` (`lib/integrations/tool-catalog.ts`) build the ungated universe; per-viewer filtering happens at consumer time via `isHiddenUnder`. Never move gating into a shared builder.
56+
- **Process-global caches stay ungated.** Shared builders such as `getExposedIntegrationTools` (`apps/sim/lib/integrations/tool-catalog.ts`) build the ungated universe; per-viewer filtering happens at consumer time via `isHiddenUnder`. Never move gating into a shared builder.
5757
- Gating is **surface hiding, not secrecy** — the full config ships in the client JS bundle. Anything truly secret cannot be a registered block.
5858

5959
## Tests

‎.agents/skills/add-block/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ When several fields are mutually exclusive alternatives, mark them all `required
310310
other paths ever get a chance to supply the value.
311311

312312
**Constraints (block-wide):**
313-
- `canonicalParamId` must not equal any subblock `id` in the block.
313+
- `canonicalParamId` must not equal the `id` of a subblock that has no `canonicalParamId`. A group member may share it, as `channel` does in the canonicalParamId Pattern below.
314314
- One canonical id links exactly one basic/advanced pair for one logical parameter. Groups are keyed by canonical id across every subblock and hold one `basicId`, so two operations that each need a pair need two canonical ids.
315315
- All members of a group share the same `required` status.
316316

‎.agents/skills/add-connector/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ The user sees a toggle button (ArrowLeftRight) to switch between the selector dr
214214

215215
1. **Every selector field MUST have a canonical pair** — a corresponding `short-input` (or `dropdown`) field with the same `canonicalParamId` and `mode: 'advanced'`.
216216
2. **`required` must be set identically on both fields** in a pair. If the selector is required, the manual input must also be required.
217-
3. **`canonicalParamId` must match the key the connector expects in `sourceConfig`** (e.g. `baseId`, `channel`, `teamId`). The advanced field's `id` should typically match `canonicalParamId` (connector config fields differ from block subBlocks here; the block rule that `canonicalParamId` must not equal a subblock id does not apply).
217+
3. **`canonicalParamId` must match the key the connector expects in `sourceConfig`** (e.g. `baseId`, `channel`, `teamId`). The advanced field's `id` should typically match `canonicalParamId` (connector config fields differ from block subBlocks here; the block rule that `canonicalParamId` must not equal the id of a subblock without a `canonicalParamId` does not apply).
218218
4. **`dependsOn` references the selector field's `id`**, not the `canonicalParamId`. The modal propagates dependency clearing across canonical siblings automatically — changing either field in a parent pair clears dependent children.
219219

220220
### Selector canonical pair example (Airtable base → table cascade)

‎.agents/skills/add-settings-page/SKILL.md‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ Each grep lists candidates; review every match against the expected ones named b
4646

4747
1. Find hand-rolled shells that should be `SettingsPanel`:
4848
`git grep -n "flex h-full flex-col bg-\[var(--bg)\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
49-
— expected matches: the workspace and organization `settings/layout.tsx` shells, the shared
50-
header shell (`components/settings/settings-header.tsx`), `CredentialDetailLayout` (the
51-
`settings/secrets/[credentialId]` exception), or an entitlement/loading gate. A detail
52-
sub-view is never a match: it passes `back={{ text, icon: ArrowLeft, onSelect }}` to
53-
`SettingsPanel`. Anything else is a violation: render it through `SettingsPanel`.
49+
— expected matches: the workspace and organization `settings/layout.tsx` shells and the
50+
shared header shell (`components/settings/settings-header.tsx`); an entitlement/loading gate
51+
is also fine. `CredentialDetailLayout` (the `settings/secrets/[credentialId]` exception) is
52+
an exempt hand-rolled shell outside these pathspecs. A detail sub-view is never a match: it
53+
passes `back={{ text, icon: ArrowLeft, onSelect }}` to `SettingsPanel`. Anything else is a
54+
violation: render it through `SettingsPanel`.
5455
2. Find hand-rolled title blocks:
5556
`git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
5657
— the only title is the `<h1>` in `settings-header.tsx`; a non-heading value at that size

‎.agents/skills/babysit/SKILL.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ conditions freshly after every push.
8888
across all pages has `isResolved: true`, and every check has finished and passed, stop —
8989
report the outcome (see "Reporting" below) and skip the rest of this list.
9090

91-
2. **If the PR has a merge conflict**, resolve it with step 6 (its rebase-based sync flow and
92-
the `/ship` gates; a merge commit would be discarded by that rebase), then steps 7–8: push
93-
with `--force-with-lease` and re-trigger review.
91+
2. **If the PR has a merge conflict**, rebase rather than merge (step 6's rebase would discard a
92+
merge commit): `git fetch origin staging && git rebase origin/staging`, resolve each conflict
93+
and `git rebase --continue` until the rebase finishes. Then run step 6 (the sync check and the
94+
`/ship` gates), then steps 7–8: push with `--force-with-lease` and re-trigger review.
9495

9596
3. **If no review has run yet** (fresh PR, no bot comments): both run automatically on PR open —
9697
confirm via `gh pr checks <n>` (look for `Greptile Review` and `cubic · AI code reviewer`) and

‎.claude/rules/sim-react-performance.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ return items.sort(compare)
7777
return [...items].sort(compare)
7878
```
7979

80-
**Do NOT use `toSorted()` / `toReversed()` / `with()` / `toSpliced()`.** They are ES2023 *runtime* methods — and a tsconfig `"lib": ["ES2023"]` only makes them **type-check**, it does not make them **run**. Next/SWC compiles syntax but does **not** polyfill prototype methods, and the default browserslist still includes browsers without them (`toSorted` landed in Safari 16 / iOS 16, so any device capped at iOS 15 throws `TypeError: x.toSorted is not a function` and crashes the page). The perf difference vs `[...arr].sort()` is negligible (both allocate one array), so the copy-then-sort form is used everywhere: whether a module reaches the browser is not visible from its path. `check:utils` flags `toSorted`/`toReversed`/`toSpliced` repo-wide and `with` when called with a numeric index (an identifier index is indistinguishable from OpenTelemetry's `context.with`).
80+
**Do NOT use `toSorted()` / `toReversed()` / `with()` / `toSpliced()`.** They are ES2023 *runtime* methods — and a tsconfig `"lib": ["ES2023"]` only makes them **type-check**, it does not make them **run**. Next/SWC compiles syntax but does **not** polyfill prototype methods, and the default browserslist still includes browsers without them (`toSorted` landed in Safari 16 / iOS 16, so any device capped at iOS 15 throws `TypeError: x.toSorted is not a function` and crashes the page). The perf difference vs `[...arr].sort()` is negligible (both allocate one array), so the copy-then-sort form is used everywhere: whether a module reaches the browser is not visible from its path. `check:utils` flags `toSorted`/`toReversed`/`toSpliced` repo-wide and any `.with(index, value)` call whose second argument is not a function literal; OpenTelemetry's `context.with(ctx, () => …)` passes, and one handed its callback as an identifier needs `// utils-lint-allow: <reason>`.
8181

8282
## Run independent awaits in parallel
8383

‎.claude/rules/sim-settings-pages.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ return (
9393
## Title + description live in navigation metadata
9494

9595
`apps/sim/components/settings/navigation.ts` is the single source of truth (the
96-
`settings/navigation.ts` in the route tree is only a re-export shim). Every `SETTINGS_SECTION_REGISTRY` entry carries a one-line `description`; `SettingsPanel`
96+
`settings/navigation.ts` in the route tree is only a re-export shim). Each `SETTINGS_SECTION_REGISTRY` entry's one-line description is
97+
`unified.description` (a plane projection's `planes.<plane>.description` overrides it where that
98+
plane's scope differs), or, for a section that exists only on a standalone plane, its
99+
`planes.<plane>.description`; `SettingsPanel`
97100
resolves both via `getSettingsSectionMeta(plane, section)` and the
98101
`SettingsSectionProvider` the settings shell wraps around the active section.
99102

‎.claude/rules/sim-styling.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Draw a line with a real `border-*` utility. Never hand-roll one as `shadow-[inse
9595
- **Errors** → `error` prop. Never `className={cn(err && 'border-[var(--text-error)]')}`.
9696
- **Leading icon** → `icon` prop (rendered 14px in `--text-icon`).
9797
- **Trailing buttons** (reveal/copy/fetch) → `endAdornment`.
98-
- **Inner-input styling** (e.g. `font-mono`, number-spinner reset) → `inputClassName` (ChipInput only). See `app/workspace/[workspaceId]/settings/components/billing/components/usage-limit-field/usage-limit-field.tsx`.
98+
- **Inner-input styling** (e.g. `font-mono`, number-spinner reset) → `inputClassName` (ChipInput only). See `ee/whitelabeling/components/whitelabeling-settings.tsx`.
9999
- **`ChipModalField` controls take NO className.** Pass `title`/`value`/`onChange`/`error`/`hint`/`required`/`flush`. The field owns label, control, and error/hint rendering. See `app/workspace/[workspaceId]/skills/components/skill-modal/skill-modal.tsx`.
100100

101101
### What className MAY carry

‎.claude/rules/sim-url-state.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Pick exactly one home for each piece of state (table below). Put state in the UR
1919
| Home | Trigger | Example |
2020
| --- | --- | --- |
2121
| **URL (nuqs)** | Client view-state worth a link: tab, filter, search, sort, pagination, selected-entity id, an open "view" modal/drawer that is a destination | `?tab=licenses`, `?category=Communication`, `?page=3`, `?skillId=abc` |
22-
| **React Query** | Server/remote data fetched from an endpoint | `useMcpServers(workspaceId)`, `useSkills(workspaceId)` |
22+
| **React Query** | Server/remote data fetched from an endpoint (hook rules: `.claude/rules/sim-queries.md`) | `useMcpServers(workspaceId)`, `useSkills(workspaceId)` |
2323
| **Zustand** | Cross-component client state that must NOT be in the URL: high-frequency, large, ephemeral, socket-synced | canvas pan/zoom, live cursor, drag state, resize widths, unsaved buffers |
2424
| **`useState`** | Purely local single-component UI; also the snappy mirror of a debounced URL search | a hover flag, a transient dialog target, the live text of a debounced search box |
2525

‎.cursor/rules/sim-react-performance.mdc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ return items.sort(compare)
8080
return [...items].sort(compare)
8181
```
8282

83-
**Do NOT use `toSorted()` / `toReversed()` / `with()` / `toSpliced()`.** They are ES2023 *runtime* methods — and a tsconfig `"lib": ["ES2023"]` only makes them **type-check**, it does not make them **run**. Next/SWC compiles syntax but does **not** polyfill prototype methods, and the default browserslist still includes browsers without them (`toSorted` landed in Safari 16 / iOS 16, so any device capped at iOS 15 throws `TypeError: x.toSorted is not a function` and crashes the page). The perf difference vs `[...arr].sort()` is negligible (both allocate one array), so the copy-then-sort form is used everywhere: whether a module reaches the browser is not visible from its path. `check:utils` flags `toSorted`/`toReversed`/`toSpliced` repo-wide and `with` when called with a numeric index (an identifier index is indistinguishable from OpenTelemetry's `context.with`).
83+
**Do NOT use `toSorted()` / `toReversed()` / `with()` / `toSpliced()`.** They are ES2023 *runtime* methods — and a tsconfig `"lib": ["ES2023"]` only makes them **type-check**, it does not make them **run**. Next/SWC compiles syntax but does **not** polyfill prototype methods, and the default browserslist still includes browsers without them (`toSorted` landed in Safari 16 / iOS 16, so any device capped at iOS 15 throws `TypeError: x.toSorted is not a function` and crashes the page). The perf difference vs `[...arr].sort()` is negligible (both allocate one array), so the copy-then-sort form is used everywhere: whether a module reaches the browser is not visible from its path. `check:utils` flags `toSorted`/`toReversed`/`toSpliced` repo-wide and any `.with(index, value)` call whose second argument is not a function literal; OpenTelemetry's `context.with(ctx, () => …)` passes, and one handed its callback as an identifier needs `// utils-lint-allow: <reason>`.
8484

8585
## Run independent awaits in parallel
8686

0 commit comments

Comments
 (0)