@cat-factory/sandbox-fixtures 0.7.2 → 0.7.5

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Igor Savin
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Savin
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.
@@ -0,0 +1,9 @@
1
+ import type { SandboxExpectation } from '@cat-factory/contracts';
2
+ /** Concise builder for a graded expectation; `matchHints` defaults to `[summary]`-matching. */
3
+ export declare function exp(id: string, summary: string, grade: {
4
+ impact: number;
5
+ trickiness: number;
6
+ detail?: string;
7
+ matchHints?: string[];
8
+ }): SandboxExpectation;
9
+ //# sourceMappingURL=expectation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expectation.d.ts","sourceRoot":"","sources":["../src/expectation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAEhE,+FAA+F;AAC/F,wBAAgB,GAAG,CACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACpF,kBAAkB,CASpB"}
@@ -0,0 +1,12 @@
1
+ /** Concise builder for a graded expectation; `matchHints` defaults to `[summary]`-matching. */
2
+ export function exp(id, summary, grade) {
3
+ return {
4
+ id,
5
+ summary,
6
+ detail: grade.detail ?? '',
7
+ impact: grade.impact,
8
+ trickiness: grade.trickiness,
9
+ matchHints: grade.matchHints ?? [],
10
+ };
11
+ }
12
+ //# sourceMappingURL=expectation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expectation.js","sourceRoot":"","sources":["../src/expectation.ts"],"names":[],"mappings":"AAEA,+FAA+F;AAC/F,MAAM,UAAU,GAAG,CACjB,EAAU,EACV,OAAe,EACf,KAAqF;IAErF,OAAO;QACL,EAAE;QACF,OAAO;QACP,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;KACnC,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SandboxFixtureDefinition } from '../types.js';
2
+ export declare const ARCHITECTURE_FIXTURES: SandboxFixtureDefinition[];
3
+ //# sourceMappingURL=architecture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture.d.ts","sourceRoot":"","sources":["../../src/fixtures/architecture.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAwB3D,eAAO,MAAM,qBAAqB,EAAE,wBAAwB,EA8L3D,CAAA"}
@@ -0,0 +1,160 @@
1
+ import { exp } from '../expectation.js';
2
+ // architecture-proposal review fixtures. Mapped to the `architect-companion` agent (it
3
+ // reviews an `architect`'s design). The proposal under review is carried as the `architect`
4
+ // step's entry in `priorOutputs`; the companion critiques it. The expectations are the
5
+ // scaling/consistency/operability gaps a strong design review should raise.
6
+ /** Build an architect-companion context whose prior output is the design proposal to review. */
7
+ function proposalContext(block, proposal) {
8
+ return {
9
+ agentKind: 'architect-companion',
10
+ pipelineName: 'sandbox',
11
+ stepIndex: 1,
12
+ isFinalStep: true,
13
+ block,
14
+ priorOutputs: [{ agentKind: 'architect', output: proposal }],
15
+ decisions: [],
16
+ resolvedDecision: null,
17
+ };
18
+ }
19
+ export const ARCHITECTURE_FIXTURES = [
20
+ {
21
+ id: 'arch-counter-redis-moderate',
22
+ agentKind: 'architect-companion',
23
+ kind: 'architecture',
24
+ name: 'View-counter design (moderate)',
25
+ difficulty: 'moderate',
26
+ summary: 'A "count page views" design that ignores cache durability and write contention.',
27
+ payload: proposalContext({
28
+ title: 'Page view counter',
29
+ type: 'service',
30
+ description: 'Show a near-real-time view count on each article.',
31
+ }, [
32
+ '# Design: page view counter',
33
+ '',
34
+ 'On each request we INCR a Redis key `views:{articleId}` and read it back to render the count.',
35
+ 'A background job copies the Redis counts into the `articles.view_count` column every hour so the',
36
+ 'numbers survive. Redis runs as a single instance. This is simple and fast.',
37
+ ].join('\n')),
38
+ expectations: [
39
+ exp('cache-durability', 'Redis is the source of truth between hourly flushes — a single-instance crash loses up to an hour of counts.', {
40
+ impact: 5,
41
+ trickiness: 3,
42
+ detail: 'Single Redis + hourly persistence makes a cache the durable store; the central design flaw.',
43
+ matchHints: [
44
+ 'lose counts',
45
+ 'lose up to',
46
+ 'data loss',
47
+ 'durability',
48
+ 'redis crash',
49
+ 'single instance',
50
+ 'single point of failure',
51
+ 'persistence',
52
+ ],
53
+ }),
54
+ exp('hot-key', 'A viral article is a single hot Redis key — a write/throughput hotspot with no sharding plan.', {
55
+ impact: 3,
56
+ trickiness: 4,
57
+ matchHints: ['hot key', 'hotspot', 'hot spot', 'contention', 'shard'],
58
+ }),
59
+ exp('read-cost', 'Reading the count back from Redis on every render is unnecessary; the count can be returned from the INCR or cached.', {
60
+ impact: 2,
61
+ trickiness: 3,
62
+ matchHints: ['read back', 'every render', 'return from incr', 'extra round trip'],
63
+ }),
64
+ exp('idempotency', 'No dedupe: refresh/bots inflate counts — is a "view" unique per user/session, and over what window?', {
65
+ impact: 3,
66
+ trickiness: 4,
67
+ detail: 'Whether a view is deduped is a real product/correctness question the design skips.',
68
+ matchHints: ['dedupe', 'deduplicat', 'unique', 'bot', 'refresh', 'idempoten'],
69
+ }),
70
+ ],
71
+ notes: 'The cache-as-durable-store flaw is the must-find; hot-key and dedupe are the higher-skill catches.',
72
+ },
73
+ {
74
+ id: 'arch-outbox-events-complex',
75
+ agentKind: 'architect-companion',
76
+ kind: 'architecture',
77
+ name: 'Order-events pipeline (complex)',
78
+ difficulty: 'complex',
79
+ summary: 'An event-publishing design with a dual-write, at-least-once, and ordering pitfalls.',
80
+ payload: proposalContext({
81
+ title: 'Publish order events',
82
+ type: 'service',
83
+ description: 'When an order changes, publish an event other services consume (fulfilment, analytics, email).',
84
+ }, [
85
+ '# Design: order event publishing',
86
+ '',
87
+ 'In the order service, after we commit the order to Postgres we publish an `OrderChanged` event to',
88
+ 'Kafka. Consumers (fulfilment, analytics, email) subscribe and react. If publishing fails we log it',
89
+ 'and retry in a background sweep. Each event carries the full order. We use a topic per event type and',
90
+ 'partition by event type so throughput is high.',
91
+ ].join('\n')),
92
+ expectations: [
93
+ exp('dual-write', 'Commit-then-publish is a dual write: a crash between the two loses the event despite a committed order — needs a transactional outbox / CDC.', {
94
+ impact: 5,
95
+ trickiness: 5,
96
+ detail: 'The headline distributed-systems flaw and the standout catch — "we commit then publish" is the tell.',
97
+ matchHints: [
98
+ 'dual write',
99
+ 'dual-write',
100
+ 'outbox',
101
+ 'cdc',
102
+ 'change data capture',
103
+ 'commit then publish',
104
+ 'two-phase',
105
+ ],
106
+ }),
107
+ exp('ordering', 'Partitioning by event TYPE (not order id) means events for one order can be processed out of order.', {
108
+ impact: 5,
109
+ trickiness: 5,
110
+ detail: 'Partition key is the subtle but critical choice; per-type partitioning destroys per-order ordering.',
111
+ matchHints: [
112
+ 'out of order',
113
+ 'ordering',
114
+ 'partition by',
115
+ 'partition key',
116
+ 'per-order',
117
+ 'order id key',
118
+ ],
119
+ }),
120
+ exp('idempotent-consumers', 'At-least-once delivery + retries means consumers must be idempotent — the email service will double-send otherwise.', {
121
+ impact: 4,
122
+ trickiness: 3,
123
+ matchHints: [
124
+ 'idempoten',
125
+ 'at least once',
126
+ 'at-least-once',
127
+ 'duplicate',
128
+ 'double-send',
129
+ 'exactly once',
130
+ ],
131
+ }),
132
+ exp('full-payload', 'Carrying the full order in every event couples consumers to the order schema and bloats the topic; consider a thin event + lookup or a versioned schema.', {
133
+ impact: 3,
134
+ trickiness: 3,
135
+ matchHints: [
136
+ 'full order',
137
+ 'full payload',
138
+ 'schema coupling',
139
+ 'schema version',
140
+ 'thin event',
141
+ 'bloat',
142
+ ],
143
+ }),
144
+ exp('retry-sweep', 'The "log and retry in a background sweep" path has no durable record of the failed publish to retry from — what does the sweep read?', {
145
+ impact: 4,
146
+ trickiness: 4,
147
+ detail: 'Ties back to the outbox: without a persisted intent there is nothing for the sweep to replay.',
148
+ matchHints: [
149
+ 'nothing to retry',
150
+ 'no record',
151
+ 'what does the sweep',
152
+ 'durable record',
153
+ 'persisted',
154
+ ],
155
+ }),
156
+ ],
157
+ notes: 'A dense distributed-systems review: the dual-write and partition-key/ordering flaws are the high-impact, high-trickiness wow catches.',
158
+ },
159
+ ];
160
+ //# sourceMappingURL=architecture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture.js","sourceRoot":"","sources":["../../src/fixtures/architecture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SandboxFixtureDefinition } from '../types.js';
2
+ export declare const CLARITY_FIXTURES: SandboxFixtureDefinition[];
3
+ //# sourceMappingURL=clarity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clarity.d.ts","sourceRoot":"","sources":["../../src/fixtures/clarity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAO3D,eAAO,MAAM,gBAAgB,EAAE,wBAAwB,EA0NtD,CAAA"}
@@ -0,0 +1,174 @@
1
+ import { exp } from '../expectation.js';
2
+ // clarity-review (bug-report triage) fixtures. The payload is a `ClarityContext`:
3
+ // `{ block: { title, type, description }, investigation? }`. Each is a vague/ambiguous
4
+ // bug report; the expectations are the missing facts or conflations a good triage should
5
+ // surface so the bug becomes actionable.
6
+ export const CLARITY_FIXTURES = [
7
+ {
8
+ id: 'clarity-slow-page-simple',
9
+ agentKind: 'clarity-review',
10
+ kind: 'clarity',
11
+ name: 'Page is slow (simple)',
12
+ difficulty: 'simple',
13
+ summary: 'A one-line "the dashboard is slow" report with no repro, scope, or baseline.',
14
+ payload: {
15
+ block: {
16
+ title: 'Dashboard is slow',
17
+ type: 'service',
18
+ description: 'The dashboard is really slow now. Please fix it, it was fine before.',
19
+ },
20
+ },
21
+ expectations: [
22
+ exp('repro', 'No reproduction steps: which dashboard/view, what actions, signed in as whom?', {
23
+ impact: 5,
24
+ trickiness: 1,
25
+ matchHints: ['reproduction', 'reproduce', 'repro', 'steps'],
26
+ }),
27
+ exp('quantify', '"Slow" is not quantified — how slow, vs what baseline, and measured how?', {
28
+ impact: 4,
29
+ trickiness: 1,
30
+ matchHints: ['how slow', 'quantif', 'load time', 'response time', 'baseline', 'measured'],
31
+ }),
32
+ exp('regression-window', '"Fine before" — when did it regress, and what changed (deploy, data growth) around then?', {
33
+ impact: 4,
34
+ trickiness: 3,
35
+ detail: 'Pinning the regression window is the highest-leverage triage question and is easy to skip past.',
36
+ matchHints: ['when did', 'regress', 'started', 'deploy', 'recently'],
37
+ }),
38
+ exp('scope', 'Is it all users or one account — could it be data-volume-dependent for a specific tenant?', {
39
+ impact: 3,
40
+ trickiness: 3,
41
+ matchHints: ['all users', 'one user', 'specific account', 'tenant', 'data volume'],
42
+ }),
43
+ ],
44
+ notes: 'Missing repro is the must-find; the regression-window question is the higher-skill catch.',
45
+ },
46
+ {
47
+ id: 'clarity-login-loop-moderate',
48
+ agentKind: 'clarity-review',
49
+ kind: 'clarity',
50
+ name: 'Login keeps failing (moderate)',
51
+ difficulty: 'moderate',
52
+ summary: 'A login bug report that conflates several distinct failure modes.',
53
+ payload: {
54
+ block: {
55
+ title: 'Login keeps failing',
56
+ type: 'service',
57
+ description: [
58
+ 'Users say login keeps failing. Sometimes it says the password is wrong even though it is right,',
59
+ 'and sometimes it just loops back to the login page. A couple of people mentioned the code from',
60
+ 'the app did not work. Happens on and off.',
61
+ ].join(' '),
62
+ },
63
+ },
64
+ expectations: [
65
+ exp('conflation', 'Three distinct failures are conflated: wrong-password, redirect loop, and 2FA code rejection.', {
66
+ impact: 5,
67
+ trickiness: 4,
68
+ detail: 'Separating the symptoms is the key triage move — each likely has a different root cause.',
69
+ matchHints: [
70
+ 'separate',
71
+ 'distinct',
72
+ 'conflate',
73
+ 'three different',
74
+ 'different issues',
75
+ '2fa',
76
+ ],
77
+ }),
78
+ exp('repro', 'No reproduction: which accounts, after what action, and is "wrong even though right" verified?', {
79
+ impact: 5,
80
+ trickiness: 1,
81
+ matchHints: ['reproduction', 'reproduce', 'repro', 'steps'],
82
+ }),
83
+ exp('environment', 'Missing environment: browser/app version, platform, and whether it correlates with any of them.', {
84
+ impact: 3,
85
+ trickiness: 1,
86
+ matchHints: ['browser', 'app version', 'platform', 'device', 'os'],
87
+ }),
88
+ exp('intermittent', '"On and off" — is the redirect loop tied to expired sessions/cookies or a specific server?', {
89
+ impact: 4,
90
+ trickiness: 4,
91
+ detail: 'The loop smells like a session/cookie or load-balancer-affinity issue; a sharp triager probes that.',
92
+ matchHints: [
93
+ 'session',
94
+ 'cookie',
95
+ 'expired',
96
+ 'load balancer',
97
+ 'sticky',
98
+ 'server instance',
99
+ ],
100
+ }),
101
+ ],
102
+ notes: 'The symptom-conflation and the session/cookie hypothesis are the high-skill catches.',
103
+ },
104
+ {
105
+ id: 'clarity-data-loss-complex',
106
+ agentKind: 'clarity-review',
107
+ kind: 'clarity',
108
+ name: 'Edits sometimes disappear (complex)',
109
+ difficulty: 'complex',
110
+ summary: 'An intermittent data-loss report with a partial investigation already attached.',
111
+ payload: {
112
+ block: {
113
+ title: 'Saved edits sometimes disappear',
114
+ type: 'service',
115
+ description: [
116
+ 'Customers report that edits they make to a document sometimes disappear after a while. They save,',
117
+ 'see the change, then later it is back to an old version. It does not happen every time. This is',
118
+ 'causing churn — please prioritize.',
119
+ ].join(' '),
120
+ },
121
+ investigation: [
122
+ 'Investigator notes: the document service has a "last write wins" update path. Two browser tabs (or the',
123
+ 'mobile app and web open at once) each hold a copy loaded at different times. There is no version check',
124
+ 'on save. Logs show overlapping saves to the same document id within a few seconds for affected users.',
125
+ ].join(' '),
126
+ },
127
+ expectations: [
128
+ exp('root-cause', 'The investigation points at a lost-update / concurrent-write race (last-write-wins, no version check) — confirm and frame it as the likely root cause.', {
129
+ impact: 5,
130
+ trickiness: 3,
131
+ detail: 'Restate the investigator’s finding as the working hypothesis instead of asking generic questions.',
132
+ matchHints: [
133
+ 'last write wins',
134
+ 'lost update',
135
+ 'concurrent',
136
+ 'race',
137
+ 'version check',
138
+ 'optimistic',
139
+ ],
140
+ }),
141
+ exp('repro-multitab', 'Targeted repro: two tabs / web + mobile editing the same document, confirming the overlap window.', {
142
+ impact: 4,
143
+ trickiness: 3,
144
+ matchHints: [
145
+ 'two tabs',
146
+ 'multiple tabs',
147
+ 'web and mobile',
148
+ 'same document',
149
+ 'concurrent edit',
150
+ ],
151
+ }),
152
+ exp('data-recovery', 'Is the overwritten version recoverable (history/audit), and how many customers/documents are affected so far?', {
153
+ impact: 5,
154
+ trickiness: 4,
155
+ detail: 'Data-loss bugs need a recovery/containment question, not just a fix — frequently missed under time pressure.',
156
+ matchHints: [
157
+ 'recover',
158
+ 'restore',
159
+ 'version history',
160
+ 'audit',
161
+ 'how many affected',
162
+ 'blast radius',
163
+ ],
164
+ }),
165
+ exp('not-every-time', 'Explain "not every time": it only manifests on overlapping concurrent saves, not on a single editor.', {
166
+ impact: 3,
167
+ trickiness: 2,
168
+ matchHints: ['not every time', 'intermittent', 'only when', 'overlap'],
169
+ }),
170
+ ],
171
+ notes: 'With an investigation attached, the skill is synthesizing it (root cause) and adding the recovery/blast-radius question — not re-asking what is already known.',
172
+ },
173
+ ];
174
+ //# sourceMappingURL=clarity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clarity.js","sourceRoot":"","sources":["../../src/fixtures/clarity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SandboxFixtureDefinition } from '../types.js';
2
+ export declare const CODE_REVIEW_FIXTURES: SandboxFixtureDefinition[];
3
+ //# sourceMappingURL=code-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-review.d.ts","sourceRoot":"","sources":["../../src/fixtures/code-review.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAwB3D,eAAO,MAAM,oBAAoB,EAAE,wBAAwB,EAkQ1D,CAAA"}
@@ -0,0 +1,214 @@
1
+ import { exp } from '../expectation.js';
2
+ // reviewer (code-review) fixtures. The payload is a reviewer `AgentRunContext`: the work
3
+ // to review is carried as the `coder` step's entry in `priorOutputs` (a code snippet in a
4
+ // fenced block). The expectations are the genuine correctness/security/edge-case problems a
5
+ // strong reviewer should find, graded by impact (how bad to miss) and trickiness (how subtle).
6
+ /** Build a reviewer context whose only prior output is the coder's snippet to review. */
7
+ function reviewerContext(block, snippet) {
8
+ return {
9
+ agentKind: 'reviewer',
10
+ pipelineName: 'sandbox',
11
+ stepIndex: 1,
12
+ isFinalStep: true,
13
+ block,
14
+ priorOutputs: [{ agentKind: 'coder', output: snippet }],
15
+ decisions: [],
16
+ resolvedDecision: null,
17
+ };
18
+ }
19
+ export const CODE_REVIEW_FIXTURES = [
20
+ {
21
+ id: 'review-token-bucket-simple',
22
+ agentKind: 'reviewer',
23
+ kind: 'code-review',
24
+ name: 'Rate limiter (simple)',
25
+ difficulty: 'simple',
26
+ summary: 'A "token bucket" rate limiter that is neither a token bucket nor concurrency-safe.',
27
+ payload: reviewerContext({
28
+ title: 'Per-IP rate limiter',
29
+ type: 'api',
30
+ description: 'A token-bucket rate limiter middleware that allows 100 requests/minute per IP.',
31
+ }, [
32
+ 'Implemented the limiter:',
33
+ '',
34
+ '```ts',
35
+ 'const counts = new Map<string, number>()',
36
+ '',
37
+ 'export function allow(ip: string): boolean {',
38
+ ' const count = counts.get(ip) ?? 0',
39
+ ' if (count >= 100) return false',
40
+ ' counts.set(ip, count + 1)',
41
+ ' return true',
42
+ '}',
43
+ '```',
44
+ '',
45
+ 'The counter increments on each request and rejects once it hits 100.',
46
+ ].join('\n')),
47
+ expectations: [
48
+ exp('no-window-reset', 'There is no time window: the count never resets, so this is a lifetime cap of 100, not 100/minute.', {
49
+ impact: 5,
50
+ trickiness: 3,
51
+ detail: 'The headline bug — the feature simply does not do what the spec ("per minute") asks.',
52
+ matchHints: [
53
+ 'never resets',
54
+ 'no window',
55
+ 'time window',
56
+ 'per minute',
57
+ 'lifetime',
58
+ 'does not reset',
59
+ ],
60
+ }),
61
+ exp('unbounded-map', 'The Map grows unbounded (one entry per IP, never evicted) — a memory leak / DoS vector.', {
62
+ impact: 4,
63
+ trickiness: 3,
64
+ matchHints: ['unbounded', 'memory leak', 'never evicted', 'grows', 'grow forever'],
65
+ }),
66
+ exp('concurrency', 'Read-modify-write on the shared Map is not atomic; concurrent requests can over-admit.', {
67
+ impact: 3,
68
+ trickiness: 4,
69
+ matchHints: ['atomic', 'race', 'concurrent', 'read-modify-write', 'thread'],
70
+ }),
71
+ ],
72
+ notes: 'The missing time-window reset is the high-impact must-find; the concurrency hazard is the subtler catch.',
73
+ },
74
+ {
75
+ id: 'review-pagination-moderate',
76
+ agentKind: 'reviewer',
77
+ kind: 'code-review',
78
+ name: 'Offset pagination (moderate)',
79
+ difficulty: 'moderate',
80
+ summary: 'A list endpoint with SQL injection, unbounded page size, and an off-by-one.',
81
+ payload: reviewerContext({
82
+ title: 'List orders endpoint',
83
+ type: 'api',
84
+ description: 'GET /orders?page=&size= returns a page of the current user’s orders, newest first.',
85
+ }, [
86
+ 'Added the handler:',
87
+ '',
88
+ '```ts',
89
+ 'async function listOrders(req) {',
90
+ ' const page = req.query.page ?? 1',
91
+ ' const size = req.query.size ?? 20',
92
+ ' const offset = page * size',
93
+ ' const sql =',
94
+ ' `SELECT * FROM orders WHERE user_id = ${req.userId} ORDER BY created_at DESC ` +',
95
+ ' `LIMIT ${size} OFFSET ${offset}`',
96
+ ' return db.query(sql)',
97
+ '}',
98
+ '```',
99
+ ].join('\n')),
100
+ expectations: [
101
+ exp('sql-injection', 'Values are interpolated straight into SQL — `size`, `page`, and `userId` must be parameterized.', {
102
+ impact: 5,
103
+ trickiness: 1,
104
+ detail: 'Classic SQL injection; the most impactful and least subtle issue here.',
105
+ matchHints: [
106
+ 'sql injection',
107
+ 'parameterize',
108
+ 'parameterized',
109
+ 'interpolat',
110
+ 'prepared statement',
111
+ ],
112
+ }),
113
+ exp('offset-off-by-one', 'Offset is `page * size`, so page 1 skips the first page; it should be `(page - 1) * size`.', {
114
+ impact: 4,
115
+ trickiness: 4,
116
+ detail: 'A subtle correctness bug: with 1-based pages, page 1 already skips `size` rows.',
117
+ matchHints: [
118
+ 'off-by-one',
119
+ 'off by one',
120
+ 'page - 1',
121
+ 'page minus one',
122
+ 'skips the first',
123
+ 'should be (page',
124
+ ],
125
+ }),
126
+ exp('unbounded-size', 'No upper bound on `size`: a client can request a huge page and exhaust memory / the DB.', {
127
+ impact: 4,
128
+ trickiness: 3,
129
+ matchHints: ['unbounded', 'max size', 'cap the', 'upper bound', 'limit the page size'],
130
+ }),
131
+ exp('query-types', 'Query params are strings: `page`/`size` are not parsed to numbers and not validated as positive integers.', {
132
+ impact: 3,
133
+ trickiness: 3,
134
+ matchHints: [
135
+ 'positive integer',
136
+ 'not a number',
137
+ 'parsed to a number',
138
+ 'coerce',
139
+ 'cast to a number',
140
+ 'nan',
141
+ ],
142
+ }),
143
+ ],
144
+ notes: 'SQL injection is the must-find; the `page * size` off-by-one is the high-trickiness catch.',
145
+ },
146
+ {
147
+ id: 'review-jwt-verify-complex',
148
+ agentKind: 'reviewer',
149
+ kind: 'code-review',
150
+ name: 'JWT verification (complex)',
151
+ difficulty: 'complex',
152
+ summary: 'A hand-rolled JWT verifier with several serious, subtle security holes.',
153
+ payload: reviewerContext({
154
+ title: 'Verify session JWT',
155
+ type: 'service',
156
+ description: 'Verify an incoming JWT and return its claims, rejecting invalid tokens.',
157
+ }, [
158
+ 'Implemented verification:',
159
+ '',
160
+ '```ts',
161
+ 'function verify(token: string, secret: string) {',
162
+ ' const [headerB64, payloadB64, sig] = token.split(".")',
163
+ ' const header = JSON.parse(atob(headerB64))',
164
+ ' const payload = JSON.parse(atob(payloadB64))',
165
+ ' if (header.alg === "none") return payload',
166
+ ' const expected = hmacSha256(`${headerB64}.${payloadB64}`, secret)',
167
+ ' if (sig === expected) {',
168
+ ' return payload',
169
+ ' }',
170
+ ' throw new Error("bad token")',
171
+ '}',
172
+ '```',
173
+ ].join('\n')),
174
+ expectations: [
175
+ exp('alg-none', 'It accepts `alg: "none"` and returns the payload unverified — anyone can forge a token.', {
176
+ impact: 5,
177
+ trickiness: 5,
178
+ detail: 'The canonical JWT "alg=none" bypass; the most dangerous and most impressive catch.',
179
+ matchHints: [
180
+ 'alg none',
181
+ 'alg: none',
182
+ 'algorithm none',
183
+ 'none algorithm',
184
+ 'forge',
185
+ 'unverified',
186
+ ],
187
+ }),
188
+ exp('no-exp', 'No expiry (`exp`)/`nbf` check, so an old or stolen token is accepted forever.', {
189
+ impact: 5,
190
+ trickiness: 2,
191
+ matchHints: ['expiry', 'expiration', 'exp claim', 'expired', 'nbf', 'not before'],
192
+ }),
193
+ exp('timing-unsafe', 'Signature compared with `===` (timing-unsafe); use a constant-time comparison.', {
194
+ impact: 3,
195
+ trickiness: 4,
196
+ detail: 'A timing side-channel on signature comparison — a hallmark of an expert review.',
197
+ matchHints: ['timing', 'constant-time', 'constant time', 'timing-safe', 'timing attack'],
198
+ }),
199
+ exp('alg-confusion', 'Header `alg` is trusted but only HMAC is computed — an RS256→HS256 key-confusion attack is possible.', {
200
+ impact: 4,
201
+ trickiness: 5,
202
+ detail: 'The classic JWT algorithm-confusion class; rarely surfaced.',
203
+ matchHints: ['algorithm confusion', 'alg confusion', 'rs256', 'hs256', 'key confusion'],
204
+ }),
205
+ exp('audience-issuer', 'No `aud`/`iss` validation, so a token minted for another service is accepted.', {
206
+ impact: 3,
207
+ trickiness: 3,
208
+ matchHints: ['audience', 'aud claim', 'issuer', 'iss claim'],
209
+ }),
210
+ ],
211
+ notes: 'A dense security review: alg=none and algorithm-confusion are the high-trickiness wow catches; alg=none and missing-exp are the high-impact must-finds.',
212
+ },
213
+ ];
214
+ //# sourceMappingURL=code-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-review.js","sourceRoot":"","sources":["../../src/fixtures/code-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAA;AAGvC,yFAAyF;AACzF,0FAA0F;AAC1F,4FAA4F;AAC5F,+FAA+F;AAE/F,yFAAyF;AACzF,SAAS,eAAe,CACtB,KAA2D,EAC3D,OAAe;IAEf,OAAO;QACL,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,SAAS;QACvB,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,IAAI;QACjB,KAAK;QACL,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACvD,SAAS,EAAE,EAAE;QACb,gBAAgB,EAAE,IAAI;KACvB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAA+B;IAC9D;QACE,EAAE,EAAE,4BAA4B;QAChC,SAAS,EAAE,UAAU;QACrB,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,uBAAuB;QAC7B,UAAU,EAAE,QAAQ;QACpB,OAAO,EAAE,oFAAoF;QAC7F,OAAO,EAAE,eAAe,CACtB;YACE,KAAK,EAAE,qBAAqB;YAC5B,IAAI,EAAE,KAAK;YACX,WAAW,EACT,gFAAgF;SACnF,EACD;YACE,0BAA0B;YAC1B,EAAE;YACF,OAAO;YACP,0CAA0C;YAC1C,EAAE;YACF,8CAA8C;YAC9C,qCAAqC;YACrC,kCAAkC;YAClC,6BAA6B;YAC7B,eAAe;YACf,GAAG;YACH,KAAK;YACL,EAAE;YACF,sEAAsE;SACvE,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;QACD,YAAY,EAAE;YACZ,GAAG,CACD,iBAAiB,EACjB,oGAAoG,EACpG;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,MAAM,EACJ,sFAAsF;gBACxF,UAAU,EAAE;oBACV,cAAc;oBACd,WAAW;oBACX,aAAa;oBACb,YAAY;oBACZ,UAAU;oBACV,gBAAgB;iBACjB;aACF,CACF;YACD,GAAG,CACD,eAAe,EACf,yFAAyF,EACzF;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,CAAC;aACnF,CACF;YACD,GAAG,CACD,aAAa,EACb,wFAAwF,EACxF;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,mBAAmB,EAAE,QAAQ,CAAC;aAC5E,CACF;SACF;QACD,KAAK,EACH,0GAA0G;KAC7G;IACD;QACE,EAAE,EAAE,4BAA4B;QAChC,SAAS,EAAE,UAAU;QACrB,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,8BAA8B;QACpC,UAAU,EAAE,UAAU;QACtB,OAAO,EAAE,6EAA6E;QACtF,OAAO,EAAE,eAAe,CACtB;YACE,KAAK,EAAE,sBAAsB;YAC7B,IAAI,EAAE,KAAK;YACX,WAAW,EACT,oFAAoF;SACvF,EACD;YACE,oBAAoB;YACpB,EAAE;YACF,OAAO;YACP,kCAAkC;YAClC,oCAAoC;YACpC,qCAAqC;YACrC,8BAA8B;YAC9B,eAAe;YACf,sFAAsF;YACtF,sCAAsC;YACtC,wBAAwB;YACxB,GAAG;YACH,KAAK;SACN,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;QACD,YAAY,EAAE;YACZ,GAAG,CACD,eAAe,EACf,iGAAiG,EACjG;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,wEAAwE;gBAChF,UAAU,EAAE;oBACV,eAAe;oBACf,cAAc;oBACd,eAAe;oBACf,YAAY;oBACZ,oBAAoB;iBACrB;aACF,CACF;YACD,GAAG,CACD,mBAAmB,EACnB,4FAA4F,EAC5F;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,iFAAiF;gBACzF,UAAU,EAAE;oBACV,YAAY;oBACZ,YAAY;oBACZ,UAAU;oBACV,gBAAgB;oBAChB,iBAAiB;oBACjB,iBAAiB;iBAClB;aACF,CACF;YACD,GAAG,CACD,gBAAgB,EAChB,yFAAyF,EACzF;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,qBAAqB,CAAC;aACvF,CACF;YACD,GAAG,CACD,aAAa,EACb,2GAA2G,EAC3G;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE;oBACV,kBAAkB;oBAClB,cAAc;oBACd,oBAAoB;oBACpB,QAAQ;oBACR,kBAAkB;oBAClB,KAAK;iBACN;aACF,CACF;SACF;QACD,KAAK,EACH,4FAA4F;KAC/F;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,SAAS,EAAE,UAAU;QACrB,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,4BAA4B;QAClC,UAAU,EAAE,SAAS;QACrB,OAAO,EAAE,yEAAyE;QAClF,OAAO,EAAE,eAAe,CACtB;YACE,KAAK,EAAE,oBAAoB;YAC3B,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,yEAAyE;SACvF,EACD;YACE,2BAA2B;YAC3B,EAAE;YACF,OAAO;YACP,kDAAkD;YAClD,yDAAyD;YACzD,8CAA8C;YAC9C,gDAAgD;YAChD,6CAA6C;YAC7C,qEAAqE;YACrE,2BAA2B;YAC3B,oBAAoB;YACpB,KAAK;YACL,gCAAgC;YAChC,GAAG;YACH,KAAK;SACN,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;QACD,YAAY,EAAE;YACZ,GAAG,CACD,UAAU,EACV,yFAAyF,EACzF;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,MAAM,EACJ,oFAAoF;gBACtF,UAAU,EAAE;oBACV,UAAU;oBACV,WAAW;oBACX,gBAAgB;oBAChB,gBAAgB;oBAChB,OAAO;oBACP,YAAY;iBACb;aACF,CACF;YACD,GAAG,CACD,QAAQ,EACR,+EAA+E,EAC/E;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,CAAC;aAClF,CACF;YACD,GAAG,CACD,eAAe,EACf,gFAAgF,EAChF;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,iFAAiF;gBACzF,UAAU,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,CAAC;aACzF,CACF;YACD,GAAG,CACD,eAAe,EACf,sGAAsG,EACtG;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,6DAA6D;gBACrE,UAAU,EAAE,CAAC,qBAAqB,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,CAAC;aACxF,CACF;YACD,GAAG,CACD,iBAAiB,EACjB,+EAA+E,EAC/E;gBACE,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC;aAC7D,CACF;SACF;QACD,KAAK,EACH,yJAAyJ;KAC5J;CACF,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { SandboxFixtureDefinition } from '../types.js';
2
+ export declare const REQUIREMENTS_FIXTURES: SandboxFixtureDefinition[];
3
+ //# sourceMappingURL=requirements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requirements.d.ts","sourceRoot":"","sources":["../../src/fixtures/requirements.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAQ3D,eAAO,MAAM,qBAAqB,EAAE,wBAAwB,EAsO3D,CAAA"}
@@ -0,0 +1,178 @@
1
+ import { exp } from '../expectation.js';
2
+ // requirements-review fixtures. The payload is a `RequirementsContext`:
3
+ // `{ block: { title, type, description }, docs: [], tasks: [] }`. Each spec is a real,
4
+ // under-specified requirement; the expectations are the gaps/ambiguities/risks a strong
5
+ // reviewer should raise, graded by how bad they are to miss (impact) and how hard they
6
+ // are to spot (trickiness).
7
+ export const REQUIREMENTS_FIXTURES = [
8
+ {
9
+ id: 'req-notify-prefs-simple',
10
+ agentKind: 'requirements-review',
11
+ kind: 'requirements',
12
+ name: 'Notification preferences (simple)',
13
+ difficulty: 'simple',
14
+ summary: 'A thin "let users mute notifications" spec with obvious unanswered questions.',
15
+ payload: {
16
+ block: {
17
+ title: 'Notification preferences',
18
+ type: 'service',
19
+ description: 'Let users turn off notifications they do not want. Add a settings page where they can toggle notifications on or off.',
20
+ },
21
+ docs: [],
22
+ tasks: [],
23
+ },
24
+ expectations: [
25
+ exp('channels', 'Which channels are in scope (email, push, in-app, SMS)?', {
26
+ impact: 4,
27
+ trickiness: 1,
28
+ detail: 'A single on/off toggle is meaningless without knowing what it governs.',
29
+ matchHints: ['channel', 'email', 'push', 'in-app', 'sms'],
30
+ }),
31
+ exp('default-state', 'What is the default state for a new user / a newly added notification type?', {
32
+ impact: 3,
33
+ trickiness: 2,
34
+ matchHints: ['default state', 'default value', 'opt-in', 'opt in', 'opt-out', 'opt out'],
35
+ }),
36
+ exp('granularity', 'Global on/off vs per-category preferences — the spec conflates them.', {
37
+ impact: 3,
38
+ trickiness: 3,
39
+ detail: '"notifications they do not want" implies per-type control, but the UI describes one toggle.',
40
+ matchHints: ['per-category', 'per category', 'granularity', 'per-type', 'per type'],
41
+ }),
42
+ exp('transactional', 'Are critical/transactional messages (security alerts, password resets) exempt from muting?', {
43
+ impact: 4,
44
+ trickiness: 4,
45
+ detail: 'Letting users mute security alerts is a real safety/compliance gap that is easy to overlook.',
46
+ matchHints: ['transactional', 'security alert', 'critical', 'mandatory'],
47
+ }),
48
+ ],
49
+ notes: 'The transactional-exemption item is the high-trickiness "wow" catch; the channel-scope item is the high-impact must-find.',
50
+ },
51
+ {
52
+ id: 'req-csv-export-moderate',
53
+ agentKind: 'requirements-review',
54
+ kind: 'requirements',
55
+ name: 'CSV export (moderate)',
56
+ difficulty: 'moderate',
57
+ summary: 'An "export my data to CSV" feature that omits scale, auth, and format details.',
58
+ payload: {
59
+ block: {
60
+ title: 'Export report to CSV',
61
+ type: 'api',
62
+ description: 'Add a button that lets a user export their transactions report as a CSV file so they can open it in Excel. The export should include all of their transactions.',
63
+ },
64
+ docs: [],
65
+ tasks: [],
66
+ },
67
+ expectations: [
68
+ exp('volume', 'How many rows can "all transactions" be — does it need streaming/pagination or a background job?', {
69
+ impact: 5,
70
+ trickiness: 3,
71
+ detail: 'A synchronous in-memory export silently breaks for large accounts; this is the most impactful gap.',
72
+ matchHints: [
73
+ 'how many rows',
74
+ 'large',
75
+ 'streaming',
76
+ 'background job',
77
+ 'pagination',
78
+ 'timeout',
79
+ ],
80
+ }),
81
+ exp('authz', 'What stops a user exporting another user’s transactions — how is ownership enforced?', {
82
+ impact: 5,
83
+ trickiness: 2,
84
+ matchHints: ['authorization', 'ownership', 'access control', 'another user', 'tenant'],
85
+ }),
86
+ exp('encoding', 'CSV specifics: delimiter, encoding (UTF-8 BOM for Excel), quoting, and date/number formatting.', {
87
+ impact: 3,
88
+ trickiness: 2,
89
+ detail: 'Excel mangles UTF-8 without a BOM and misreads locale-formatted numbers/dates.',
90
+ matchHints: ['encoding', 'utf-8', 'utf8', 'delimiter', 'bom', 'quoting', 'escaping'],
91
+ }),
92
+ exp('injection', 'CSV/formula injection: a cell starting with =, +, -, @ executes when opened in Excel.', {
93
+ impact: 4,
94
+ trickiness: 5,
95
+ detail: 'A genuine security issue ("CSV injection") almost no one raises — the standout catch.',
96
+ matchHints: [
97
+ 'csv injection',
98
+ 'formula injection',
99
+ 'starts with =',
100
+ 'spreadsheet injection',
101
+ ],
102
+ }),
103
+ ],
104
+ notes: 'CSV/formula injection is the trick item; the row-volume and authorization items are the must-finds.',
105
+ },
106
+ {
107
+ id: 'req-billing-proration-complex',
108
+ agentKind: 'requirements-review',
109
+ kind: 'requirements',
110
+ name: 'Mid-cycle plan change billing (complex)',
111
+ difficulty: 'complex',
112
+ summary: 'A subscription plan-change spec dense with proration, timezone, and currency edge cases.',
113
+ payload: {
114
+ block: {
115
+ title: 'Mid-cycle plan upgrades and downgrades',
116
+ type: 'service',
117
+ description: [
118
+ 'Let a customer change their subscription plan at any time. When they upgrade, charge them the',
119
+ 'difference for the rest of the billing cycle. When they downgrade, credit the difference toward',
120
+ 'their next invoice. The change takes effect immediately. Plans are billed monthly on the date the',
121
+ 'customer first subscribed.',
122
+ ].join(' '),
123
+ },
124
+ docs: [],
125
+ tasks: [],
126
+ },
127
+ expectations: [
128
+ exp('proration-basis', 'How is the prorated amount computed — by remaining days, seconds, or a fixed fraction — and how are partial-cent results rounded?', {
129
+ impact: 5,
130
+ trickiness: 5,
131
+ detail: 'Rounding/credit accumulation across repeated mid-cycle changes is where real billing bugs and revenue leakage hide; the standout catch.',
132
+ matchHints: [
133
+ 'proration',
134
+ 'prorate',
135
+ 'rounding',
136
+ 'round',
137
+ 'partial cent',
138
+ 'remaining days',
139
+ ],
140
+ }),
141
+ exp('cycle-anchor', 'Billing on "the date the customer subscribed" is undefined for the 29th–31st in short months.', {
142
+ impact: 4,
143
+ trickiness: 4,
144
+ detail: 'Anniversary billing on Jan 31 has no Feb 31 — the cycle-anchor rule must be pinned down.',
145
+ matchHints: [
146
+ '29th',
147
+ '30th',
148
+ '31st',
149
+ 'short month',
150
+ 'anniversary',
151
+ 'last day of the month',
152
+ ],
153
+ }),
154
+ exp('timezone', 'In which timezone is "immediately" / the cycle boundary evaluated (customer, merchant, UTC)?', {
155
+ impact: 4,
156
+ trickiness: 4,
157
+ matchHints: ['timezone', 'time zone', 'utc', 'midnight'],
158
+ }),
159
+ exp('downgrade-credit', 'Credit vs refund: is a downgrade credit refundable, does it expire, and what if it exceeds the next invoice?', {
160
+ impact: 4,
161
+ trickiness: 2,
162
+ matchHints: ['credit', 'refund', 'exceeds', 'expire'],
163
+ }),
164
+ exp('currency', 'No mention of currency, tax/VAT recomputation, or multi-currency accounts.', {
165
+ impact: 3,
166
+ trickiness: 2,
167
+ matchHints: ['currency', 'tax', 'vat'],
168
+ }),
169
+ exp('payment-failure', 'What happens if the immediate upgrade charge fails — is the plan change rolled back or left active unpaid?', {
170
+ impact: 5,
171
+ trickiness: 3,
172
+ matchHints: ['payment fails', 'charge fails', 'declined', 'rolled back', 'rollback'],
173
+ }),
174
+ ],
175
+ notes: 'A deliberately dense spec: proration rounding (trick + impact) is the headline; payment-failure handling and cycle-anchor are the high-impact must-finds.',
176
+ },
177
+ ];
178
+ //# sourceMappingURL=requirements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requirements.js","sourceRoot":"","sources":["../../src/fixtures/requirements.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { type SandboxFixtureDefinition, type SandboxFixtureDifficulty, type SandboxExpectation, type SandboxFixtureKind, } from './types.js';
2
+ export { exp } from './expectation.js';
3
+ export { BUILTIN_SANDBOX_FIXTURES, builtinFixturesFor, builtinFixture, toSandboxFixture, } from './registry.js';
4
+ export { REQUIREMENTS_FIXTURES } from './fixtures/requirements.js';
5
+ export { CLARITY_FIXTURES } from './fixtures/clarity.js';
6
+ export { CODE_REVIEW_FIXTURES } from './fixtures/code-review.js';
7
+ export { ARCHITECTURE_FIXTURES } from './fixtures/architecture.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAEtC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,GACjB,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ // @cat-factory/sandbox-fixtures — hand-authored, standardized, graded no-repo fixtures for
2
+ // the Sandbox. These are the inline (text-only) agent inputs that need NO repository
3
+ // checkout — requirements review, bug-report (clarity) review, code review, and
4
+ // architecture-proposal review — each with a set of expected findings graded by trickiness
5
+ // (how hard to spot; catching it is a "wow") and impact (how bad to miss). Depends only on
6
+ // @cat-factory/contracts so the published @cat-factory/sandbox can load it via workspace:*.
7
+ export {} from './types.js';
8
+ export { exp } from './expectation.js';
9
+ export { BUILTIN_SANDBOX_FIXTURES, builtinFixturesFor, builtinFixture, toSandboxFixture, } from './registry.js';
10
+ export { REQUIREMENTS_FIXTURES } from './fixtures/requirements.js';
11
+ export { CLARITY_FIXTURES } from './fixtures/clarity.js';
12
+ export { CODE_REVIEW_FIXTURES } from './fixtures/code-review.js';
13
+ export { ARCHITECTURE_FIXTURES } from './fixtures/architecture.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,qFAAqF;AACrF,gFAAgF;AAChF,2FAA2F;AAC3F,2FAA2F;AAC3F,4FAA4F;AAE5F,OAAO,EAKN,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAEtC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,GACjB,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,19 @@
1
+ import { type SandboxFixture } from '@cat-factory/contracts';
2
+ import type { SandboxFixtureDefinition } from './types.js';
3
+ /**
4
+ * Every builtin, no-repo Sandbox fixture, hand-authored and committed for reproducibility.
5
+ * Ordered by agent then difficulty (simple → complex) for stable display.
6
+ */
7
+ export declare const BUILTIN_SANDBOX_FIXTURES: readonly SandboxFixtureDefinition[];
8
+ /** The builtin fixtures authored for a given agent kind. */
9
+ export declare function builtinFixturesFor(agentKind: string): SandboxFixtureDefinition[];
10
+ /** A builtin fixture by id, or undefined. */
11
+ export declare function builtinFixture(id: string): SandboxFixtureDefinition | undefined;
12
+ /**
13
+ * Project an authoring {@link SandboxFixtureDefinition} into the wire `SandboxFixture` the
14
+ * Sandbox stores/serves: an inline `builtin` fixture whose objective is the graded
15
+ * `findings` set. Validates against the contract schema so a malformed fixture fails loudly
16
+ * at load (e.g. an inline payload missing, or an expectation out of the 1..5 range).
17
+ */
18
+ export declare function toSandboxFixture(def: SandboxFixtureDefinition, now: number): SandboxFixture;
19
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,wBAAwB,CAAA;AAMlF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAE1D;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,wBAAwB,EAKvE,CAAA;AAED,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,wBAAwB,EAAE,CAEhF;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAE/E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAW3F"}
@@ -0,0 +1,43 @@
1
+ import { sandboxFixtureSchema } from '@cat-factory/contracts';
2
+ import * as v from 'valibot';
3
+ import { ARCHITECTURE_FIXTURES } from './fixtures/architecture.js';
4
+ import { CLARITY_FIXTURES } from './fixtures/clarity.js';
5
+ import { CODE_REVIEW_FIXTURES } from './fixtures/code-review.js';
6
+ import { REQUIREMENTS_FIXTURES } from './fixtures/requirements.js';
7
+ /**
8
+ * Every builtin, no-repo Sandbox fixture, hand-authored and committed for reproducibility.
9
+ * Ordered by agent then difficulty (simple → complex) for stable display.
10
+ */
11
+ export const BUILTIN_SANDBOX_FIXTURES = [
12
+ ...REQUIREMENTS_FIXTURES,
13
+ ...CLARITY_FIXTURES,
14
+ ...CODE_REVIEW_FIXTURES,
15
+ ...ARCHITECTURE_FIXTURES,
16
+ ];
17
+ /** The builtin fixtures authored for a given agent kind. */
18
+ export function builtinFixturesFor(agentKind) {
19
+ return BUILTIN_SANDBOX_FIXTURES.filter((f) => f.agentKind === agentKind);
20
+ }
21
+ /** A builtin fixture by id, or undefined. */
22
+ export function builtinFixture(id) {
23
+ return BUILTIN_SANDBOX_FIXTURES.find((f) => f.id === id);
24
+ }
25
+ /**
26
+ * Project an authoring {@link SandboxFixtureDefinition} into the wire `SandboxFixture` the
27
+ * Sandbox stores/serves: an inline `builtin` fixture whose objective is the graded
28
+ * `findings` set. Validates against the contract schema so a malformed fixture fails loudly
29
+ * at load (e.g. an inline payload missing, or an expectation out of the 1..5 range).
30
+ */
31
+ export function toSandboxFixture(def, now) {
32
+ return v.parse(sandboxFixtureSchema, {
33
+ id: def.id,
34
+ kind: def.kind,
35
+ name: def.name,
36
+ payload: def.payload,
37
+ repoRef: null,
38
+ objective: { kind: 'findings', expectations: def.expectations },
39
+ origin: 'builtin',
40
+ createdAt: now,
41
+ });
42
+ }
43
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAGlE;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAwC;IAC3E,GAAG,qBAAqB;IACxB,GAAG,gBAAgB;IACnB,GAAG,oBAAoB;IACvB,GAAG,qBAAqB;CACzB,CAAA;AAED,4DAA4D;AAC5D,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,OAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAA;AAC1E,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAA6B,EAAE,GAAW;IACzE,OAAO,CAAC,CAAC,KAAK,CAAC,oBAAoB,EAAE;QACnC,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE;QAC/D,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,GAAG;KACf,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { SandboxExpectation, SandboxFixtureKind } from '@cat-factory/contracts';
2
+ /** How hard the fixture is, used to offer a simple → complex range per agent. */
3
+ export type SandboxFixtureDifficulty = 'simple' | 'moderate' | 'complex';
4
+ export interface SandboxFixtureDefinition {
5
+ /** Stable, unique kebab id, e.g. `req-notify-prefs-simple`. */
6
+ id: string;
7
+ /**
8
+ * The agent kind this fixture exercises (an `AgentKind` string, e.g.
9
+ * `requirements-review`, `clarity-review`, `reviewer`, `architect-companion`). Used to
10
+ * group fixtures by agent and to look the agent up in the Sandbox catalog.
11
+ */
12
+ agentKind: string;
13
+ /** The inline fixture kind (`requirements` | `architecture` | `code-review`). */
14
+ kind: SandboxFixtureKind;
15
+ /** Human label for the fixture browser. */
16
+ name: string;
17
+ /** Difficulty tier (the simple → complex range). */
18
+ difficulty: SandboxFixtureDifficulty;
19
+ /** One-line description of what this fixture probes. */
20
+ summary: string;
21
+ /**
22
+ * The inline agent-run context this fixture supplies as input — the synthesized
23
+ * context the agent reasons over (a `RequirementsContext` / `ClarityContext` /
24
+ * reviewer `AgentRunContext`). Kept as a record to match the wire contract; the
25
+ * payload-conformance test asserts each one against the real context type.
26
+ */
27
+ payload: Record<string, unknown>;
28
+ /** What a strong answer should surface, each graded by trickiness/impact. */
29
+ expectations: SandboxExpectation[];
30
+ /** Authoring rationale — why this fixture is interesting / what the tricky bits are. */
31
+ notes?: string;
32
+ }
33
+ export type { SandboxExpectation, SandboxFixtureKind };
34
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAQpF,iFAAiF;AACjF,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAA;AAExE,MAAM,WAAW,wBAAwB;IACvC,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAA;IACV;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,IAAI,EAAE,kBAAkB,CAAA;IACxB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,UAAU,EAAE,wBAAwB,CAAA;IACpC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,6EAA6E;IAC7E,YAAY,EAAE,kBAAkB,EAAE,CAAA;IAClC,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@cat-factory/sandbox-fixtures",
3
- "version": "0.7.2",
3
+ "version": "0.7.5",
4
+ "description": "Hand-authored, standardized, graded no-repo fixtures for the Sandbox: inline agent inputs (requirements/clarity/code-review/architecture-proposal review) with expectations rated by trickiness and impact.",
4
5
  "repository": {
5
6
  "type": "git",
6
7
  "url": "git+https://github.com/kibertoad/cat-factory.git",
7
8
  "directory": "backend/packages/sandbox-fixtures"
8
9
  },
9
- "description": "Hand-authored, standardized, graded no-repo fixtures for the Sandbox: inline agent inputs (requirements/clarity/code-review/architecture-proposal review) with expectations rated by trickiness and impact.",
10
10
  "files": [
11
11
  "dist"
12
12
  ],
@@ -25,13 +25,13 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "valibot": "^1.4.1",
28
- "@cat-factory/contracts": "0.7.2"
28
+ "@cat-factory/contracts": "0.10.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "typescript": "7.0.1-rc",
32
32
  "vitest": "^4.1.9",
33
- "@cat-factory/kernel": "0.7.2",
34
- "@cat-factory/orchestration": "0.7.2"
33
+ "@cat-factory/kernel": "0.10.1",
34
+ "@cat-factory/orchestration": "0.7.7"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "tsc -b tsconfig.build.json",