Skip to content

Commit 3d5651f

Browse files
author
DavidQ
committed
Establish an explicit shared public-reader contract for the promotion gate and reduce local gate-specific state read assumptions.
1 parent e750c3c commit 3d5651f

10 files changed

Lines changed: 109 additions & 36 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ MODEL: GPT-5.4-codex
22
REASONING: high
33

44
COMMAND:
5-
Execute exactly docs/pr/BUILD_PR_SHARED_EXTRACTION_54_ASOBJECT_ASARRAY_TO_SHARED_UTILS.md.
6-
Modify only listed files.
7-
Package to:
8-
<project folder>/tmp/BUILD_PR_SHARED_EXTRACTION_54_ASOBJECT_ASARRAY_TO_SHARED_UTILS_delta.zip
5+
Execute exactly docs/pr/BUILD_PR_PROMOTION_GATE_55_CONTRACT_AND_PUBLIC_READERS.md.
6+
Modify only the exact target files listed in the PR doc.
7+
Do not expand scope.
8+
Package the delta zip to:
9+
<project folder>/tmp/BUILD_PR_PROMOTION_GATE_55_CONTRACT_AND_PUBLIC_READERS_delta.zip

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Promote asObject/asArray into shared utils and remove duplicates from debug network utilities.
1+
Establish an explicit shared public-reader contract for the promotion gate and reduce local gate-specific state read assumptions.

docs/dev/NEXT_COMMAND.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
After commit, identify next duplicate cluster (likely normalizeNumber or string utils) with exact files only.
1+
After commit, inspect the promotion-gate delta and build the next exact slice only if authoritative/passive handoff files are explicit.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
- Consolidated asObject/asArray into shared utils
2-
- Removed duplicates from debug network utilities
1+
- narrow promotion-gate BUILD focused on contract and public-reader boundary only
2+
- exact target files limited to createPromotionGate + shared state reader + promotion snapshot
3+
- explicitly excludes replay/timeline/sample/game/debug widening

docs/dev/reports/file_tree.txt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1-
src/shared/utils/objectUtils.js
2-
src/shared/utils/networkDebugUtils.js
3-
src/engine/debug/network/shared/networkDebugUtils.js
1+
docs/pr/BUILD_PR_PROMOTION_GATE_55_CONTRACT_AND_PUBLIC_READERS.md
2+
docs/dev/codex_commands.md
3+
docs/dev/commit_comment.txt
4+
docs/dev/next_command.txt
5+
docs/dev/reports/file_tree.txt
6+
docs/dev/reports/change_summary.txt
7+
docs/dev/reports/validation_checklist.txt
8+
src/advanced/promotion/createPromotionGate.js
9+
src/shared/state/getState.js
10+
src/shared/state/createPromotionStateSnapshot.js
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
- Exact files only
2-
- No duplicate helpers remain
3-
- Imports resolve
4-
- No behavior change
1+
- single PR purpose only
2+
- exact target files only
3+
- executable BUILD with Codex command included
4+
- no roadmap edits
5+
- no docs-only commit intent
6+
- no replay/timeline/sample/game/debug scope expansion
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# BUILD PR — Promotion Gate Contract And Public Readers
2+
3+
## Purpose
4+
Make the promotion-gate read boundary explicit and remove local gate-state reading assumptions by routing promotion-gate reads through the shared public reader path.
5+
6+
## Exact Target Files
7+
- `src/advanced/promotion/createPromotionGate.js`
8+
- `src/shared/state/getState.js`
9+
- `src/shared/state/createPromotionStateSnapshot.js`
10+
11+
## Why These Files
12+
Current repo evidence shows:
13+
- `src/advanced/promotion/createPromotionGate.js` contains a local `getState()` function
14+
- `src/shared/state/getState.js` is the shared state-reader file
15+
- `src/shared/state/createPromotionStateSnapshot.js` is the existing shared promotion snapshot file
16+
17+
This PR is limited to those exact files only.
18+
19+
## Required Code Changes
20+
1. In `src/shared/state/getState.js`
21+
- confirm/export the public reader contract needed by the promotion gate
22+
- make the reader shape explicit enough that promotion-gate code does not need a private/local `getState()` helper for lane-critical reads
23+
24+
2. In `src/shared/state/createPromotionStateSnapshot.js`
25+
- align the shared promotion snapshot contract with the public reader shape if required by the exact current implementation
26+
- keep this limited to promotion-gate contract/read compatibility only
27+
28+
3. In `src/advanced/promotion/createPromotionGate.js`
29+
- remove or reduce the local gate-specific `getState()` implementation where the shared public reader can be used instead
30+
- route promotion-gate state reads through the shared public reader path
31+
- preserve current promotion-gate behavior; this PR is contract/read-boundary work, not a replay/timeline rewrite
32+
33+
## Hard Constraints
34+
- exact files only
35+
- do not modify replay files
36+
- do not modify timeline files
37+
- do not modify sample files
38+
- do not modify game files
39+
- do not widen into debug UI work
40+
- do not rename unrelated exports
41+
- do not perform general state cleanup
42+
- do not change promotion behavior semantics beyond replacing local/private read assumptions with the shared contract path
43+
44+
## Validation Steps
45+
- confirm only the exact target files changed
46+
- confirm `createPromotionGate.js` no longer depends on a lane-critical private/local read path when the shared public reader can be used
47+
- confirm imports/exports resolve
48+
- confirm no unrelated refactor or formatting-only churn was introduced
49+
- confirm the promotion gate still builds/runs with the same behavior surface
50+
51+
## Acceptance Criteria
52+
- promotion-gate read boundary is explicit
53+
- shared public reader path is used for promotion-gate state reads where applicable
54+
- no unnecessary local gate-only `getState()` reader remains for the contract-covered path
55+
- promotion snapshot/read contract remains coherent
56+
- no replay/timeline/sample/game scope expansion occurred

src/advanced/promotion/createPromotionGate.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ createPromotionGate.js
77

88
import { asFiniteNumber, asPositiveInteger } from '../../shared/utils/numberUtils.js';
99
import { isPlainObject } from '../../shared/utils/objectUtils.js';
10-
import { createPromotionStateSnapshot } from '../../shared/state/createPromotionStateSnapshot.js';
10+
import { getState as getPromotionPublicState } from '../../shared/state/getState.js';
1111

1212
function normalizeCriteriaMap(input, requiredCriteria = []) {
1313
const normalized = {};
@@ -70,17 +70,6 @@ function createPromotionGate(options = {}) {
7070
};
7171
}
7272

73-
function getState() {
74-
return createPromotionStateSnapshot({
75-
promoted,
76-
stableFrames,
77-
stabilityWindowFrames,
78-
lastReason,
79-
lastEvaluation,
80-
cloneLastEvaluation: (value) => (value ? { ...value } : null)
81-
});
82-
}
83-
8473
function evaluate({
8574
criteria = {},
8675
rollbackTriggered = false,
@@ -184,7 +173,16 @@ function createPromotionGate(options = {}) {
184173
return {
185174
evaluate,
186175
getMetrics,
187-
getState,
176+
getState() {
177+
return getPromotionPublicState({
178+
promoted,
179+
stableFrames,
180+
stabilityWindowFrames,
181+
lastReason,
182+
lastEvaluation,
183+
cloneLastEvaluation: (value) => (value ? { ...value } : null)
184+
});
185+
},
188186
reset
189187
};
190188
}

src/shared/state/createPromotionStateSnapshot.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
function defaultCloneLastEvaluation(value) {
2+
return value ? { ...value } : null;
3+
}
4+
15
export function createPromotionStateSnapshot({
26
promoted,
37
stableFrames,
@@ -11,8 +15,8 @@ export function createPromotionStateSnapshot({
1115
stableFrames,
1216
stabilityWindowFrames,
1317
lastReason,
14-
lastEvaluation: typeof cloneLastEvaluation === 'function'
15-
? cloneLastEvaluation(lastEvaluation)
16-
: lastEvaluation ?? null
18+
lastEvaluation: (typeof cloneLastEvaluation === 'function'
19+
? cloneLastEvaluation
20+
: defaultCloneLastEvaluation)(lastEvaluation)
1721
};
1822
}

src/shared/state/getState.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,24 @@ David Quesenberry
55
getState.js
66
*/
77

8+
import { createPromotionStateSnapshot } from './createPromotionStateSnapshot.js';
9+
810
function getState({
911
promoted,
1012
stableFrames,
1113
stabilityWindowFrames,
1214
lastReason,
13-
lastEvaluation
14-
}) {
15-
return {
15+
lastEvaluation,
16+
cloneLastEvaluation
17+
} = {}) {
18+
return createPromotionStateSnapshot({
1619
promoted,
1720
stableFrames,
1821
stabilityWindowFrames,
1922
lastReason,
20-
lastEvaluation: lastEvaluation || null
21-
};
23+
lastEvaluation,
24+
cloneLastEvaluation
25+
});
2226
}
2327

2428
export { getState };

0 commit comments

Comments
 (0)