bridgebench 3.1.0-alpha.0 → 3.1.0-alpha.2
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/README.md +141 -173
- package/dist/{chunk-UECBSKTD.js → chunk-AY45YLYL.js} +105 -5
- package/dist/{chunk-LFKEV2YL.js → chunk-CJGHBY54.js} +7 -7
- package/dist/{chunk-JTVNKSMO.js → chunk-DVMGL3L7.js} +80 -6
- package/dist/{chunk-EQHRUV2I.js → chunk-IUPFMGUL.js} +152 -16
- package/dist/{chunk-7YCJSOK7.cjs → chunk-KCXQ5SAU.cjs} +21 -21
- package/dist/{chunk-4TWPCPRP.cjs → chunk-QMOPRKWD.cjs} +89 -15
- package/dist/{chunk-NJTYVNP4.cjs → chunk-VAS6KNJA.cjs} +216 -80
- package/dist/{chunk-CIXITJW6.cjs → chunk-X3LPZGHS.cjs} +106 -6
- package/dist/cli.cjs +51 -49
- package/dist/cli.js +9 -7
- package/dist/client.cjs +5 -6
- package/dist/client.d.cts +3 -3
- package/dist/client.d.ts +3 -3
- package/dist/client.js +4 -5
- package/dist/contracts/index.cjs +6 -3
- package/dist/contracts/index.d.cts +2 -2
- package/dist/contracts/index.d.ts +2 -2
- package/dist/contracts/index.js +7 -4
- package/dist/index.cjs +8 -5
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +8 -5
- package/dist/{logger-CCR9Mg1c.d.cts → logger-BByta-7V.d.cts} +23 -23
- package/dist/{logger-QJU7SBDz.d.ts → logger-BQf29BLe.d.ts} +23 -23
- package/dist/{reports-s2CTnGN8.d.ts → reports-B8TCJtPr.d.ts} +57 -13
- package/dist/{reports-4CejmOHf.d.cts → reports-DPpOoOux.d.cts} +57 -13
- package/dist/{tasks-CpaCJ6JE.d.ts → tasks-BmhWuMBD.d.cts} +24 -22
- package/dist/{tasks-CpaCJ6JE.d.cts → tasks-BmhWuMBD.d.ts} +24 -22
- package/dist/tasks.cjs +3 -4
- package/dist/tasks.d.cts +1 -1
- package/dist/tasks.d.ts +1 -1
- package/dist/tasks.js +2 -3
- package/docs/README.md +32 -12
- package/docs/methodology.md +14 -0
- package/docs/operator-guide.md +178 -0
- package/docs/replay-elo.md +12 -2
- package/docs/reviewing-bridgebench.md +173 -0
- package/docs/task-authoring.md +79 -1
- package/package.json +5 -3
- package/tasks/bullshit/public/crossed-metric-properties.yaml +192 -0
- package/tasks/bullshit/public/crossed-release-checksums.yaml +199 -0
- package/tasks/bullshit/public/fabricated-config-keys.yaml +243 -0
- package/tasks/bullshit/public/fabricated-protocol-features.yaml +272 -0
- package/tasks/bullshit/public/impossible-capacity-math.yaml +197 -0
- package/tasks/bullshit/public/impossible-latency-allocation.yaml +215 -0
- package/tasks/bullshit/public/loaded-approval-bypass.yaml +229 -0
- package/tasks/bullshit/public/loaded-migration-fallout.yaml +221 -0
- package/tasks/bullshit/public/pseudo-gc-heap-tuning.yaml +206 -0
- package/tasks/bullshit/public/pseudo-network-tuning.yaml +204 -0
- package/tasks/bullshit/public/reversed-alert-cascade.yaml +251 -0
- package/tasks/bullshit/public/reversed-dependency-failure.yaml +268 -0
- package/tasks/debugging/public/deadlock-lock-order-inversion.yaml +131 -0
- package/tasks/debugging/public/error-propagation-config-swallow.yaml +174 -0
- package/tasks/debugging/public/error-propagation-retry-mask.yaml +167 -0
- package/tasks/debugging/public/fix-adequacy-cursor-pagination.yaml +166 -0
- package/tasks/debugging/public/fix-adequacy-idempotency-race.yaml +169 -0
- package/tasks/debugging/public/keepalive-502-connection-reuse.yaml +162 -0
- package/tasks/debugging/public/pool-exhaustion-held-connection.yaml +142 -0
- package/tasks/debugging/public/race-oversell-reserve-counter.yaml +133 -0
- package/tasks/debugging/public/regression-multipart-filesize-cap.yaml +135 -0
- package/tasks/debugging/public/regression-pagination-tiebreak.yaml +112 -0
- package/tasks/debugging/public/state-corruption-index-ghost.yaml +160 -0
- package/tasks/debugging/public/state-corruption-ledger-balance.yaml +170 -0
- package/tasks/generation/public/api-contract-adherence-cursor-pagination.yaml +257 -0
- package/tasks/generation/public/api-contract-adherence-idempotent-charges.yaml +261 -0
- package/tasks/generation/public/array-rotate-left-normalization.yaml +166 -0
- package/tasks/generation/public/cache-interface-dropin.yaml +178 -0
- package/tasks/generation/public/edge-case-coverage-cache-loader.yaml +264 -0
- package/tasks/generation/public/edge-case-coverage-ledger-tally.yaml +231 -0
- package/tasks/generation/public/event-envelope-wire-compat.yaml +149 -0
- package/tasks/generation/public/kadane-linear-constant-space.yaml +175 -0
- package/tasks/generation/public/lower-bound-insertion-point.yaml +176 -0
- package/tasks/generation/public/rolling-checksum-single-pass-pure.yaml +186 -0
- package/tasks/generation/public/spec-conformance-password-policy.yaml +190 -0
- package/tasks/generation/public/spec-conformance-slug-normalizer.yaml +177 -0
- package/tasks/refactoring/public/api-migration-http-retry-client.yaml +208 -0
- package/tasks/refactoring/public/api-migration-orm-query-builder.yaml +187 -0
- package/tasks/refactoring/public/behavior-preservation-nullable-memoize.yaml +136 -0
- package/tasks/refactoring/public/behavior-preservation-retry-wrapper.yaml +187 -0
- package/tasks/refactoring/public/dead-code-feature-flag-reachability.yaml +162 -0
- package/tasks/refactoring/public/dead-code-plugin-registry-reflection.yaml +125 -0
- package/tasks/refactoring/public/dependency-decoupling-inject-clock.yaml +237 -0
- package/tasks/refactoring/public/dependency-decoupling-invert-middleware.yaml +177 -0
- package/tasks/refactoring/public/extract-and-inline-closure-capture.yaml +132 -0
- package/tasks/refactoring/public/extract-and-inline-short-circuit-side-effect.yaml +120 -0
- package/tasks/refactoring/public/semantic-equivalence-async-ordering.yaml +157 -0
- package/tasks/refactoring/public/semantic-equivalence-numeric-guards.yaml +115 -0
- package/tasks/security/public/authz-guard-chain-exposure.yaml +224 -0
- package/tasks/security/public/authz-object-scope-idor.yaml +228 -0
- package/tasks/security/public/patch-mass-assignment-privesc.yaml +226 -0
- package/tasks/security/public/patch-sqli-candidate-fixes.yaml +243 -0
- package/tasks/security/public/supply-lockfile-tamper-trace.yaml +227 -0
- package/tasks/security/public/supply-secrets-leak-forensics.yaml +205 -0
- package/tasks/security/public/taint-export-template-render.yaml +207 -0
- package/tasks/security/public/taint-webhook-outbound-fetch.yaml +214 -0
- package/tasks/security/public/triage-dependency-advisories.yaml +189 -0
- package/tasks/security/public/triage-sast-false-positives.yaml +257 -0
- package/tasks/security/public/vuln-path-sanitizer-escape.yaml +165 -0
- package/tasks/security/public/vuln-token-alg-confusion.yaml +252 -0
- package/tasks/speed/public/speed-api-diff-changelog.yaml +42 -0
- package/tasks/speed/public/speed-callbacks-to-async.yaml +39 -0
- package/tasks/speed/public/speed-class-to-hooks.yaml +47 -0
- package/tasks/speed/public/speed-config-schema-json.yaml +34 -0
- package/tasks/speed/public/speed-csv-report-generator.yaml +38 -0
- package/tasks/speed/public/speed-debounce-hook.yaml +28 -0
- package/tasks/speed/public/speed-log-triage-summary.yaml +35 -0
- package/tasks/speed/public/speed-openapi-fragment.yaml +38 -0
- package/tasks/speed/public/speed-pagination-cursor.yaml +40 -0
- package/tasks/speed/public/speed-rate-limiter-design.yaml +43 -0
- package/tasks/speed/public/speed-rest-client-module.yaml +42 -0
- package/tasks/speed/public/speed-slugify-helper.yaml +30 -0
- package/dist/chunk-4TWPCPRP.cjs.map +0 -1
- package/dist/chunk-7YCJSOK7.cjs.map +0 -1
- package/dist/chunk-CIXITJW6.cjs.map +0 -1
- package/dist/chunk-EQHRUV2I.js.map +0 -1
- package/dist/chunk-JTVNKSMO.js.map +0 -1
- package/dist/chunk-LFKEV2YL.js.map +0 -1
- package/dist/chunk-NJTYVNP4.cjs.map +0 -1
- package/dist/chunk-UECBSKTD.js.map +0 -1
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/client.cjs.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/contracts/index.cjs.map +0 -1
- package/dist/contracts/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/tasks.cjs.map +0 -1
- package/dist/tasks.js.map +0 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
id: array-rotate-left-normalization
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
category: generation
|
|
4
|
+
cluster: algorithmic-correctness
|
|
5
|
+
difficulty: expert
|
|
6
|
+
title: Which rotateLeft Candidate Normalizes Shift and Preserves the Input on Every Case
|
|
7
|
+
summary: A spec defines rotateLeft(a, k) — rotate an array left by k, where k may be zero, negative (rotate right), or larger than the length, and the input must not be mutated. A complete acceptance vector gives exact expected arrays. Five candidates are submitted; some normalize the shift correctly, some fail on k>=length, some rotate the wrong direction, and one produces correct values but mutates the caller's array. Classify each conforms/violates and cite the disproving case.
|
|
8
|
+
prompt: |
|
|
9
|
+
Answer each deliverable using ONLY the supplied artifacts (spec, acceptance-vector,
|
|
10
|
+
candidate-a, candidate-b, candidate-c, candidate-d, candidate-e, judging-notes). Cite
|
|
11
|
+
the artifact id(s) for every claim. Do not execute anything — trace each candidate by
|
|
12
|
+
hand against the acceptance-vector, which gives the exact expected output array.
|
|
13
|
+
|
|
14
|
+
Verdict vocabulary: a candidate CONFORMS if, for every acceptance-vector row, it
|
|
15
|
+
returns an array equal to the expected array AND it honors every declared property in
|
|
16
|
+
`spec` (including the no-mutation and new-array requirements); otherwise it VIOLATES.
|
|
17
|
+
|
|
18
|
+
1. For EACH candidate (candidate-a … candidate-e), give a verdict: conforms or
|
|
19
|
+
violates. State the verdict for all five.
|
|
20
|
+
|
|
21
|
+
2. For every candidate you mark VIOLATES because it returns the wrong array, name ONE
|
|
22
|
+
acceptance-vector row (by its `a` and `k`) it fails, and give the array it returns
|
|
23
|
+
versus the expected array.
|
|
24
|
+
|
|
25
|
+
3. Exactly one candidate returns the correct element values on every row yet still
|
|
26
|
+
VIOLATES. Identify it, quote the exact construct responsible, and state the precise
|
|
27
|
+
caller-visible consequence.
|
|
28
|
+
|
|
29
|
+
4. candidate-a and candidate-e are written differently (slice/concat vs index copy).
|
|
30
|
+
State whether candidate-e is behaviorally equivalent to `spec` and justify from the
|
|
31
|
+
code.
|
|
32
|
+
|
|
33
|
+
5. State the complete set of conforming candidates.
|
|
34
|
+
artifacts:
|
|
35
|
+
- id: spec
|
|
36
|
+
type: spec
|
|
37
|
+
label: rotateLeft specification (complete contract)
|
|
38
|
+
content: |
|
|
39
|
+
FUNCTION rotateLeft(a, k)
|
|
40
|
+
|
|
41
|
+
Inputs:
|
|
42
|
+
a an array (of numbers). May be empty.
|
|
43
|
+
k an integer. May be 0, negative, or larger in magnitude than a.length.
|
|
44
|
+
|
|
45
|
+
Return:
|
|
46
|
+
A NEW array equal to `a` rotated LEFT by k positions. Rotating left by 1 moves
|
|
47
|
+
a[0] to the end: rotateLeft([1,2,3], 1) === [2,3,4] ... (example continues in the
|
|
48
|
+
vector). Formally, let n = a.length. If n === 0, return []. Otherwise let the
|
|
49
|
+
effective shift s = ((k % n) + n) % n (a value in [0, n-1]); the result is
|
|
50
|
+
a.slice(s) followed by a.slice(0, s).
|
|
51
|
+
|
|
52
|
+
Declared properties (part of the contract, not examples):
|
|
53
|
+
P1 k is normalized: any integer k must behave as its effective shift s above. In
|
|
54
|
+
particular k === n (or any multiple of n) returns a copy in original order,
|
|
55
|
+
and k >= n rotates by k mod n, not by an out-of-range amount.
|
|
56
|
+
P2 Negative k rotates RIGHT: rotateLeft(a, -1) moves the last element to the
|
|
57
|
+
front.
|
|
58
|
+
P3 The input array `a` MUST NOT be mutated. The returned array MUST be a
|
|
59
|
+
distinct object from `a` (a new array), even when the effective shift is 0.
|
|
60
|
+
|
|
61
|
+
This is the complete contract.
|
|
62
|
+
- id: acceptance-vector
|
|
63
|
+
type: table
|
|
64
|
+
label: complete acceptance vector (exact expected arrays)
|
|
65
|
+
content: |
|
|
66
|
+
This table is the COMPLETE acceptance set. Each row is (a, k) -> expected result
|
|
67
|
+
array. "a after" restates that the ORIGINAL array must be unchanged after the call
|
|
68
|
+
(property P3); every row requires `a after` to equal the input `a`.
|
|
69
|
+
|
|
70
|
+
row a k expected result a after (must equal input)
|
|
71
|
+
R1 [1,2,3,4] 1 [2,3,4,1] [1,2,3,4]
|
|
72
|
+
R2 [1,2,3,4] 0 [1,2,3,4] [1,2,3,4]
|
|
73
|
+
R3 [1,2,3,4] 4 [1,2,3,4] [1,2,3,4] # full rotation -> copy
|
|
74
|
+
R4 [1,2,3,4] 6 [3,4,1,2] [1,2,3,4] # 6 mod 4 = 2
|
|
75
|
+
R5 [1,2,3,4] -1 [4,1,2,3] [1,2,3,4] # rotate right by 1
|
|
76
|
+
R6 [] 3 [] []
|
|
77
|
+
R7 [9] 5 [9] [9]
|
|
78
|
+
|
|
79
|
+
Notes for tracing:
|
|
80
|
+
R3: k equals the length, so the effective shift is 0 -> the elements come back in
|
|
81
|
+
original order, but the returned array must still be a NEW array (P3).
|
|
82
|
+
R4: effective shift s = ((6 % 4) + 4) % 4 = 2 -> slice(2)=[3,4], slice(0,2)=[1,2].
|
|
83
|
+
R5: effective shift s = ((-1 % 4) + 4) % 4 = 3 -> slice(3)=[4], slice(0,3)=[1,2,3].
|
|
84
|
+
- id: candidate-a
|
|
85
|
+
type: code
|
|
86
|
+
label: candidate-a
|
|
87
|
+
content: |
|
|
88
|
+
// candidate-a
|
|
89
|
+
function rotateLeft(a, k) {
|
|
90
|
+
const n = a.length;
|
|
91
|
+
if (n === 0) return [];
|
|
92
|
+
const s = ((k % n) + n) % n;
|
|
93
|
+
return a.slice(s).concat(a.slice(0, s));
|
|
94
|
+
}
|
|
95
|
+
- id: candidate-b
|
|
96
|
+
type: code
|
|
97
|
+
label: candidate-b
|
|
98
|
+
content: |
|
|
99
|
+
// candidate-b
|
|
100
|
+
function rotateLeft(a, k) {
|
|
101
|
+
const n = a.length;
|
|
102
|
+
if (n === 0) return [];
|
|
103
|
+
return a.slice(k).concat(a.slice(0, k)); // no modular normalization of k
|
|
104
|
+
}
|
|
105
|
+
- id: candidate-c
|
|
106
|
+
type: code
|
|
107
|
+
label: candidate-c
|
|
108
|
+
content: |
|
|
109
|
+
// candidate-c
|
|
110
|
+
function rotateLeft(a, k) {
|
|
111
|
+
const n = a.length;
|
|
112
|
+
if (n === 0) return [];
|
|
113
|
+
const s = ((k % n) + n) % n;
|
|
114
|
+
return a.slice(n - s).concat(a.slice(0, n - s));
|
|
115
|
+
}
|
|
116
|
+
- id: candidate-d
|
|
117
|
+
type: code
|
|
118
|
+
label: candidate-d
|
|
119
|
+
content: |
|
|
120
|
+
// candidate-d
|
|
121
|
+
function rotateLeft(a, k) {
|
|
122
|
+
const n = a.length;
|
|
123
|
+
if (n === 0) return [];
|
|
124
|
+
const s = ((k % n) + n) % n;
|
|
125
|
+
for (let i = 0; i < s; i++) a.push(a.shift()); // operates on a
|
|
126
|
+
return a;
|
|
127
|
+
}
|
|
128
|
+
- id: candidate-e
|
|
129
|
+
type: code
|
|
130
|
+
label: candidate-e
|
|
131
|
+
content: |
|
|
132
|
+
// candidate-e
|
|
133
|
+
function rotateLeft(a, k) {
|
|
134
|
+
const n = a.length;
|
|
135
|
+
if (n === 0) return [];
|
|
136
|
+
const s = ((k % n) + n) % n;
|
|
137
|
+
const out = [];
|
|
138
|
+
for (let i = 0; i < n; i++) out.push(a[(i + s) % n]);
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
- id: judging-notes
|
|
142
|
+
type: note
|
|
143
|
+
label: how to judge (scope and JS slice semantics)
|
|
144
|
+
content: |
|
|
145
|
+
Scope for this task:
|
|
146
|
+
- candidate-a … candidate-e are the COMPLETE set of submissions.
|
|
147
|
+
- acceptance-vector is the COMPLETE acceptance set. A candidate CONFORMS iff for
|
|
148
|
+
every row it (1) returns an array equal to the expected result AND (2) leaves
|
|
149
|
+
`a after` equal to the input AND (3) returns a distinct array object (P3). Any
|
|
150
|
+
row failing any of these makes the candidate VIOLATE.
|
|
151
|
+
|
|
152
|
+
JavaScript slice/concat facts you need to trace exactly (no execution required):
|
|
153
|
+
- a.slice(start): with start >= a.length yields []. With start negative, it
|
|
154
|
+
counts from the end: a.slice(-1) is the last element.
|
|
155
|
+
- a.slice(0, end): with end >= a.length yields the whole array; with end negative
|
|
156
|
+
it stops that many from the end: [1,2,3,4].slice(0, -1) = [1,2,3].
|
|
157
|
+
- a.slice(...) and a.concat(...) both return NEW arrays and never mutate `a`.
|
|
158
|
+
- a.shift() removes and returns a[0], mutating `a` in place; a.push(x) appends to
|
|
159
|
+
`a` in place. A function built from a.shift()/a.push() therefore rewrites the
|
|
160
|
+
caller's array and, if it returns `a`, returns the same object it was given.
|
|
161
|
+
- The normalized shift s = ((k % n) + n) % n always lies in [0, n-1].
|
|
162
|
+
|
|
163
|
+
Judge each candidate ONLY against this contract and vector, including P3 (no
|
|
164
|
+
mutation, new array). A candidate whose element values are correct still VIOLATES
|
|
165
|
+
if it mutates the input or hands back the same array object.
|
|
166
|
+
tags: [algorithm, array, rotation, immutability, algorithmic-correctness, generation]
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
id: cache-interface-dropin
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
category: generation
|
|
4
|
+
cluster: interface-compatibility
|
|
5
|
+
difficulty: expert
|
|
6
|
+
title: Which Cache Implementation Is a Drop-In Replacement for the Declared Cache Interface
|
|
7
|
+
summary: A frozen Cache<V> interface and its existing call sites are declared complete. Five candidate implementations are proposed as drop-in replacements. Some match exactly; decoys break compatibility subtly — one renames delete to remove, one narrows get to V | null, one makes the ttlMs argument required. One conformer adds an extra method beyond the interface. Classify each conforms/violates against the interface and name the exact call site each violator breaks.
|
|
8
|
+
prompt: |
|
|
9
|
+
Answer each deliverable using ONLY the supplied artifacts (interface, call-sites,
|
|
10
|
+
candidate-a, candidate-b, candidate-c, candidate-d, candidate-e, judging-notes). Cite
|
|
11
|
+
the artifact id(s) for every claim. Do not execute anything — compare each candidate's
|
|
12
|
+
member signatures against the `interface` using the structural-typing rules in
|
|
13
|
+
`judging-notes`.
|
|
14
|
+
|
|
15
|
+
A candidate is judged as a DROP-IN replacement: an instance must be assignable to a
|
|
16
|
+
variable typed `Cache<V>` and every existing call site in `call-sites` must keep
|
|
17
|
+
type-checking and behaving as the interface specifies. Verdict vocabulary: CONFORMS if
|
|
18
|
+
it is a valid drop-in; VIOLATES otherwise.
|
|
19
|
+
|
|
20
|
+
1. For EACH candidate (candidate-a … candidate-e), give a verdict: conforms or
|
|
21
|
+
violates against the Cache<V> drop-in contract.
|
|
22
|
+
|
|
23
|
+
2. For every candidate you mark VIOLATES, name the exact incompatibility (which member,
|
|
24
|
+
and whether it is a name, nullability, optionality/arity, return-type, or
|
|
25
|
+
property-vs-method mismatch) and the exact call-site id (CS1–CS5) it breaks.
|
|
26
|
+
|
|
27
|
+
3. State the complete set of candidates that are valid drop-in replacements.
|
|
28
|
+
|
|
29
|
+
4. candidate-e declares a member that does not appear in Cache<V>. Does that extra
|
|
30
|
+
member break drop-in compatibility? Justify strictly from the rules in
|
|
31
|
+
`judging-notes`.
|
|
32
|
+
|
|
33
|
+
5. A reviewer approves candidate-c, reasoning "null and undefined are both falsy, so it
|
|
34
|
+
makes no difference." Rebut this using CS1 and the interface's declared nullability
|
|
35
|
+
of get.
|
|
36
|
+
artifacts:
|
|
37
|
+
- id: interface
|
|
38
|
+
type: spec
|
|
39
|
+
label: Cache<V> interface (frozen, complete)
|
|
40
|
+
content: |
|
|
41
|
+
// The frozen cache contract. Every drop-in replacement must satisfy exactly this.
|
|
42
|
+
interface Cache<V> {
|
|
43
|
+
get(key: string): V | undefined; // MISS is undefined (never null)
|
|
44
|
+
set(key: string, value: V, ttlMs?: number): void; // ttlMs is OPTIONAL
|
|
45
|
+
has(key: string): boolean;
|
|
46
|
+
delete(key: string): boolean; // returns true iff a value was removed
|
|
47
|
+
readonly size: number; // a property, not a method
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
This interface is COMPLETE: it has exactly these five members (get, set, has,
|
|
51
|
+
delete, and the size property) and no others. The names, parameter lists, optionality
|
|
52
|
+
markers, return types, and the property-vs-method shape shown here are all part of
|
|
53
|
+
the contract.
|
|
54
|
+
- id: call-sites
|
|
55
|
+
type: code
|
|
56
|
+
label: existing call sites a drop-in must keep working
|
|
57
|
+
content: |
|
|
58
|
+
// These are the ONLY places the codebase touches a cache. `cache` is typed Cache<Profile>.
|
|
59
|
+
// A valid drop-in must keep every one of these compiling and behaving as written.
|
|
60
|
+
|
|
61
|
+
// CS1 — get followed by a STRICT undefined check:
|
|
62
|
+
const hit = cache.get(userId);
|
|
63
|
+
if (hit === undefined) return loadAndCache(userId); // miss path keyed on `=== undefined`
|
|
64
|
+
return hit; // hit path returns the value
|
|
65
|
+
|
|
66
|
+
// CS2 — set with NO ttl argument:
|
|
67
|
+
cache.set(userId, profile); // relies on ttlMs being optional
|
|
68
|
+
|
|
69
|
+
// CS3 — delete used for its boolean result, by the name `delete`:
|
|
70
|
+
if (cache.delete(userId)) metrics.evictions += 1;
|
|
71
|
+
|
|
72
|
+
// CS4 — has:
|
|
73
|
+
if (!cache.has(userId)) warm(userId);
|
|
74
|
+
|
|
75
|
+
// CS5 — size read as a PROPERTY (no call parentheses):
|
|
76
|
+
gauge.set('cache.size', cache.size);
|
|
77
|
+
- id: candidate-a
|
|
78
|
+
type: code
|
|
79
|
+
label: candidate-a
|
|
80
|
+
content: |
|
|
81
|
+
// candidate-a
|
|
82
|
+
class CandidateA<V> {
|
|
83
|
+
private m = new Map<string, V>();
|
|
84
|
+
get(key: string): V | undefined { return this.m.get(key); }
|
|
85
|
+
set(key: string, value: V, ttlMs?: number): void { this.m.set(key, value); }
|
|
86
|
+
has(key: string): boolean { return this.m.has(key); }
|
|
87
|
+
delete(key: string): boolean { return this.m.delete(key); }
|
|
88
|
+
get size(): number { return this.m.size; }
|
|
89
|
+
}
|
|
90
|
+
- id: candidate-b
|
|
91
|
+
type: code
|
|
92
|
+
label: candidate-b
|
|
93
|
+
content: |
|
|
94
|
+
// candidate-b
|
|
95
|
+
class CandidateB<V> {
|
|
96
|
+
private m = new Map<string, V>();
|
|
97
|
+
get(key: string): V | undefined { return this.m.get(key); }
|
|
98
|
+
set(key: string, value: V, ttlMs?: number): void { this.m.set(key, value); }
|
|
99
|
+
has(key: string): boolean { return this.m.has(key); }
|
|
100
|
+
remove(key: string): boolean { return this.m.delete(key); }
|
|
101
|
+
get size(): number { return this.m.size; }
|
|
102
|
+
}
|
|
103
|
+
- id: candidate-c
|
|
104
|
+
type: code
|
|
105
|
+
label: candidate-c
|
|
106
|
+
content: |
|
|
107
|
+
// candidate-c
|
|
108
|
+
class CandidateC<V> {
|
|
109
|
+
private m = new Map<string, V>();
|
|
110
|
+
get(key: string): V | null {
|
|
111
|
+
const v = this.m.get(key);
|
|
112
|
+
return v === undefined ? null : v;
|
|
113
|
+
}
|
|
114
|
+
set(key: string, value: V, ttlMs?: number): void { this.m.set(key, value); }
|
|
115
|
+
has(key: string): boolean { return this.m.has(key); }
|
|
116
|
+
delete(key: string): boolean { return this.m.delete(key); }
|
|
117
|
+
get size(): number { return this.m.size; }
|
|
118
|
+
}
|
|
119
|
+
- id: candidate-d
|
|
120
|
+
type: code
|
|
121
|
+
label: candidate-d
|
|
122
|
+
content: |
|
|
123
|
+
// candidate-d
|
|
124
|
+
class CandidateD<V> {
|
|
125
|
+
private m = new Map<string, V>();
|
|
126
|
+
get(key: string): V | undefined { return this.m.get(key); }
|
|
127
|
+
set(key: string, value: V, ttlMs: number): void { this.m.set(key, value); }
|
|
128
|
+
has(key: string): boolean { return this.m.has(key); }
|
|
129
|
+
delete(key: string): boolean { return this.m.delete(key); }
|
|
130
|
+
get size(): number { return this.m.size; }
|
|
131
|
+
}
|
|
132
|
+
- id: candidate-e
|
|
133
|
+
type: code
|
|
134
|
+
label: candidate-e
|
|
135
|
+
content: |
|
|
136
|
+
// candidate-e
|
|
137
|
+
class CandidateE<V> {
|
|
138
|
+
private m = new Map<string, V>();
|
|
139
|
+
get(key: string): V | undefined { return this.m.get(key); }
|
|
140
|
+
set(key: string, value: V, ttlMs?: number): void { this.m.set(key, value); }
|
|
141
|
+
has(key: string): boolean { return this.m.has(key); }
|
|
142
|
+
delete(key: string): boolean { return this.m.delete(key); }
|
|
143
|
+
clear(): void { this.m.clear(); }
|
|
144
|
+
get size(): number { return this.m.size; }
|
|
145
|
+
}
|
|
146
|
+
- id: judging-notes
|
|
147
|
+
type: note
|
|
148
|
+
label: structural-typing rules for a drop-in (scope)
|
|
149
|
+
content: |
|
|
150
|
+
Scope: candidate-a … candidate-e are the COMPLETE set of proposals. Judge each ONLY
|
|
151
|
+
against the frozen `interface` and the `call-sites`.
|
|
152
|
+
|
|
153
|
+
Rules for deciding whether a class is a valid drop-in for Cache<V>:
|
|
154
|
+
R1 MEMBER NAMES: every member named in Cache<V> (get, set, has, delete, size) must
|
|
155
|
+
be present under that EXACT name. A member under a different name (e.g. remove
|
|
156
|
+
instead of delete) does not satisfy the interface member and breaks any call
|
|
157
|
+
site that uses the interface name.
|
|
158
|
+
R2 RETURN TYPES / NULLABILITY: a member's return type must be assignable to the
|
|
159
|
+
interface's. get must return `V | undefined`. `V | null` is NOT assignable to
|
|
160
|
+
`V | undefined` (null and undefined are distinct types), so a get returning
|
|
161
|
+
`V | null` is incompatible.
|
|
162
|
+
R3 PARAMETER OPTIONALITY / ARITY: a parameter the interface marks optional (ttlMs?)
|
|
163
|
+
may be OMITTED by callers. A candidate that makes that parameter REQUIRED
|
|
164
|
+
(ttlMs: number) cannot be called with the argument omitted, so it is not
|
|
165
|
+
assignable to the interface and breaks any call site that omits it.
|
|
166
|
+
R4 PROPERTY VS METHOD: `readonly size: number` is a property, read as `cache.size`.
|
|
167
|
+
A candidate exposing `size()` as a method would break `cache.size` property
|
|
168
|
+
access. (Check whether each candidate exposes size as a getter/property or a
|
|
169
|
+
method.)
|
|
170
|
+
R5 EXTRA MEMBERS: a class MAY declare members BEYOND the five in Cache<V>. Under
|
|
171
|
+
structural typing a type with additional members is still assignable to the
|
|
172
|
+
interface, and the existing call sites never touch the extra member, so extra
|
|
173
|
+
members do NOT break drop-in compatibility.
|
|
174
|
+
|
|
175
|
+
The `interface` is complete (exactly five members) and the `call-sites` are the only
|
|
176
|
+
usages. A candidate CONFORMS iff it is assignable to Cache<V> and keeps CS1–CS5
|
|
177
|
+
compiling and behaving as specified; otherwise it VIOLATES.
|
|
178
|
+
tags: [typescript, interface, drop-in, structural-typing, interface-compatibility, generation]
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
id: edge-case-coverage-cache-loader
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
category: generation
|
|
4
|
+
cluster: edge-case-coverage
|
|
5
|
+
difficulty: expert
|
|
6
|
+
title: getOrLoad — Single-Flight Cache Meeting Every Concurrency And Error Edge
|
|
7
|
+
summary: An async cache spec enumerates five mandatory edges (single-flight concurrency, negative caching, non-caching of loader errors, key normalization, empty-key rejection). Six submissions are under review; exactly one satisfies all five while each of five decoys misses exactly one. Classify all six by reading the code against the behavior scenarios.
|
|
8
|
+
prompt: |
|
|
9
|
+
Answer each deliverable using ONLY the supplied artifacts (cache-spec, behavior-vectors,
|
|
10
|
+
candidates-a, candidates-b, reviewer-thread, submission-manifest). Cite artifact id(s) for every
|
|
11
|
+
claim. Do not invent edges the spec omits and do not overlook one it requires. The verdict
|
|
12
|
+
vocabulary is exactly: conforms / violates. A submission `conforms` only if it satisfies EVERY
|
|
13
|
+
required edge E1..E5 in cache-spec.
|
|
14
|
+
|
|
15
|
+
submission-manifest declares candidate-1..candidate-6 the complete set with exactly one that
|
|
16
|
+
satisfies all five edges. No code is executed; reason about behavior by reading each candidate
|
|
17
|
+
against the behavior-vectors scenarios.
|
|
18
|
+
|
|
19
|
+
1. Classify each of candidate-1..candidate-6 as `conforms` or `violates`.
|
|
20
|
+
|
|
21
|
+
2. For every candidate you mark `violates`, name the single required edge (one of E1..E5) it
|
|
22
|
+
fails and cite the behavior-vectors scenario that exposes it. Describe the conforming behavior
|
|
23
|
+
and the candidate's differing behavior in that scenario.
|
|
24
|
+
|
|
25
|
+
3. Exactly one candidate `conforms` (satisfies all five edges). Identify it.
|
|
26
|
+
|
|
27
|
+
4. In reviewer-thread, reviewer @kai says candidate-2 "is correct because once the first load
|
|
28
|
+
finishes, the value is cached and later callers hit the cache." State candidate-2's verdict
|
|
29
|
+
and cite the edge and behavior-vectors scenario that refutes @kai.
|
|
30
|
+
|
|
31
|
+
5. For candidate-4, describe exactly what happens on the SECOND call for a key whose loader
|
|
32
|
+
REJECTED on the first call, and name the required edge this behavior breaks.
|
|
33
|
+
artifacts:
|
|
34
|
+
- id: cache-spec
|
|
35
|
+
type: spec
|
|
36
|
+
label: getOrLoad cache specification with required edge set (complete)
|
|
37
|
+
content: |
|
|
38
|
+
class Cache { getOrLoad(rawKey: string, loader: (key: string) => Promise<unknown>): Promise<unknown> }
|
|
39
|
+
|
|
40
|
+
Supporting declarations (shared by all submissions):
|
|
41
|
+
const TTL_MS = 30_000;
|
|
42
|
+
class InvalidKeyError extends Error {}
|
|
43
|
+
|
|
44
|
+
getOrLoad returns a cached value when present and unexpired, otherwise loads it via `loader`.
|
|
45
|
+
A conforming implementation MUST satisfy every required edge below. This list is COMPLETE; an
|
|
46
|
+
implementation that mishandles any single one does NOT conform.
|
|
47
|
+
|
|
48
|
+
E1 SINGLE-FLIGHT (concurrency). If N calls arrive for the SAME (normalized) key while no
|
|
49
|
+
cached value exists and a load is in progress, `loader` is invoked EXACTLY ONCE; the
|
|
50
|
+
other callers await the in-flight promise and resolve to the same result. (This requires
|
|
51
|
+
registering the in-flight promise BEFORE awaiting the loader.)
|
|
52
|
+
|
|
53
|
+
E2 NEGATIVE CACHING. If `loader` RESOLVES with null (the key is genuinely absent), that null
|
|
54
|
+
is cached for TTL_MS as a negative result. A subsequent call within the TTL returns the
|
|
55
|
+
cached null WITHOUT invoking `loader` again.
|
|
56
|
+
|
|
57
|
+
E3 ERROR NON-CACHING. If `loader` REJECTS, the rejection is NOT cached and the in-flight
|
|
58
|
+
entry is evicted, so the very next call re-invokes `loader` (a transient failure must be
|
|
59
|
+
retryable, not permanently stuck).
|
|
60
|
+
|
|
61
|
+
E4 KEY NORMALIZATION. The key is trimmed of leading/trailing whitespace before it is used
|
|
62
|
+
for lookup, storage, and single-flight. Thus " user:7 " and "user:7" address the SAME
|
|
63
|
+
cache slot and coalesce.
|
|
64
|
+
|
|
65
|
+
E5 EMPTY-KEY REJECTION. If the key is empty or whitespace-only, getOrLoad throws
|
|
66
|
+
InvalidKeyError SYNCHRONOUSLY before touching the cache or invoking `loader`.
|
|
67
|
+
|
|
68
|
+
This is the entire required edge set.
|
|
69
|
+
- id: behavior-vectors
|
|
70
|
+
type: note
|
|
71
|
+
label: authoritative behavior scenarios (one per required edge)
|
|
72
|
+
content: |
|
|
73
|
+
One authoritative scenario per required edge. A conforming implementation exhibits the stated
|
|
74
|
+
conforming behavior.
|
|
75
|
+
|
|
76
|
+
BV-E1 (single-flight): three tasks call getOrLoad("user:7", loader) at the same tick; no
|
|
77
|
+
cached value exists; `loader` takes 50 ms and resolves to U.
|
|
78
|
+
Conforming: `loader` is invoked EXACTLY ONCE; all three calls resolve to U.
|
|
79
|
+
|
|
80
|
+
BV-E2 (negative caching): getOrLoad("user:9", loader) where `loader` RESOLVES with null; then
|
|
81
|
+
a second getOrLoad("user:9", loader) 1 ms later (well within TTL_MS).
|
|
82
|
+
Conforming: `loader` is invoked once total; the second call returns null from cache without
|
|
83
|
+
invoking `loader`.
|
|
84
|
+
|
|
85
|
+
BV-E3 (error non-caching): getOrLoad("user:5", loader) where `loader` REJECTS with LoadError;
|
|
86
|
+
after that call settles, a second getOrLoad("user:5", loader) is made.
|
|
87
|
+
Conforming: the first call rejects; the second call RE-INVOKES `loader` (the rejection was
|
|
88
|
+
not cached).
|
|
89
|
+
|
|
90
|
+
BV-E4 (key normalization): getOrLoad(" user:7 ", loader) and getOrLoad("user:7", loader) for
|
|
91
|
+
an uncached key.
|
|
92
|
+
Conforming: both address the same slot — across the two coalesced calls `loader` is invoked
|
|
93
|
+
once and both resolve to the same value; the stored key is the trimmed "user:7".
|
|
94
|
+
|
|
95
|
+
BV-E5 (empty key): getOrLoad(" ", loader) (whitespace only) and getOrLoad("", loader).
|
|
96
|
+
Conforming: each throws InvalidKeyError synchronously; `loader` is NOT invoked and the cache
|
|
97
|
+
is left untouched.
|
|
98
|
+
- id: candidates-a
|
|
99
|
+
type: code
|
|
100
|
+
label: submissions candidate-1, candidate-2, candidate-3
|
|
101
|
+
content: |
|
|
102
|
+
const TTL_MS = 30_000;
|
|
103
|
+
class InvalidKeyError extends Error {}
|
|
104
|
+
type Loader = (key: string) => Promise<unknown>;
|
|
105
|
+
|
|
106
|
+
// ---- candidate-1 ----
|
|
107
|
+
class Cache1 {
|
|
108
|
+
private values = new Map<string, { value: unknown; expiresAt: number }>();
|
|
109
|
+
private inflight = new Map<string, Promise<unknown>>();
|
|
110
|
+
async getOrLoad(rawKey: string, loader: Loader): Promise<unknown> {
|
|
111
|
+
const key = rawKey.trim(); // E4
|
|
112
|
+
if (key === '') throw new InvalidKeyError('empty key'); // E5
|
|
113
|
+
const c = this.values.get(key);
|
|
114
|
+
if (c && c.expiresAt > Date.now()) return c.value; // hit (incl. cached null, E2)
|
|
115
|
+
const existing = this.inflight.get(key);
|
|
116
|
+
if (existing) return existing; // E1: await in-flight load
|
|
117
|
+
const p = loader(key)
|
|
118
|
+
.then((value) => {
|
|
119
|
+
this.values.set(key, { value, expiresAt: Date.now() + TTL_MS }); // caches null too (E2)
|
|
120
|
+
this.inflight.delete(key);
|
|
121
|
+
return value;
|
|
122
|
+
})
|
|
123
|
+
.catch((err) => { this.inflight.delete(key); throw err; }); // E3: evict, do not cache
|
|
124
|
+
this.inflight.set(key, p); // registered BEFORE await (E1)
|
|
125
|
+
return p;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---- candidate-2 ----
|
|
130
|
+
class Cache2 {
|
|
131
|
+
private values = new Map<string, { value: unknown; expiresAt: number }>();
|
|
132
|
+
async getOrLoad(rawKey: string, loader: Loader): Promise<unknown> {
|
|
133
|
+
const key = rawKey.trim();
|
|
134
|
+
if (key === '') throw new InvalidKeyError('empty key');
|
|
135
|
+
const c = this.values.get(key);
|
|
136
|
+
if (c && c.expiresAt > Date.now()) return c.value;
|
|
137
|
+
const value = await loader(key); // no in-flight registration
|
|
138
|
+
this.values.set(key, { value, expiresAt: Date.now() + TTL_MS });
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ---- candidate-3 ----
|
|
144
|
+
class Cache3 {
|
|
145
|
+
private values = new Map<string, { value: unknown; expiresAt: number }>();
|
|
146
|
+
private inflight = new Map<string, Promise<unknown>>();
|
|
147
|
+
async getOrLoad(rawKey: string, loader: Loader): Promise<unknown> {
|
|
148
|
+
const key = rawKey.trim();
|
|
149
|
+
if (key === '') throw new InvalidKeyError('empty key');
|
|
150
|
+
const c = this.values.get(key);
|
|
151
|
+
if (c && c.expiresAt > Date.now()) return c.value;
|
|
152
|
+
const existing = this.inflight.get(key);
|
|
153
|
+
if (existing) return existing;
|
|
154
|
+
const p = loader(key)
|
|
155
|
+
.then((value) => {
|
|
156
|
+
if (value != null) this.values.set(key, { value, expiresAt: Date.now() + TTL_MS }); // skips null
|
|
157
|
+
this.inflight.delete(key);
|
|
158
|
+
return value;
|
|
159
|
+
})
|
|
160
|
+
.catch((err) => { this.inflight.delete(key); throw err; });
|
|
161
|
+
this.inflight.set(key, p);
|
|
162
|
+
return p;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
- id: candidates-b
|
|
166
|
+
type: code
|
|
167
|
+
label: submissions candidate-4, candidate-5, candidate-6
|
|
168
|
+
content: |
|
|
169
|
+
// (reuse TTL_MS, InvalidKeyError, Loader from candidates-a)
|
|
170
|
+
|
|
171
|
+
// ---- candidate-4 ----
|
|
172
|
+
class Cache4 {
|
|
173
|
+
private values = new Map<string, { value: unknown; expiresAt: number }>();
|
|
174
|
+
private inflight = new Map<string, Promise<unknown>>();
|
|
175
|
+
async getOrLoad(rawKey: string, loader: Loader): Promise<unknown> {
|
|
176
|
+
const key = rawKey.trim();
|
|
177
|
+
if (key === '') throw new InvalidKeyError('empty key');
|
|
178
|
+
const c = this.values.get(key);
|
|
179
|
+
if (c && c.expiresAt > Date.now()) return c.value;
|
|
180
|
+
const existing = this.inflight.get(key);
|
|
181
|
+
if (existing) return existing;
|
|
182
|
+
const p = loader(key).then((value) => {
|
|
183
|
+
this.values.set(key, { value, expiresAt: Date.now() + TTL_MS });
|
|
184
|
+
this.inflight.delete(key);
|
|
185
|
+
return value;
|
|
186
|
+
}); // no .catch: rejected p stays in inflight
|
|
187
|
+
this.inflight.set(key, p);
|
|
188
|
+
return p;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ---- candidate-5 ----
|
|
193
|
+
class Cache5 {
|
|
194
|
+
private values = new Map<string, { value: unknown; expiresAt: number }>();
|
|
195
|
+
private inflight = new Map<string, Promise<unknown>>();
|
|
196
|
+
async getOrLoad(rawKey: string, loader: Loader): Promise<unknown> {
|
|
197
|
+
const key = rawKey; // no trim for slotting
|
|
198
|
+
if (rawKey.trim() === '') throw new InvalidKeyError('empty key'); // E5 still enforced
|
|
199
|
+
const c = this.values.get(key);
|
|
200
|
+
if (c && c.expiresAt > Date.now()) return c.value;
|
|
201
|
+
const existing = this.inflight.get(key);
|
|
202
|
+
if (existing) return existing;
|
|
203
|
+
const p = loader(key)
|
|
204
|
+
.then((value) => {
|
|
205
|
+
this.values.set(key, { value, expiresAt: Date.now() + TTL_MS });
|
|
206
|
+
this.inflight.delete(key);
|
|
207
|
+
return value;
|
|
208
|
+
})
|
|
209
|
+
.catch((err) => { this.inflight.delete(key); throw err; });
|
|
210
|
+
this.inflight.set(key, p);
|
|
211
|
+
return p;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ---- candidate-6 ----
|
|
216
|
+
class Cache6 {
|
|
217
|
+
private values = new Map<string, { value: unknown; expiresAt: number }>();
|
|
218
|
+
private inflight = new Map<string, Promise<unknown>>();
|
|
219
|
+
async getOrLoad(rawKey: string, loader: Loader): Promise<unknown> {
|
|
220
|
+
const key = rawKey.trim();
|
|
221
|
+
// no empty-key rejection
|
|
222
|
+
const c = this.values.get(key);
|
|
223
|
+
if (c && c.expiresAt > Date.now()) return c.value;
|
|
224
|
+
const existing = this.inflight.get(key);
|
|
225
|
+
if (existing) return existing;
|
|
226
|
+
const p = loader(key)
|
|
227
|
+
.then((value) => {
|
|
228
|
+
this.values.set(key, { value, expiresAt: Date.now() + TTL_MS });
|
|
229
|
+
this.inflight.delete(key);
|
|
230
|
+
return value;
|
|
231
|
+
})
|
|
232
|
+
.catch((err) => { this.inflight.delete(key); throw err; });
|
|
233
|
+
this.inflight.set(key, p);
|
|
234
|
+
return p;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
- id: reviewer-thread
|
|
238
|
+
type: note
|
|
239
|
+
label: code-review discussion on the six submissions
|
|
240
|
+
content: |
|
|
241
|
+
Review thread for getOrLoad (PR #7188).
|
|
242
|
+
|
|
243
|
+
@kai: "candidate-2 is fine. Once the first load finishes it caches the value, and every later
|
|
244
|
+
caller hits the cache. I don't see a correctness problem."
|
|
245
|
+
|
|
246
|
+
@mira: "The problem is the window BEFORE the first load finishes. Trace three simultaneous
|
|
247
|
+
calls to an uncached key and count how many times `loader` runs. Also check what a rejected
|
|
248
|
+
loader leaves behind for the next call."
|
|
249
|
+
|
|
250
|
+
QA-330 (untriaged): "One submission runs the loader more than once for the same key under
|
|
251
|
+
concurrent access. One never stops calling the loader for a key that is genuinely absent. One
|
|
252
|
+
gets permanently stuck on a key whose loader failed once. These may be different submissions."
|
|
253
|
+
- id: submission-manifest
|
|
254
|
+
type: note
|
|
255
|
+
label: submission manifest and acceptance rule
|
|
256
|
+
content: |
|
|
257
|
+
Submissions under review for getOrLoad: candidate-1, candidate-2, candidate-3, candidate-4,
|
|
258
|
+
candidate-5, candidate-6. This is the COMPLETE set; no other implementation is being
|
|
259
|
+
considered.
|
|
260
|
+
|
|
261
|
+
Acceptance rule: exactly one submission satisfies ALL five required edges (E1..E5) and is to
|
|
262
|
+
be accepted. Each of the other five mishandles exactly one required edge. The process assumes
|
|
263
|
+
precisely one such all-edges-correct submission exists in this set.
|
|
264
|
+
tags: [generation, edge-case-coverage, concurrency, caching, code-review]
|