sdkproof 0.1.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +192 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +201 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/core/classify.d.ts +4 -0
  7. package/dist/core/classify.js +72 -0
  8. package/dist/core/classify.js.map +1 -0
  9. package/dist/core/model.d.ts +30 -0
  10. package/dist/core/model.js +27 -0
  11. package/dist/core/model.js.map +1 -0
  12. package/dist/core/prompt.d.ts +4 -0
  13. package/dist/core/prompt.js +43 -0
  14. package/dist/core/prompt.js.map +1 -0
  15. package/dist/core/score.d.ts +3 -0
  16. package/dist/core/score.js +37 -0
  17. package/dist/core/score.js.map +1 -0
  18. package/dist/core/stats.d.ts +99 -0
  19. package/dist/core/stats.js +121 -0
  20. package/dist/core/stats.js.map +1 -0
  21. package/dist/core/types.d.ts +162 -0
  22. package/dist/core/types.js +11 -0
  23. package/dist/core/types.js.map +1 -0
  24. package/dist/core/verify.d.ts +33 -0
  25. package/dist/core/verify.js +191 -0
  26. package/dist/core/verify.js.map +1 -0
  27. package/dist/drift.d.ts +87 -0
  28. package/dist/drift.js +105 -0
  29. package/dist/drift.js.map +1 -0
  30. package/dist/index.d.ts +19 -0
  31. package/dist/index.js +19 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/models.d.ts +33 -0
  34. package/dist/models.js +186 -0
  35. package/dist/models.js.map +1 -0
  36. package/dist/registry.d.ts +65 -0
  37. package/dist/registry.js +98 -0
  38. package/dist/registry.js.map +1 -0
  39. package/dist/report.d.ts +26 -0
  40. package/dist/report.js +240 -0
  41. package/dist/report.js.map +1 -0
  42. package/dist/run.d.ts +36 -0
  43. package/dist/run.js +188 -0
  44. package/dist/run.js.map +1 -0
  45. package/dist/surface.d.ts +95 -0
  46. package/dist/surface.js +281 -0
  47. package/dist/surface.js.map +1 -0
  48. package/dist/tarball.d.ts +7 -0
  49. package/dist/tarball.js +66 -0
  50. package/dist/tarball.js.map +1 -0
  51. package/dist/tasks.d.ts +41 -0
  52. package/dist/tasks.js +199 -0
  53. package/dist/tasks.js.map +1 -0
  54. package/dist/workspace.d.ts +42 -0
  55. package/dist/workspace.js +251 -0
  56. package/dist/workspace.js.map +1 -0
  57. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kalpit Rathore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,192 @@
1
+ # sdkproof
2
+
3
+ `npx sdkproof zod` asks a model to write small realistic jobs against a package, then compiles every answer against the real installed package with `tsc`, the TypeScript compiler. Pass = it compiles. No model judges another model.
4
+
5
+ You need an API key for the model you want to score. The other half of the tool, `npx sdkproof drift <package>`, needs no key at all.
6
+
7
+ ## What a run looks like
8
+
9
+ ```
10
+ $ npx sdkproof @tanstack/react-table --model claude-sonnet-5 --limit 3
11
+
12
+ Target: @tanstack/react-table@9.1.2
13
+ Drift: v8 -> v9 — 40 functions, hooks and classes gone from the entrypoint with no deprecation first, in a major that is 1 months old
14
+ Generating 3 x 1 ...
15
+ Verifying ✗✗✗
16
+
17
+ ────────────────────────────────────────────────────────────
18
+ @tanstack/react-table@9.1.2 — 0 of 3 answers compiled
19
+ ────────────────────────────────────────────────────────────
20
+
21
+ claude-sonnet-5 0/3 compiled (0%, 95% CI 0–56.1%)
22
+
23
+ WHAT BROKE
24
+
25
+ basic-people-table (core, easy)
26
+ TS2724: '"@tanstack/react-table"' has no exported member named 'getCoreRowModel'. Did you mean 'createCoreRowModel'?
27
+ +6 more diagnostics
28
+
29
+ sortable-product-headers (sorting, easy)
30
+ TS2724: '"@tanstack/react-table"' has no exported member named 'useReactTable'. Did you mean 'ReactTable'?
31
+ +7 more diagnostics
32
+
33
+ global-search-employees (filtering, medium)
34
+ TS2724: '"@tanstack/react-table"' has no exported member named 'useReactTable'. Did you mean 'ReactTable'?
35
+ +7 more diagnostics
36
+
37
+ FAILURE PATTERNS
38
+ deprecated-or-removed 8x
39
+ wrong-arguments 3x
40
+ other 12x
41
+ ```
42
+
43
+ That is a real run on 22 Aug 2026, trimmed at the last line. `TS2724` is the compiler saying "this import doesn't exist, did you mean this other thing".
44
+
45
+ TanStack Table v9 renamed `useReactTable` to `useTable` & renamed the whole row-model family, so `getCoreRowModel` became `createCoreRowModel`. The model still writes v8 from memory. It looks right and it doesn't compile.
46
+
47
+ ## What it measures, and what it doesn't
48
+
49
+ It measures **the model**, not the library. A 0 of 3 says the model has not caught up with v9 yet. It says nothing about whether v9 is a good release.
50
+
51
+ The one real limit: it type-checks, it doesn't run anything. Code that compiles can still be wrong at runtime. That is on purpose — a type error against the real installed package is a fact the compiler produced, and anything softer would be one AI grading another, which is the thing this exists to avoid.
52
+
53
+ ## Use it
54
+
55
+ ```bash
56
+ npx sdkproof <package> # score it
57
+ npx sdkproof drift <package> # what its latest major removed, no API key
58
+ ```
59
+
60
+ Keys, in the environment or a `.env` in the current directory:
61
+
62
+ ```bash
63
+ export ANTHROPIC_API_KEY=... # scores claude-opus-5 by default
64
+ export OPENAI_API_KEY=... # scores gpt-5 by default
65
+ ```
66
+
67
+ Both set = both get scored on the same tasks, side by side.
68
+
69
+ ```bash
70
+ npx sdkproof zod
71
+ npx sdkproof @apollo/client@3 --model claude-opus-5 --model gpt-5
72
+ npx sdkproof next --task-count 20 --out ./reports
73
+ npx sdkproof drift @tanstack/react-table
74
+ ```
75
+
76
+ ## Check whether it's worth scoring first
77
+
78
+ `drift` reads two published versions straight off npm and diffs the type declarations. No install, no model, no key, a few seconds.
79
+
80
+ ```
81
+ $ npx sdkproof drift @apollo/client
82
+
83
+ ────────────────────────────────────────────────────────────
84
+ @apollo/client v3.14.1 -> v4.2.12
85
+ ────────────────────────────────────────────────────────────
86
+
87
+ v4 landed 12 months ago
88
+ 132 exported symbols -> 133 (entry-only diff)
89
+
90
+ WHAT LEFT (24) — functions, hooks and classes gone from the entrypoint with no deprecation first
91
+ This is what a model trained on v3 will still write.
92
+
93
+ ApolloConsumer
94
+ ApolloProvider
95
+ createQueryPreloader
96
+ getApolloContext
97
+ useApolloClient
98
+ useLazyQuery
99
+ useMutation
100
+ useQuery
101
+ useSubscription
102
+ useSuspenseQuery
103
+ ...
104
+
105
+ Deprecated first, then removed (8) — these rarely produce drift:
106
+ ApolloError, fromError, fromPromise, isApolloError, parser, resetApolloContext, throwServerError, toPromise
107
+
108
+ (29 type-only export(s) also left the entrypoint. They are listed in --json; a model writes a hook far more often than it writes a type name.)
109
+
110
+ WORTH SCORING — 24 functions, hooks and classes gone from the entrypoint with no deprecation first, in a major that is 12 months old
111
+ ```
112
+
113
+ Apollo Client 4 moved its React hooks to a different import path, which is why `useQuery` reads as gone from the package root. That's the drift a model hits: the import it writes from memory no longer resolves.
114
+
115
+ Three things narrow that list, all measured across 35 libraries:
116
+
117
+ - **Values before types.** A model writes a hook far more often than it writes a type name, so the 29 removed type aliases sit behind the 24 callables.
118
+ - **A removal that was deprecated first produces almost no drift.** The deprecation is a signal in the training data; a silent removal isn't. Apollo's eight deprecated-then-removed symbols are separated out for that reason.
119
+ - **The window closes.** How old the major is predicts drift better than how big it was. Apollo v4 scored 0 of 12 once it had been out long enough, & zustand v5 was fully absorbed by about 19 months.
120
+
121
+ ## How a run works
122
+
123
+ 1. Installs the package into a throwaway sandbox under `~/.cache/sdkproof`. Lifecycle scripts are off unless you pass `--allow-scripts`.
124
+ 2. Writes 12 small coding tasks from that exact version's own README.
125
+ 3. Asks the model to solve them, with no hints about the API surface.
126
+ 4. Compiles every answer against the real installed package and reports what broke.
127
+
128
+ Step 2 has two rules the tool enforces rather than requests. A task skeleton may not import from the package under test, and neither the task nor its skeleton may name an export of it. Hand the model `import { useTable }` and you have answered the hard half of the question before it starts. Tasks that break either rule are thrown away and counted in the output.
129
+
130
+ Tasks are cached per `package@version`, so a re-run scores the same set. `--no-task-cache` writes a fresh one.
131
+
132
+ ## Options
133
+
134
+ ```
135
+ --model <id> model under test; repeatable. claude-*, gpt-*, or an
136
+ explicit anthropic:<id> / openai:<id>
137
+ --task-model <id> model that writes the tasks (default: the first --model)
138
+ --tasks <file> use a task file instead of writing one
139
+ --task-count <n> how many tasks to write (default 12)
140
+ --limit <n> run only the first n tasks
141
+ --concurrency <n> generations in flight (default 5; drop it if the API 429s)
142
+ --max-tokens <n> per-generation cap (default 16000)
143
+ --out <dir> write <package>@<version>.md and .json there
144
+ --json print the raw result JSON instead of the report
145
+ --markdown print the markdown report instead of the terminal one
146
+ --no-task-cache re-write the tasks even if this version has a cached set
147
+ --fresh reinstall the sandbox instead of reusing the cached one
148
+ --allow-scripts run npm lifecycle scripts during install (off by default)
149
+ --tsc <path> use a different tsc entrypoint
150
+ --from <v> --to <v> drift: compare two specific versions
151
+ ```
152
+
153
+ ## Things that will trip you up
154
+
155
+ **A package with no type declarations can't be scored.** There is nothing for the compiler to check against, and the run stops and says so.
156
+
157
+ **A refusal is not a failure.** If the model won't attempt a task, no code was written, so nothing about the library was measured. Refusals are reported separately and left out of the score.
158
+
159
+ **A lost task is worse than a slow one.** If generation errors out — an overloaded API, a timeout — the run prints `INCOMPLETE RUN` and exits 3. A partial run that loses the hard tasks scores higher than the real one, so don't publish that number.
160
+
161
+ **A thin README makes weak tasks.** Plenty of packages ship a badge wall that links out to a docs site. The tasks then lean on what the model already knows about the package. The run says so when it happens.
162
+
163
+ ## In a script
164
+
165
+ ```ts
166
+ import { run, computeDrift, driftVerdict, fetchPackument, anthropicAdapter } from "sdkproof";
167
+
168
+ // Check the cheap thing first — no model call, no install.
169
+ const packument = await fetchPackument("@apollo/client");
170
+ const verdict = driftVerdict(await computeDrift(packument));
171
+ if (!verdict.worth) {
172
+ console.log(`skipping: ${verdict.reason}`);
173
+ } else {
174
+ const out = await run({
175
+ spec: "@apollo/client",
176
+ adapters: [anthropicAdapter("claude-opus-5")],
177
+ taskCount: 12,
178
+ concurrency: 5,
179
+ log: console.error,
180
+ });
181
+ console.log(out.markdown);
182
+ if (out.incomplete) process.exit(3);
183
+ }
184
+ ```
185
+
186
+ Exit codes: `0` fine, `1` bad arguments or a broken target, `2` the API key or account is dead, `3` the run lost tasks and is not publishable.
187
+
188
+ ## Requirements
189
+
190
+ Node 20.12 or newer, `npm` on the PATH, and network access to the npm registry. One dependency: `typescript`.
191
+
192
+ MIT. Part of [SDKProof](https://sdkproof.dev) — [source](https://github.com/Kalpitrathore/sdkproof/tree/main/packages/cli).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
5
+ import { FatalApiError } from "./core/model.js";
6
+ import { computeDrift, driftVerdict } from "./drift.js";
7
+ import { adapterFor, defaultAdapters, DEFAULT_ANTHROPIC_MODEL, DEFAULT_OPENAI_MODEL, hasKeyFor, parseModelRef, } from "./models.js";
8
+ import { fetchPackument, resolveVersion } from "./registry.js";
9
+ import { renderDrift } from "./report.js";
10
+ import { parseSpec, run } from "./run.js";
11
+ const require_ = createRequire(import.meta.url);
12
+ function version() {
13
+ try {
14
+ return JSON.parse(readFileSync(require_.resolve("../package.json"), "utf8")).version;
15
+ }
16
+ catch {
17
+ return "0.0.0";
18
+ }
19
+ }
20
+ const HELP = `
21
+ sdkproof — does the code an AI writes for this package actually compile?
22
+
23
+ USAGE
24
+ npx sdkproof <package>[@version] score a package
25
+ npx sdkproof drift <package> what its latest major removed (no API key needed)
26
+
27
+ HOW A RUN WORKS
28
+ 1. installs the package into a throwaway sandbox
29
+ 2. writes small, realistic coding tasks from that version's own README
30
+ 3. asks the model to solve them, with no hints about the API surface
31
+ 4. compiles every answer against the real installed package with tsc
32
+
33
+ Pass = it compiles. No model judges another model.
34
+
35
+ OPTIONS
36
+ --model <id> model under test; repeatable. Accepts claude-*, gpt-*,
37
+ or an explicit anthropic:<id> / openai:<id>.
38
+ Default: every provider you have a key for.
39
+ --task-model <id> model that writes the tasks (default: the first --model)
40
+ --tasks <file> use a task file instead of writing one
41
+ --task-count <n> how many tasks to write (default 12)
42
+ --limit <n> run only the first n tasks
43
+ --concurrency <n> generations in flight (default 5; drop it if the API 429s)
44
+ --max-tokens <n> per-generation cap (default 16000)
45
+ --out <dir> write <package>@<version>.md and .json there
46
+ --json print the raw result JSON instead of the report
47
+ --markdown print the markdown report instead of the terminal one
48
+ --no-task-cache re-write the tasks even if this version has a cached set
49
+ --fresh reinstall the sandbox instead of reusing the cached one
50
+ --allow-scripts run npm lifecycle scripts during install (off by default)
51
+ --tsc <path> use a different tsc entrypoint
52
+ --from <v> --to <v> drift: compare two specific versions
53
+ -h, --help this
54
+ -v, --version print the version
55
+
56
+ KEYS
57
+ ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN, and/or OPENAI_API_KEY.
58
+ A .env in the current directory is loaded if present.
59
+ \`drift\` needs no key at all.
60
+
61
+ EXAMPLES
62
+ npx sdkproof zod
63
+ npx sdkproof @tanstack/react-table@9 --model claude-opus-5 --out ./reports
64
+ npx sdkproof drift @apollo/client
65
+ `;
66
+ const VALUE_FLAGS = new Set([
67
+ "--model", "--task-model", "--tasks", "--task-count", "--limit",
68
+ "--concurrency", "--max-tokens", "--out", "--tsc", "--from", "--to",
69
+ ]);
70
+ function parseArgs(argv) {
71
+ const positional = [];
72
+ const values = new Map();
73
+ const bools = new Set();
74
+ for (let i = 0; i < argv.length; i++) {
75
+ const a = argv[i];
76
+ if (!a.startsWith("-")) {
77
+ positional.push(a);
78
+ continue;
79
+ }
80
+ if (VALUE_FLAGS.has(a)) {
81
+ const v = argv[++i];
82
+ if (v === undefined)
83
+ throw new Error(`${a} needs a value`);
84
+ values.set(a, [...(values.get(a) ?? []), v]);
85
+ continue;
86
+ }
87
+ bools.add(a);
88
+ }
89
+ return { positional, values, bools };
90
+ }
91
+ const num = (f, name, fallback) => {
92
+ const raw = f.values.get(name)?.[0];
93
+ if (raw === undefined)
94
+ return fallback;
95
+ const n = Number(raw);
96
+ if (!Number.isFinite(n) || n <= 0)
97
+ throw new Error(`${name} must be a positive number, got "${raw}"`);
98
+ return Math.floor(n);
99
+ };
100
+ async function main() {
101
+ // A .env beside the user's project is where an API key usually already lives.
102
+ try {
103
+ process.loadEnvFile?.(path.join(process.cwd(), ".env"));
104
+ }
105
+ catch {
106
+ // no .env — use the ambient environment
107
+ }
108
+ const flags = parseArgs(process.argv.slice(2));
109
+ // Checked before the help fallback: `--version` carries no positional, and
110
+ // the fallback would otherwise answer it with the whole help text.
111
+ if (flags.bools.has("-v") || flags.bools.has("--version")) {
112
+ console.log(version());
113
+ return 0;
114
+ }
115
+ const askedForHelp = flags.bools.has("-h") || flags.bools.has("--help");
116
+ if (askedForHelp || !flags.positional.length) {
117
+ console.log(HELP.trim());
118
+ return askedForHelp ? 0 : 1;
119
+ }
120
+ const log = (line) => console.error(line);
121
+ if (flags.positional[0] === "drift") {
122
+ const target = flags.positional[1];
123
+ if (!target)
124
+ throw new Error("drift needs a package name: npx sdkproof drift <package>");
125
+ const { name, version: wanted } = parseSpec(target);
126
+ const packument = await fetchPackument(name);
127
+ const d = await computeDrift(packument, {
128
+ from: flags.values.get("--from")?.[0],
129
+ to: flags.values.get("--to")?.[0] ?? (wanted ? resolveVersion(packument, wanted) : undefined),
130
+ });
131
+ if (flags.bools.has("--json")) {
132
+ console.log(JSON.stringify({ ...d, verdict: driftVerdict(d) }, null, 2));
133
+ }
134
+ else {
135
+ console.log(renderDrift(d, driftVerdict(d)));
136
+ }
137
+ return 0;
138
+ }
139
+ const modelFlags = flags.values.get("--model") ?? [];
140
+ const adapters = modelFlags.length
141
+ ? modelFlags.map((m) => {
142
+ const ref = parseModelRef(m);
143
+ if (!hasKeyFor(ref.provider)) {
144
+ throw new Error(ref.provider === "anthropic"
145
+ ? `--model ${m} needs ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN) in the environment`
146
+ : `--model ${m} needs OPENAI_API_KEY in the environment`);
147
+ }
148
+ return adapterFor(ref);
149
+ })
150
+ : defaultAdapters();
151
+ if (!adapters.length) {
152
+ console.error([
153
+ "No model API key found.",
154
+ "",
155
+ " export ANTHROPIC_API_KEY=... scores " + DEFAULT_ANTHROPIC_MODEL,
156
+ " export OPENAI_API_KEY=... scores " + DEFAULT_OPENAI_MODEL,
157
+ "",
158
+ "Or run the part that needs no key:",
159
+ ` npx sdkproof drift ${flags.positional[0]}`,
160
+ ].join("\n"));
161
+ return 1;
162
+ }
163
+ const taskModelFlag = flags.values.get("--task-model")?.[0];
164
+ const outcome = await run({
165
+ spec: flags.positional[0],
166
+ adapters,
167
+ taskModel: taskModelFlag ? adapterFor(parseModelRef(taskModelFlag)) : undefined,
168
+ taskCount: num(flags, "--task-count", 12),
169
+ tasksFile: flags.values.get("--tasks")?.[0],
170
+ limit: flags.values.get("--limit") ? num(flags, "--limit", 0) : undefined,
171
+ concurrency: num(flags, "--concurrency", 5),
172
+ maxTokens: flags.values.get("--max-tokens") ? num(flags, "--max-tokens", 16000) : undefined,
173
+ fresh: flags.bools.has("--fresh"),
174
+ allowScripts: flags.bools.has("--allow-scripts"),
175
+ noTaskCache: flags.bools.has("--no-task-cache"),
176
+ tscEntry: flags.values.get("--tsc")?.[0],
177
+ outDir: flags.values.get("--out")?.[0],
178
+ log,
179
+ });
180
+ if (flags.bools.has("--json"))
181
+ console.log(outcome.json);
182
+ else if (flags.bools.has("--markdown"))
183
+ console.log(outcome.markdown);
184
+ else
185
+ console.log(outcome.terminal);
186
+ // An incomplete run is not a result. Exiting non-zero keeps it out of CI
187
+ // dashboards that would otherwise publish a score built on a shrunk denominator.
188
+ return outcome.incomplete ? 3 : 0;
189
+ }
190
+ main()
191
+ .then((code) => process.exit(code))
192
+ .catch((e) => {
193
+ if (e instanceof FatalApiError) {
194
+ console.error(`\nRUN ABORTED — ${e.message}`);
195
+ console.error("Nothing further was attempted. Fix the account, then re-run.");
196
+ process.exit(2);
197
+ }
198
+ console.error(`\nsdkproof: ${e.message}`);
199
+ process.exit(1);
200
+ });
201
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FailureCategory, FailurePattern, Verdict } from "./types.ts";
2
+ export declare function categorize(code: string): FailureCategory;
3
+ /** Bucket every error across all verdicts into ranked failure patterns. */
4
+ export declare function classify(verdicts: Verdict[]): FailurePattern[];
@@ -0,0 +1,72 @@
1
+ // Map tsc diagnostic codes to human failure categories.
2
+ const CODE_CATEGORY = {
3
+ TS2339: "hallucinated-member", // property does not exist
4
+ TS2551: "hallucinated-member", // property does not exist — did you mean
5
+ TS2353: "hallucinated-member", // invented object-literal field
6
+ TS2561: "hallucinated-member",
7
+ TS2694: "hallucinated-member",
8
+ // The three canonical shapes of "you imported the API that used to be here":
9
+ // the member moved entrypoint (TS2305), the same with a did-you-mean attached
10
+ // (TS2724), or the default export is gone (TS1192).
11
+ //
12
+ // TS2305 and TS1192 were added to API_SHAPE_CODES on 2026-08-13 but never
13
+ // here, so they fell through to "other" — and "other" is what the scorecard
14
+ // prints as the top failure pattern. Apollo Client 4, this project's flagship
15
+ // finding, publishes "other: 4" for four TS2305s that are the entire point of
16
+ // the measurement. Found 2026-08-18 re-scoring the AI SDK, whose scorecard
17
+ // led with "other: 13x".
18
+ //
19
+ // TS2724 moves with them: it is TS2305 with a suggestion attached, and
20
+ // splitting one error family across two categories is the same inconsistency
21
+ // the 08-13 fix was about. `deprecated-or-removed` was declared in
22
+ // FailureCategory and mapped from nothing; for a harness whose whole subject
23
+ // is removed and moved APIs, it is the accurate label for all three.
24
+ TS2305: "deprecated-or-removed",
25
+ TS2724: "deprecated-or-removed",
26
+ TS1192: "deprecated-or-removed",
27
+ TS2554: "wrong-arguments", // wrong number of arguments
28
+ TS2345: "wrong-arguments", // argument type not assignable
29
+ // The same family one level up: the call or the generic was handed the wrong
30
+ // shape. Unmapped until 2026-08-22, when a `zod` run through the published
31
+ // CLI reported "other: 2x" for two TS2769s that were the whole finding —
32
+ // the identical failure the 08-18 note describes for TS2305.
33
+ TS2769: "wrong-arguments", // no overload matches this call
34
+ TS2314: "wrong-arguments", // generic type requires N type argument(s)
35
+ TS2558: "wrong-arguments", // expected N type arguments, but got M
36
+ TS2707: "wrong-arguments", // generic type requires between N and M type arguments
37
+ TS2347: "wrong-arguments", // untyped function calls may not accept type arguments
38
+ TS2559: "type-mismatch", // no properties in common
39
+ TS2322: "type-mismatch", // type not assignable
40
+ TS2307: "bad-import", // cannot find module
41
+ };
42
+ export function categorize(code) {
43
+ return CODE_CATEGORY[code] ?? "other";
44
+ }
45
+ /** Bucket every error across all verdicts into ranked failure patterns. */
46
+ export function classify(verdicts) {
47
+ const byCategory = new Map();
48
+ for (const v of verdicts) {
49
+ for (const e of v.errors) {
50
+ const category = categorize(e.code);
51
+ const existing = byCategory.get(category);
52
+ if (existing) {
53
+ existing.count += 1;
54
+ }
55
+ else {
56
+ byCategory.set(category, {
57
+ category,
58
+ count: 1,
59
+ example: { taskId: v.taskId, model: v.model, message: e.message },
60
+ });
61
+ }
62
+ }
63
+ }
64
+ // "other" is the residual bucket and must never lead the scorecard. Ranking
65
+ // purely by count let it: a single failed type import produces one TS2305
66
+ // plus one TS7031 per parameter that lost its annotation, so on the AI SDK
67
+ // the DOWNSTREAM noise (11x "implicitly has an 'any' type") outranked the
68
+ // four removed types that caused it. The consequence was printed as the
69
+ // headline and the cause was printed underneath.
70
+ return [...byCategory.values()].sort((a, b) => Number(a.category === "other") - Number(b.category === "other") || b.count - a.count);
71
+ }
72
+ //# sourceMappingURL=classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/core/classify.ts"],"names":[],"mappings":"AAEA,wDAAwD;AACxD,MAAM,aAAa,GAAoC;IACrD,MAAM,EAAE,qBAAqB,EAAE,0BAA0B;IACzD,MAAM,EAAE,qBAAqB,EAAE,yCAAyC;IACxE,MAAM,EAAE,qBAAqB,EAAE,gCAAgC;IAC/D,MAAM,EAAE,qBAAqB;IAC7B,MAAM,EAAE,qBAAqB;IAC7B,6EAA6E;IAC7E,8EAA8E;IAC9E,oDAAoD;IACpD,EAAE;IACF,0EAA0E;IAC1E,4EAA4E;IAC5E,8EAA8E;IAC9E,8EAA8E;IAC9E,2EAA2E;IAC3E,yBAAyB;IACzB,EAAE;IACF,uEAAuE;IACvE,6EAA6E;IAC7E,mEAAmE;IACnE,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,EAAE,uBAAuB;IAC/B,MAAM,EAAE,uBAAuB;IAC/B,MAAM,EAAE,uBAAuB;IAC/B,MAAM,EAAE,iBAAiB,EAAE,4BAA4B;IACvD,MAAM,EAAE,iBAAiB,EAAE,+BAA+B;IAC1D,6EAA6E;IAC7E,2EAA2E;IAC3E,yEAAyE;IACzE,6DAA6D;IAC7D,MAAM,EAAE,iBAAiB,EAAE,gCAAgC;IAC3D,MAAM,EAAE,iBAAiB,EAAE,2CAA2C;IACtE,MAAM,EAAE,iBAAiB,EAAE,uCAAuC;IAClE,MAAM,EAAE,iBAAiB,EAAE,uDAAuD;IAClF,MAAM,EAAE,iBAAiB,EAAE,uDAAuD;IAClF,MAAM,EAAE,eAAe,EAAE,0BAA0B;IACnD,MAAM,EAAE,eAAe,EAAE,sBAAsB;IAC/C,MAAM,EAAE,YAAY,EAAE,qBAAqB;CAC5C,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;AACxC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,QAAQ,CAAC,QAAmB;IAC1C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE;oBACvB,QAAQ;oBACR,KAAK,EAAE,CAAC;oBACR,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;iBAClE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IACD,4EAA4E;IAC5E,0EAA0E;IAC1E,2EAA2E;IAC3E,0EAA0E;IAC1E,wEAAwE;IACxE,iDAAiD;IACjD,OAAO,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAClC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAC/F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ export interface GenerateRequest {
2
+ system: string;
3
+ user: string;
4
+ maxTokens?: number;
5
+ }
6
+ /** A model that generates code for a task. The "agent under test." */
7
+ export interface ModelAdapter {
8
+ /** the model id, used as the scorecard column name */
9
+ id: string;
10
+ generate(req: GenerateRequest): Promise<string>;
11
+ }
12
+ /**
13
+ * Thrown when a model refuses the identical prompt every time it is sampled.
14
+ * Typed so the CLI can record it as a refusal rather than a generic failure —
15
+ * a refusal is an unmeasured task, not a failed one.
16
+ */
17
+ export declare class RefusalError extends Error {
18
+ readonly attempts: number;
19
+ constructor(attempts: number);
20
+ }
21
+ /**
22
+ * An error that makes every remaining request pointless — an exhausted credit
23
+ * balance, a revoked key. Distinct from a refusal (one task) or a 529 (retry),
24
+ * because the right response is to stop the run, not to keep paying for
25
+ * failures. On 2026-08-05 a credit exhaustion burned 30 further attempts
26
+ * against a dead key before the run ended with nothing.
27
+ */
28
+ export declare class FatalApiError extends Error {
29
+ constructor(message: string);
30
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Thrown when a model refuses the identical prompt every time it is sampled.
3
+ * Typed so the CLI can record it as a refusal rather than a generic failure —
4
+ * a refusal is an unmeasured task, not a failed one.
5
+ */
6
+ export class RefusalError extends Error {
7
+ attempts;
8
+ constructor(attempts) {
9
+ super(`model refused this task ${attempts}x — not library drift, excluded from the score`);
10
+ this.attempts = attempts;
11
+ this.name = "RefusalError";
12
+ }
13
+ }
14
+ /**
15
+ * An error that makes every remaining request pointless — an exhausted credit
16
+ * balance, a revoked key. Distinct from a refusal (one task) or a 529 (retry),
17
+ * because the right response is to stop the run, not to keep paying for
18
+ * failures. On 2026-08-05 a credit exhaustion burned 30 further attempts
19
+ * against a dead key before the run ended with nothing.
20
+ */
21
+ export class FatalApiError extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = "FatalApiError";
25
+ }
26
+ }
27
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/core/model.ts"],"names":[],"mappings":"AAaA;;;;GAIG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAChB,QAAQ;IAA7B,YAAqB,QAAgB;QACnC,KAAK,CAAC,2BAA2B,QAAQ,gDAAgD,CAAC,CAAC;wBADxE,QAAQ;QAE3B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ import type { PromptTarget, Task } from "./types.ts";
2
+ export declare const GENERATION_SYSTEM: string;
3
+ export declare function buildUserPrompt(task: Task, spec: PromptTarget, context?: string): string;
4
+ export declare function extractCode(text: string): string;
@@ -0,0 +1,43 @@
1
+ export const GENERATION_SYSTEM = "You are an expert TypeScript developer. Implement the requested function using the specified library. " +
2
+ "Respond with ONLY the complete TypeScript module inside a single ```ts code block — no explanation before or after. " +
3
+ "Keep the provided imports and any `declare` lines exactly as given. " +
4
+ "Fill in the function body so the module type-checks against the real installed package.";
5
+ export function buildUserPrompt(task, spec, context) {
6
+ const base = [
7
+ `Library: ${spec.displayName}, imported from "${spec.packageName}".`,
8
+ spec.docsHint,
9
+ "",
10
+ `Task: ${task.prompt}`,
11
+ "",
12
+ "Complete this module:",
13
+ "```ts",
14
+ task.skeleton,
15
+ "```",
16
+ ].join("\n");
17
+ // No context => byte-identical to every prompt that produced a published
18
+ // score. That equality is asserted in test/prompt.test.ts, because a silent
19
+ // change here would move six numbers that are already on the web.
20
+ if (!context)
21
+ return base;
22
+ return [
23
+ "Project context — the agent files this library ships:",
24
+ "",
25
+ context,
26
+ "",
27
+ "---",
28
+ "",
29
+ base,
30
+ ].join("\n");
31
+ }
32
+ // Prefer the *longest* fenced ts/js block; fall back to the raw text with any
33
+ // stray fence markers stripped. Taking the longest (not the first) guards
34
+ // against a stray early ``` — in a comment or string — truncating the capture,
35
+ // which otherwise produces a broken fragment and a false compile failure.
36
+ const FENCE = /```(?:ts|typescript|tsx|js|javascript)?[^\S\r\n]*\r?\n([\s\S]*?)```/g;
37
+ export function extractCode(text) {
38
+ const blocks = [...text.matchAll(FENCE)].map((m) => m[1].trim());
39
+ if (blocks.length > 0)
40
+ return blocks.reduce((a, b) => (b.length > a.length ? b : a));
41
+ return text.replace(/^```[a-z]*[^\S\r\n]*\r?\n?/i, "").replace(/```\s*$/i, "").trim();
42
+ }
43
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/core/prompt.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAC5B,wGAAwG;IACxG,sHAAsH;IACtH,sEAAsE;IACtE,yFAAyF,CAAC;AAE5F,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,IAAkB,EAAE,OAAgB;IAC9E,MAAM,IAAI,GAAG;QACX,YAAY,IAAI,CAAC,WAAW,oBAAoB,IAAI,CAAC,WAAW,IAAI;QACpE,IAAI,CAAC,QAAQ;QACb,EAAE;QACF,SAAS,IAAI,CAAC,MAAM,EAAE;QACtB,EAAE;QACF,uBAAuB;QACvB,OAAO;QACP,IAAI,CAAC,QAAQ;QACb,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,yEAAyE;IACzE,4EAA4E;IAC5E,kEAAkE;IAClE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO;QACL,uDAAuD;QACvD,EAAE;QACF,OAAO;QACP,EAAE;QACF,KAAK;QACL,EAAE;QACF,IAAI;KACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,KAAK,GAAG,sEAAsE,CAAC;AAErF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,OAAO,IAAI,CAAC,OAAO,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACxF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { LostTask, ArmScore, Refusal, Result, Verdict } from "./types.ts";
2
+ /** Aggregate verdicts into a per-model + overall score with ranked failures. */
3
+ export declare function score(library: string, libraryVersion: string, generatedAt: string, verdicts: Verdict[], refusals?: Refusal[], contextArms?: ArmScore[], lost?: LostTask[]): Result;