Skip to content

Commit 5b7ca54

Browse files
author
DavidQ
committed
Level 18.6 overlay diagnostics and debug tooling.
Add visibility into overlay state and cycle behavior.
1 parent 287a3e3 commit 5b7ca54

6 files changed

Lines changed: 158 additions & 24 deletions

File tree

docs/dev/CODEX_COMMANDS.md

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

44
COMMAND:
5-
Externalize overlay configuration:
6-
- Create config for overlay stacks per sample
7-
- Refactor runtime to consume config
8-
- Ensure no behavior change
5+
Add overlay diagnostics tooling:
6+
- Log overlay index and stack state
7+
- Add optional debug toggle
8+
- Ensure zero impact when disabled
9+
- Do not change overlay behavior
910

1011
Package ZIP to <project folder>/tmp/

docs/dev/COMMIT_COMMENT.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Level 18.5 overlay configuration externalization.
2-
Move stack definitions to config-driven model.
1+
Level 18.6 overlay diagnostics and debug tooling.
2+
Add visibility into overlay state and cycle behavior.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[ ] Config file defines stacks
2-
[ ] Runtime reads config
3-
[ ] Behavior unchanged
4-
[ ] Per-sample mapping preserved
1+
[ ] Diagnostics output correct state
2+
[ ] Toggle enables/disables logs
3+
[ ] No performance impact when disabled
4+
[ ] No behavior change

docs/pr/BUILD_PR.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
1-
# BUILD_PR_LEVEL_18_5_OVERLAY_CONFIGURATION_EXTERNALIZATION
1+
# BUILD_PR_LEVEL_18_6_OVERLAY_DIAGNOSTICS_DEBUG_TOOLING
22

33
## PLAN
44

55
### Purpose
6-
Externalize overlay stack definitions and configuration to remove hardcoded mappings and improve maintainability.
6+
Introduce lightweight diagnostics and debug tooling for overlay system to aid validation and future debugging.
77

88
### Goals
9-
- Move overlay stack definitions to config
10-
- Allow per-sample configuration
11-
- Reduce hardcoded logic
9+
- Provide visibility into overlay state
10+
- Expose current stack + index
11+
- Enable debug logging toggle
1212

1313
---
1414

1515
## BUILD
1616

1717
### Scope
18-
- Define external config structure for overlay stacks
19-
- Refactor runtime to read from config
20-
- Preserve existing behavior exactly
21-
- No UI or feature changes
18+
- Add diagnostic hooks (non-invasive)
19+
- Add debug output for:
20+
- Current overlay index
21+
- Active stack
22+
- Cycle key events
23+
- Optional debug toggle (no UI change required)
24+
- No behavior change
2225

2326
### Test Steps
24-
1. Load samples
25-
2. Verify overlays match previous stacks
26-
3. Modify config and confirm behavior updates
27+
1. Enable diagnostics
28+
2. Cycle overlays
29+
3. Verify logs show correct state transitions
30+
4. Disable diagnostics
2731

2832
### Expected
29-
- Same behavior as before
30-
- Config-driven overlay stacks
33+
- Clear debug visibility
34+
- No runtime impact when disabled

samples/phase-17/shared/tabDebugOverlayCycle.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,40 @@ import { isOverlayCycleReverseModifierActive } from '/samples/phase-17/shared/ov
88

99
const overlayIndexMemoryStore = new Map();
1010
const overlayPersistenceKeys = new Set();
11+
let overlayDiagnosticsEnabled = false;
12+
13+
function getOverlayStackSnapshot(controller) {
14+
if (!controller || !Array.isArray(controller.overlays)) {
15+
return [];
16+
}
17+
return controller.overlays.map((overlay) => ({
18+
id: overlay.id,
19+
label: overlay.label,
20+
}));
21+
}
22+
23+
function getOverlayDiagnosticsSnapshot(controller) {
24+
const stack = getOverlayStackSnapshot(controller);
25+
const activeIndex = normalizeActiveIndex(controller);
26+
const activeEntry = stack[activeIndex] || null;
27+
return {
28+
activeIndex,
29+
activeId: activeEntry?.id || '',
30+
stack,
31+
cycleKey: String(controller?.cycleKey || ''),
32+
persistenceKey: String(controller?.persistenceKey || ''),
33+
};
34+
}
35+
36+
function logOverlayDiagnostics(eventName, controller) {
37+
if (!overlayDiagnosticsEnabled) {
38+
return;
39+
}
40+
if (typeof console === 'undefined' || typeof console.debug !== 'function') {
41+
return;
42+
}
43+
console.debug(`[overlay-diagnostics] ${eventName}`, getOverlayDiagnosticsSnapshot(controller));
44+
}
1145

1246
function normalizeOverlayEntry(entry) {
1347
const id = String(entry?.id ?? '').trim();
@@ -180,6 +214,7 @@ export function setTabDebugOverlayMap(controller, { overlays = [], initialOverla
180214
applyPersistedActiveIndex(controller);
181215
normalizeActiveIndex(controller);
182216
controller.cycleLatch = false;
217+
logOverlayDiagnostics('set-map', controller);
183218
return true;
184219
}
185220

@@ -190,6 +225,7 @@ export function setTabDebugOverlayCycleKey(controller, cycleKey) {
190225
const normalized = String(cycleKey || '').trim();
191226
controller.cycleKey = normalized || 'Tab';
192227
controller.cycleLatch = false;
228+
logOverlayDiagnostics('set-cycle-key', controller);
193229
return true;
194230
}
195231

@@ -206,6 +242,7 @@ export function setTabDebugOverlayPersistenceKey(controller, persistenceKey) {
206242
overlayPersistenceKeys.add(controller.persistenceKey);
207243
applyPersistedActiveIndex(controller);
208244
normalizeActiveIndex(controller);
245+
logOverlayDiagnostics('set-persistence-key', controller);
209246
return true;
210247
}
211248

@@ -241,6 +278,7 @@ export function setTabDebugOverlayActive(controller, overlayId) {
241278
controller.activeIndex = nextIndex;
242279
normalizeActiveIndex(controller);
243280
persistActiveIndex(controller);
281+
logOverlayDiagnostics('set-active', controller);
244282
return true;
245283
}
246284

@@ -269,6 +307,7 @@ export function stepTabDebugOverlayController(controller, input) {
269307
const count = controller.overlays.length;
270308
controller.activeIndex = (controller.activeIndex + delta + count) % count;
271309
persistActiveIndex(controller);
310+
logOverlayDiagnostics('step-cycle', controller);
272311
}
273312

274313
export function isTabDebugOverlayActive(controller, overlayId) {
@@ -297,3 +336,12 @@ export function resetTabDebugOverlayPersistenceForTests() {
297336
overlayPersistenceKeys.clear();
298337
overlayIndexMemoryStore.clear();
299338
}
339+
340+
export function setTabDebugOverlayDiagnosticsEnabled(enabled) {
341+
overlayDiagnosticsEnabled = enabled === true;
342+
return overlayDiagnosticsEnabled;
343+
}
344+
345+
export function isTabDebugOverlayDiagnosticsEnabled() {
346+
return overlayDiagnosticsEnabled;
347+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
Toolbox Aid
3+
David Quesenberry
4+
04/16/2026
5+
Phase17OverlayDiagnosticsTooling.test.mjs
6+
*/
7+
import assert from 'node:assert/strict';
8+
import { LEVEL17_OVERLAY_CYCLE_KEY } from '../../samples/phase-17/shared/overlayCycleInput.js';
9+
import {
10+
createTabDebugOverlayController,
11+
isTabDebugOverlayDiagnosticsEnabled,
12+
resetTabDebugOverlayPersistenceForTests,
13+
setTabDebugOverlayCycleKey,
14+
setTabDebugOverlayDiagnosticsEnabled,
15+
setTabDebugOverlayMap,
16+
stepTabDebugOverlayController,
17+
} from '../../samples/phase-17/shared/tabDebugOverlayCycle.js';
18+
19+
function makeInput(keys = []) {
20+
const down = new Set(keys);
21+
return {
22+
isDown(code) {
23+
return down.has(code);
24+
},
25+
};
26+
}
27+
28+
function assertDiagnosticsAreOptionalAndNonBlocking() {
29+
const controller = createTabDebugOverlayController({
30+
overlays: [
31+
{ id: 'ui-layer', label: 'UI Layer' },
32+
{ id: 'mission-feed', label: 'Mission Feed' },
33+
],
34+
initialOverlayId: 'ui-layer',
35+
});
36+
setTabDebugOverlayCycleKey(controller, LEVEL17_OVERLAY_CYCLE_KEY);
37+
38+
const calls = [];
39+
const originalConsoleDebug = console.debug;
40+
console.debug = (...args) => {
41+
calls.push(args);
42+
};
43+
44+
try {
45+
setTabDebugOverlayDiagnosticsEnabled(false);
46+
assert.equal(isTabDebugOverlayDiagnosticsEnabled(), false, 'Diagnostics should default to disabled state.');
47+
48+
stepTabDebugOverlayController(controller, makeInput([LEVEL17_OVERLAY_CYCLE_KEY]));
49+
stepTabDebugOverlayController(controller, makeInput([]));
50+
assert.equal(controller.activeIndex, 1, 'Overlay cycling behavior should work when diagnostics are disabled.');
51+
assert.equal(calls.length, 0, 'No diagnostics logs should emit when diagnostics are disabled.');
52+
53+
setTabDebugOverlayDiagnosticsEnabled(true);
54+
assert.equal(isTabDebugOverlayDiagnosticsEnabled(), true, 'Diagnostics toggle should enable logging.');
55+
56+
setTabDebugOverlayMap(controller, {
57+
overlays: [
58+
{ id: 'ui-layer', label: 'UI Layer' },
59+
{ id: 'mission-feed', label: 'Mission Feed' },
60+
],
61+
initialOverlayId: 'ui-layer',
62+
});
63+
stepTabDebugOverlayController(controller, makeInput([LEVEL17_OVERLAY_CYCLE_KEY]));
64+
65+
assert.equal(calls.length >= 2, true, 'Diagnostics should log stack state when enabled.');
66+
const [firstMessage, firstPayload] = calls[0];
67+
assert.equal(String(firstMessage).includes('[overlay-diagnostics]'), true, 'Diagnostics prefix should be emitted.');
68+
assert.equal(typeof firstPayload.activeIndex, 'number', 'Diagnostics payload should include activeIndex.');
69+
assert.equal(Array.isArray(firstPayload.stack), true, 'Diagnostics payload should include stack state.');
70+
assert.equal(firstPayload.stack.length, 2, 'Diagnostics payload should include all overlay entries.');
71+
} finally {
72+
console.debug = originalConsoleDebug;
73+
setTabDebugOverlayDiagnosticsEnabled(false);
74+
}
75+
}
76+
77+
export function run() {
78+
resetTabDebugOverlayPersistenceForTests();
79+
setTabDebugOverlayDiagnosticsEnabled(false);
80+
assertDiagnosticsAreOptionalAndNonBlocking();
81+
}

0 commit comments

Comments
 (0)