-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcases.json
More file actions
276 lines (276 loc) · 16.2 KB
/
Copy pathcases.json
File metadata and controls
276 lines (276 loc) · 16.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
{
"version": 1,
"cases": [
{
"id": "ask-oauth-account-linking",
"category": "identity",
"expectedRoute": "ASK",
"request": "Add Google sign-in to this application. Existing password users should be able to use it. Implement all required changes.",
"decisionUnderTest": "How a Google identity with the same email should interact with an existing password account.",
"decisiveSignals": [
"link|matching email|same email",
"existing password|password account",
"explicit|automatic|auto-link"
],
"decidingEvidencePaths": ["src/auth/schema.sql", "docs/auth.md"],
"files": {
"src/auth/schema.sql": "CREATE TABLE users (\n id UUID PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n password_hash TEXT NOT NULL\n);\n\nCREATE TABLE sessions (\n id UUID PRIMARY KEY,\n user_id UUID NOT NULL REFERENCES users(id)\n);\n",
"docs/auth.md": "# Authentication\n\nUsers currently register with an email and password. Email addresses are normalized to lowercase and unique. Password reset and session revocation are supported. Google sign-in has not been implemented before.\n"
}
},
{
"id": "ask-admin-authority",
"category": "authorization",
"expectedRoute": "ASK",
"request": "Add an admin role so admins can manage users and workspace settings.",
"decisionUnderTest": "Which actions the new admin role may perform and whether its authority is workspace-scoped or global.",
"decisiveSignals": [
"workspace|tenant|global",
"permission|authority|scope",
"delete|billing|owner|admin"
],
"decidingEvidencePaths": ["src/authz/roles.ts", "src/db/schema.sql"],
"files": {
"src/authz/roles.ts": "export type Role = 'owner' | 'member' | 'support';\n\nexport const permissions = {\n owner: ['workspace:read', 'workspace:write', 'billing:manage', 'user:remove'],\n member: ['workspace:read'],\n support: ['workspace:read', 'user:read'],\n} as const;\n",
"src/db/schema.sql": "CREATE TABLE workspace_memberships (\n workspace_id UUID NOT NULL,\n user_id UUID NOT NULL,\n role TEXT NOT NULL,\n PRIMARY KEY (workspace_id, user_id)\n);\n"
}
},
{
"id": "ask-account-deletion-semantics",
"category": "data-lifecycle",
"expectedRoute": "ASK",
"request": "Add a Delete account button and make the account disappear immediately after confirmation.",
"decisionUnderTest": "What account disappearance means for profile data, invoices, audit records, and active subscriptions.",
"decisiveSignals": [
"hard delete|soft delete|retention|anonym",
"invoice|audit",
"subscription|billing provider|cancel"
],
"decidingEvidencePaths": ["src/db/schema.sql", "docs/product.md"],
"files": {
"src/db/schema.sql": "CREATE TABLE users (id UUID PRIMARY KEY, email TEXT NOT NULL);\nCREATE TABLE invoices (id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id));\nCREATE TABLE audit_events (id UUID PRIMARY KEY, actor_user_id UUID REFERENCES users(id), payload JSONB NOT NULL);\nCREATE TABLE subscriptions (id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id), provider_id TEXT NOT NULL);\n",
"docs/product.md": "# Accounts\n\nUsers can create an account, subscribe to a paid plan, and download invoices. Account deletion has not previously been offered.\n"
}
},
{
"id": "ask-pagination-compatibility",
"category": "public-contract",
"expectedRoute": "ASK",
"request": "Paginate GET /events because large accounts are timing out. Update the endpoint.",
"decisionUnderTest": "How pagination changes the public response while handling compatibility with existing clients.",
"decisiveSignals": [
"breaking|compatib|existing client|response shape",
"array|cursor|page",
"version|opt-in|new endpoint"
],
"decidingEvidencePaths": ["openapi.yaml", "docs/api.md"],
"files": {
"openapi.yaml": "openapi: 3.1.0\npaths:\n /events:\n get:\n responses:\n '200':\n content:\n application/json:\n schema:\n type: array\n items:\n $ref: '#/components/schemas/Event'\n",
"docs/api.md": "# Public API\n\nGET /events is used by external integrations. Clients currently receive a top-level JSON array. No API versioning or pagination compatibility policy is documented.\n"
}
},
{
"id": "follow-explicit-oauth-policy",
"category": "identity",
"expectedRoute": "FOLLOW",
"request": "Add Google sign-in using the authentication policy already defined by this project.",
"decisionUnderTest": "How a Google identity with the same email should interact with an existing password account.",
"decisiveSignals": [
"never auto-link|must not.*email",
"explicit linking|signed-in",
"docs/identity-policy|identity-policy"
],
"decidingEvidencePaths": ["docs/identity-policy.md"],
"files": {
"docs/identity-policy.md": "# External identities\n\nNever auto-link an external identity to an existing account by matching email. When a matching password account exists, deny Google sign-in and direct the user to sign in with their password, then explicitly link Google after re-authentication. A Google identity with no matching email creates a new account. Store the provider subject as the stable identifier.\n",
"src/auth/schema.sql": "CREATE TABLE users (id UUID PRIMARY KEY, email TEXT NOT NULL UNIQUE);\nCREATE TABLE external_identities (provider TEXT NOT NULL, subject TEXT NOT NULL, user_id UUID NOT NULL REFERENCES users(id), UNIQUE(provider, subject));\n",
"test/identity-policy.test.ts": "// Contract: matching email alone never links accounts.\n"
}
},
{
"id": "follow-retention-policy",
"category": "data-lifecycle",
"expectedRoute": "FOLLOW",
"request": "Implement the account deletion flow described by the repository policy.",
"decisionUnderTest": "Which account data is disabled, deleted, or retained, and when those lifecycle transitions occur.",
"decisiveSignals": [
"30 days|thirty days",
"cancel.*subscription",
"invoice|audit.*retain|seven years|7 years"
],
"decidingEvidencePaths": ["docs/account-deletion.md", "src/jobs/README.md"],
"files": {
"docs/account-deletion.md": "# Account deletion contract\n\nImmediately disable sign-in and revoke all sessions. Cancel the active provider subscription before starting the recovery period; if cancellation fails, retry it and do not start the deletion clock. After successful cancellation, queue personal profile data for permanent deletion after a 30-day recovery period. Retain invoices and immutable audit events for seven years, replacing direct profile fields with the deletion subject ID.\n",
"src/jobs/README.md": "Durable jobs use a unique operation key and may be retried safely.\n"
}
},
{
"id": "follow-retry-policy",
"category": "operations",
"expectedRoute": "FOLLOW",
"request": "Add automatic retries to failed report exports using the project's existing retry policy.",
"decisionUnderTest": "Which export failures retry, how many attempts occur, which backoffs apply, and which idempotency key is reused.",
"decisiveSignals": [
"four|4.*attempt",
"30.*120.*600|backoff",
"export_id|idempotency|same job"
],
"decidingEvidencePaths": ["config/retry-policy.json", "docs/jobs.md"],
"files": {
"config/retry-policy.json": "{\n \"reportExport\": {\n \"maxAttempts\": 4,\n \"backoffSeconds\": [30, 120, 600],\n \"idempotencyKey\": \"export_id\",\n \"retryable\": [\"timeout\", \"provider_5xx\"]\n }\n}\n",
"docs/jobs.md": "Report exports must reuse the original export_id on every attempt. maxAttempts includes the initial attempt, so four attempts means one initial call and at most three retries. Validation failures and permission failures are terminal.\n"
}
},
{
"id": "follow-feature-rollout",
"category": "rollout",
"expectedRoute": "FOLLOW",
"request": "Put the existing analytics dashboard behind a feature flag and follow the normal rollout policy.",
"decisionUnderTest": "Which default state, cohorts, percentages, and approvals govern the dashboard rollout.",
"decisiveSignals": [
"default.*false|off by default",
"staff|internal",
"10%|ten percent|rollout"
],
"decidingEvidencePaths": ["docs/rollouts.md", "src/flags.ts", "src/dashboard.ts"],
"files": {
"docs/rollouts.md": "# Feature rollout\n\nNew user-facing flags are off by default in production. Enable for the staff cohort first. After one healthy business day, roll out to 10% of workspaces. Further expansion requires the product owner to update the flag configuration.\n",
"src/flags.ts": "export const flags = { legacyReports: { default: false, cohort: 'staff' } } as const;\n",
"src/dashboard.ts": "export function renderAnalyticsDashboard() { return '<main>Analytics</main>'; }\n"
}
},
{
"id": "choose-private-helper",
"category": "implementation-detail",
"expectedRoute": "CHOOSE",
"request": "Remove the duplicated slug normalization in this module without changing its exported behavior.",
"decisionUnderTest": "How the duplicated private normalization logic should be organized.",
"decisiveSignals": [
"private|internal|local helper",
"preserve|unchanged.*behavior|tests"
],
"decidingEvidencePaths": ["src/slug.ts", "test/slug.test.ts"],
"files": {
"src/slug.ts": "export function articleSlug(title: string) {\n return title.trim().toLowerCase().replace(/\\s+/g, '-');\n}\n\nexport function categorySlug(name: string) {\n return name.trim().toLowerCase().replace(/\\s+/g, '-');\n}\n",
"test/slug.test.ts": "// Both exported functions must keep their current input/output behavior.\n"
}
},
{
"id": "choose-test-organization",
"category": "implementation-detail",
"expectedRoute": "CHOOSE",
"request": "Add unit tests for the documented clamp boundaries. Choose a clear test structure.",
"decisionUnderTest": "How the boundary cases should be organized within the unit tests.",
"decisiveSignals": [
"test structure|table|individual test|implementation detail",
"documented|specified|0.*100"
],
"decidingEvidencePaths": ["src/clamp.ts", "docs/clamp.md"],
"files": {
"src/clamp.ts": "export function clampPercent(value: number): number {\n return Math.min(100, Math.max(0, value));\n}\n",
"docs/clamp.md": "clampPercent returns 0 below zero, 100 above one hundred, and the input at both inclusive boundaries. NaN behavior is outside this task.\n"
}
},
{
"id": "choose-private-refactor",
"category": "implementation-detail",
"expectedRoute": "CHOOSE",
"request": "Refactor the repeated private mapping logic for readability. Preserve every public return value and do not add dependencies.",
"decisionUnderTest": "How the repeated private mapping logic should be factored internally.",
"decisiveSignals": [
"private|internal",
"preserve|same.*return|no.*behavior",
"reversible|helper|local"
],
"decidingEvidencePaths": ["src/labels.ts", "test/labels.test.ts"],
"files": {
"src/labels.ts": "const short = (items: string[]) => items.map((item) => ({ id: item, label: item.trim() }));\nconst long = (items: string[]) => items.map((item) => ({ id: item, label: item.trim() }));\nexport const labels = { short, long };\n",
"test/labels.test.ts": "// Public return values are snapshot-tested. The internal organization is not part of the contract.\n"
}
},
{
"id": "choose-local-name",
"category": "implementation-detail",
"expectedRoute": "CHOOSE",
"request": "Fix the no-shadow lint error in this private function without changing behavior.",
"decisionUnderTest": "Which local identifier rename should remove the shadowing error.",
"decisiveSignals": [
"rename|local variable|parameter",
"private|reversible|no behavior"
],
"decidingEvidencePaths": ["src/parse.ts", ".eslintrc.json"],
"files": {
"src/parse.ts": "type Result = { error?: string };\n\nfunction parseLine(error: string | undefined): Result {\n try {\n return error ? { error } : {};\n } catch (error) {\n return { error: String(error) };\n }\n}\n\nexport { parseLine };\n",
".eslintrc.json": "{ \"rules\": { \"no-shadow\": \"error\" } }\n"
}
},
{
"id": "conflict-session-duration",
"category": "conflicting-sources",
"expectedRoute": "CONFLICT",
"request": "Add a Remember me checkbox using the repository's security requirements.",
"decisionUnderTest": "How long a remember-me session should remain valid.",
"decisiveSignals": [
"30 days|thirty days",
"7 days|seven days",
"conflict|contradict|disagree"
],
"decidingEvidencePaths": ["docs/security.md", "config/auth.json"],
"files": {
"docs/security.md": "Remember-me sessions must remain valid for 30 days unless explicitly revoked. This is the approved product and security requirement.\n",
"config/auth.json": "{ \"rememberMeSessionDays\": 7, \"source\": \"security-review\" }\n"
}
},
{
"id": "conflict-delete-response",
"category": "conflicting-sources",
"expectedRoute": "CONFLICT",
"request": "Implement DELETE /widgets/:id according to the current contract.",
"decisionUnderTest": "Which HTTP status and response body DELETE /widgets/:id should return.",
"decisiveSignals": [
"204",
"200",
"conflict|contradict|spec.*test|test.*spec"
],
"decidingEvidencePaths": ["openapi.yaml", "test/widgets.contract.test.ts"],
"files": {
"openapi.yaml": "paths:\n /widgets/{id}:\n delete:\n responses:\n '204':\n description: Deleted with no response body\n",
"test/widgets.contract.test.ts": "// Current contract assertion:\n// DELETE /widgets/123 returns status 200 and body { deleted: true }.\n"
}
},
{
"id": "conflict-editor-publishing",
"category": "conflicting-sources",
"expectedRoute": "CONFLICT",
"request": "Add the Publish action to the editor UI and enforce the existing authorization rules.",
"decisionUnderTest": "Whether an editor is authorized to publish an article.",
"decisiveSignals": [
"editor.*publish|publish.*editor",
"deny|owner",
"conflict|contradict|policy.*test|test.*policy"
],
"decidingEvidencePaths": ["docs/roles.md", "test/authorization.test.ts"],
"files": {
"docs/roles.md": "Editors may create, edit, and publish articles in their workspace. Only owners may delete an article.\n",
"test/authorization.test.ts": "// Contract currently enforced in CI:\n// expect(can('editor', 'article:publish')).toBe(false)\n// expect(can('owner', 'article:publish')).toBe(true)\n"
}
},
{
"id": "conflict-schedule-timezone",
"category": "conflicting-sources",
"expectedRoute": "CONFLICT",
"request": "Implement scheduled notifications using the project's documented time semantics.",
"decisionUnderTest": "Whether a scheduled wall-clock time is interpreted in the workspace timezone or as literal UTC.",
"decisiveSignals": [
"workspace timezone|local time",
"UTC",
"conflict|contradict|disagree"
],
"decidingEvidencePaths": ["docs/notifications.md", "db/notification_schedule.sql"],
"files": {
"docs/notifications.md": "A schedule such as 09:00 is interpreted in the workspace timezone and follows its daylight-saving transitions.\n",
"db/notification_schedule.sql": "-- Approved database contract: scheduled_at stores the literal UTC wall-clock value supplied by the client; no timezone conversion is performed.\nCREATE TABLE notification_schedule (scheduled_at TIMESTAMP WITHOUT TIME ZONE NOT NULL);\n"
}
}
]
}