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
Copy file name to clipboardExpand all lines: .agents/skills/cleanup/SKILL.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,3 +23,8 @@ Run each of these skills in order on the specified scope, passing through the sc
23
23
6.`/emcn-design-review $ARGUMENTS`
24
24
25
25
After all skills have run, output a summary of what was found and fixed (or proposed) across all six passes.
26
+
27
+
## Boundary Audit Guidance
28
+
29
+
- When removing route-local Zod schemas, replacing raw `fetch(` calls in hooks, or removing `as unknown as X` casts, do not introduce `// boundary-raw-fetch: <reason>` or `// double-cast-allowed: <reason>` annotations to silence the audit. Fix the underlying call instead — adopt a contract from `@/lib/api/contracts/**` and use `requestJson(contract, ...)` from `@/lib/api/client/request`, or refine the type so the double cast is unnecessary.
30
+
- Annotations are reserved for legitimate exceptions only: streaming responses, binary downloads, multipart uploads, signed-URL flows, OAuth redirects, external-origin requests, and double casts where no narrower type is available. Each annotation requires a non-empty reason; empty reasons fail `bun run check:api-validation:strict`.
Copy file name to clipboardExpand all lines: .cursor/rules/sim-architecture.mdc
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -65,3 +65,5 @@ Boundary HTTP request and response shapes for all routes under `apps/sim/app/api
65
65
- Clients call `requestJson(contract, ...)` from `apps/sim/lib/api/client/request.ts`; hooks import named type aliases from contracts, never `z.input/z.output`.
66
66
- Routes under `apps/sim/app/api/v1/**` use `apps/sim/app/api/v1/middleware.ts` for shared auth, rate-limit, and workspace access. Compose contract validation inside that middleware.
67
67
- `bun run check:api-validation` enforces this policy and must pass on PRs.
68
+
69
+
`bun run check:api-validation:strict` is the strict CI gate and additionally fails on annotations with empty reasons. Two per-line opt-out forms are recognized: `// boundary-raw-fetch: <reason>` (placed immediately above a legitimate raw `fetch(` call in `apps/sim/hooks/queries/**` or `apps/sim/hooks/selectors/**` for stream/binary/multipart/signed-URL/OAuth-redirect/external-origin cases) and `// double-cast-allowed: <reason>` (placed immediately above an `as unknown as X` cast outside test files). The reason must be non-empty. Whole-file allowlists for routes that legitimately import Zod for non-boundary reasons go through `INDIRECT_ZOD_ROUTES` in `scripts/check-api-validation-contracts.ts`, not per-line annotations.
- Hooks must import named type aliases from `@/lib/api/contracts/**` (e.g., `import { listEntitiesContract, type EntityList } from '@/lib/api/contracts/entities'`). Never write `z.input<...>` or `z.output<...>` in hooks.
130
130
- Hooks must not `import { z } from 'zod'`. Boundary types come from contract aliases; non-boundary helpers can stay in plain TypeScript.
131
-
- For non-contract endpoints (multipart uploads, binary downloads, streaming responses, signed-URL flows, OAuth redirects, external origins), it is OK to keep raw `fetch`. Mark each raw `fetch` with a TSDoc comment explaining which exception applies.
131
+
- For non-contract endpoints (multipart uploads, binary downloads, streaming responses, signed-URL flows, OAuth redirects, external origins), it is OK to keep raw `fetch`. Each legitimate raw `fetch(` call inside `apps/sim/hooks/queries/**` or `apps/sim/hooks/selectors/**` must be preceded by a `// boundary-raw-fetch: <reason>` annotation on the immediately preceding line (up to three non-empty preceding comment lines are tolerated). The reason must be non-empty — empty reasons fail strict mode. The audit script `scripts/check-api-validation-contracts.ts` (`bun run check:api-validation` / `bun run check:api-validation:strict`) enforces this.
Copy file name to clipboardExpand all lines: AGENTS.md
+24-1Lines changed: 24 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -124,10 +124,33 @@ Boundary HTTP request and response shapes for all routes under `apps/sim/app/api
124
124
- Contracts export named schemas (e.g., `createFolderBodySchema`) AND named TypeScript type aliases (e.g., `export type CreateFolderBody = z.input<typeof createFolderBodySchema>`)
125
125
- Clients (hooks, utilities, components) import the named type aliases from the contract file. They must never write `z.input<...>` / `z.output<...>` themselves
126
126
- Shared identifier schemas live in `apps/sim/lib/api/contracts/primitives.ts` (e.g., `workspaceIdSchema`, `workflowIdSchema`). Reuse these instead of redefining string-based ID schemas
127
-
- Audit script: `bun run check:api-validation` enforces boundary policy and prints ratchet metrics for route Zod imports, route-local schema constructors, route `ZodError` references, client hook Zod imports, and related counters. It must pass on PRs
127
+
- Audit script: `bun run check:api-validation` enforces boundary policy and prints ratchet metrics for route Zod imports, route-local schema constructors, route `ZodError` references, client hook Zod imports, and related counters. It must pass on PRs. `bun run check:api-validation:strict` is the strict CI gate and additionally fails on annotations with empty reasons
128
128
129
129
Domain validators that are not HTTP boundaries — tools, blocks, triggers, connectors, realtime handlers, and internal helpers — may still use Zod directly. The contract rule is boundary-only.
130
130
131
+
### Boundary annotations
132
+
133
+
A small number of legitimate exceptions to the boundary rules are tolerated when annotated. The audit script recognizes two annotation forms:
134
+
135
+
-`// boundary-raw-fetch: <reason>` — placed on the line directly above a raw `fetch(` call inside `apps/sim/hooks/queries/**` or `apps/sim/hooks/selectors/**`. Use only for documented exceptions: streaming responses, binary downloads, multipart uploads, signed-URL flows, OAuth redirects, and external-origin requests
136
+
-`// double-cast-allowed: <reason>` — placed on the line directly above an `as unknown as X` cast outside test files
137
+
138
+
Placement rule: the annotation must immediately precede the call or cast. Up to three non-empty preceding comment lines are tolerated, so additional context comments above the annotation are fine. The reason must be non-empty after trimming — annotations with empty reasons fail strict mode (`annotationsMissingReason`).
139
+
140
+
Whole-file allowlists for routes (legitimate non-boundary or auth-handled routes that legitimately import Zod for non-boundary reasons) go through `INDIRECT_ZOD_ROUTES` in `scripts/check-api-validation-contracts.ts`, not per-line annotations.
141
+
142
+
Examples:
143
+
144
+
```ts
145
+
// boundary-raw-fetch: streaming SSE chunks must be processed as they arrive
146
+
const response =awaitfetch(`/api/copilot/chat/stream?chatId=${chatId}`, { signal })
147
+
```
148
+
149
+
```ts
150
+
// double-cast-allowed: legacy provider type lacks the discriminator field we need
151
+
const provider =configasunknownasLegacyProvider
152
+
```
153
+
131
154
## API Route Pattern
132
155
133
156
Routes never `import { z } from 'zod'` and never define route-local boundary schemas. They consume the contract from `@/lib/api/contracts/**` and validate with canonical helpers from `@/lib/api/server`:
Copy file name to clipboardExpand all lines: CLAUDE.md
+24-1Lines changed: 24 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,10 +103,33 @@ Boundary HTTP request and response shapes for all routes under `apps/sim/app/api
103
103
- Contracts export named schemas (e.g., `createFolderBodySchema`) AND named TypeScript type aliases (e.g., `export type CreateFolderBody = z.input<typeof createFolderBodySchema>`)
104
104
- Clients (hooks, utilities, components) import the named type aliases from the contract file. They must never write `z.input<...>` / `z.output<...>` themselves
105
105
- Shared identifier schemas live in `apps/sim/lib/api/contracts/primitives.ts` (e.g., `workspaceIdSchema`, `workflowIdSchema`). Reuse these instead of redefining string-based ID schemas
106
-
- Audit script: `bun run check:api-validation` enforces boundary policy and prints ratchet metrics for route Zod imports, route-local schema constructors, route `ZodError` references, client hook Zod imports, and related counters. It must pass on PRs
106
+
- Audit script: `bun run check:api-validation` enforces boundary policy and prints ratchet metrics for route Zod imports, route-local schema constructors, route `ZodError` references, client hook Zod imports, and related counters. It must pass on PRs. `bun run check:api-validation:strict` is the strict CI gate and additionally fails on annotations with empty reasons
107
107
108
108
Domain validators that are not HTTP boundaries — tools, blocks, triggers, connectors, realtime handlers, and internal helpers — may still use Zod directly. The contract rule is boundary-only.
109
109
110
+
### Boundary annotations
111
+
112
+
A small number of legitimate exceptions to the boundary rules are tolerated when annotated. The audit script recognizes two annotation forms:
113
+
114
+
-`// boundary-raw-fetch: <reason>` — placed on the line directly above a raw `fetch(` call inside `apps/sim/hooks/queries/**` or `apps/sim/hooks/selectors/**`. Use only for documented exceptions: streaming responses, binary downloads, multipart uploads, signed-URL flows, OAuth redirects, and external-origin requests
115
+
-`// double-cast-allowed: <reason>` — placed on the line directly above an `as unknown as X` cast outside test files
116
+
117
+
Placement rule: the annotation must immediately precede the call or cast. Up to three non-empty preceding comment lines are tolerated, so additional context comments above the annotation are fine. The reason must be non-empty after trimming — annotations with empty reasons fail strict mode (`annotationsMissingReason`).
118
+
119
+
Whole-file allowlists for routes (legitimate non-boundary or auth-handled routes that legitimately import Zod for non-boundary reasons) go through `INDIRECT_ZOD_ROUTES` in `scripts/check-api-validation-contracts.ts`, not per-line annotations.
120
+
121
+
Examples:
122
+
123
+
```ts
124
+
// boundary-raw-fetch: streaming SSE chunks must be processed as they arrive
125
+
const response =awaitfetch(`/api/copilot/chat/stream?chatId=${chatId}`, { signal })
126
+
```
127
+
128
+
```ts
129
+
// double-cast-allowed: legacy provider type lacks the discriminator field we need
130
+
const provider =configasunknownasLegacyProvider
131
+
```
132
+
110
133
## API Route Pattern
111
134
112
135
Every API route handler must be wrapped with `withRouteHandler`. This sets up `AsyncLocalStorage`-based request context so all loggers in the request lifecycle automatically include the request ID.
Copy file name to clipboardExpand all lines: apps/sim/AGENTS.md
+24-1Lines changed: 24 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -76,9 +76,32 @@ Boundary HTTP request and response shapes for all routes under `apps/sim/app/api
76
76
- Each contract is built with `defineRouteContract({ method, path, params?, query?, body?, headers?, response: { mode: 'json', schema } })` from `@/lib/api/contracts`.
77
77
- Contracts export named schemas AND named TypeScript type aliases (e.g., `export type CreateFolderBody = z.input<typeof createFolderBodySchema>`). Clients import the named aliases — never `z.input<...>` / `z.output<...>` in hooks.
78
78
- Shared identifier schemas live in `apps/sim/lib/api/contracts/primitives.ts` (e.g., `workspaceIdSchema`, `workflowIdSchema`).
79
-
- Audit script: `bun run check:api-validation` enforces boundary policy and prints ratchet metrics for route Zod imports, route-local schema constructors, route `ZodError` references, client hook Zod imports, and related counters. It must pass on PRs.
79
+
- Audit script: `bun run check:api-validation` enforces boundary policy and prints ratchet metrics for route Zod imports, route-local schema constructors, route `ZodError` references, client hook Zod imports, and related counters. It must pass on PRs.`bun run check:api-validation:strict` is the strict CI gate and additionally fails on annotations with empty reasons.
80
80
- Domain validators that are not HTTP boundaries — tools, blocks, triggers, connectors, realtime handlers, and internal helpers — may still use Zod directly. The contract rule is boundary-only.
81
81
82
+
### Boundary annotations
83
+
84
+
A small number of legitimate exceptions to the boundary rules are tolerated when annotated. The audit script recognizes two annotation forms:
85
+
86
+
-`// boundary-raw-fetch: <reason>` — placed on the line directly above a raw `fetch(` call inside `apps/sim/hooks/queries/**` or `apps/sim/hooks/selectors/**`. Use only for documented exceptions: streaming responses, binary downloads, multipart uploads, signed-URL flows, OAuth redirects, and external-origin requests.
87
+
-`// double-cast-allowed: <reason>` — placed on the line directly above an `as unknown as X` cast outside test files.
88
+
89
+
Placement rule: the annotation must immediately precede the call or cast. Up to three non-empty preceding comment lines are tolerated, so additional context comments above the annotation are fine. The reason must be non-empty after trimming — annotations with empty reasons fail strict mode (`annotationsMissingReason`).
90
+
91
+
Whole-file allowlists for routes (legitimate non-boundary or auth-handled routes that legitimately import Zod for non-boundary reasons) go through `INDIRECT_ZOD_ROUTES` in `scripts/check-api-validation-contracts.ts`, not per-line annotations.
92
+
93
+
Examples:
94
+
95
+
```ts
96
+
// boundary-raw-fetch: streaming SSE chunks must be processed as they arrive
97
+
const response =awaitfetch(`/api/copilot/chat/stream?chatId=${chatId}`, { signal })
98
+
```
99
+
100
+
```ts
101
+
// double-cast-allowed: legacy provider type lacks the discriminator field we need
102
+
const provider =configasunknownasLegacyProvider
103
+
```
104
+
82
105
## API Route Pattern
83
106
84
107
Routes never `import { z } from 'zod'` and never define route-local boundary schemas. They consume the contract from `@/lib/api/contracts/**` and validate with canonical helpers from `@/lib/api/server`:
0 commit comments