@stupify/cli 0.0.16 → 0.2.0
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/.review/CORPUS.md +44 -0
- package/.review/CORPUS.template.md +73 -0
- package/.review/REVIEW-PROMPT.md +52 -0
- package/.review/RUBRIC.md +46 -0
- package/LICENSE +1 -1
- package/README.md +95 -37
- package/package.json +27 -26
- package/packs/antirez.md +10 -0
- package/packs/anton-kropp.md +10 -0
- package/packs/dhh.md +10 -0
- package/packs/dtolnay.md +10 -0
- package/packs/jarred-sumner.md +9 -0
- package/packs/mitchell-hashimoto.md +10 -0
- package/packs/rich-harris.md +10 -0
- package/packs/simon-willison.md +10 -0
- package/packs/sindre-sorhus.md +10 -0
- package/packs/tanner-linsley.md +10 -0
- package/packs/zod.md +10 -0
- package/src/cli.ts +626 -0
- package/src/prime-install.test.ts +109 -0
- package/src/prime.ts +50 -0
- package/src/review-sweep.test.ts +101 -0
- package/src/review-sweep.ts +526 -0
- package/dist/analysis.d.ts +0 -16
- package/dist/analysis.js +0 -168
- package/dist/cache.d.ts +0 -2
- package/dist/cache.js +0 -57
- package/dist/checks.d.ts +0 -4
- package/dist/checks.js +0 -228
- package/dist/command.d.ts +0 -2
- package/dist/command.js +0 -147
- package/dist/constants.d.ts +0 -4
- package/dist/constants.js +0 -53
- package/dist/counter-scout.d.ts +0 -21
- package/dist/counter-scout.js +0 -167
- package/dist/diff.d.ts +0 -1
- package/dist/diff.js +0 -10
- package/dist/doctor.d.ts +0 -16
- package/dist/doctor.js +0 -143
- package/dist/git.d.ts +0 -17
- package/dist/git.js +0 -368
- package/dist/hooks.d.ts +0 -5
- package/dist/hooks.js +0 -135
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/model.d.ts +0 -11
- package/dist/model.js +0 -296
- package/dist/prompts.d.ts +0 -8
- package/dist/prompts.js +0 -89
- package/dist/render.d.ts +0 -6
- package/dist/render.js +0 -295
- package/dist/repomix-provider.d.ts +0 -12
- package/dist/repomix-provider.js +0 -196
- package/dist/search-bench.d.ts +0 -1
- package/dist/search-bench.js +0 -677
- package/dist/search-profile.d.ts +0 -6
- package/dist/search-profile.js +0 -73
- package/dist/sem-provider.d.ts +0 -2
- package/dist/sem-provider.js +0 -255
- package/dist/stupify.d.ts +0 -38
- package/dist/stupify.js +0 -505
- package/dist/trace.d.ts +0 -31
- package/dist/trace.js +0 -86
- package/dist/types.d.ts +0 -341
- package/dist/types.js +0 -6
- package/dist/ui.d.ts +0 -34
- package/dist/ui.js +0 -143
- package/src/analysis.ts +0 -223
- package/src/cache.ts +0 -63
- package/src/checks.ts +0 -231
- package/src/command.ts +0 -173
- package/src/constants.ts +0 -56
- package/src/counter-scout.ts +0 -195
- package/src/diff.ts +0 -9
- package/src/doctor.ts +0 -166
- package/src/git.ts +0 -380
- package/src/hooks.ts +0 -151
- package/src/index.ts +0 -1
- package/src/model.ts +0 -367
- package/src/prompts.ts +0 -100
- package/src/render.ts +0 -328
- package/src/repomix-provider.ts +0 -219
- package/src/search-bench.ts +0 -783
- package/src/search-profile.ts +0 -89
- package/src/sem-provider.ts +0 -300
- package/src/stupify.ts +0 -604
- package/src/trace.ts +0 -126
- package/src/types.ts +0 -362
- package/src/ui.ts +0 -187
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Good-code reference — taste packs
|
|
2
|
+
|
|
3
|
+
Judge every diff against the standards below. When you flag slop, name the principle (or the linked file) the change should have followed. The links are commit-pinned exemplars — open them when you need detail.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Code like Sindre Sorhus (@sindresorhus) · one file, one job
|
|
8
|
+
|
|
9
|
+
Radical minimalism: each module does exactly one thing and is small enough to read in five minutes. A function
|
|
10
|
+
where a class would do; no surprise dependencies; inputs validated eagerly at the top so failures are loud and
|
|
11
|
+
early. Tiny public surface, deep comments on the *why*. If it can't be read top-to-bottom in one sitting, it's
|
|
12
|
+
too big.
|
|
13
|
+
|
|
14
|
+
- [`p-limit/index.js`](https://github.com/sindresorhus/p-limit/blob/42599ebbbb1228a5bdab381fcf8f4ac20eb8d551/index.js) — a whole concurrency limiter in one short, obvious file.
|
|
15
|
+
- [`execa/options.js`](https://github.com/sindresorhus/execa/blob/f3a2e8481a1e9138de3895827895c834078b9456/lib/arguments/options.js) — careful, explicit input normalization before anything runs.
|
|
16
|
+
- [`chalk/index.js`](https://github.com/sindresorhus/chalk/blob/aa06bb5ac3f14df9fda8cfb54274dfc165ddfdef/source/index.js) — a clean, composable API with a minimal surface.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Code like Anton Kropp (@devshorts) · DI + branded types
|
|
22
|
+
|
|
23
|
+
The Startup Architecture house style: every domain concept gets its own tiny wrapper type (a `QueueName`,
|
|
24
|
+
never a raw `String`), so a primitive never leaks across a boundary. Dependencies are wired through small,
|
|
25
|
+
single-purpose DI modules listed explicitly at one auditable composition root. Interfaces are single-method
|
|
26
|
+
contracts. `Clock` is injected so tests can move time. Fail fast and loud; no silent fallbacks.
|
|
27
|
+
|
|
28
|
+
- [`QueueName.java`](https://github.com/paradoxical-io/cassieq/blob/3856962f13e5f7d84893a2ef274d08016b2c828b/model/src/main/java/io/paradoxical/cassieq/model/QueueName.java) — a branded value type: a raw string can't masquerade as a `QueueName`.
|
|
29
|
+
- [`DefaultApplicationModules.java`](https://github.com/paradoxical-io/cassieq/blob/3856962f13e5f7d84893a2ef274d08016b2c828b/core/src/main/java/io/paradoxical/cassieq/modules/DefaultApplicationModules.java) — the composition root: one explicit list of named DI modules, no magic scanning.
|
|
30
|
+
- [`ClockModule.java`](https://github.com/paradoxical-io/cassieq/blob/3856962f13e5f7d84893a2ef274d08016b2c828b/core/src/main/java/io/paradoxical/cassieq/modules/ClockModule.java) — one module, one concern (binds `Clock`), trivially swapped in tests.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Code like Colin McDonnell (@colinhacks) · parse, don't validate
|
|
36
|
+
|
|
37
|
+
Data never enters the system as an unvalidated primitive — it's parsed at the boundary and the parsed type
|
|
38
|
+
guarantees its shape. Schemas are immutable values (methods return new instances). Errors are discriminated
|
|
39
|
+
unions with a `code`, so every branch is exhaustive and typed. `parse` throws (fail fast); `safeParse` returns
|
|
40
|
+
a typed result for callers that want to branch. Composable validators replace hand-rolled type guards.
|
|
41
|
+
|
|
42
|
+
- [`parse.ts`](https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/parse.ts) — symmetric `parse`/`safeParse` with the sync/async boundary enforced; the error class is injected, not hardcoded.
|
|
43
|
+
- [`errors.ts`](https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/errors.ts) — a discriminated-union error type, every field `readonly`, a `path[]` for nested location.
|
|
44
|
+
- [`schemas.ts`](https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/schemas.ts) — distinct compile-time types per schema kind: illegal states are unrepresentable.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Good-code reference — YOUR curated exemplars (template)
|
|
2
|
+
|
|
3
|
+
> This is a template. **Replace it with 3–6 files from your own codebase that you'd point a new hire at** —
|
|
4
|
+
> the code you wish all your code looked like. The reviewer treats these as the standard and measures every
|
|
5
|
+
> diff against them. Taste can't be auto-extracted: hand-pick these, and say *why* each is good. A vague
|
|
6
|
+
> corpus produces vague reviews; a sharp one produces sharp ones.
|
|
7
|
+
|
|
8
|
+
How to write an entry:
|
|
9
|
+
- **Name the file** (a real path in this repo) and **one sentence on what makes it good** — the principle it
|
|
10
|
+
embodies (e.g. "complexity tamed by decomposition", "type makes illegal states unrepresentable",
|
|
11
|
+
"fail-fast at the boundary"). The reviewer opens the live file; the excerpt just shows the shape.
|
|
12
|
+
- Keep a short code excerpt that captures the pattern. The point is the *principle*, not the lines.
|
|
13
|
+
- Group loosely (e.g. "complex but readable", "clean service boundary") so the reviewer can cite the right one.
|
|
14
|
+
|
|
15
|
+
Pick principles you actually care about. Common ones worth encoding:
|
|
16
|
+
**dependency injection** (collaborators injected, never `new`d inline; config read only at a composition root),
|
|
17
|
+
**type-system-first invariants** (`satisfies`, discriminated unions, schemas at boundaries — illegal states
|
|
18
|
+
hard to represent), **fail fast and loud** (no silent fallback), **small single-responsibility units**,
|
|
19
|
+
**declarative over imperative**, **readable signatures** (≤3 positional params → options object).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## A. Complex, kept readable
|
|
24
|
+
|
|
25
|
+
### 1. `src/path/to/your-exemplar.ts` — one line on why it's good
|
|
26
|
+
`src/path/to/your-exemplar.ts`
|
|
27
|
+
|
|
28
|
+
Say what makes it the standard — e.g. the complexity (optimistic UI, retries, sync) is tamed by decomposition:
|
|
29
|
+
the orchestrator only *coordinates*; every concern is a small focused unit, and every operation is the same
|
|
30
|
+
shape, so N of them read like one.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// a short excerpt that shows the pattern — the shape, not the whole file
|
|
34
|
+
export function handle(input: Input): Result {
|
|
35
|
+
const state = read()
|
|
36
|
+
const ops = compute(state, input) // pure
|
|
37
|
+
return apply(ops) // effectful shell
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. `src/path/to/another.ts` — composition + named pieces
|
|
42
|
+
`src/path/to/another.ts`
|
|
43
|
+
|
|
44
|
+
e.g. pure composition — each piece a named small component, conditions become named type-guards, not inline
|
|
45
|
+
boolean soup.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
function hasMeasuredWidth(width: number | undefined): width is number {
|
|
49
|
+
return width !== undefined && width > 0
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## B. Clean boundary / DI
|
|
56
|
+
|
|
57
|
+
### `src/path/to/service.ts` — injected collaborator + composition-root factory
|
|
58
|
+
`src/path/to/service.ts`
|
|
59
|
+
|
|
60
|
+
e.g. constructor injection — the collaborator is never `new`d inline; a small factory is the composition root;
|
|
61
|
+
the method parses input at the boundary, logs with structured context, and **fails loud** (catch → log → rethrow).
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
export function createService() {
|
|
65
|
+
const scope = container.createChildContainer()
|
|
66
|
+
scope.register(CLIENT, { useValue: makeClient() })
|
|
67
|
+
return scope.resolve(Service)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
> Add a "Fine — do NOT flag" set of your own here too, if there are patterns reviewers keep wrongly dinging.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Review spec — corpus-grounded, anti-slop, with a personality
|
|
2
|
+
|
|
3
|
+
You are reviewing a code diff for this repo. You're running in the repo with `gh` / `git` / file access and
|
|
4
|
+
your own model — no API key needed. Run these steps:
|
|
5
|
+
|
|
6
|
+
1. Read `RUBRIC.md` (the anti-slop rubric + finding taxonomy) and `CORPUS.md` (this team's curated "good code"
|
|
7
|
+
— the primitives it actually uses). Treat the corpus as the standard. Open the live files it points at.
|
|
8
|
+
2. Get the diff for the target PR.
|
|
9
|
+
3. Review every changed code file (skip lockfiles, generated/snapshot files, pure deletions). Catch BOTH
|
|
10
|
+
kinds from the rubric — the "just wrong" (bug / type-lie / dead-code / footgun) and the "taste / reuse"
|
|
11
|
+
(reinvents-primitive / slop). "Slop" is code RELATIVE to the simpler or already-existing way: does it
|
|
12
|
+
reinvent a corpus primitive, or is it bigger / more abstract / more speculative than the corpus pattern for
|
|
13
|
+
the same job? When you cite a fix, name the actual corpus file/primitive it should use.
|
|
14
|
+
4. Format the review per the **Comment format** below. Report everything incl. low-confidence; don't self-filter.
|
|
15
|
+
5. Post it with the `gh pr comment` command you were given (write the comment to the file, then post).
|
|
16
|
+
|
|
17
|
+
## Prior reviews on this PR (your memory)
|
|
18
|
+
|
|
19
|
+
If the runner hands you a **"Prior reviews on this PR"** block, it's the existing review conversation — your
|
|
20
|
+
past reviews and the author's replies. You are CONTINUING that thread, not starting fresh. Treat it as memory:
|
|
21
|
+
|
|
22
|
+
- **Don't re-raise what's settled.** If you already flagged something and it's now fixed, or the author
|
|
23
|
+
**declined it with a reason**, do not raise it again — unless the diff brings new evidence that actually
|
|
24
|
+
rebuts their reason. Re-litigating a reasoned decline is noise (and the fastest way to be ignored).
|
|
25
|
+
- **Report only what's new.** Surface issues introduced since your last review, or ones you genuinely missed.
|
|
26
|
+
Do not manufacture marginal findings just to have something to say — a nit you wouldn't have raised on
|
|
27
|
+
round one doesn't become worth raising on round six.
|
|
28
|
+
- **Converge — knowing when to stop is part of the job.** If there are no new issues and the prior ones are
|
|
29
|
+
addressed or reasonably declined, do NOT write a review. Post exactly this line and nothing else:
|
|
30
|
+
`no new blocking issues — prior items addressed ✅`
|
|
31
|
+
|
|
32
|
+
(No prior-reviews block = this is the first review of this PR; ignore this section.)
|
|
33
|
+
|
|
34
|
+
## Comment format (GitHub markdown — warm + scannable)
|
|
35
|
+
|
|
36
|
+
- **Opening line — write it yourself: direct, genuinely silly, honest.** ONE short, lowercase-casual line —
|
|
37
|
+
goofy human noises, drawn-out exclamations, mild swears, the way someone reacts while scrolling code:
|
|
38
|
+
"uhhhh ummm", "shieeeeet", "oof", "ohhh boy", "ok so… yeah". NOT corporate, NOT clever-witty, NOT a linter
|
|
39
|
+
header, no praise-padding. Be a little dumb on purpose, then get to what you found. Vary it every run:
|
|
40
|
+
- nothing wrong → `yep. clean. no notes 🎉` and **stop** (no blocks).
|
|
41
|
+
- a few small things → `uhhhh ummm a couple things 👇` · `shieeeeet, found some stuff:` · `ok so. some stuff:`
|
|
42
|
+
- something real → `oh no. ok there's a real one in here:` · `oof, yeah this'll break:`
|
|
43
|
+
Then a blank line. (Tune this register to your taste — or delete it for a dry tone.)
|
|
44
|
+
- **Each finding** worst-first, as a 3-line block with a blank line between blocks:
|
|
45
|
+
- line 1: `<emoji> **`path:line`** · <kind> · conf <0–1>`
|
|
46
|
+
- line 2: what's wrong and why (1–2 sentences, plain — describe the code, don't scold)
|
|
47
|
+
- line 3: `**→ Fix:** <corpus primitive to reuse, or the correct approach> (`<reference file>`)`
|
|
48
|
+
- Severity emoji: 🔴 high · 🟠 med · 🟡 low.
|
|
49
|
+
- Close with a quiet attribution on its own line so it's clearly the auto-reviewer, not a person:
|
|
50
|
+
`_— stupify, against the good-code corpus_`
|
|
51
|
+
- No tables, no nested bullets, no preamble before the opener. End the comment with the exact hidden marker
|
|
52
|
+
line you were given.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Anti-slop rubric — the single source of truth for taste
|
|
2
|
+
|
|
3
|
+
This is what the reviewer judges against, alongside `CORPUS.md`. Edit it to match your team. A reviewer
|
|
4
|
+
catches two kinds of problem. Tag every finding with its `kind`.
|
|
5
|
+
|
|
6
|
+
## Just wrong — flag regardless of the corpus
|
|
7
|
+
- `kind: bug` — correctness bugs; off-by-one; broken null/empty handling; wrong condition.
|
|
8
|
+
- `kind: type-lie` — a type/annotation that does not match what the code actually returns
|
|
9
|
+
(e.g. annotated `T | null` but every path returns a non-null value cast to `T`).
|
|
10
|
+
- `kind: dead-code` — unreachable or dead branches; a declared-and-unused const/import/function.
|
|
11
|
+
- `kind: footgun` — swallowed errors / catch-and-continue with no owned degraded state; silent fallbacks;
|
|
12
|
+
test-only special-casing (`NODE_ENV === 'test'`, env-name string checks) leaking into production code.
|
|
13
|
+
|
|
14
|
+
## Taste / reuse — relative to the corpus and the simpler way
|
|
15
|
+
- `kind: reinvents-primitive` — a NEW abstraction/layer/wrapper/facade/shim/fallback-reader when a corpus
|
|
16
|
+
primitive already does it (name the primitive). Or hand-rolling what a corpus file does.
|
|
17
|
+
- `kind: slop` — bigger / more abstract / more speculative than the corpus pattern for the same job:
|
|
18
|
+
- speculative `unknown` in hand-authored types; `TResult = unknown` generic defaults;
|
|
19
|
+
`z.unknown()` / `z.array(z.unknown())`
|
|
20
|
+
- generic-parameter explosion on a call site that is not actually reused generically
|
|
21
|
+
- `let best*/latest*` imperative argmax/latest accumulator loops
|
|
22
|
+
- throwaway one-call helpers, or wrapper functions that add no value — a pure pass-through to another fn
|
|
23
|
+
with the same signature; inline it / call the inner directly
|
|
24
|
+
- a defensive `?.` / `??` fallback on a value the type or schema already guarantees — e.g. `x?.foo ?? x.y.foo`
|
|
25
|
+
when `x` is required (or should be). Drop the optional chain and the fallback (it's `x.foo`); if `x` is
|
|
26
|
+
wrongly optional, fix the schema/type, don't paper over it at the call site
|
|
27
|
+
- denormalized parallel constants or hardcoded membership lists (derive a Set/Record from ONE `as const` array)
|
|
28
|
+
- speculative config seams / unused `mode` switches / injectable-override defaults nothing needs yet
|
|
29
|
+
- additive churn on a cleanup; code that "looks productive" over the minimal change
|
|
30
|
+
|
|
31
|
+
## Fine — do NOT flag
|
|
32
|
+
- `unknown` at a real parse boundary fed into a normalizer; `Record<string, unknown>` context bags
|
|
33
|
+
- Set/Map-building or dedupe loops (not argmax accumulators)
|
|
34
|
+
- a single choke-point helper its owner reuses
|
|
35
|
+
|
|
36
|
+
## Weigh the fix against the owner
|
|
37
|
+
Right-size the remedy to the code that owns it. Don't prescribe a heavier primitive than the context warrants:
|
|
38
|
+
a one-off script shouldn't grow a schema library, glue code shouldn't sprout an interface, a guaranteed-shape
|
|
39
|
+
boundary doesn't need the validation an untrusted one does, and an unattended job usually wants a loud default
|
|
40
|
+
over a hard exit. Demanding more rigor than the owner needs is its own slop. If the minimal fix is a one-liner,
|
|
41
|
+
the fix is the one-liner — propose that, not an architecture.
|
|
42
|
+
|
|
43
|
+
## Output per finding
|
|
44
|
+
`path:line` — [kind] — what's wrong and why — **fix:** the corpus primitive to reuse OR (for a bug) the
|
|
45
|
+
correct approach — severity(high|med|low) · confidence(0–1). Sort worst-first. Report everything incl.
|
|
46
|
+
low-confidence — do not self-filter; a downstream ranker (and your own memory) handles that.
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,58 +1,116 @@
|
|
|
1
|
-
|
|
1
|
+
> Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as
|
|
2
|
+
> cleverly as possible, you are, by definition, not smart enough to debug it.
|
|
3
|
+
>
|
|
4
|
+
> — **Kernighan's Law**
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# stupify
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Tired of [wasting your time](https://github.com/thesysdev/openui/issues/517) reviewing [AI](https://github.com/RsyncProject/rsync/issues/929) [slop](https://github.com/anthropics/claudes-c-compiler/issues/1)?
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
[](https://www.npmjs.com/package/@stupify/cli)
|
|
11
|
+
[](LICENSE)
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
sem diff -> counter scout -> Repomix context -> local search model
|
|
11
|
-
```
|
|
13
|
+
**A code reviewer that talks like an idiot and catches real bugs.**
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
Kernighan was right: the clever code is the code you can't debug. stupify drags your code back toward boring —
|
|
16
|
+
at **both ends** of the loop:
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
- **before you code** — [`stupify prime`](#prime-your-agent-instant-local-no-servers) seeds every Claude Code session with your taste, so the agent writes to your standard from line one.
|
|
19
|
+
- **after you PR** — the reviewer reads every PR on [Codex](https://github.com/openai/codex) against that *same* taste and flags what drifted.
|
|
20
|
+
|
|
21
|
+
You encode your taste once — a `CORPUS.md` of files you already think are good (or a [taste pack](#taste-packs)) — and stupify enforces it going in and coming out. Not some model's idea of "best practice." So it catches the stuff that actually bugs *you*: premature abstractions, cute one-liners with a bug hiding in them, helpers someone reinvented. Then it points at the boring thing they should've used.
|
|
22
|
+
|
|
23
|
+
Most AI reviewers carpet-bomb your PR with `consider renaming this`. stupify stays quiet until it finds
|
|
24
|
+
something real, says it in one sentence, and shuts up.
|
|
25
|
+
|
|
26
|
+
> uhhhh ummm this cleanup got a little cleanup-y:
|
|
27
|
+
>
|
|
28
|
+
> 🟠 **`server/checkout.ts:40`** · slop · conf 0.82
|
|
29
|
+
> you inlined `validateCart` and `applyDiscounts` into the handler, so it's branch soup with two mutable `let`s now, instead of validate → price → charge. those weren't throwaway wrappers, they were the steps.
|
|
30
|
+
> **→ Fix:** put the named steps back. the handler should orchestrate, not do all of it.
|
|
31
|
+
>
|
|
32
|
+
> 🟡 **`server/checkout.ts:12`** · slop · conf 0.7
|
|
33
|
+
> `order?.total ?? order.cart.total` — `order` is required here, so the `?.` never fires and the fallback is dead code cosplaying as safety. it's `order.total`.
|
|
34
|
+
> **→ Fix:** drop the `?.` and the `??`. if order's actually optional, fix the type, don't paper over it.
|
|
35
|
+
>
|
|
36
|
+
> _— stupify, against the good-code corpus_
|
|
22
37
|
|
|
23
|
-
|
|
38
|
+
### What you get
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
- **Your taste, not the model's.** Everything is judged against a `CORPUS.md` — a [taste pack](#taste-packs) ("code like dtolnay / DHH / antirez …") or your own best files. Nothing to write to start.
|
|
41
|
+
- **Slop, named.** `RUBRIC.md` is your list of what counts as slop: reinvented primitives, speculative abstraction, fallbacks the types already guarantee. It keeps the fix small.
|
|
42
|
+
- **Both ends of the loop.** The *same* `.review/` primes the agent before it writes (prevention) and reviews the PR after (detection). The best review is the one you didn't need.
|
|
43
|
+
- **It remembers.** Reads the PR thread, won't re-raise what you fixed or waved off, posts `no new blocking issues ✅` when there's nothing left.
|
|
44
|
+
- **It's funny.** `oof, yeah this'll break:`. Turn it off if you hate joy.
|
|
45
|
+
|
|
46
|
+
## Prime your agent (instant, local, no servers)
|
|
47
|
+
|
|
48
|
+
The best slop is the slop never written. `prime` wires a Claude Code [SessionStart hook](https://docs.claude.com/en/docs/claude-code/hooks) that injects your taste into every session — so the agent holds your standard *before* it touches a line. Pure file read, ~30ms, no model call.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
bunx @stupify/cli taste --pack sindre-sorhus,zod # pick the code yours should look like
|
|
52
|
+
bunx @stupify/cli prime --install # every Claude Code session now opens knowing it
|
|
27
53
|
```
|
|
28
54
|
|
|
29
|
-
|
|
55
|
+
That's it. Open Claude Code in any repo and it's already primed. A repo's own `.review/` wins; otherwise it
|
|
56
|
+
falls back to the taste you assembled. `bunx @stupify/cli prime --uninstall` removes the hook cleanly.
|
|
57
|
+
|
|
58
|
+
## Add the reviewer (rides exe.dev — no keys, no servers *you* run)
|
|
30
59
|
|
|
31
|
-
|
|
60
|
+
From your laptop, **one command** provisions a VM that reviews your repo's PRs. No API keys, no tokens — you
|
|
61
|
+
never even SSH anywhere.
|
|
32
62
|
|
|
33
|
-
```
|
|
34
|
-
stupify
|
|
63
|
+
```bash
|
|
64
|
+
bunx @stupify/cli
|
|
35
65
|
```
|
|
36
66
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
67
|
+
```
|
|
68
|
+
┌ stupify — provision a reviewer on exe.dev
|
|
69
|
+
◇ using integration acme-widgets
|
|
70
|
+
◇ VM stupify-acme-widgets created
|
|
71
|
+
└ stupify is provisioned for acme/widgets 👀
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
New to [exe.dev](https://exe.dev)? `ssh exe.dev` to onboard and link GitHub at
|
|
75
|
+
[exe.dev/integrations](https://exe.dev/integrations) — both one-time, both painless. Then just **open a PR** —
|
|
76
|
+
stupify reviews every non-draft, non-bot PR in ~60s, no labels or workflows to wire up. (Want manual control?
|
|
77
|
+
`SCOPE=label` flips it to opt-in: only PRs you tag get reviewed.)
|
|
41
78
|
|
|
42
|
-
```
|
|
43
|
-
stupify
|
|
79
|
+
```bash
|
|
80
|
+
bunx @stupify/cli <owner/repo> # provision for a specific repo
|
|
81
|
+
bunx @stupify/cli setup # run the reviewer on this machine instead of a VM
|
|
82
|
+
ssh exe.dev rm stupify-<owner>-<repo> # tear it down
|
|
44
83
|
```
|
|
45
84
|
|
|
46
|
-
|
|
85
|
+
## Taste packs
|
|
86
|
+
|
|
87
|
+
Don't have a corpus yet? Borrow one. Pick a programmer whose code you'd point a new hire at and review (and
|
|
88
|
+
write) like them — or compose several:
|
|
89
|
+
|
|
90
|
+
[dtolnay](packs/dtolnay.md) · [DHH](packs/dhh.md) · [antirez](packs/antirez.md) ·
|
|
91
|
+
[Sindre Sorhus](packs/sindre-sorhus.md) · [Rich Harris](packs/rich-harris.md) ·
|
|
92
|
+
[zod](packs/zod.md) · [Mitchell Hashimoto](packs/mitchell-hashimoto.md) ·
|
|
93
|
+
[Tanner Linsley](packs/tanner-linsley.md) · [Simon Willison](packs/simon-willison.md) ·
|
|
94
|
+
[Anton Kropp](packs/anton-kropp.md) · [the perf pack](packs/jarred-sumner.md) · [browse all →](packs)
|
|
95
|
+
|
|
96
|
+
Each pack is concrete principles plus commit-pinned exemplar files. Or bring your own: drop a
|
|
97
|
+
[`.review/`](.review) in your repo and point `CORPUS.md` at the files you *wish* all your code looked like (it
|
|
98
|
+
always wins over a pack). stupify dogfoods this — its own [`.review/CORPUS.md`](.review/CORPUS.md) is real.
|
|
99
|
+
|
|
100
|
+
## How it works
|
|
47
101
|
|
|
48
|
-
```sh
|
|
49
|
-
stupify --staged --max-search-input-tokens 24000
|
|
50
102
|
```
|
|
103
|
+
prime Claude Code SessionStart hook → bun ~/.stupify/prime.ts → inject .review/ (rubric + corpus)
|
|
104
|
+
review cron (~60s) → review-sweep.ts → codex exec → gh pr comment
|
|
105
|
+
refresh checkout · list open PRs (skip drafts/bots) · skip already-reviewed heads
|
|
106
|
+
feed the PR's thread back as memory · review against .review/* · post
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Both halves read the same `.review/` (a repo's own wins; else the pack taste you assembled). The CLI
|
|
110
|
+
(`src/cli.ts`) sets things up; the engines (`src/prime.ts` and `src/review-sweep.ts`) are dependency-free Bun.
|
|
111
|
+
The whole design — including why it *remembers* instead of debouncing — is in
|
|
112
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
51
113
|
|
|
52
|
-
|
|
53
|
-
use the repository release workflow so npm receives Trusted Publishing
|
|
54
|
-
provenance. See the repository release docs.
|
|
114
|
+
## License
|
|
55
115
|
|
|
56
|
-
|
|
57
|
-
baselines, hosted LLM APIs, GitHub integration, dashboards, or repo-wide
|
|
58
|
-
crawling.
|
|
116
|
+
[MIT](LICENSE) © Noah Lindner. Built by the team at [Bevyl](https://bevyl.ai). `stupif.ai` — read it "stupify". PRs welcome — it'll review them 😈
|
package/package.json
CHANGED
|
@@ -1,53 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stupify/cli",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
5
|
-
"private": false,
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A code reviewer that talks like an idiot and catches real bugs — corpus-grounded, anti-slop, runs on Codex.",
|
|
6
5
|
"type": "module",
|
|
7
6
|
"bin": {
|
|
8
|
-
"stupify": "
|
|
7
|
+
"stupify": "src/cli.ts"
|
|
9
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
".review",
|
|
12
|
+
"packs",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"homepage": "https://stupif.ai",
|
|
10
18
|
"repository": {
|
|
11
19
|
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/Octember/
|
|
13
|
-
"directory": "packages/cli"
|
|
20
|
+
"url": "git+https://github.com/Octember/stupify.git"
|
|
14
21
|
},
|
|
15
|
-
"homepage": "https://stupif.ai",
|
|
16
22
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/Octember/
|
|
23
|
+
"url": "https://github.com/Octember/stupify/issues"
|
|
18
24
|
},
|
|
19
25
|
"keywords": [
|
|
26
|
+
"code-review",
|
|
27
|
+
"codex",
|
|
20
28
|
"ai",
|
|
21
|
-
"
|
|
29
|
+
"pull-request",
|
|
22
30
|
"developer-tools",
|
|
23
|
-
"
|
|
24
|
-
"code-review"
|
|
31
|
+
"anti-slop"
|
|
25
32
|
],
|
|
26
|
-
"license": "MIT",
|
|
27
33
|
"engines": {
|
|
28
|
-
"
|
|
34
|
+
"bun": ">=1.3"
|
|
29
35
|
},
|
|
30
36
|
"publishConfig": {
|
|
31
37
|
"access": "public",
|
|
32
38
|
"provenance": true
|
|
33
39
|
},
|
|
34
|
-
"files": [
|
|
35
|
-
"dist",
|
|
36
|
-
"src",
|
|
37
|
-
"LICENSE",
|
|
38
|
-
"README.md",
|
|
39
|
-
"package.json"
|
|
40
|
-
],
|
|
41
40
|
"scripts": {
|
|
42
|
-
"build": "tsc -p tsconfig.build.json",
|
|
43
|
-
"prepack": "bun run build",
|
|
44
41
|
"typecheck": "tsc -p tsconfig.json",
|
|
45
|
-
"
|
|
42
|
+
"test": "bun test",
|
|
43
|
+
"cli": "bun src/cli.ts"
|
|
46
44
|
},
|
|
47
45
|
"dependencies": {
|
|
48
|
-
"@ataraxy-labs/sem": "^0.3.24",
|
|
49
46
|
"@clack/prompts": "^1.2.0",
|
|
50
|
-
"picocolors": "^1.1.1"
|
|
51
|
-
|
|
47
|
+
"picocolors": "^1.1.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/bun": "^1.3.14",
|
|
51
|
+
"@types/node": "^22.10.2",
|
|
52
|
+
"typescript": "^5.7.2"
|
|
52
53
|
}
|
|
53
54
|
}
|
package/packs/antirez.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Salvatore Sanfilippo / antirez (@antirez) · comments that earn their keep
|
|
2
|
+
|
|
3
|
+
Readable C, of all things — because the comments do real work. ASCII-art diagrams of the data structure sit
|
|
4
|
+
above the code that implements it. Banner section dividers read like chapters. Every function comment states
|
|
5
|
+
the contract, the error return, and the ownership of any pointer it touches. Nothing non-obvious goes
|
|
6
|
+
unexplained; nothing obvious gets a comment.
|
|
7
|
+
|
|
8
|
+
- [`rax.h`](https://github.com/antirez/rax/blob/1927550cb218ec3c3dda8b39d82d1d019bf0476d/rax.h) — the radix tree drawn in ASCII before a line of it is implemented.
|
|
9
|
+
- [`rax.c`](https://github.com/antirez/rax/blob/1927550cb218ec3c3dda8b39d82d1d019bf0476d/rax.c) — banner-divided sections; each function comment states its contract and pointer ownership.
|
|
10
|
+
- [`sds.h`](https://github.com/antirez/sds/blob/5347739b1581fcba74fd5cab1fc21d2aef317d71/sds.h) — a string library whose header comments are the spec.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Anton Kropp (@devshorts) · DI + branded types
|
|
2
|
+
|
|
3
|
+
The Startup Architecture house style: every domain concept gets its own tiny wrapper type (a `QueueName`,
|
|
4
|
+
never a raw `String`), so a primitive never leaks across a boundary. Dependencies are wired through small,
|
|
5
|
+
single-purpose DI modules listed explicitly at one auditable composition root. Interfaces are single-method
|
|
6
|
+
contracts. `Clock` is injected so tests can move time. Fail fast and loud; no silent fallbacks.
|
|
7
|
+
|
|
8
|
+
- [`QueueName.java`](https://github.com/paradoxical-io/cassieq/blob/3856962f13e5f7d84893a2ef274d08016b2c828b/model/src/main/java/io/paradoxical/cassieq/model/QueueName.java) — a branded value type: a raw string can't masquerade as a `QueueName`.
|
|
9
|
+
- [`DefaultApplicationModules.java`](https://github.com/paradoxical-io/cassieq/blob/3856962f13e5f7d84893a2ef274d08016b2c828b/core/src/main/java/io/paradoxical/cassieq/modules/DefaultApplicationModules.java) — the composition root: one explicit list of named DI modules, no magic scanning.
|
|
10
|
+
- [`ClockModule.java`](https://github.com/paradoxical-io/cassieq/blob/3856962f13e5f7d84893a2ef274d08016b2c828b/core/src/main/java/io/paradoxical/cassieq/modules/ClockModule.java) — one module, one concern (binds `Clock`), trivially swapped in tests.
|
package/packs/dhh.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like DHH (@dhh) · controllers that tell the story
|
|
2
|
+
|
|
3
|
+
Conventions used so consistently that a new file is predictable. Controllers fit on one screen: actions are a
|
|
4
|
+
few lines, all setup pushed into `before_action` filters with self-documenting names (`set_room`,
|
|
5
|
+
`ensure_can_administer`). Cross-cutting behavior is extracted into named concerns (`Authentication`,
|
|
6
|
+
`Authorization`), not sprinkled inline. The code reads like the product, top to bottom.
|
|
7
|
+
|
|
8
|
+
- [`messages_controller.rb`](https://github.com/basecamp/once-campfire/blob/8d3c2bbd2be070008a275330efbee1001fd202dc/app/controllers/messages_controller.rb) — a controller you can read in one screen; the actions tell the story.
|
|
9
|
+
- [`authentication.rb`](https://github.com/basecamp/once-campfire/blob/8d3c2bbd2be070008a275330efbee1001fd202dc/app/controllers/concerns/authentication.rb) — a named policy extracted as a concern, reused everywhere.
|
|
10
|
+
- [`message.rb`](https://github.com/basecamp/once-campfire/blob/8d3c2bbd2be070008a275330efbee1001fd202dc/app/models/message.rb) — a fat-but-organized model with the domain rules where they belong.
|
package/packs/dtolnay.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like David Tolnay (@dtolnay) · the API that disappears
|
|
2
|
+
|
|
3
|
+
The gold standard of idiomatic Rust. Every public type earns its existence; the API surface collapses to the
|
|
4
|
+
minimum, and correct usage is the *only* usage. Errors carry context without leaking internals. Derive macros
|
|
5
|
+
vanish into your types and leave no fingerprint. Trait impls over free functions. Expose the smallest thing
|
|
6
|
+
that works.
|
|
7
|
+
|
|
8
|
+
- [`thiserror/lib.rs`](https://github.com/dtolnay/thiserror/blob/7214e0e8331d76afbea7173d8a14997512ac8713/src/lib.rs) — a tiny public surface that generates exactly the error impls you'd hand-write.
|
|
9
|
+
- [`thiserror/expand.rs`](https://github.com/dtolnay/thiserror/blob/7214e0e8331d76afbea7173d8a14997512ac8713/impl/src/expand.rs) — the macro internals: precise, readable codegen with no fingerprint left behind.
|
|
10
|
+
- [`anyhow/context.rs`](https://github.com/dtolnay/anyhow/blob/841522b2aa09732fecee40804440d2c35c68c480/src/context.rs) — errors with context attached, internals never leaked.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## Code like Jarred Sumner (@Jarred-Sumner) · perf as a correctness concern
|
|
2
|
+
|
|
3
|
+
The perf pack. Performance decided *structurally*, not by micro-tweaking later: stack-fallback allocators
|
|
4
|
+
before the heap, atomic counters instead of mutexes, `comptime` conditionals that delete dead paths at zero
|
|
5
|
+
runtime cost. Names encode invariants. The root module is a curated namespace, not a junk drawer. Fast because
|
|
6
|
+
the *shape* is fast — and still readable.
|
|
7
|
+
|
|
8
|
+
- [`bun.zig`](https://github.com/oven-sh/bun/blob/454e3b2884c2bfabfa424ebecc3e9a1a9ee32773/src/bun.zig) — the root namespace, deliberately curated so the fast path is the obvious one.
|
|
9
|
+
- [`AsyncHTTP.zig`](https://github.com/oven-sh/bun/blob/454e3b2884c2bfabfa424ebecc3e9a1a9ee32773/src/http/AsyncHTTP.zig) — concurrency built from atomics and explicit state, not locks bolted on.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Mitchell Hashimoto (@mitchellh) · documented tradeoffs
|
|
2
|
+
|
|
3
|
+
State machines as exhaustive tagged unions, so every case is handled or it won't compile. Data structures that
|
|
4
|
+
document their own tradeoffs inline. Comments explain the *why* and the tradeoff taken, never the *what*.
|
|
5
|
+
Explicit `MAX_*` constants with the empirical reason next to them. When something is non-obvious, it says so
|
|
6
|
+
candidly instead of pretending it's clean.
|
|
7
|
+
|
|
8
|
+
- [`Parser.zig`](https://github.com/mitchellh/ghostty/blob/49a9181560707936c587ae121656d2d762d27849/src/terminal/Parser.zig) — a real state machine as an exhaustive enum; no `default:` swallowing the unknown.
|
|
9
|
+
- [`circ_buf.zig`](https://github.com/mitchellh/ghostty/blob/49a9181560707936c587ae121656d2d762d27849/src/datastruct/circ_buf.zig) — a data structure whose comments justify the layout and its costs.
|
|
10
|
+
- [`Config.zig`](https://github.com/mitchellh/ghostty/blob/49a9181560707936c587ae121656d2d762d27849/src/config/Config.zig) — config as typed data with the constraints stated, not scattered through the code.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Rich Harris (@Rich-Harris) · compiler-grade precision
|
|
2
|
+
|
|
3
|
+
Library code written with a compiler author's discipline: small named classes with one responsibility,
|
|
4
|
+
immutable sentinel constants (`BLANK`, `EMPTY_SET`) instead of re-allocating, errors that carry a `code` and a
|
|
5
|
+
docs URL. No defensive fallbacks — methods throw immediately with a precise message rather than papering over a
|
|
6
|
+
bad state.
|
|
7
|
+
|
|
8
|
+
- [`magic-string/Chunk.js`](https://github.com/Rich-Harris/magic-string/blob/410fd4d080d8bf0b5be900c16c8ba11276fd8749/src/Chunk.js) — a focused, mutation-careful data structure.
|
|
9
|
+
- [`rollup/blank.ts`](https://github.com/rollup/rollup/blob/5e0066d92defee0097f10fb814e63f60b2a7b612/src/utils/blank.ts) — shared sentinel objects, named and reused instead of re-allocated.
|
|
10
|
+
- [`rollup/getOrCreate.ts`](https://github.com/rollup/rollup/blob/5e0066d92defee0097f10fb814e63f60b2a7b612/src/utils/getOrCreate.ts) — a one-job helper extracted and reused, not inlined everywhere.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Simon Willison (@simonw) · one concept per file
|
|
2
|
+
|
|
3
|
+
(Yes — the person who coined "slop".) Plugin-first design: every extension point is a named hookspec, declared
|
|
4
|
+
before it's implemented. One concept per file (`recipes.py`, `events.py`, `hookspecs.py`). Dataclasses for
|
|
5
|
+
typed events and data. Sentinel values over magic booleans. Docstrings explain the contract, not the
|
|
6
|
+
implementation. Small, obvious, testable seams.
|
|
7
|
+
|
|
8
|
+
- [`recipes.py`](https://github.com/simonw/sqlite-utils/blob/8f0c06e1889513ed0f01cb57783ddf07c442d4be/sqlite_utils/recipes.py) — one concept per module: small, composable transforms.
|
|
9
|
+
- [`hookspecs.py`](https://github.com/simonw/sqlite-utils/blob/8f0c06e1889513ed0f01cb57783ddf07c442d4be/sqlite_utils/hookspecs.py) — plugin seams declared up front, before any implementation.
|
|
10
|
+
- [`events.py`](https://github.com/simonw/datasette/blob/dfd5b95ec8adc425b683df22148cb1c14bb01128/datasette/events.py) — typed dataclass events instead of loose dicts.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Sindre Sorhus (@sindresorhus) · one file, one job
|
|
2
|
+
|
|
3
|
+
Radical minimalism: each module does exactly one thing and is small enough to read in five minutes. A function
|
|
4
|
+
where a class would do; no surprise dependencies; inputs validated eagerly at the top so failures are loud and
|
|
5
|
+
early. Tiny public surface, deep comments on the *why*. If it can't be read top-to-bottom in one sitting, it's
|
|
6
|
+
too big.
|
|
7
|
+
|
|
8
|
+
- [`p-limit/index.js`](https://github.com/sindresorhus/p-limit/blob/42599ebbbb1228a5bdab381fcf8f4ac20eb8d551/index.js) — a whole concurrency limiter in one short, obvious file.
|
|
9
|
+
- [`execa/options.js`](https://github.com/sindresorhus/execa/blob/f3a2e8481a1e9138de3895827895c834078b9456/lib/arguments/options.js) — careful, explicit input normalization before anything runs.
|
|
10
|
+
- [`chalk/index.js`](https://github.com/sindresorhus/chalk/blob/aa06bb5ac3f14df9fda8cfb54274dfc165ddfdef/source/index.js) — a clean, composable API with a minimal surface.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Tanner Linsley (@tannerlinsley) · types that forbid bad states
|
|
2
|
+
|
|
3
|
+
Private class fields (`#field`) for real encapsulation. Types do the enforcing: `Updater<T> = T | ((old: T) =>
|
|
4
|
+
T)`, recursion-guarded `DeepKeys<T>`, tuple utilities — illegal states are structurally unrepresentable, caught
|
|
5
|
+
at compile time, not asserted at runtime. Big interfaces are assembled from small feature slices rather than
|
|
6
|
+
written as one god-type.
|
|
7
|
+
|
|
8
|
+
- [`query/subscribable.ts`](https://github.com/TanStack/query/blob/0bed37a91efa1b6e84b192ca3629d6e0c6cfcb73/packages/query-core/src/subscribable.ts) — a tiny single-purpose unit with truly private state.
|
|
9
|
+
- [`query/focusManager.ts`](https://github.com/TanStack/query/blob/0bed37a91efa1b6e84b192ca3629d6e0c6cfcb73/packages/query-core/src/focusManager.ts) — one concern, encapsulated, testable.
|
|
10
|
+
- [`table/type-utils.ts`](https://github.com/TanStack/table/blob/ed814260e0a863861f8387087e72feef1b75cd37/packages/table-core/src/types/type-utils.ts) — type-algebra that makes the wrong shape a compile error.
|
package/packs/zod.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Code like Colin McDonnell (@colinhacks) · parse, don't validate
|
|
2
|
+
|
|
3
|
+
Data never enters the system as an unvalidated primitive — it's parsed at the boundary and the parsed type
|
|
4
|
+
guarantees its shape. Schemas are immutable values (methods return new instances). Errors are discriminated
|
|
5
|
+
unions with a `code`, so every branch is exhaustive and typed. `parse` throws (fail fast); `safeParse` returns
|
|
6
|
+
a typed result for callers that want to branch. Composable validators replace hand-rolled type guards.
|
|
7
|
+
|
|
8
|
+
- [`parse.ts`](https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/parse.ts) — symmetric `parse`/`safeParse` with the sync/async boundary enforced; the error class is injected, not hardcoded.
|
|
9
|
+
- [`errors.ts`](https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/errors.ts) — a discriminated-union error type, every field `readonly`, a `path[]` for nested location.
|
|
10
|
+
- [`schemas.ts`](https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/schemas.ts) — distinct compile-time types per schema kind: illegal states are unrepresentable.
|