@deslop/coding-standards 0.1.761 → 0.1.804
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/dist/{MutableRef-DT4DAKeI.mjs → MutableRef-NhSl8G9M.mjs} +145 -4
- package/dist/install.js +2 -2
- package/dist/oxlint.d.ts +9 -1
- package/dist/oxlint.js +305 -148
- package/package.json +1 -1
- package/skills/design/SKILL.md +73 -61
- package/skills/engineering/SKILL.md +31 -17
- package/skills/testing/SKILL.md +6 -4
package/package.json
CHANGED
package/skills/design/SKILL.md
CHANGED
|
@@ -5,103 +5,115 @@ description: 'UI and UX rules for screens and visual explanations. Use when buil
|
|
|
5
5
|
|
|
6
6
|
# Design
|
|
7
7
|
|
|
8
|
-
**Scope.** Follow repository-specific CODING_STANDARDS.md
|
|
8
|
+
**Scope.** Follow repository-specific CODING_STANDARDS.md and engineering.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Decide
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
**Direction.** Start from the actual task, audience, content and settled preferences. Make the next user action and its relevant content dominant, not generic "premium" styling. When a reference is useful, inspect the relevant accepted one for transferable hierarchy, density and interaction choices; distinguish observed details from inferred ones. Community brand analyses are inspiration, not verified current tokens. Keep durable visual choices at their owner, not repeated briefs. Ask only about a consequential tradeoff the evidence cannot settle; another agent cannot establish user taste.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<Empty><EmptyTitle>No runs yet</EmptyTitle><Button onClick={() => startRun()}>Run</Button></Empty>
|
|
18
|
-
// bad — "without hardcoding those values the desing/ui/ux need to be consistent with the rest of the app"
|
|
19
|
-
<span className="rounded-full bg-[#eef] px-[7px] text-[11px]">Draft</span>
|
|
20
|
-
<div className="flex flex-col items-center gap-2 p-6 text-muted-foreground">No runs yet</div>
|
|
21
|
-
```
|
|
14
|
+
**One meaning.** Each visible element must add information, enable a distinct action or clarify a relationship. Delete repeated headings, summaries, counts, status badges, decorative wrappers and controls that say or do the same thing. Remove explanations that merely restate the visible example/state. Keyboard shortcuts, screen-reader labels and responsive placement are not redundant visible controls; preserve their function.
|
|
15
|
+
|
|
16
|
+
**Scan-first.** Put the task, relevant content and next action where they can be identified without reading a paragraph. Use stable visual roles, not another card/badge/icon for every fact. Expose needed detail on demand, never hide a consequential warning or essential action.
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
| Content | Preferred treatment |
|
|
19
|
+
| -------------------------- | ------------------------------------------------------------------------- |
|
|
20
|
+
| Comparable records/options | Aligned rows/columns; consistent order, units and metadata placement |
|
|
21
|
+
| Familiar action | Conventional icon-only control with an accessible name; one visible owner |
|
|
22
|
+
| Ambiguous action | Clear text label, not an invented/guessed icon or redundant icon + text |
|
|
23
|
+
| Explanation | Real state/example first; text only for missing context or consequences |
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
|
-
//
|
|
27
|
-
<
|
|
28
|
-
//
|
|
29
|
-
<
|
|
26
|
+
// one visible action, named for assistive technology
|
|
27
|
+
<Button aria-label="Rename" size="icon"><PencilIcon aria-hidden /></Button>
|
|
28
|
+
// redundant label for an already-obvious action
|
|
29
|
+
<Button><PencilIcon />Rename</Button>
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Do not remove necessary names, status, comfortable hit targets or instructions merely to make a screen smaller.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
// good
|
|
36
|
-
<StarIcon aria-label="Default" />
|
|
37
|
-
// bad — "i don't want refresh buttons or stuffs like that in the ui/app"
|
|
38
|
-
<Button onClick={refetch}><RefreshIcon /></Button>
|
|
39
|
-
<Badge><StarIcon /> Default</Badge> // "Don't have icons/emoji and text that say the same thing"
|
|
40
|
-
```
|
|
34
|
+
## Build
|
|
41
35
|
|
|
42
|
-
**
|
|
36
|
+
**Canonical components.** Reuse the existing renderer, states and interactions for the same role. Inspect its relevant source/API, not a full catalogue; add missing primitives through the repository registry command. Fix wrong shared patterns at their owner when delivering retained code, not before an exploratory preview. Without a sibling, use the supplied reference and component defaults within settled preferences.
|
|
43
37
|
|
|
44
38
|
```tsx
|
|
45
|
-
//
|
|
46
|
-
<
|
|
47
|
-
//
|
|
48
|
-
<
|
|
39
|
+
// same model-selection control used elsewhere
|
|
40
|
+
<ModelPicker value={model} onValueChange={setModel} />
|
|
41
|
+
// another representation of the same job
|
|
42
|
+
<Select value={model} onValueChange={setModel} />
|
|
49
43
|
```
|
|
50
44
|
|
|
51
|
-
**
|
|
45
|
+
**Tokens and structure.** Use the existing app host, compiler, theme, shared components and Tailwind tokens. No custom-CSS/dynamic-class escape, hardcoded color/size exception or weakened shared rules. Keep surfaces flat and dense; group by proximity before adding borders or elevation. No nested cards or wrappers that merely label content again. Whitespace must support hierarchy, separation or comfortable use, not fill the page.
|
|
52
46
|
|
|
53
47
|
```tsx
|
|
54
|
-
//
|
|
55
|
-
<
|
|
56
|
-
//
|
|
57
|
-
<
|
|
48
|
+
// existing primitives and semantic tokens
|
|
49
|
+
<Empty><EmptyTitle>No runs yet</EmptyTitle><Button onClick={startRun}>Run</Button></Empty>
|
|
50
|
+
// parallel hand-built appearance
|
|
51
|
+
<div className="rounded-full bg-[#eef] px-[7px] text-[11px]">No runs yet</div>
|
|
58
52
|
```
|
|
59
53
|
|
|
60
|
-
**
|
|
54
|
+
**Typography.** Give headings, navigation, body text and data deliberate roles through the existing type scale, weights, line heights and readable line lengths. Use tabular numerals where values need comparison; let prose wrap without making controls inconsistent. Preserve established fonts and tokens rather than changing them for novelty. Do not substitute tiny labels, gratuitous capitals or isolated accent words for hierarchy.
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
// good
|
|
64
|
-
<TableRow data-state={selected ? 'selected' : undefined}>
|
|
65
|
-
// bad — "i'm not a fan that things like the empty star comes out on hover"
|
|
66
|
-
<Button className="opacity-0 group-hover:opacity-100" variant="ghost">
|
|
67
|
-
```
|
|
56
|
+
**Copy.** Name actions from the user's task, not implementation internals. Keep the same vocabulary across controls and confirmations. Use plain verbs and sentence case; labels describe outcomes, not decoration. Empty states offer a relevant next action; errors identify the failed action and available recovery. Reuse its existing control rather than repeating the action in text or adding another button; do not invent a recovery that cannot work.
|
|
68
57
|
|
|
69
|
-
|
|
58
|
+
| Weak | Useful |
|
|
59
|
+
| ---------------------- | ----------------------------------------------------------------- |
|
|
60
|
+
| `Submit` | `Save changes` → `Changes saved` |
|
|
61
|
+
| `Something went wrong` | `Couldn't save.` beside the existing retry action; keep the draft |
|
|
62
|
+
| `No data` | `No notes yet` beside the existing create action |
|
|
70
63
|
|
|
71
|
-
**
|
|
64
|
+
**Alignment.** Give related headings, search, pinned rows, dividers and records one owning grid/inset. Headers and row contents share columns; action columns stay fixed when labels wrap or are absent. Use the same component/size variant for equivalent controls: icon box/stroke, hit target, control height, baseline and spacing. Pinned content stays outside the scroll area; borders do not jump while scrolling. Fix the owning layout/component, not per-instance offsets; matching boxes alone does not establish optical alignment or legibility. Trace the cause before applying these repairs:
|
|
72
65
|
|
|
73
|
-
|
|
66
|
+
| Defect | Check | Owning repair |
|
|
67
|
+
| ---------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| Squashed icon/avatar | Fixed-size flex child shrinks | Preserve its canonical box with `shrink-0` |
|
|
69
|
+
| Trailing action disappears | Content track refuses to shrink | `min-w-0` on content; `shrink-0` on the control, or a shrinkable grid track |
|
|
70
|
+
| Wrapped rows look adrift | Center alignment against variable-height text | Consistent, deliberate top/baseline alignment |
|
|
71
|
+
| Identifiers look identical | Truncation hides the distinguishing segment | Preserve that segment; expose the full value through an existing keyboard/touch-accessible surface |
|
|
72
|
+
| Counts shift during updates | Proportional digits/inconsistent formatting | `tabular-nums` + consistent locale/units |
|
|
73
|
+
| Accents/tall scripts clip | Tight line height or text-box clipping | Fix the owning type-scale/overflow choice; don't shrink the font to fit |
|
|
74
|
+
| Missing metadata leaves separators | Empty optional slots still render | Omit orphaned separators/lines; reserve space only when the layout needs it |
|
|
74
75
|
|
|
75
|
-
**
|
|
76
|
+
**Interaction and state.** Controls remain discoverable, never hover-only. Use the canonical selected-row/active-tab treatment; do not add a second badge or check column that echoes it. Keep pending/error feedback beside its owner and preserve recoverable input. No redundant refresh, copied state or polling shortcut around the existing reactive integration.
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
**Motion.** Explain change without delaying input or moving content just for decoration. Reuse existing tokens/components; no new library for a fade or universal curve, duration, bounce or press scale.
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
| Interaction | Treatment |
|
|
81
|
+
| -------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| Typing, shortcuts, frequent navigation | Immediate response; no decorative movement |
|
|
83
|
+
| Trigger-anchored surface | Enter/exit from its trigger; a centered unanchored modal keeps a centered origin |
|
|
84
|
+
| Rapid toggle/reversal | Retarget from the visible state; no input lock, stale-target snap or wait for the prior transition |
|
|
85
|
+
| Drag/gesture | Follow the pointer; preserve the existing primitive's capture, cancellation and release behavior |
|
|
86
|
+
| Reduced motion | Preserve feedback through a suitable static or gentle non-spatial equivalent |
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
Use responsive entry easing and brief existing durations. Simple retargetable states suit transitions; gestures may need the existing spring. Prefer transform/opacity where appropriate, but CSS/WAAPI does not guarantee compositor execution. Profile observed performance problems, not every animation. Inspect rapid repetition/reversal and reduced motion, not only the final frame.
|
|
82
89
|
|
|
83
|
-
**
|
|
90
|
+
**Access and responsiveness.** Preserve the complete task on phones, not merely stacked desktop panes. Keep essential actions reachable with keyboard, touch and zoom. Use semantic structure, accessible names, visible focus, logical order and deliberate focus return. Inspect long/duplicate content, overflow, contrast and relevant failure/permission states. Do not remove an accessible affordance to satisfy visual minimalism.
|
|
84
91
|
|
|
85
|
-
|
|
92
|
+
| Mobile defect | Check |
|
|
93
|
+
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
94
|
+
| Hover remains after tap | Capability-aware styles; inspect the framework's handling before adding another gate |
|
|
95
|
+
| Input zoom/wrong keyboard | Readable input sizing + correct input type/mode; never disable browser zoom |
|
|
96
|
+
| Bottom controls disappear | Real browser chrome, software keyboard and safe areas; appropriate supported viewport sizing/insets |
|
|
97
|
+
| Drag blocks scrolling/content can't be copied | Scope gesture/selection restrictions to their owner; preserve scrolling, zoom and selectable content |
|
|
86
98
|
|
|
87
|
-
|
|
99
|
+
Touch and mouse can coexist; do not infer capabilities from user-agent strings or viewport width. No blanket suppression of overscroll, selection or native feedback without a demonstrated need and working replacement. Emulation verifies selected layout cases, not every phone behavior: affected device-specific keyboard/viewport/gesture contracts need target-device proof before completion.
|
|
88
100
|
|
|
89
|
-
##
|
|
101
|
+
## Prototype
|
|
90
102
|
|
|
91
|
-
**
|
|
103
|
+
**Try the question.** Build one rough representative screen or interaction in the existing host with realistic data. Inspect enough to make the trial trustworthy, then show it to the user before merge-readiness work. Label stubs and limits; a conceptual sketch is sufficient only when execution is unnecessary, never proof of working software. Set a short first-preview budget; show a partial result or blocker rather than expanding unseen. No production completeness or polished gallery first.
|
|
92
104
|
|
|
93
|
-
**
|
|
105
|
+
**Use the findings.** For layout questions, compare hierarchy or interaction, not color-only variants. Add attempts only for unresolved uncertainty, feedback or an explicit request—no fixed count; a style question can compare style. Keep useful comparisons; discard/rebuild freely and combine compatible strengths, not incompatible mechanisms. Test the weakest assumption while it can change the choice. A settled direction needs no manufactured taste question or exploration round.
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
## Verify and show
|
|
96
108
|
|
|
97
|
-
**
|
|
109
|
+
**Inspect retained UI.** Open actual captures at the sizes needed for the task. Compare related edges, columns, baselines and equivalent controls across rows/screens—not just successful clicks. Use realistic long names/URLs, translated labels, Unicode, missing fields and relevant 0/1/many records at the actual container width. Respect schema/API limits; never add a validation limit to make layout pass. Mix cases across rows. Check selected/focus/error states and scrolling; a clean default row can hide misalignment. Inspect hierarchy, density, legibility and clipping. Exercise the relevant keyboard/touch, narrow/wide, zoom and focus-return journeys; run axe where applicable. A clean scan does not prove contrast or usability. Inspect meaningful video frames and sequence; a playable file is not proof of a good composition. Batch relevant inspection/repairs; recheck affected views rather than restart a whole audit after each micro-edit. Visible misalignment, inconsistent controls or redundant elements remain defects even when types/tests pass; fix them before claiming acceptance.
|
|
98
110
|
|
|
99
|
-
**
|
|
111
|
+
**Show the design.** Use inspected screenshots for layout and short video for behavior. Compare at consistent sizes with states needed for the decision; no variant switcher just to see the options. A visual must add spatial or interactive information, not reproduce prose, a file list or a fake runtime screenshot. Link useful existing evidence rather than render another explanation page. Use the user's theme and verify the actual browser color preference. Preserve useful media and retire settled attempts; persistent previews are opt-in.
|
|
100
112
|
|
|
101
|
-
|
|
113
|
+
**Review surfaces.** Open on the outcome the user needs to judge, with technical detail available on demand. Group by changed behavior, not files or agent stages. A selected example, diagram or diff must reveal its scope; never make curated evidence look like complete coverage. Do not build a custom review dashboard when existing captures and the PR can answer the question. A design-skill edit is not a product-screen change.
|
|
102
114
|
|
|
103
|
-
|
|
115
|
+
## Image assets
|
|
104
116
|
|
|
105
|
-
|
|
117
|
+
Use image generation only for a needed illustrative asset, atmosphere, texture or icon exploration—not ordinary text, exact diagrams or fake working UI. Use the native tool exposed by the harness; no invented invocation or replacement API client when unavailable. Report missing capability honestly.
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
Describe purpose, placement, composition, palette and intended size/aspect ratio. For edits, supply the real source and state what remains unchanged. Generate only what the chosen direction needs; prefer existing icons/CSS when they express the job precisely. Inspect the returned asset at its intended size for crop, text/edge artifacts, contrast and fit. Preserve useful originals and identify generated assets as such; they are not runtime/browser proof. Keep only used assets in product source.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: engineering
|
|
3
|
-
description: '
|
|
3
|
+
description: 'TypeScript and Effect code conventions paired with shared lint. Use when designing, implementing or reviewing product/test code, including prototypes.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
**Scope.** Apply these rules and repository-specific CODING_STANDARDS.md.
|
|
6
|
+
**Scope.** Apply these rules and repository-specific CODING_STANDARDS.md.
|
|
7
7
|
|
|
8
|
-
**
|
|
8
|
+
**Dependency APIs.** Match manifest/lock versions. Inspect the relevant cloned upstream implementation, types and nearest real usage before inventing an API wrapper or workaround; never node_modules. Follow only the paths needed to settle the question, with no dependency install/build just to read source. Library APIs do not define coding policy.
|
|
9
9
|
|
|
10
10
|
**Diagnostics.** Use the shown idiom, not casts, weakened rules or a rewrite trading one diagnostic for another.
|
|
11
11
|
|
|
@@ -13,16 +13,18 @@ description: 'Engineering rules for product code, paired with the shared lint. U
|
|
|
13
13
|
|
|
14
14
|
**Clarity.** Plain, explicit, idiomatic code, names and files; read top to bottom without commentary or cleverness.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**Experiments.** Write with these idioms; reserve the full refactor/cleanup pass for retained delivery. Keep disposable source isolated and shared rules intact.
|
|
17
|
+
|
|
18
|
+
- **Requested only.** Check whether existing code, an installed module or a platform capability already satisfies the contract before writing more. Implement only the missing behavior; shorter code never justifies dropping requested behavior, safety or accessibility. Touch only what the request needs; unrelated improvements are reported. A refactor or cleanup request asks for depth instead: every rule applies to every line of the owned files.
|
|
17
19
|
- **Inward layers.** Domain and service code never import HTTP, RPC, or other transport types.
|
|
18
|
-
- **Building blocks.** Offer services, Layers
|
|
20
|
+
- **Building blocks.** For a consequential new interface, start with a realistic caller operation and its ordering, failure and lifetime obligations; hide useful complexity, not forwarded names. Offer services, Layers and functions the caller composes like any Effect module, never a bundle such as `serve(app)`. No mandatory architecture document or alternatives round.
|
|
19
21
|
- **No machinery.** Behave correctly instead of building hooks, guards, or generators to enforce behavior.
|
|
20
22
|
- **Behavior kept.** A refactor keeps behavior at every usage point. Two differences are accepted and reported with the change: one no usage point observes that makes the code simpler, and one a rule here causes, such as an error keeping its cause or sorted keys, unless a usage point parses it; printed diagnostics are not a contract. Any other behavior change is the user's decision, except a reachable bug's fix.
|
|
21
|
-
- **Reachable bugs.** A bug a real input from a usage point triggers is fixed and reported, with every consumer of the changed output checked. Handling for input no caller produces is deleted; anything that looks intentional or that other code relies on is kept and reported as possibly intentional.
|
|
22
|
-
- **Performance.** Improve performance in the touched code where you know how; measure on a realistic input only when a change claims speed or keeps a slower-looking form. Diagnose at the layer that owns the symptom: distributed spans for RPC/backend dependencies, React commits for rerenders, a browser performance profile for main-thread work. Correlate one real action before changing code, then repeat it on the fix; neither a screenshot nor a service name proves latency or trace coverage.
|
|
23
|
+
- **Reachable bugs.** A bug a real input from a usage point triggers is fixed and reported, with every consumer of the changed output checked. For hard bugs, use one symptom-specific replay and a prediction per probe; compare known-good/broken states when useful. Remove edits motivated by disproven hypotheses and check the original scenario after reducing a reproduction. Handling for input no caller produces is deleted; anything that looks intentional or that other code relies on is kept and reported as possibly intentional.
|
|
24
|
+
- **Performance.** Improve performance in the touched code where you know how; measure on a realistic input only when a change claims speed or keeps a slower-looking form. Diagnose at the layer that owns the symptom: distributed spans for RPC/backend dependencies, React commits for rerenders, a browser performance profile for main-thread work. Correlate one real action before changing code, then repeat it on the fix; neither a screenshot nor a service name proves latency or trace coverage. Time correct completed work under equivalent workloads/configuration; distinguish setup/cache/profiling cost and report run count/variation. Differences within noise are unproved, not speedups. Use existing instrumentation; profiling is not a ritual on every change.
|
|
23
25
|
- **Type safety.** A fix never weakens types to make a symptom go away: no widened or erased type, cast, dropped generic, or loosened exported type.
|
|
24
26
|
- **Domain.** Implement the definition the domain uses, such as a cycle for recursion, never the nearest syntactic proxy.
|
|
25
|
-
- **Reread.** Before
|
|
27
|
+
- **Reread.** Before delivering retained code, reread the diff and delete every line the outcome does not require.
|
|
26
28
|
|
|
27
29
|
**Happy path.** Failures flow through the error channel: no catch, retry, fallback, backup, or defensive check unless the request or an existing contract needs it.
|
|
28
30
|
|
|
@@ -52,7 +54,7 @@ Math.floor(Duration.toDays(DateTime.distance(oldest.timestamp, newest.timestamp)
|
|
|
52
54
|
import {glob} from 'glob' // a dependency Effect's FileSystem replaces
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
**Whole values.** Pass whole values or spread them. No parameter/callback/loop destructuring except useState and component ref; project fields only to exclude data the recipient must not receive.
|
|
57
|
+
**Whole values.** Pass whole values or spread them. No parameter/callback/loop destructuring except labeled tuple parameters, useState and component ref; project fields only to exclude data the recipient must not receive.
|
|
56
58
|
|
|
57
59
|
```ts
|
|
58
60
|
// good
|
|
@@ -176,7 +178,7 @@ const parsed = Option.getOrUndefined(Number.parse(event.target.value))
|
|
|
176
178
|
|
|
177
179
|
**Handlers.** A handler used once is an arrow in place; a handler used twice is a `function`.
|
|
178
180
|
|
|
179
|
-
**Pairs.**
|
|
181
|
+
**Pairs.** Positional tuples stay whole, read by index. Meaningful named bindings such as React state/setter pairs and explicitly labeled tuple parameters are useful exceptions.
|
|
180
182
|
|
|
181
183
|
**Accumulators.** No `let`: a fold or an Effect collection operation that says what it selects.
|
|
182
184
|
|
|
@@ -223,7 +225,7 @@ process.env.HOST ?? '0.0.0.0'
|
|
|
223
225
|
|
|
224
226
|
**Pipe.** A standalone `pipe`, nested at most three deep; never the `.pipe` method.
|
|
225
227
|
|
|
226
|
-
**Failures.**
|
|
228
|
+
**Failures.** Yield a yieldable domain error directly in a generator: `return yield* E.make(...)`. Keep `Effect.fail(error)` when the error is not yieldable; outside a generator, use `Effect.fail`. Do not infer yieldability from factory-call syntax.
|
|
227
229
|
|
|
228
230
|
```ts
|
|
229
231
|
// good
|
|
@@ -240,7 +242,7 @@ const text = Effect.fn('Ai.text')(function* (response: AiResponse) {
|
|
|
240
242
|
})
|
|
241
243
|
```
|
|
242
244
|
|
|
243
|
-
**Casts.** No `as`, `any
|
|
245
|
+
**Casts.** No `as`, `any` or erasing a known shape into `unknown`; `satisfies` and `as const` are the only assertions. Genuinely opaque SDK/framework inputs remain `unknown` until narrowed or decoded at their boundary—do not fabricate a shape to avoid that type. Decode incoming protocol data once with Schema before use.
|
|
244
246
|
|
|
245
247
|
```ts
|
|
246
248
|
// good
|
|
@@ -248,7 +250,7 @@ const params = Schema.decodeUnknownOption(Schema.Record(Schema.String, Schema.Un
|
|
|
248
250
|
return Effect.succeed([{text: part.text, type: 'text'} satisfies TextContent])
|
|
249
251
|
// bad — a cast satisfies one rule and the next flags it
|
|
250
252
|
const params = part.params as Record<string, unknown>
|
|
251
|
-
|
|
253
|
+
const params: unknown = part.params // erases an already-known shape
|
|
252
254
|
```
|
|
253
255
|
|
|
254
256
|
**Decoders.** `Schema.decodeUnknownEffect` only for `unknown` input; typed input uses `Schema.decodeEffect`, and JSON text goes through `Schema.fromJsonString`.
|
|
@@ -279,7 +281,7 @@ import {type Plugin, createServer} from 'vite'
|
|
|
279
281
|
export const EntryKind = Schema.Literals(['income', 'expense']) // no importer
|
|
280
282
|
```
|
|
281
283
|
|
|
282
|
-
**Readonly.**
|
|
284
|
+
**Readonly.** Required on service-shape properties. Allowed on class members and handwritten `Schema.suspend` cycle types; otherwise forbidden.
|
|
283
285
|
|
|
284
286
|
**Disables.** Fix the idiom or reproduce a rule defect. Inline disables require an unavoidable conflict and -- reason; never disable ordering or weaken file configuration. Report dependency-only diagnostics; rename filename violations.
|
|
285
287
|
|
|
@@ -377,7 +379,7 @@ static readonly layer = Layer.effect(Ledger, makeLedger) // a make with one call
|
|
|
377
379
|
query(sql: string): Effect.Effect<Rows> // a method signature instead of a readonly property
|
|
378
380
|
```
|
|
379
381
|
|
|
380
|
-
**Primitives.** Use Effect's primitives directly; rpcs and services already trace, and one scope owns each lifetime.
|
|
382
|
+
**Primitives.** Use Effect's primitives directly; rpcs and services already trace, and one scope owns each lifetime. Compose established independent I/O with Effect.all and explicit appropriate concurrency; keep order-dependent, transactional or resource-conflicting work sequential.
|
|
381
383
|
|
|
382
384
|
```ts
|
|
383
385
|
// good
|
|
@@ -442,7 +444,7 @@ const label = MutableRef.make<string>('') // repeats the inferred type
|
|
|
442
444
|
export type SandboxLike = {id: string; renew: (seconds: number) => Promise<unknown>} // a copy of an inferred shape
|
|
443
445
|
```
|
|
444
446
|
|
|
445
|
-
**Schema pairs.** Type pair immediately before every schema. Structs use Schema.Struct, never Schema.Class; reuse fields by spreading.
|
|
447
|
+
**Schema pairs.** Type pair immediately before every schema. Structs use Schema.Struct, never Schema.Class; reuse fields by spreading. Use Schema.optionalKey for absent fields; Schema.optional allows explicit undefined too, so reserve it for that contract.
|
|
446
448
|
|
|
447
449
|
```ts
|
|
448
450
|
// good
|
|
@@ -460,6 +462,18 @@ function cursorFromBigInt(value: bigint) {
|
|
|
460
462
|
payload: Schema.Struct(pipe(PortfolioVisitor.fields, Struct.pick(['color', 'id', 'name', 'x', 'y']))) // the schema itself fits
|
|
461
463
|
```
|
|
462
464
|
|
|
465
|
+
**Construction.** `schema.make` applies defaults and validates synchronously, throwing on failure; use it for trusted construction. For reachable fallible construction with defaults, use `schema.makeEffect` and map its `SchemaIssue.Issue` to the owning domain error. Effect decoders report `SchemaError`; use the correct error contract and do not revalidate already-narrowed data.
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
// good — reachable constructor failure stays in the error channel
|
|
469
|
+
pipe(
|
|
470
|
+
Name.makeEffect(input),
|
|
471
|
+
Effect.mapError(cause => NameError.make({cause, message: 'Invalid name'}))
|
|
472
|
+
)
|
|
473
|
+
// bad — input can fail a refinement even though its TypeScript type is string
|
|
474
|
+
Name.make(input)
|
|
475
|
+
```
|
|
476
|
+
|
|
463
477
|
**Cycles.** Handwrite each recursive-cycle type; annotate only Schema.suspend thunks. Noncycle types stay inferred; unions follow members.
|
|
464
478
|
|
|
465
479
|
```ts
|
|
@@ -557,6 +571,6 @@ const state = useState(false)
|
|
|
557
571
|
```
|
|
558
572
|
|
|
559
573
|
- **Pure render.** Derive display values from props and subscribed state during render; never mutate them or perform an RPC, write or subscription there. Event handlers own user-triggered actions; Effects synchronize external systems, not copied state or calculations. Reuse the existing router/atom integration rather than fetching in a new Effect.
|
|
560
|
-
- **State identity.** Keep one owner for each value, stable domain keys for list items and deliberate reset boundaries. Compiler memoization is a performance optimization, never a correctness or lifetime guarantee. Do not add manual memoization, compiler escape directives or weakened hook rules to hide an ownership problem.
|
|
574
|
+
- **State identity.** Keep one owner for each value, stable domain keys for list items and deliberate reset boundaries. For an observed rerender problem, derive the needed value in the existing atom graph instead of subscribing to frequently changing unrelated state. Compiler memoization is a performance optimization, never a correctness or lifetime guarantee. Do not add manual memoization, compiler escape directives or weakened hook rules to hide an ownership problem.
|
|
561
575
|
|
|
562
576
|
Testing judgment, fixtures, assertions and verification belong to the testing skill; these engineering rules still apply to test code.
|
package/skills/testing/SKILL.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: testing
|
|
3
|
-
description: '
|
|
3
|
+
description: 'Select and run black-box behavior proof for Effect apps/tools. Use when choosing, writing, reviewing or running tests; apply engineering to test code and keep exploratory proof question-sized.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Testing
|
|
7
7
|
|
|
8
|
-
**Scope.** Guard owned behavior, not coverage.
|
|
8
|
+
**Scope.** Guard owned behavior, not coverage.
|
|
9
|
+
|
|
10
|
+
**Timing.** An experiment needs trustworthy proof of its question, not comprehensive release coverage. Final acceptance applies to retained delivery; label stubbed/unproved behavior.
|
|
9
11
|
|
|
10
12
|
- **Worth it.** Test owned branching, computation, parsing/state transitions a plausible regression breaks; add missing valuable coverage before refactoring.
|
|
11
13
|
- **Seam.** Test the exported layer, service, or function of a package or an app's service as a black box, so rewriting the implementation leaves every test green; the browser proves UI components.
|
|
@@ -38,7 +40,7 @@ assert.strictEqual(Array.flatMap(attioProvider.groups, group => group.actions).l
|
|
|
38
40
|
|
|
39
41
|
## Choose cases
|
|
40
42
|
|
|
41
|
-
- **Contract.** Reachable input → observable output; a plausible wrong implementation must fail. Use the nearest public seam, not private helpers/new harnesses.
|
|
43
|
+
- **Contract.** Reachable input → observable output; a plausible wrong implementation must fail. Use the nearest public seam, not private helpers/new harnesses. When behavior is uncertain, settle one reachable case with a focused check and minimal implementation, then choose the next case from the findings; do not batch tests for an imagined implementation or require universal TDD.
|
|
42
44
|
- **Branches.** Exercise reachable empty/duplicate/concurrent/dependency-failure distinctions; no Cartesian product or random/repeated happy paths without a hypothesis.
|
|
43
45
|
- **Failure.** Effect.flip for expected failure; Effect.exit for both outcomes. Assert domain identity and preserved state/resources: no partial write, lost value, extra retry or leak. Wording/rejection alone is insufficient; no incidental order assertions.
|
|
44
46
|
- **Control.** Run against the unfixed implementation: the intended assertion fails, not setup/import/compilation. For refactoring, add missing coverage on old behavior first. Keep durable regressions, remove settled probes.
|
|
@@ -60,4 +62,4 @@ assert.strictEqual(Array.flatMap(attioProvider.groups, group => group.actions).l
|
|
|
60
62
|
- **Inventory.** Collect independent failures once instead of cancelling the suite at the first failure. Distinguish separate cases from repeated observations. A timeout receives one isolated rerun of that same test; after a genuine pass, stop investigating it. Do not call a bypassed selector or a skipped operation flaky.
|
|
61
63
|
- **Evidence.** Preserve the first failure, exact command, execution count and exit status. Separate cause from hypothesis, product defect from setup failure, and a skipped criterion from a passing one. A source read or overall green command never substitutes for a missing behavior check.
|
|
62
64
|
- **Stable inputs.** No writer changes a running check's source, dependencies, configuration or build inputs. A relevant edit invalidates its prior result; rerun affected criteria and reuse unaffected evidence. Independent research or browser journeys may continue without mutating those inputs.
|
|
63
|
-
- **Final proof.** Reconcile every required behavior on the final code. Screenshots/video prove visible outcomes; public-seam execution proves nonvisual behavior; fresh agents
|
|
65
|
+
- **Final proof.** Reconcile every required behavior on the final code. Screenshots/video prove visible outcomes; public-seam execution proves nonvisual behavior; use fresh agents for changed instructions only when they can settle a consequential unresolved uncertainty, not routine wording edits. Keep the result and useful evidence, not disposable drivers, fixture installs, reports or preview services.
|