Skip to content

Commit 34c0fef

Browse files
abbaseyaclaude
andcommitted
wf(wf-jssdk-qs01): [FIX-R1] correct stale RED/TDD comments in anchored test files
Beads: ai-driven-product-dev-kz6x Review R1 (conf 95): header comments claimed methods/gate not-yet-implemented (RED); now shipped + passing. Rewrote to describe shipped behavior for sibling-SDK porters; fixed stale data-manager.ts:620-637 -> :685 gate ref. Comment-only. Suites unchanged (bucketing 28, data 97). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 92ac5db commit 34c0fef

2 files changed

Lines changed: 45 additions & 28 deletions

File tree

packages/bucketing/tests/bucketing-manager-anchored.tests.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,34 @@
77
*/
88

99
/**
10-
* qs-01 (BUCK-2) — anchored bucketing algorithm tests.
10+
* qs-01 — anchored bucketing algorithm tests.
1111
*
1212
* Spec of record: _bmad-output/planning-artifacts/2026-07-02-convert-js-sdk/qs-01-anchored-bucketing-layout.md
1313
* "The contract (normative)" section, AC2/AC3/AC4/AC5.
1414
*
15+
* These tests lock the shipped behavior of the three anchored bucketing methods on
16+
* BucketingManager (packages/bucketing/src/bucketing-manager.ts): `getBucketRanges`
17+
* (builds the anchor/width layout from a set of variation allocations), `selectBucketAnchored`
18+
* (resolves a raw bucket value against that layout via a half-open [anchor, anchor + width)
19+
* interval), and `getBucketForVisitorAnchored` (reuses the existing visitor-based hash,
20+
* unmodified, and routes it through the two methods above). Together the suites below verify:
21+
* - the raise-superset property: anchors are computed over the total weight of ALL
22+
* entries so growing an experience's total allocation only ever grows arms and never
23+
* reshuffles an already-bucketed visitor into a different arm (AC2 thirds/superset
24+
* fixtures);
25+
* - half-open boundary semantics at the anchor and anchor + width edges (AC5);
26+
* - zero/inactive-arm handling: stopped or explicit zero-allocation entries keep their
27+
* weight for anchor stability but get a zero-width range so they can never be selected,
28+
* and a totalWeight <= 0 layout yields no bucketing (AC4/AC5);
29+
* - determinism: getBucketForVisitorAnchored returns the same result for the same
30+
* (visitorId, experienceId) and matches selectBucketAnchored(getBucketRanges(...), hash)
31+
* composed directly from the existing hash oracle.
32+
*
1533
* Expected numbers below are derived BY HAND directly from the spec's normative
1634
* pseudocode (anchor = (cumWeight / totalWeight) * 10000; width = active ? allocation * 100 : 0),
1735
* written as literal arithmetic expressions so the doubles are IEEE754-exact and
1836
* independently verifiable against the spec's layout table — never computed by calling
19-
* the SUT. `getBucketRanges`, `selectBucketAnchored` and `getBucketForVisitorAnchored`
20-
* are declared on BucketingManagerInterface (packages/bucketing/src/interfaces/bucketing-manager.ts)
21-
* but are NOT YET implemented on the BucketingManager class — every assertion below is
22-
* expected to FAIL (RED) until BUCK-3 implements them.
37+
* the SUT.
2338
*/
2439
import 'mocha';
2540
import {expect} from 'chai';
@@ -154,9 +169,9 @@ const ZERO_TOTAL_WEIGHT_CASES: Array<{
154169
];
155170

156171
describe('BucketingManager anchored tests (qs-01 / BUCK-2 — contract v9 anchored algorithm)', function () {
157-
// Matches the existing packed-path suite's convention: no explicit type annotation,
158-
// so calls to the not-yet-implemented anchored methods do not introduce additional
159-
// (pre-implementation) compile errors beyond the ones already tracked separately.
172+
// Matches the existing packed-path suite's convention: no explicit type annotation
173+
// is needed since the anchored methods are implemented directly on the
174+
// BucketingManager class.
160175
let bucketingManager;
161176

162177
beforeEach(function () {

packages/data/tests/data-manager-anchored-gate.tests.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,43 @@
66
*/
77

88
/**
9-
* qs-01 (DATA-1) — anchored-vs-packed GATE tests in DataManager._retrieveBucketing.
9+
* qs-01 — anchored-vs-packed GATE tests in DataManager._retrieveBucketing.
1010
*
1111
* Spec of record: _bmad-output/planning-artifacts/2026-07-02-convert-js-sdk/qs-01-anchored-bucketing-layout.md
1212
* "The contract (normative)" section (the Gate paragraph + the allocation-build mapping),
1313
* AC1, AC4, AC8, AC9.
1414
*
15-
* The gate ("run anchored iff Number(experience.version) > 8") does not exist yet in
16-
* DataManager._retrieveBucketing's fresh-bucketing branch (packages/data/src/data-manager.ts:620-637)
17-
* -- every experience, regardless of `version`, currently goes through the existing packed
18-
* cumulative walk. The AC1 and AC4 assertions below therefore FAIL today (RED) because the
19-
* disagreement they assert between "what a version-9 experience should do" (anchored) and
20-
* "what it actually does" (still packed, pre-implementation) is real. AC8/AC9 protect
21-
* EXISTING behavior that runs entirely before/independently of the gate (the stored-decision
22-
* guard short-circuits before the version check is ever reached; the returned object's shape
23-
* doesn't change with the algorithm) -- those are expected to already PASS, and are included
24-
* as regression locks for after the gate lands. See this feature's decision log for why each
25-
* fixture is (or isn't) expected to fail pre-implementation.
15+
* These tests lock the shipped gate in DataManager._retrieveBucketing's fresh-bucketing
16+
* branch (packages/data/src/data-manager.ts:685): `Number(experience.version) > 8` routes
17+
* fresh bucketing through the anchored layout (built by `_buildVariationAllocations`,
18+
* data-manager.ts:586, and resolved via `BucketingManager.getBucketForVisitorAnchored`);
19+
* version <= 8, missing/undefined, or non-numeric version keeps the existing packed
20+
* cumulative walk unchanged (built by `_buildPackedBuckets`, data-manager.ts:556, and
21+
* resolved via `BucketingManager.getBucketForVisitor`). AC1 asserts the gate actually
22+
* branches by exploiting a real packed-vs-anchored disagreement on the same fixture (see
23+
* below). AC4 asserts stops only zero their own width under the anchored path and never
24+
* move neighboring arms' anchors. AC8/AC9 protect existing behavior that runs entirely
25+
* before/independently of the gate: the stored-decision guard (data-manager.ts:658-665)
26+
* short-circuits before the version check is ever reached, and the returned
27+
* BucketedVariation shape is unchanged across versions.
2628
*
2729
* Fixture derivation methodology: every raw bucket VALUE used below (e.g. 4957, 9807, 102)
2830
* is a real MurmurHash3 output from BucketingManager.getValueVisitorBased -- the same,
2931
* already-implemented, already-unit-tested hash oracle the packed and anchored paths both
30-
* call unmodified (packages/bucketing/src/bucketing-manager.ts:95-108; see
32+
* call unmodified (packages/bucketing/src/bucketing-manager.ts:91-112; see
3133
* packages/bucketing/tests/bucketing-manager.tests.ts for its own tests). Values were
3234
* derived once (for the fixed (visitorId, experienceId) string pairs used below, with the
3335
* default hash seed) via that exact method, then frozen as literal numbers so every
3436
* packed/anchored expectation in this file is independently re-derivable by hand from the
3537
* spec's normative formulas (anchor = (cumWeight / totalWeight) * 10000; width = active ?
3638
* allocation * 100 : 0) against the fixed traffic_allocation values declared alongside them,
37-
* without needing to re-run any tool. This is the same class of technique BUCK-2 used to
38-
* freeze its THIRDS_15/THIRDS_25 expected ranges from the spec's own pseudocode, applied one
39-
* level up (the raw hash value is looked up from the hash oracle instead of hand-computed,
40-
* since MurmurHash3 output cannot reasonably be hand-derived; everything downstream of that
41-
* single looked-up number -- which bucket it falls into under each layout -- is plain
42-
* arithmetic against the fixed weights, independently checkable inline in each fixture's
43-
* comment).
39+
* without needing to re-run any tool. This is the same class of technique used in
40+
* bucketing-manager-anchored.tests.ts to freeze its THIRDS_15/THIRDS_25 expected ranges
41+
* from the spec's own pseudocode, applied one level up (the raw hash value is looked up
42+
* from the hash oracle instead of hand-computed, since MurmurHash3 output cannot reasonably
43+
* be hand-derived; everything downstream of that single looked-up number -- which bucket it
44+
* falls into under each layout -- is plain arithmetic against the fixed weights,
45+
* independently checkable inline in each fixture's comment).
4446
*/
4547
import 'mocha';
4648
import {expect} from 'chai';

0 commit comments

Comments
 (0)