import test from 'node:test'; import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import { upstream58e2204Operations } from '../src/upstream-58e2204.ts'; import { operationAcceptance58e2204, operationAcceptanceOverrides58e2204, acceptancePolicyCatalog, controlPlaneAcceptance, fixtureDisposition58e2204, renderOperationAcceptanceMatrix, surfaceGroups58e2204, policyGroups58e2204, scenarioGroups58e2204, availabilityGroups58e2204, } from '../src/acceptance-58e2204.ts'; import { DENY_REASONS, selectReadonlyOperations } from '../../test-fixtures/scripts/collector.ts'; const fixtureManifestPath = fileURLToPath( new URL('../../test-fixtures/src/manifest.json', import.meta.url), ); const matrixPath = fileURLToPath( new URL('../../../docs/product/operation-acceptance-matrix.md', import.meta.url), ); const acceptanceSourcePath = fileURLToPath( new URL('../src/acceptance-58e2204.ts', import.meta.url), ); const iaPath = fileURLToPath( new URL('../../../docs/product/information-architecture.md', import.meta.url), ); const manifest = JSON.parse(await readFile(fixtureManifestPath, 'utf8')); const byId = new Map(upstream58e2204Operations.map((o: any) => [o.operationId, o])); const canonicalRoutes = new Set([ '/fleet', '/instances/new', '/instances/:id/overview', '/instances/:id/cellular', '/instances/:id/device-network', '/instances/:id/messages', '/instances/:id/calls', '/instances/:id/esim', '/instances/:id/notifications', '/instances/:id/automation', '/instances/:id/ota', '/settings/instances/:id', ]); const assertExactPartition = (groups: readonly { ids: readonly string[] }[]) => { const ids = groups.flatMap((g) => [...g.ids]); assert.equal(ids.length, 117); assert.equal(new Set(ids).size, 117); assert.deepEqual([...ids].sort(), [...byId.keys()].sort()); }; test('RED→GREEN: surface/policy/scenario/availability are literal exact operation partitions', () => { for (const groups of [ surfaceGroups58e2204, policyGroups58e2204, scenarioGroups58e2204, availabilityGroups58e2204, ]) assertExactPartition(groups); assert.ok(surfaceGroups58e2204.filter((g) => g.surfaceId.startsWith('calls/')).length >= 5); assert.ok(surfaceGroups58e2204.filter((g) => g.surfaceId.startsWith('cellular/')).length >= 5); for (const group of surfaceGroups58e2204) for (const id of group.ids) { const row = operationAcceptance58e2204.find((x) => x.operationId === id)!; assert.equal(row.surfaceId, group.surfaceId); assert.equal(row.primaryRoute, group.primaryRoute); } const tuples = new Set(policyGroups58e2204.map((g) => Object.values(g.policies).join('/'))); assert.ok(policyGroups58e2204.length >= 8); assert.ok(tuples.size >= 8); const policy = (id: string) => policyGroups58e2204.find((g) => g.ids.includes(id))!; assert.match(policy('getSmsList').groupId, /list/); assert.match(policy('getHealth').groupId, /detail/); assert.match(policy('getNetworkOperatorsScan').groupId, /scan/); assert.match(policy('postData').groupId, /direct/); assert.match(policy('postAuthLogin').groupId, /auth/); assert.match(policy('postSmsBatchDelete').groupId, /destructive/); assert.match(policy('postOtaApply').groupId, /ota/); assert.ok(scenarioGroups58e2204.length >= 8); const scenario = (id: string) => scenarioGroups58e2204.find((g) => g.ids.includes(id))!.scenarios; assert.equal(scenario('getHealth').empty.applicable, false); assert.equal(scenario('getSmsList').empty.applicable, true); assert.equal(scenario('getStats').partial.applicable, true); assert.equal(scenario('getAuthStatus').partial.applicable, false); assert.equal(scenario('getNetworkOperatorsScan').empty.applicable, true); assert.equal(scenario('getNetworkOperatorsScan').partial.applicable, true); assert.equal(scenario('getNetworkOperatorsScan')['policy-forbidden'].applicable, true); assert.equal(scenario('getNetworkOperatorsScan')['unknown-result'].applicable, false); for (const id of [ 'postSmsBatchDelete', 'postNotificationsQueueRetryAll', 'postNotificationsQueueClear', ]) assert.equal(scenario(id).partial.applicable, true, id); for (const id of [ 'postSystemReboot', 'postServiceRestart', 'deleteCallHistoryId', 'postBandLock', 'postOtaApply', 'postOtaUpload', 'postOtaOnlinePrepare', 'postOtaLatestRelease', 'postOtaCancel', 'postData', ]) assert.equal(scenario(id).partial.applicable, false, id); for (const id of ['postData', 'postSmsBatchDelete']) { assert.equal(scenario(id)['policy-forbidden'].applicable, true); assert.equal(scenario(id)['unknown-result'].applicable, true); } for (const id of ['getHealth', 'getSmsList']) { assert.equal(scenario(id)['policy-forbidden'].applicable, false); assert.equal(scenario(id)['unknown-result'].applicable, false); } for (const group of scenarioGroups58e2204) assert.equal(group.scenarios['owner-switch'].applicable, true); assert.ok(availabilityGroups58e2204.length >= 4); for (const group of availabilityGroups58e2204) assert.ok(group.reason.length > 20); }); test('RED→GREEN: acceptance ledger is exact, Registry-bound and IA-owned', () => { assert.equal(operationAcceptance58e2204.length, 117); assert.equal(new Set(operationAcceptance58e2204.map((x) => x.operationId)).size, 117); assert.deepEqual( [...operationAcceptance58e2204.map((x) => x.operationId)].sort(), [...byId.keys()].sort(), ); for (const row of operationAcceptance58e2204) { const op: any = byId.get(row.operationId); assert.ok(op); assert.equal(row.method, op.method); assert.equal(row.pathTemplate, op.pathTemplate); assert.equal(row.upstreamDomain, op.upstreamDomain); assert.equal(row.riskLevel, op.riskLevel); assert.equal(row.confirmationUX, op.confirmationPolicy); assert.ok(canonicalRoutes.has(row.primaryRoute), row.operationId); assert.ok(row.surfaceId); assert.ok(row.uiStrategy); assert.match(row.availability, /^(planned|unsupported-version|deferred-with-reason)$/); if (row.availability === 'deferred-with-reason') assert.ok(row.availabilityReason); assert.ok( row.requiredStates.request.length && row.requiredStates.freshness.length && row.requiredStates.support.length, ); assert.ok(row.requiredStates.scenarios.length || row.requiredStates.naRationale); assert.ok(row.evidenceIds.length); } }); test('RED→GREEN: exact overrides and policy-bound acceptance are auditable', () => { assert.deepEqual( Object.keys(operationAcceptanceOverrides58e2204).sort(), [...byId.keys()].sort(), ); const policyFields = [ 'preconditionPolicyId', 'stalePolicyId', 'unsupportedPolicyId', 'retryPolicyId', 'resultPolicyId', ]; for (const row of operationAcceptance58e2204) { const override: any = (operationAcceptanceOverrides58e2204 as any)[row.operationId]; assert.ok(override); assert.ok(row.availabilityReason?.length > 20, row.operationId); assert.ok(row.versionEvidencePolicy?.length > 20, row.operationId); assert.equal(row.surfaceId, override.surfaceId); assert.equal(row.uiStrategy, override.uiStrategy); for (const scenario of [ 'empty', 'partial', 'policy-forbidden', 'unknown-result', 'owner-switch', ]) { assert.equal(typeof row.scenarioAcceptance[scenario].applicable, 'boolean'); assert.ok(row.scenarioAcceptance[scenario].rationale.length > 8); } for (const field of policyFields) { assert.equal((row as any)[field], override[field]); assert.ok( (acceptancePolicyCatalog as any)[field][(row as any)[field]], `${row.operationId}:${field}`, ); } } }); test('real acceptance is an explicit availability decision coherent with fixture disposition', async () => { const fixture = new Map(fixtureDisposition58e2204.map((x) => [x.operationId, x])); const valid = new Set([ 'REAL_READ', 'REAL_READ_DEFERRED', 'REAL_WRITE_LATER', 'SIMULATED_HIGH_RISK', 'CONTRACT_ONLY', ]); for (const group of availabilityGroups58e2204) { assert.ok(valid.has(group.realAcceptance), group.groupId); for (const id of group.ids) { const row = operationAcceptance58e2204.find((x) => x.operationId === id)!; assert.equal(row.realAcceptance, group.realAcceptance, id); const status = fixture.get(id)!.runtimeFixtureStatus; if (status === 'captured-readonly') assert.equal(group.realAcceptance, 'REAL_READ', id); if (status === 'denied-readonly-candidate') assert.equal(group.realAcceptance, 'REAL_READ_DEFERRED', id); if (group.realAcceptance === 'REAL_READ') assert.equal(status, 'captured-readonly', id); if (group.realAcceptance === 'REAL_READ_DEFERRED') assert.equal(status, 'denied-readonly-candidate', id); } } const source = await readFile(acceptanceSourcePath, 'utf8'); assert.doesNotMatch(source, /function\s+realAcceptance\s*\(/); assert.doesNotMatch(source, /realAcceptanceIntent/); assert.equal( operationAcceptance58e2204.filter((x) => x.realAcceptance === 'REAL_READ').length, 39, ); assert.equal( operationAcceptance58e2204.filter((x) => x.realAcceptance === 'REAL_READ_DEFERRED').length, 11, ); }); test('Phase 1 bootstrap gate defers Fleet component/E2E evidence to the Phase 5 implementation gate', async () => { const ia = await readFile(iaPath, 'utf8'); const bootstrap = ia.match( /### Phase 0 → Phase 1 workspace\/contract bootstrap gate([\s\S]*?)(?=### Phase 5 implementation gate)/, )?.[1]; const phase5 = ia.match(/### Phase 5 implementation gate([\s\S]*)/)?.[1]; assert.ok(bootstrap); assert.ok(phase5); assert.doesNotMatch(bootstrap!, /Fleet[^\n]*组件\/E2E/); assert.match(phase5!, /Fleet[^\n]*组件\/E2E/); assert.match(phase5!, /\[ \][^\n]*Fleet/); assert.match(bootstrap!, /\[x\][^\n]*最终独立规格与质量\/安全复审均已通过/); assert.doesNotMatch(bootstrap!, /PENDING final independent review/); assert.match(ia, /E2E[^\n]*N\/A[^\n]*Phase 5/); }); test('control-plane flows are independent, structured, and preserve safety invariants', () => { const ids = [ 'instance-create', 'instance-update', 'instance-delete', 'secret-set', 'secret-preserve', 'secret-clear', 'config-import-preview', 'config-import-confirm', 'credential-verify', 'saved-secret-login', 'temporary-secret-login', 'logout', '401-recovery', 'auth-setup', 'auth-password-change', 'auth-settings-read', 'auth-settings-write', 'job-cancel', 'job-retry', 'audit-export', 'system-settings-update', ]; assert.deepEqual(controlPlaneAcceptance.map((x) => x.flowId).sort(), ids.sort()); for (const flow of controlPlaneAcceptance) for (const field of [ 'route', 'risk', 'riskSubtype', 'confirmation', 'preconditions', 'result', 'failureRecovery', 'secretPolicy', 'evidence', ]) assert.ok(String((flow as any)[field]).length > 1, `${flow.flowId}:${field}`); assert.match( controlPlaneAcceptance.find((x) => x.flowId === 'instance-delete')!.result, /new jobId.*two-phase/i, ); for (const id of ['secret-set', 'secret-preserve', 'secret-clear']) assert.match( controlPlaneAcceptance.find((x) => x.flowId === id)!.secretPolicy, /never.*value/i, ); for (const id of ['saved-secret-login', 'temporary-secret-login']) assert.match( controlPlaneAcceptance.find((x) => x.flowId === id)!.failureRecovery, /no automatic replay/i, ); assert.match( controlPlaneAcceptance.find((x) => x.flowId === 'job-retry')!.result, /new jobId.*lineage/i, ); }); test('product risk prose has no conflicting action summaries', async () => { const root = fileURLToPath(new URL('../../../docs/product/', import.meta.url)); const names = [ 'project-charter.md', 'personas-and-workflows.md', 'information-architecture.md', 'current-system-audit.md', ]; const docs = (await Promise.all(names.map((n) => readFile(`${root}${n}`, 'utf8')))).join('\n'); for (const expected of [ /notifications config[^\n]*R2[^\n]*Job/i, /automation config[^\n]*R2[^\n]*Job/i, /eSIM[^\n]*download[^\n]*R1[^\n]*direct/i, /WLAN connect[^\n]*R1[^\n]*forget[^\n]*R2/i, /DDNS config[^\n]*R2[^\n]*Job/i, /baseband restart[^\n]*R3[^\n]*status[^\n]*R0/i, ]) assert.match(docs, expected); assert.doesNotMatch(docs, /Notifications[^\n]*config R1/i); assert.doesNotMatch(docs, /Automation[^\n]*config R1/i); }); test('R2/R3, dedicated auth, write strategy, and split bulk/fleet policy are gated', () => { for (const row of operationAcceptance58e2204) { const op: any = byId.get(row.operationId); if (['R2', 'R3'].includes(row.riskLevel)) { assert.equal( row.executionMode, op.executionPolicy === 'dedicatedFlow' ? 'dedicated-flow' : 'preparation-job', ); assert.match(row.preconditions, /fresh preflight/i); assert.match(row.confirmationUX, /explicit|strong/); assert.match(row.resultDestination, /jobs\/:jobId/); assert.match(row.retryRecovery, /new Job lineage/i); } if (row.riskLevel === 'R3') assert.equal(op.capability, 'job'); if (row.method !== 'GET') { assert.notEqual(row.uiStrategy, 'read-panel'); assert.notEqual(row.realAcceptance, 'REAL_READ'); assert.equal(row.fleetBatchable, false); } } const auth = operationAcceptance58e2204.filter((x) => [ 'postAuthSetup', 'postAuthPassword', 'postAuthSettings', 'postAuthLogin', 'postAuthLogout', ].includes(x.operationId), ); assert.equal(auth.length, 5); assert.ok( auth.every( (x) => x.uiStrategy === 'dedicated-auth-flow' && x.executionMode === 'dedicated-flow', ), ); for (const id of ['postAuthLogin', 'postAuthLogout']) { const row = auth.find((x) => x.operationId === id)!; assert.equal(row.sessionSubtype, 'session-sensitive'); assert.match(row.retryRecovery, /no automatic replay/i); assert.match(row.resultDestination, /metadata-only audit/i); } const sms = operationAcceptance58e2204.find((x) => x.operationId === 'postSmsBatchDelete')!; assert.equal(sms.resourceBulk, true); assert.equal(sms.fleetBatchable, false); for (const id of ['postNotificationsQueueRetryAll', 'postNotificationsQueueClear']) assert.equal( operationAcceptance58e2204.find((x) => x.operationId === id)!.resourceBulk, true, id, ); for (const id of [ 'postSmsClear', 'postCallHistoryClear', 'postNotificationsLogsClear', 'postAutomationLogsClear', ]) assert.equal( operationAcceptance58e2204.find((x) => x.operationId === id)!.resourceBulk, false, id, ); const health = operationAcceptance58e2204.find((x) => x.operationId === 'getHealth')!; assert.equal(health.fleetBatchable, true); assert.equal(health.partialAggregationPolicy, 'per-item'); }); test('fixture disposition is authoritative and exactly follows collector plus 78-file manifest', () => { assert.equal(fixtureDisposition58e2204.length, 117); assert.equal(new Set(fixtureDisposition58e2204.map((x) => x.operationId)).size, 117); const selected = selectReadonlyOperations(upstream58e2204Operations as any[]); assert.equal(selected.selected.length, 39); assert.equal(selected.denied.length, 11); assert.equal(Object.keys(DENY_REASONS).length, 11); const selectedIds = new Set(selected.selected.map((x: any) => x.operationId)); const denied = new Map(selected.denied.map((x: any) => [x.operationId, x.denyReason])); const filesById = new Map(); for (const file of manifest.files) { const match = /instance-[12]--([^.]+)\.json$/.exec(file.path); assert.ok(match); const list = filesById.get(match[1]) ?? []; list.push(file); filesById.set(match[1], list); } for (const d of fixtureDisposition58e2204) { if (selectedIds.has(d.operationId)) { assert.equal(d.runtimeFixtureStatus, 'captured-readonly'); assert.equal(d.fixtureCount, 2); assert.equal(filesById.get(d.operationId)?.length, 2); assert.deepEqual(d.aliases, ['instance-1', 'instance-2']); assert.ok(d.observedCategories.length); } else if (denied.has(d.operationId)) { assert.equal(d.runtimeFixtureStatus, 'denied-readonly-candidate'); assert.equal(d.reason, denied.get(d.operationId)); assert.equal(d.fixtureCount, 0); } else { assert.match(d.runtimeFixtureStatus, /^not-eligible-readonly-capture/); assert.equal(d.fixtureCount, 0); } } assert.equal(manifest.realFixtureCount, 78); }); test('product risk prose defers to Registry and known conflicts stay corrected', async () => { const productRoot = fileURLToPath(new URL('../../../docs/product/', import.meta.url)); const workflows = await readFile(`${productRoot}personas-and-workflows.md`, 'utf8'); const charter = await readFile(`${productRoot}project-charter.md`, 'utf8'); assert.doesNotMatch(workflows, /下载 profile[^\n]*R2 Job/); assert.match(workflows, /WLAN connect 为 R1/); assert.match(workflows, /notifications config 为 R2 Job/); assert.match(workflows, /fleetBatchable=true/); assert.match(charter, /resourceBulk.*fleetBatchable/); for (const id of [ 'postEsimProfiles', 'postEsimProfilesIccidEnable', 'postDeviceNetworkWlanConnect', 'postNotificationsConfig', 'postAutomationConfig', 'postDeviceNetworkDdnsConfig', 'postBasebandRestart', ]) { assert.ok( operationAcceptance58e2204.find((x) => x.operationId === id), id, ); } }); test('generated matrix is synchronized and contains each operation exactly once', async () => { const doc = await readFile(matrixPath, 'utf8'); assert.equal(doc, renderOperationAcceptanceMatrix()); const ids = [...doc.matchAll(/^\| `([^`]+)` \|/gm)].map((x) => x[1]).filter((id) => byId.has(id)); assert.equal(ids.length, 117); assert.deepEqual(ids.sort(), [...byId.keys()].sort()); }); test('matrix renders metadata-only safe fixture categories for every operation', () => { const doc = renderOperationAcceptanceMatrix(); const safeCategories = new Set(['success', 'unsupported', 'auth-required']); const fixture = new Map(fixtureDisposition58e2204.map((x) => [x.operationId, x])); const rows = [ ...doc.matchAll(/^\| `([^`]+)` \|.*?\| ([^|]*categories=([^;|]+);[^|]*) \|/gm), ].filter((match) => byId.has(match[1])); assert.equal(rows.length, 117); for (const [, id, metadata, rendered] of rows) { const disposition = fixture.get(id)!; const expected = disposition.observedCategories.length ? [...disposition.observedCategories].sort().join(',') : 'none'; assert.equal(rendered.trim(), expected, id); for (const category of disposition.observedCategories) assert.ok(safeCategories.has(category), `${id}:${category}`); assert.doesNotMatch(metadata, /"(?:response|body|sourceInstanceAlias)"\s*:|https?:\/\//i, id); } assert.match(doc, /metadata-only/i); });