fix(voice): drop viewport decision codes the caller can never log, name the crop decision eligible (#835)

The decision no longer reports not-entity-context or channel-closed, which
its only caller rules out first, nor pointer-scale-not-useful, which the
crop path already checks and logs. A closed channel returns before any
record, as on main. The crop decision is pointer-crop-eligible, since the
crop checks after it decide whether the pointer is on ground, and a sender
called on a closed channel logs channel-lost.
This commit is contained in:
Sameh Khamis committed 2026-11-10 15:44:17 -08:00
1 parent 9bd2b7ca37
commit 9234c1b3d2
3 files changed
+27 -36

No files matched your search

+18 -17
View File
@@ -73,26 +73,23 @@ const POINTER_CROP_MAX_AGE_MS = 20000;
const POINTER_CROP_SCALES = new Set(['local', 'city']);
/**
* Reason-coded explanation of the existing visual escalation policy.
* Reason-coded explanation of the existing visual escalation policy, for an
* entity-context answer on an open channel (the caller checks both).
* Pointer crops remain a separate path from full-frame screenshots.
* These reasons are static diagnostics, never model-generated claims.
*/
export function viewportContextDecision(result, { channelOpen = true } = {}) {
if (result?.action !== 'get_entity_context')
return { send: false, reason: 'not-entity-context' };
if (!channelOpen) return { send: false, reason: 'channel-closed' };
const viewScale = result.scene?.basemap?.viewScale ?? null;
if (result.scope === 'pointer') {
export function viewportContextDecision(result) {
const viewScale = result?.scene?.basemap?.viewScale ?? null;
if (result?.scope === 'pointer') {
if (result.selected)
return { send: false, reason: 'pointer-identity-present', viewScale };
if (!result.pointer)
return { send: false, reason: 'pointer-missing', viewScale };
if (!POINTER_CROP_SCALES.has(viewScale))
return { send: false, reason: 'pointer-scale-not-useful', viewScale };
// The crop path checks ground, freshness and scale itself, and logs why.
return {
send: true,
kind: 'crop',
reason: 'pointer-ground-crop',
reason: 'pointer-crop-eligible',
viewScale,
};
}
@@ -390,13 +387,17 @@ export class RealtimeViewport {
* requests pair up.
*/
async sendVisualContextIfUseful(result) {
// Runs after every tool output. Only entity context can escalate, so
// other tools log nothing and leave the shared debug-log budget alone.
if (result?.action !== 'get_entity_context') return false;
// Runs after every tool output. Only entity context on an open channel
// can escalate, so anything else logs nothing and leaves the shared
// debug-log budget alone.
if (
result?.action !== 'get_entity_context' ||
!this.dc ||
this.dc.readyState !== 'open'
)
return false;
const contextId = ++this.contextSeq;
const decision = viewportContextDecision(result, {
channelOpen: this.dc?.readyState === 'open',
});
const decision = viewportContextDecision(result);
this.debugLog?.('viewport_context.decision', { contextId, ...decision });
if (!decision.send) return false;
const diag = diagnosticsRecord(contextId);
@@ -481,7 +482,7 @@ export class RealtimeViewport {
const report = (event, reason) =>
reportOutcome(this, diag, event, kind, reason);
if (!this.dc || this.dc.readyState !== 'open') {
report('viewport_context.skipped', 'channel-closed');
report('viewport_context.skipped', 'channel-lost');
return false;
}
const generation = this.generation;
+8 -18
View File
@@ -13,17 +13,6 @@ const localContext = (overrides = {}) => ({
});
test('viewport context reasons preserve the existing escalation gate', () => {
assert.deepEqual(
viewportContextDecision({ action: 'get_current_view_state' }),
{
send: false,
reason: 'not-entity-context',
},
);
assert.deepEqual(
viewportContextDecision(localContext(), { channelOpen: false }),
{ send: false, reason: 'channel-closed' },
);
assert.deepEqual(
viewportContextDecision({
action: 'get_entity_context',
@@ -87,7 +76,7 @@ test('pointer ground selects the #837 crop path, not a full viewport', () => {
assert.deepEqual(viewportContextDecision(pointerContext), {
send: true,
kind: 'crop',
reason: 'pointer-ground-crop',
reason: 'pointer-crop-eligible',
viewScale: 'city',
});
assert.deepEqual(
@@ -96,8 +85,9 @@ test('pointer ground selects the #837 crop path, not a full viewport', () => {
scene: { basemap: { viewScale: 'global' } },
}),
{
send: false,
reason: 'pointer-scale-not-useful',
send: true,
kind: 'crop',
reason: 'pointer-crop-eligible',
viewScale: 'global',
},
);
@@ -173,7 +163,7 @@ test('runtime dispatch preserves pointer crop and full image separation', async
calls.some(
(call) =>
call.event === 'viewport_context.decision' &&
call.detail.reason === 'pointer-ground-crop',
call.detail.reason === 'pointer-crop-eligible',
),
);
});
@@ -333,7 +323,7 @@ test('a crop decision that cannot send logs why, under the same id', async () =>
assert.equal(events.length, 2, reason);
const [decision, outcome] = events;
assert.equal(decision.event, 'viewport_context.decision');
assert.equal(decision.detail.reason, 'pointer-ground-crop');
assert.equal(decision.detail.reason, 'pointer-crop-eligible');
assert.deepEqual(outcome, {
event: 'viewport_context.skipped',
detail: { contextId: decision.detail.contextId, kind: 'crop', reason },
@@ -573,8 +563,8 @@ test('direct calls log their defensive skips without a decision id', async () =>
[...open.events, ...closed.events].map((item) => item.detail),
[
{ contextId: null, kind: 'crop', reason: 'pointer-scale-not-useful' },
{ contextId: null, kind: 'crop', reason: 'channel-closed' },
{ contextId: null, kind: 'viewport', reason: 'channel-closed' },
{ contextId: null, kind: 'crop', reason: 'channel-lost' },
{ contextId: null, kind: 'viewport', reason: 'channel-lost' },
],
);
});