mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix(voice): refuse direct cctv toggles outside the shared lifecycle
This commit is contained in:
1 parent
b920d5f404
commit
b48fcc42ae
4 files changed
+21
-10
No files matched your search
@@ -1,3 +1,2 @@
|
|||||||
- Report actual outcomes when voice enables or disables CCTV through the shared
|
- Report actual outcomes when voice enables or disables CCTV through the shared
|
||||||
layer lifecycle, including failed and cancelled changes (manjunath22466,
|
layer lifecycle, including failed and cancelled changes (Manjunath, #1205).
|
||||||
#1205).
|
|
||||||
@@ -628,8 +628,9 @@ Voice action argument schemas have one portable owner under `src/voice/actionSch
|
|||||||
layer visibility lifecycle. Results distinguish successful changes from
|
layer visibility lifecycle. Results distinguish successful changes from
|
||||||
manager-reported failures or cancellation and report enabled state and lifecycle
|
manager-reported failures or cancellation and report enabled state and lifecycle
|
||||||
uncertainty. A caller-supplied abort signal reaches the manager; a late abort
|
uncertainty. A caller-supplied abort signal reaches the manager; a late abort
|
||||||
preserves an already committed change. Missing-layer errors, other CCTV actions
|
preserves an already committed change. Missing-layer errors and other CCTV
|
||||||
and the exported `controlCctv` helper retain their existing behavior.
|
actions retain their existing behavior. The exported `controlCctv` helper refuses direct
|
||||||
|
enable/disable requests and directs callers to `set_layer_visibility`.
|
||||||
|
|
||||||
`src/voice/layerManifest.js` declares each catalog layer's voice capabilities: spoken aliases, `toggle`, in-view `context`, `track`, and analyst `query` fields with type and unit, or `noQuery` with the reason. The `set_layer_visibility`, `show_data_layers_menu`, `get_entity_context` and `analyst_query` layer enums, the runner's alias table and the analyst field hints are generated from it. `src/voice/layerManifest.test.mjs` fails when a catalog layer is neither listed nor named in `VOICE_OFF_LAYERS` (today only the two scene-driven Bhote Koshi layers). Global Context is listed with `toggle: false`; `set_context_mode` reaches it. `set_panel_open` also opens `weather-panel` and `recent-imagery-panel`.
|
`src/voice/layerManifest.js` declares each catalog layer's voice capabilities: spoken aliases, `toggle`, in-view `context`, `track`, and analyst `query` fields with type and unit, or `noQuery` with the reason. The `set_layer_visibility`, `show_data_layers_menu`, `get_entity_context` and `analyst_query` layer enums, the runner's alias table and the analyst field hints are generated from it. `src/voice/layerManifest.test.mjs` fails when a catalog layer is neither listed nor named in `VOICE_OFF_LAYERS` (today only the two scene-driven Bhote Koshi layers). Global Context is listed with `toggle: false`; `set_context_mode` reaches it. `set_panel_open` also opens `weather-panel` and `recent-imagery-panel`.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { after, before, test } from 'node:test';
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { DataLayerManager } from '../data/manager.js';
|
import { DataLayerManager } from '../data/manager.js';
|
||||||
import { CCTV_FOCUS_RESULT } from '../layers/cctv/index.js';
|
import { CCTV_FOCUS_RESULT } from '../layers/cctv/index.js';
|
||||||
import { createGevActionRunner } from './gevActions.js';
|
import { controlCctv, createGevActionRunner } from './gevActions.js';
|
||||||
|
|
||||||
const originalWindow = globalThis.window;
|
const originalWindow = globalThis.window;
|
||||||
before(() => {
|
before(() => {
|
||||||
@@ -294,6 +294,20 @@ test(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test('exported controlCctv refuses toggles without calling the manager', async () => {
|
||||||
|
const manager = {
|
||||||
|
layers: new Map([['cctv', { module: {} }]]),
|
||||||
|
setEnabled: () => assert.fail('direct helper must not change visibility'),
|
||||||
|
isEnabled: () => assert.fail('direct toggle must not read enabled state'),
|
||||||
|
};
|
||||||
|
for (const action of ['ENABLE', 'disable']) {
|
||||||
|
const result = await controlCctv(manager, { action });
|
||||||
|
assert.equal(result.ok, false);
|
||||||
|
assert.equal(result.action, 'control_cctv');
|
||||||
|
assert.match(result.error, /set_layer_visibility/);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'CCTV fallback managers report rejection, transitional state, and uncertainty',
|
'CCTV fallback managers report rejection, transitional state, and uncertainty',
|
||||||
{ timeout: 2000 },
|
{ timeout: 2000 },
|
||||||
|
|||||||
@@ -1444,13 +1444,10 @@ export async function controlCctv(dataManager, args = {}, styleManager = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'enable' || action === 'disable') {
|
if (action === 'enable' || action === 'disable') {
|
||||||
await dataManager.setEnabled('cctv', action === 'enable', {
|
|
||||||
origin: 'voice',
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: false,
|
||||||
action: 'control_cctv',
|
action: 'control_cctv',
|
||||||
enabled: dataManager.isEnabled('cctv'),
|
error: 'Enable or disable CCTV through set_layer_visibility',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!dataManager.isEnabled('cctv')) {
|
if (!dataManager.isEnabled('cctv')) {
|
||||||
|
|||||||
Reference in new issue
Block a user