import assert from 'node:assert/strict'; import test from 'node:test'; import { OPERATION_TIMING_SCHEMA_VERSION, sanitizeOperationTiming } from '../src/operation-timing.js'; test('control plane keeps only the operation timing allowlisted shape', () => { const sanitized = sanitizeOperationTiming({ schema_version: OPERATION_TIMING_SCHEMA_VERSION, status: 'completed', total_ms: 12_345.6, stage_count: 2, started_at: '2026-08-25T00:00:00.000Z', customer: '测试客户', stages: [{ stage: 'preflight', status: 'completed', duration_ms: 2_345.4, url: 'https://example.invalid/private', details: [{ step: 'network_wait.preflight_raw_instruction', status: 'completed', duration_ms: 1_800, response_text: 'private', counters: { request_count: 4, customer_name: 1, invalid_negative: -1, invalid_text: 'secret' } }] }, { stage: 'john_smith', status: 'completed', duration_ms: 100 }] }); assert.deepEqual(sanitized, { schema_version: OPERATION_TIMING_SCHEMA_VERSION, status: 'completed', total_ms: 12_346, stage_count: 2, stages: [{ stage: 'preflight', status: 'completed', duration_ms: 2_345, details: [{ step: 'network_wait.preflight_raw_instruction', status: 'completed', duration_ms: 1_800, counters: { request_count: 4 } }] }] }); assert.equal(JSON.stringify(sanitized).includes('测试客户'), false); assert.equal(JSON.stringify(sanitized).includes('example.invalid'), false); assert.equal(JSON.stringify(sanitized).includes('response_text'), false); }); test('control plane rejects unknown timing contracts', () => { assert.equal(sanitizeOperationTiming(null), null); assert.equal(sanitizeOperationTiming({ schema_version: 'other', stages: [] }), null); assert.equal(sanitizeOperationTiming({ stages: [] }), null); }); test('control plane accepts every plugin page-action timing code', () => { const actions = [ 'cleanup_completed_lifecycle_dialog', 'create_split_child_live', 'create_split_parent_live', 'export_confirmation_sources', 'inspect_operation_context', 'live_submit_approved', 'live_submit_lifecycle_operation', 'live_submit_team_batch_approved', 'open_order_form', 'open_team_batch_form', 'ping_order_frame', 'ping_team_batch_frame', 'preflight_lifecycle_operation', 'preflight_raw_instruction', 'preflight_team_batch_native', 'prepare_lifecycle_operation', 'resolve_lifecycle_operation', 'return_to_order_list', 'unknown_action', 'verify_lifecycle_operation', 'verify_order_marker', 'verify_team_batch_receipts' ]; const sanitized = sanitizeOperationTiming({ schema_version: OPERATION_TIMING_SCHEMA_VERSION, status: 'completed', total_ms: 1, stages: [{ stage: 'browser_execution', status: 'completed', duration_ms: 1, details: actions.map((action) => ({ step: `action_roundtrip.${action}`, status: 'completed', duration_ms: 1, counters: { call_count: 1 } })) }] }); const details = sanitized?.stages as Array<{ details?: Array<{ step: string }> }>; assert.deepEqual(details[0]?.details?.map((detail) => detail.step), actions.map((action) => `action_roundtrip.${action}`)); }); test('control plane keeps the privacy-safe orchestration breakdown used to locate unattributed time', () => { const safeDetails = [ { step: 'storage_prune.local_history', counters: { removed_result_count: 8, protected_root_count: 2 } }, { step: 'storage_read.result_state', counters: { result_count: 12, execution_count: 12, timing_count: 1 } }, { step: 'storage_write.result_state', counters: { call_count: 1 } }, { step: 'tab_lookup.cache_hit', counters: { cache_hit_count: 1 } }, { step: 'preflight_lookup.parallel_wall', counters: { request_count: 4 } }, { step: 'preflight_product_linkage', counters: { sample_count: 5, stable_sample_count: 4 } }, { step: 'preflight_submit_intercept', counters: { submit_count: 1, quiet_wait_ms: 150 } } ]; const sanitized = sanitizeOperationTiming({ schema_version: OPERATION_TIMING_SCHEMA_VERSION, status: 'completed', total_ms: 10, stages: [{ stage: 'preflight', status: 'completed', duration_ms: 10, details: safeDetails.map((detail) => ({ ...detail, status: 'completed', duration_ms: 1 })) }] }); const stages = sanitized?.stages as Array<{ details?: Array<{ step: string }> }>; assert.deepEqual(stages[0]?.details?.map((detail) => detail.step), safeDetails.map((detail) => detail.step)); const rejected = sanitizeOperationTiming({ schema_version: OPERATION_TIMING_SCHEMA_VERSION, status: 'completed', total_ms: 1, stages: [{ stage: 'preflight', status: 'completed', duration_ms: 1, details: [{ step: 'storage_read.customer_value', duration_ms: 1, counters: { customer_name: 1 } }] }] }); const rejectedStages = rejected?.stages as Array<{ details?: Array }>; assert.equal(rejectedStages[0]?.details, undefined); });