History

agents, notes

Rhys Sullivan committed 6 months ago

Commit bfb87a01 parent 63cdca32 files · +200 −0Browse files

Unified · Split

2 files
  1. AGENTS.md +4 −0
  2. notes/livestore-effect-testing-porting.md +196 −0
AGENTS.md+4−0
@@ -55,3 +55,7 @@ inspect it there. · 54 unmodified lines
55- `packages/kernel/*`: execution runtimes and code execution substrate.55- `packages/kernel/*`: execution runtimes and code execution substrate.
56- `apps/local`, `apps/cloud`, `apps/cli`, and `apps/desktop`: product entry56- `apps/local`, `apps/cloud`, `apps/cli`, and `apps/desktop`: product entry
57 points that compose the packages.57 points that compose the packages.
58
59## Other
60
61Please make note of mistakes you make in MISTAKES.md. If you find you wish you had more context or tools, write that down in DESIRES.md. If you learn anything about your env write that down in LEARNINGS.md.
notes/livestore-effect-testing-porting.md+196−0
@@ -0,0 +1,196 @@
1# LiveStore Effect Testing Patterns Worth Porting
2
3LiveStore is useful as a reference repo for Effect-heavy test ergonomics, not
4as a wholesale tooling model. Executor already has the stricter Effect lint
5posture and a simpler Bun/Turbo toolchain. The part worth copying is the small
6test harness shape that makes scoped Effect tests easier to write and easier to
7debug when they hang.
8
9Reference checkout:
10
11```txt
12.reference/livestore
13```
14
15## What to Port
16
17### Effect test context helper
18
19LiveStore's `packages/@livestore/utils-dev/src/node-vitest/Vitest.ts` wraps
20`@effect/vitest` with:
21
22- `withTestCtx(test)` for per-test Effect setup.
23- `makeWithTestCtx(...)` for reusable layer/timeout config.
24- A default timeout, longer in CI.
25- `Effect.logWarnIfTakesLongerThan` before the timeout trips.
26- `Effect.timeout(...)`.
27- `Effect.provide(...)` for per-test layers.
28- `Effect.scoped` so finalizers and spans close predictably.
29- Optional tracing/log layer wiring.
30
31Executor should port the shape, not the exact implementation. LiveStore is on
32Effect 3, while Executor is on Effect 4 beta. The local helper should be tiny
33and typed against the current `@effect/vitest` and `effect` APIs.
34
35Likely home:
36
37```txt
38packages/core/sdk/src/testing.ts
39```
40
41If the helper starts pulling in cloud-specific, Node-server, or plugin-specific
42dependencies, stop and keep those helpers package-local instead.
43
44### Timeout diagnostics for slow Effect tests
45
46Several Executor tests already have manual sleeps, `Promise.race`, test-level
47timeouts, or long-running fixtures. A `withTestCtx`-style helper would make
48failures more readable by logging before timeout rather than only surfacing a
49late Vitest timeout.
50
51Good initial targets:
52
53- `apps/cloud/src/mcp-miniflare.e2e.node.test.ts`
54- `apps/cloud/src/mcp-session.e2e.node.test.ts`
55- `packages/plugins/openapi/src/sdk/oauth-refresh.test.ts`
56- `packages/plugins/mcp/src/sdk/connection-pool.test.ts`
57- `packages/core/execution/src/tool-invoker.test.ts`
58
59The first slice should convert only one painful test cluster. If it makes the
60test body clearer and failure output better, then expand.
61
62### Scoped fixture/runtime pattern
63
64LiveStore's `tests/sync-provider/src/sync-provider.test.ts` builds a shared
65`ManagedRuntime` in `beforeAll`, disposes it in `afterAll`, then creates
66per-test providers with isolated ids. That pattern is a good fit for expensive
67Executor integration fixtures:
68
69- local HTTP protocol servers,
70- MCP servers,
71- OAuth mock servers,
72- Miniflare environments,
73- database-backed cloud services,
74- plugin SDK tests that need realistic server behavior.
75
76Executor already uses `layer(TestLayer)(...)` in some OpenAPI and cloud tests.
77Keep that where it works. Use the LiveStore runtime pattern only where the
78fixture is expensive enough that rebuilding it per test is wasteful or flaky.
79
80### Property-test wrapper later
81
82LiveStore's `asProp` wrapper normalizes FastCheck options and makes shrinking
83progress clearer. Do not port it preemptively.
84
85It becomes useful if Executor adds property tests for:
86
87- OpenAPI parameter encoding,
88- form/multipart request bodies,
89- schema round-trips,
90- scope ordering and shadowing,
91- tool/source dedupe,
92- storage adapter conformance.
93
94Until then, direct `@effect/vitest` property tests are enough.
95
96### Possibly scoped React perf lint
97
98LiveStore enables `react-perf` oxlint rules for JSX props:
99
100- no new functions as props,
101- no new objects as props,
102- no JSX as props,
103- no new arrays as props.
104
105This might be useful in `packages/react`, but it should start as a scoped
106experiment. Do not enable it repo-wide. The risk is turning useful UI work into
107memoization churn.
108
109## What Not to Port
110
111### Biome
112
113LiveStore uses Biome for formatting/import organization plus oxlint for linting.
114Executor already uses `oxfmt` and oxlint:
115
116```txt
117bun run format
118bun run format:check
119bun run lint
120```
121
122Adding Biome would split formatter ownership without solving an Executor
123problem.
124
125### devenv / genie / effect-utils repo generation
126
127LiveStore's config generation and `devenv` task setup are substantial
128infrastructure. Executor's Bun/Turbo setup is smaller and easier to reason
129about. Do not port that unless there is a concrete repo-management problem that
130cannot be solved locally.
131
132### LiveStore's lint rules wholesale
133
134Executor's lint posture is already stronger and more domain-specific. Executor
135currently bans or guides:
136
137- raw Vitest imports,
138- conditional tests,
139- double casts,
140- cross-package relative imports,
141- missing effect-atom reactivity keys,
142- Effect escape hatches,
143- unsupported Effect APIs,
144- `new Error`,
145- `try`/`catch` and raw `throw`,
146- `Promise.catch` / `Promise.reject`,
147- raw fetch outside approved boundaries,
148- manual tagged-error checks,
149- duplicated schema/value-derived types.
150
151LiveStore disables several things Executor intentionally cares about, including
152some broad TypeScript strictness. Their rule set should stay reference-only.
153
154### An Effect barrel module
155
156LiveStore centralizes Effect exports through `@livestore/utils/effect`.
157Executor mostly imports from `effect` directly. Do not introduce a broad
158`@executor-js/.../effect` barrel just for symmetry. It would add another import
159surface without a concrete need.
160
161## First Implementation Slice
162
163Add a tiny test helper, then use it in one test cluster.
164
165Possible local API:
166
167```ts
168export const withTestCtx =
169 (test: TestContext, options?: TestContextOptions) =>
170 <A, E, R>(effect: Effect.Effect<A, E, R>) =>
171 effect.pipe(
172 Effect.logWarnIfTakesLongerThan({
173 duration: "...",
174 label: "...",
175 }),
176 Effect.timeout("..."),
177 Effect.provide(options?.layer ?? Layer.empty),
178 Effect.scoped,
179 );
180```
181
182Keep the helper small:
183
184- no tracing dependency in the first pass,
185- no generic framework package,
186- no large fixture registry,
187- no migration of every test.
188
189Validation should be narrow:
190
191```txt
192vitest run <converted test file> --testNamePattern "<converted test>"
193```
194
195If the first conversion produces clearer test bodies and better failure output,
196then expand it to the other long-running Effect integration tests.