docs: close Phase 0 acceptance gate

This commit is contained in:
chick
2026-07-16 08:07:58 +08:00
parent c7da857aff
commit 43a69d8617
10 changed files with 473 additions and 23 deletions
@@ -0,0 +1,116 @@
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { upstream58e2204Operations } from './upstream-58e2204.ts';
import { DENY_REASONS, selectReadonlyOperations } from '../../test-fixtures/scripts/collector.ts';
type Risk='R0'|'R1'|'R2'|'R3';
export type RuntimeFixtureStatus='captured-readonly'|'denied-readonly-candidate'|'not-eligible-readonly-capture'|'not-eligible-readonly-capture-parameterized-r0';
const routeByOwner:Record<string,string>={fleet:'/fleet','instances-new':'/instances/new','settings-instance':'/settings/instances/:id',overview:'/instances/:id/overview',cellular:'/instances/:id/cellular','device-network':'/instances/:id/device-network',messages:'/instances/:id/messages',calls:'/instances/:id/calls',esim:'/instances/:id/esim',notifications:'/instances/:id/notifications',automation:'/instances/:id/automation',ota:'/instances/:id/ota'};
const dedicatedAuth=new Set(['postAuthSetup','postAuthPassword','postAuthSettings','postAuthLogin','postAuthLogout']);
const resourceBulk=new Set(['postSmsBatchDelete','postNotificationsQueueRetryAll','postNotificationsQueueClear']);
const fixtureManifest=JSON.parse(readFileSync(fileURLToPath(new URL('../../test-fixtures/src/manifest.json',import.meta.url)),'utf8'));
const fixtureRoot=fileURLToPath(new URL('../../test-fixtures/',import.meta.url));
const selected=selectReadonlyOperations(upstream58e2204Operations as any[]);
const selectedIds=new Set(selected.selected.map((x:any)=>x.operationId));
const deniedById=new Map(selected.denied.map((x:any)=>[x.operationId,x.denyReason]));
const observations=new Map<string,{aliases:Set<string>,categories:Set<string>,count:number}>();
for(const file of fixtureManifest.files){const envelope=JSON.parse(readFileSync(`${fixtureRoot}${file.path}`,'utf8'));const current=observations.get(envelope.operationId)??{aliases:new Set(),categories:new Set(),count:0};current.aliases.add(envelope.sourceInstanceAlias);current.categories.add(envelope.statusCategory);current.count++;observations.set(envelope.operationId,current);}
export const fixtureDisposition58e2204=upstream58e2204Operations.map((op:any)=>{const observed=observations.get(op.operationId);if(selectedIds.has(op.operationId))return {operationId:op.operationId,runtimeFixtureStatus:'captured-readonly' as RuntimeFixtureStatus,fixtureCount:observed?.count??0,aliases:[...(observed?.aliases??[])].sort(),observedCategories:[...(observed?.categories??[])].sort(),reason:'collector-selected fully-bound GET R0; two redacted real captures'};const deny=deniedById.get(op.operationId);if(deny)return {operationId:op.operationId,runtimeFixtureStatus:'denied-readonly-candidate' as RuntimeFixtureStatus,fixtureCount:0,aliases:[],observedCategories:[],reason:deny};const parameterized=op.method==='GET'&&op.riskLevel==='R0'&&/[{}]/.test(op.pathTemplate);return {operationId:op.operationId,runtimeFixtureStatus:(parameterized?'not-eligible-readonly-capture-parameterized-r0':'not-eligible-readonly-capture') as RuntimeFixtureStatus,fixtureCount:0,aliases:[],observedCategories:[],reason:parameterized?'R0 read requires bound path parameters; collector accepts only fully-bound Registry paths':'not a collector-eligible fully-bound GET R0 operation'};});
const fixtureById=new Map(fixtureDisposition58e2204.map(x=>[x.operationId,x]));
export const acceptancePolicyCatalog={
preconditionPolicyId:{'query-capability':'Registered instance, authorized actor, and runtime capability decision are required.','command-current-state':'Refresh current state when available and bind the actor decision to its revision.','job-fresh-preflight':'Required fresh preflight; inability to refresh blocks execution.','auth-dedicated':'Dedicated auth endpoint, actor/session/instance rate limits, and fresh preflight of authentication state are required.'},
stalePolicyId:{'read-retain':'Retain last success as stale and permit an explicit safe refresh.','write-revision':'Refresh current state or require an explicit recorded revision-bound override.','high-risk-block':'Fresh preflight is mandatory; stale, expired, or unknown state blocks execution.','auth-no-replay':'Credential state is never inferred from stale data; require actor-initiated auth flow and no replay.'},
unsupportedPolicyId:{'version-probe':'404/405/501 is capability evidence for this frozen version, not permanent product unsupported; retain probe evidence.','auth-version-probe':'Auth 404/405/501 is version evidence; do not downgrade to a generic proxy or expose credentials.','ota-version-probe':'OTA 404/405/501 is frozen-version evidence; preserve release/status probe context and never infer global support.'},
retryPolicyId:{'safe-read':'Safe reads may retry within deadline and retain stale success.','verify-write':'Writes require outcome verification before actor-initiated retry.','new-job-lineage':'Retry creates a new Job lineage (retryOfJobId/rootJobId); never replay successful items.','auth-actor-only':'No automatic replay; require an actor-initiated dedicated flow.'},
resultPolicyId:{'route-result':'Structured result returns to the owning route with a redacted audit link.','job-result':'/jobs/:jobId contains per-item result, attempt lineage, and redacted audit.','auth-result':'Dedicated auth jobs return through /jobs/:jobId; session flows return a credential metadata-only audit result and link.'}
} as const;
/* Exact declarative UI partition. Every operation ID occurs in exactly one group; construction below throws on overlap/omission. */
const uiGroups:Record<string,string[]>= {
detail:['getDevice','getSim','getNetwork','getHealth','getAuthStatus','getAuthSettings'],
table:['getCells','getNetworkInterfaces','getNetworkOperators','getDeviceNetworkWlanProfiles','getEsimProfiles','getCalls','getCallHistory','getSmsList','getSmsConversation','getNotificationsLogs','getNotificationsQueue','getAutomationLogs'],
'dedicated-auth-flow':['postAuthSetup','postAuthPassword','postAuthSettings','postAuthLogin','postAuthLogout'],
'dedicated-upload-flow':['postOtaUpload'],
'job-action':['postBandLock','postDeviceNetworkDdnsConfig','postDeviceNetworkDdnsLogsClear','postDeviceNetworkWlanForget','postNetworkRegisterManual','postNetworkRegisterAuto','postCellLock','postCellLockUnlockAll','postBasebandRestart','postWorkMode','postEsimConfig','postEsimLpacRepair','deleteEsimProfilesIccid','postCallSettings','deleteCallHistoryId','postCallHistoryClear','postSmsSend','postSmsBatchDelete','deleteSmsConversationPhoneNumber','deleteSmsMessageId','postSmsClear','postSystemReboot','postServiceRestart','postNotificationsConfig','postNotificationsTestChannel','postNotificationsLogsClear','postNotificationsQueueRetryAll','postNotificationsQueueClear','deleteNotificationsQueueId','postNotificationsQueueIdRetry','postAutomationConfig','postAutomationLogsClear','postAutomationTestTaskId','postOtaApply','postOtaOnlinePrepare'],
form:['postSimCache','postRadioMode','postDeviceNetworkWlanEnabled','postDeviceNetworkWlanConnect','postDeviceNetworkWlanProfile','postApn','postData','postRoaming','postAirplaneMode','postEsimProfiles','postEsimProfilesIccidRename','postCallDial','postCallHangup','postCallAnswer','postCallVolume','postCallForwarding','postOtaLatestRelease'],
action:['postSimDetailsRefresh','postCellMonitorStart','postCellMonitorStop','postDeviceNetworkDdnsSync','postDeviceNetworkWlanScan','postDeviceNetworkWlanDisconnect','postEsimProfilesIccidEnable','postCallHangupAll','postOtaCancel'],
'read-panel':['getRadioMode','getBandLock','getNetworkConnectionAddresses','getDeviceNetworkDdnsConfig','getDeviceNetworkDdnsStatus','getDeviceNetworkDdnsLogs','getDeviceNetworkWlanStatus','getNetworkSignalStrength','getLocationCellInfo','getNetworkOperatorsScan','getApn','getCellLock','getData','getRoaming','getAirplaneMode','getBasebandRestartStatus','getWorkMode','getEsimConfig','getEsimLpacStatus','getEsimEuicc','getCallVolume','getCallForwarding','getCallSettings','getImsStatus','getVoicemailStatus','getSmsStats','getStats','getStatsCpu','getConnectivity','getNotificationsConfig','getAutomationConfig','getOtaStatus']
};
const strategyById=new Map<string,string>();for(const [strategy,ids] of Object.entries(uiGroups))for(const id of ids){if(strategyById.has(id))throw new Error(`duplicate acceptance override ${id}`);strategyById.set(id,strategy);}
const operationIds=new Set(upstream58e2204Operations.map((x:any)=>x.operationId));if(strategyById.size!==operationIds.size||[...operationIds].some(id=>!strategyById.has(id)))throw new Error('acceptance override partition must exactly cover frozen 117 operations');
const route=(owner:string)=>routeByOwner[owner];
export const surfaceGroups58e2204=[
{surfaceId:'overview/device',primaryRoute:route('overview'),ids:['getDevice']},{surfaceId:'overview/sim',primaryRoute:route('overview'),ids:['getSim','postSimDetailsRefresh','postSimCache']},{surfaceId:'overview/stats',primaryRoute:route('overview'),ids:['getStats','getStatsCpu']},{surfaceId:'overview/auth-health',primaryRoute:route('overview'),ids:['getConnectivity']},{surfaceId:'overview/system-actions',primaryRoute:route('overview'),ids:['postSystemReboot','postServiceRestart']},
{surfaceId:'cellular/serving-network',primaryRoute:route('cellular'),ids:['getNetwork']},{surfaceId:'cellular/cells',primaryRoute:route('cellular'),ids:['getCells','postCellMonitorStart','postCellMonitorStop','getLocationCellInfo']},{surfaceId:'cellular/signal',primaryRoute:route('cellular'),ids:['getNetworkSignalStrength']},{surfaceId:'cellular/operator-registration',primaryRoute:route('cellular'),ids:['getNetworkOperators','getNetworkOperatorsScan','postNetworkRegisterManual','postNetworkRegisterAuto']},{surfaceId:'cellular/radio-locks',primaryRoute:route('cellular'),ids:['getRadioMode','postRadioMode','getBandLock','postBandLock','getCellLock','postCellLock','postCellLockUnlockAll']},{surfaceId:'cellular/data-apn',primaryRoute:route('cellular'),ids:['getApn','postApn','getData','postData','getRoaming','postRoaming','getAirplaneMode','postAirplaneMode','postBasebandRestart','getBasebandRestartStatus']},
{surfaceId:'device-network/interfaces',primaryRoute:route('device-network'),ids:['getNetworkInterfaces','getNetworkConnectionAddresses']},{surfaceId:'device-network/ddns',primaryRoute:route('device-network'),ids:['getDeviceNetworkDdnsConfig','postDeviceNetworkDdnsConfig','getDeviceNetworkDdnsStatus','postDeviceNetworkDdnsSync','getDeviceNetworkDdnsLogs','postDeviceNetworkDdnsLogsClear']},{surfaceId:'device-network/wlan',primaryRoute:route('device-network'),ids:['getDeviceNetworkWlanStatus','postDeviceNetworkWlanEnabled','postDeviceNetworkWlanScan','getDeviceNetworkWlanProfiles','postDeviceNetworkWlanForget','postDeviceNetworkWlanConnect','postDeviceNetworkWlanDisconnect','postDeviceNetworkWlanProfile']},
{surfaceId:'calls/live',primaryRoute:route('calls'),ids:['getCalls','postCallDial','postCallHangup','postCallHangupAll','postCallAnswer']},{surfaceId:'calls/volume',primaryRoute:route('calls'),ids:['getCallVolume','postCallVolume']},{surfaceId:'calls/forwarding',primaryRoute:route('calls'),ids:['getCallForwarding','postCallForwarding']},{surfaceId:'calls/settings',primaryRoute:route('calls'),ids:['getCallSettings','postCallSettings']},{surfaceId:'calls/history',primaryRoute:route('calls'),ids:['getCallHistory','deleteCallHistoryId','postCallHistoryClear']},{surfaceId:'calls/ims-voicemail',primaryRoute:route('calls'),ids:['getImsStatus','getVoicemailStatus']},
{surfaceId:'messages/stats',primaryRoute:route('messages'),ids:['getSmsStats']},{surfaceId:'messages/list',primaryRoute:route('messages'),ids:['getSmsList']},{surfaceId:'messages/conversation',primaryRoute:route('messages'),ids:['getSmsConversation']},{surfaceId:'messages/compose',primaryRoute:route('messages'),ids:['postSmsSend']},{surfaceId:'messages/destructive',primaryRoute:route('messages'),ids:['postSmsBatchDelete','deleteSmsConversationPhoneNumber','deleteSmsMessageId','postSmsClear']},
{surfaceId:'esim/mode',primaryRoute:route('esim'),ids:['getWorkMode','postWorkMode']},{surfaceId:'esim/config',primaryRoute:route('esim'),ids:['getEsimConfig','postEsimConfig']},{surfaceId:'esim/lpac',primaryRoute:route('esim'),ids:['getEsimLpacStatus','postEsimLpacRepair']},{surfaceId:'esim/euicc',primaryRoute:route('esim'),ids:['getEsimEuicc']},{surfaceId:'esim/profiles',primaryRoute:route('esim'),ids:['getEsimProfiles','postEsimProfiles','postEsimProfilesIccidEnable','postEsimProfilesIccidRename','deleteEsimProfilesIccid']},
{surfaceId:'notifications/config',primaryRoute:route('notifications'),ids:['getNotificationsConfig','postNotificationsConfig','postNotificationsTestChannel']},{surfaceId:'notifications/logs',primaryRoute:route('notifications'),ids:['getNotificationsLogs','postNotificationsLogsClear']},{surfaceId:'notifications/queue',primaryRoute:route('notifications'),ids:['getNotificationsQueue','postNotificationsQueueRetryAll','postNotificationsQueueClear','deleteNotificationsQueueId','postNotificationsQueueIdRetry']},
{surfaceId:'automation/config',primaryRoute:route('automation'),ids:['getAutomationConfig','postAutomationConfig']},{surfaceId:'automation/logs',primaryRoute:route('automation'),ids:['getAutomationLogs','postAutomationLogsClear']},{surfaceId:'automation/task-test',primaryRoute:route('automation'),ids:['postAutomationTestTaskId']},
{surfaceId:'ota/status',primaryRoute:route('ota'),ids:['getOtaStatus','postOtaCancel']},{surfaceId:'ota/release',primaryRoute:route('ota'),ids:['postOtaLatestRelease','postOtaOnlinePrepare']},{surfaceId:'ota/upload',primaryRoute:route('ota'),ids:['postOtaUpload']},{surfaceId:'ota/apply',primaryRoute:route('ota'),ids:['postOtaApply']},
{surfaceId:'settings/auth-settings',primaryRoute:route('settings-instance'),ids:['postAuthPassword','getAuthSettings','postAuthSettings','postAuthLogout']},{surfaceId:'settings/auth-entry',primaryRoute:route('instances-new'),ids:['getHealth','getAuthStatus','postAuthSetup','postAuthLogin']}
] as const;
const policies=(preconditionPolicyId:string,stalePolicyId:string,retryPolicyId:string,resultPolicyId:string,unsupportedPolicyId='version-probe')=>({preconditionPolicyId,stalePolicyId,unsupportedPolicyId,retryPolicyId,resultPolicyId});
export const policyGroups58e2204=[
{groupId:'query-list',ids:['getCells','getNetworkInterfaces','getDeviceNetworkDdnsLogs','getDeviceNetworkWlanProfiles','getNetworkOperators','getEsimProfiles','getCalls','getCallHistory','getSmsList','getSmsConversation','getNotificationsLogs','getNotificationsQueue','getAutomationLogs'],policies:policies('query-capability','read-retain','safe-read','route-result')},
{groupId:'query-detail',ids:['getDevice','getSim','getNetwork','getRadioMode','getBandLock','getNetworkConnectionAddresses','getDeviceNetworkDdnsConfig','getDeviceNetworkDdnsStatus','getDeviceNetworkWlanStatus','getNetworkSignalStrength','getLocationCellInfo','getApn','getCellLock','getData','getRoaming','getAirplaneMode','getBasebandRestartStatus','getWorkMode','getEsimConfig','getEsimLpacStatus','getEsimEuicc','getCallVolume','getCallForwarding','getCallSettings','getImsStatus','getVoicemailStatus','getSmsStats','getNotificationsConfig','getAutomationConfig','getOtaStatus'],policies:policies('query-capability','read-retain','safe-read','route-result')},
{groupId:'query-composite',ids:['getStats','getStatsCpu','getConnectivity'],policies:policies('command-current-state','read-retain','safe-read','route-result')},
{groupId:'query-active-scan',ids:['getNetworkOperatorsScan'],policies:policies('command-current-state','write-revision','verify-write','route-result')},
{groupId:'query-auth-detail',ids:['getAuthSettings','getHealth','getAuthStatus'],policies:policies('query-capability','auth-no-replay','auth-actor-only','auth-result','auth-version-probe')},
{groupId:'direct-reversible-setting',ids:['postSimDetailsRefresh','postSimCache','postCellMonitorStart','postCellMonitorStop','postRadioMode','postDeviceNetworkDdnsSync','postDeviceNetworkWlanEnabled','postDeviceNetworkWlanScan','postDeviceNetworkWlanConnect','postDeviceNetworkWlanDisconnect','postDeviceNetworkWlanProfile','postApn','postData','postRoaming','postAirplaneMode','postEsimProfiles','postEsimProfilesIccidEnable','postEsimProfilesIccidRename','postCallDial','postCallHangup','postCallHangupAll','postCallAnswer','postCallVolume','postCallForwarding'],policies:policies('command-current-state','write-revision','verify-write','route-result')},
{groupId:'session-auth-flow',ids:['postAuthLogin','postAuthLogout'],policies:policies('auth-dedicated','auth-no-replay','auth-actor-only','auth-result','auth-version-probe')},
{groupId:'high-risk-network-job',ids:['postBandLock','postDeviceNetworkDdnsConfig','postDeviceNetworkDdnsLogsClear','postDeviceNetworkWlanForget','postNetworkRegisterManual','postNetworkRegisterAuto','postCellLock','postCellLockUnlockAll','postBasebandRestart','postWorkMode','postEsimConfig','postEsimLpacRepair','postCallSettings','postSmsSend','postNotificationsConfig','postNotificationsTestChannel','postNotificationsQueueRetryAll','postNotificationsQueueIdRetry','postAutomationConfig','postAutomationTestTaskId'],policies:policies('job-fresh-preflight','high-risk-block','new-job-lineage','job-result')},
{groupId:'destructive-cleanup-job',ids:['deleteEsimProfilesIccid','deleteCallHistoryId','postCallHistoryClear','postSmsBatchDelete','deleteSmsConversationPhoneNumber','deleteSmsMessageId','postSmsClear','postSystemReboot','postServiceRestart','postNotificationsLogsClear','postNotificationsQueueClear','deleteNotificationsQueueId','postAutomationLogsClear'],policies:policies('job-fresh-preflight','high-risk-block','new-job-lineage','job-result')},
{groupId:'ota-direct-control',ids:['postOtaLatestRelease','postOtaCancel'],policies:policies('command-current-state','write-revision','verify-write','route-result')},
{groupId:'ota-job',ids:['postOtaUpload','postOtaOnlinePrepare','postOtaApply'],policies:policies('job-fresh-preflight','high-risk-block','new-job-lineage','job-result','ota-version-probe')},
{groupId:'high-risk-auth-flow',ids:['postAuthPassword','postAuthSettings','postAuthSetup'],policies:policies('auth-dedicated','auth-no-replay','new-job-lineage','auth-result','auth-version-probe')}
] as const;
const readScenario=(empty:boolean,partial:boolean)=>({empty:{applicable:empty,rationale:empty?'Successful collection may contain no rows.':'Detail resource has no collection-empty rendering.'},partial:{applicable:partial,rationale:partial?'Independent response sections may succeed or fail.':'Atomic detail read has no meaningful partial rendering.'},'policy-forbidden':{applicable:false,rationale:'Safe read has no write-confirmation policy; support remains orthogonal.'},'unknown-result':{applicable:false,rationale:'Read failure is an error/freshness state, not unknown write outcome.'},'owner-switch':{applicable:true,rationale:'Owner switch discards responses with a mismatched instance key.'}});
const writeScenario=(partial:boolean)=>({empty:{applicable:false,rationale:'Command result is not a collection-empty state.'},partial:{applicable:partial,rationale:partial?'Job items may independently succeed, fail, or be skipped.':'Single-target command has no meaningful partial result.'},'policy-forbidden':{applicable:true,rationale:'Write can be blocked by capability, authorization, risk, or preflight policy.'},'unknown-result':{applicable:true,rationale:'Disconnect or timeout requires outcome verification before retry.'},'owner-switch':{applicable:true,rationale:'Owner switch preserves execution lineage but discards mismatched route responses.'}});
const activeScanScenario={empty:{applicable:true,rationale:'A successful active operator scan may return no operators.'},partial:{applicable:true,rationale:'The scan response may contain usable operators alongside per-result failures or incomplete entries.'},'policy-forbidden':{applicable:true,rationale:'Active scan may be blocked by capability, authorization, preflight, or active-scan policy.'},'unknown-result':{applicable:false,rationale:'A timed-out scan result may be discarded; it is not an unknown persistent write outcome.'},'owner-switch':{applicable:true,rationale:'Owner switch discards scan responses with a mismatched instance key.'}};
export const scenarioGroups58e2204=[
{profileId:'list-read',ids:['getCells','getNetworkInterfaces','getDeviceNetworkDdnsLogs','getDeviceNetworkWlanProfiles','getNetworkOperators','getEsimProfiles','getCalls','getCallHistory','getSmsList','getSmsConversation','getNotificationsLogs','getNotificationsQueue','getAutomationLogs'],scenarios:readScenario(true,true)},
{profileId:'detail-read',ids:['getDevice','getSim','getNetwork','getRadioMode','getBandLock','getNetworkConnectionAddresses','getDeviceNetworkDdnsConfig','getDeviceNetworkDdnsStatus','getDeviceNetworkWlanStatus','getNetworkSignalStrength','getLocationCellInfo','getApn','getCellLock','getData','getRoaming','getAirplaneMode','getBasebandRestartStatus','getWorkMode','getEsimConfig','getEsimLpacStatus','getEsimEuicc','getCallVolume','getCallForwarding','getCallSettings','getImsStatus','getVoicemailStatus','getSmsStats','getNotificationsConfig','getAutomationConfig','getOtaStatus','getAuthSettings','getHealth','getAuthStatus'],scenarios:readScenario(false,false)},
{profileId:'composite-read',ids:['getStats','getStatsCpu','getConnectivity'],scenarios:readScenario(false,true)},
{profileId:'active-scan',ids:['getNetworkOperatorsScan'],scenarios:activeScanScenario},
{profileId:'direct-write',ids:['postSimDetailsRefresh','postSimCache','postCellMonitorStart','postCellMonitorStop','postRadioMode','postDeviceNetworkDdnsSync','postDeviceNetworkWlanEnabled','postDeviceNetworkWlanScan','postDeviceNetworkWlanConnect','postDeviceNetworkWlanDisconnect','postDeviceNetworkWlanProfile','postApn','postData','postRoaming','postAirplaneMode','postEsimProfiles','postEsimProfilesIccidEnable','postEsimProfilesIccidRename','postCallDial','postCallHangup','postCallHangupAll','postCallAnswer','postCallVolume','postCallForwarding'],scenarios:writeScenario(false)},
{profileId:'job-single',ids:['postBandLock','postDeviceNetworkDdnsConfig','postDeviceNetworkDdnsLogsClear','postDeviceNetworkWlanForget','postNetworkRegisterManual','postNetworkRegisterAuto','postCellLock','postCellLockUnlockAll','postWorkMode','postEsimConfig','postEsimLpacRepair','postCallSettings','postSmsSend','postNotificationsConfig','postNotificationsTestChannel','postNotificationsQueueIdRetry','postAutomationConfig','postAutomationTestTaskId','deleteEsimProfilesIccid','deleteCallHistoryId','postCallHistoryClear','deleteSmsConversationPhoneNumber','deleteSmsMessageId','postSmsClear','postBasebandRestart','postSystemReboot','postServiceRestart','postNotificationsLogsClear','deleteNotificationsQueueId','postAutomationLogsClear'],scenarios:writeScenario(false)},
{profileId:'job-resource-bulk',ids:['postSmsBatchDelete','postNotificationsQueueRetryAll','postNotificationsQueueClear'],scenarios:writeScenario(true)},
{profileId:'ota-direct',ids:['postOtaLatestRelease','postOtaCancel'],scenarios:writeScenario(false)},
{profileId:'ota-job-single',ids:['postOtaUpload','postOtaOnlinePrepare','postOtaApply'],scenarios:writeScenario(false)},
{profileId:'auth-flow',ids:['postAuthPassword','postAuthSettings','postAuthSetup','postAuthLogin','postAuthLogout'],scenarios:writeScenario(false)}
] as const;
const versionEvidencePolicy='Persist the audited commit plus runtime capability probes; 404/405/501 is version-scoped evidence and never a permanent global verdict.';
export const availabilityGroups58e2204=[
{groupId:'captured-real-read',realAcceptance:'REAL_READ',availability:'planned',reason:'Frozen-scope read has two redacted captured responses; runtime support is still decided per registered instance.',versionEvidencePolicy,ids:['getDevice','getSim','getNetwork','getCells','getRadioMode','getBandLock','getNetworkInterfaces','getNetworkConnectionAddresses','getDeviceNetworkDdnsConfig','getDeviceNetworkDdnsStatus','getDeviceNetworkWlanStatus','getDeviceNetworkWlanProfiles','getNetworkSignalStrength','getLocationCellInfo','getNetworkOperators','getApn','getCellLock','getData','getRoaming','getAirplaneMode','getBasebandRestartStatus','getWorkMode','getEsimConfig','getEsimLpacStatus','getCalls','getCallVolume','getCallForwarding','getCallSettings','getImsStatus','getVoicemailStatus','getSmsStats','getStats','getStatsCpu','getNotificationsConfig','getAutomationConfig','getOtaStatus','getAuthSettings','getHealth','getAuthStatus']},
{groupId:'denied-read-candidate',realAcceptance:'REAL_READ_DEFERRED',availability:'planned',reason:'Frozen-scope read is modeled but real capture was explicitly denied; runtime support is probed per instance.',versionEvidencePolicy,ids:['getDeviceNetworkDdnsLogs','getNetworkOperatorsScan','getEsimEuicc','getEsimProfiles','getCallHistory','getSmsList','getSmsConversation','getConnectivity','getNotificationsLogs','getNotificationsQueue','getAutomationLogs']},
{groupId:'write-later',realAcceptance:'REAL_WRITE_LATER',availability:'planned',reason:'Frozen-scope reversible command is contract-planned for a later controlled real-write acceptance phase.',versionEvidencePolicy,ids:['postSimDetailsRefresh','postSimCache','postCellMonitorStart','postCellMonitorStop','postRadioMode','postDeviceNetworkDdnsSync','postDeviceNetworkWlanEnabled','postDeviceNetworkWlanScan','postDeviceNetworkWlanConnect','postDeviceNetworkWlanDisconnect','postDeviceNetworkWlanProfile','postApn','postData','postRoaming','postAirplaneMode','postEsimProfiles','postEsimProfilesIccidEnable','postEsimProfilesIccidRename','postCallDial','postCallHangup','postCallHangupAll','postCallAnswer','postCallVolume','postCallForwarding','postOtaLatestRelease','postOtaCancel','postAuthLogin','postAuthLogout']},
{groupId:'high-risk-simulated',realAcceptance:'SIMULATED_HIGH_RISK',availability:'planned',reason:'Frozen-scope high-risk operation is planned with simulation-only acceptance until controlled safety authorization exists.',versionEvidencePolicy,ids:['postBandLock','postDeviceNetworkDdnsConfig','postDeviceNetworkDdnsLogsClear','postDeviceNetworkWlanForget','postNetworkRegisterManual','postNetworkRegisterAuto','postCellLock','postCellLockUnlockAll','postBasebandRestart','postWorkMode','postEsimConfig','postEsimLpacRepair','deleteEsimProfilesIccid','postCallSettings','deleteCallHistoryId','postCallHistoryClear','postSmsSend','postSmsBatchDelete','deleteSmsConversationPhoneNumber','deleteSmsMessageId','postSmsClear','postSystemReboot','postServiceRestart','postNotificationsConfig','postNotificationsTestChannel','postNotificationsLogsClear','postNotificationsQueueRetryAll','postNotificationsQueueClear','deleteNotificationsQueueId','postNotificationsQueueIdRetry','postAutomationConfig','postAutomationLogsClear','postAutomationTestTaskId','postOtaUpload','postOtaOnlinePrepare','postOtaApply','postAuthPassword','postAuthSettings','postAuthSetup']}
] as const;
function exactLookup(groups:readonly any[],label:string){const map=new Map<string,any>();for(const group of groups)for(const id of group.ids){if(map.has(id))throw new Error(`${label} overlap: ${id}`);map.set(id,group);}for(const id of map.keys())if(!operationIds.has(id))throw new Error(`${label} unknown operation: ${id}`);if(map.size!==operationIds.size||[...operationIds].some(id=>!map.has(id)))throw new Error(`${label} must exactly cover frozen 117 operations`);return map;}
const surfaceById=exactLookup(surfaceGroups58e2204,'surface');const policyById=exactLookup(policyGroups58e2204,'policy');const scenarioById=exactLookup(scenarioGroups58e2204,'scenario');const availabilityById=exactLookup(availabilityGroups58e2204,'availability');
export const operationAcceptanceOverrides58e2204=Object.fromEntries(upstream58e2204Operations.map((op:any)=>{const surface=surfaceById.get(op.operationId);const policy=policyById.get(op.operationId);const scenario=scenarioById.get(op.operationId);const availability=availabilityById.get(op.operationId);if(!surface||!policy||!scenario||!availability)throw new Error(`missing exact acceptance decision: ${op.operationId}`);return [op.operationId,{surfaceId:surface.surfaceId,primaryRoute:surface.primaryRoute,uiStrategy:strategyById.get(op.operationId),...policy.policies,scenarioAcceptance:scenario.scenarios,availability:availability.availability,availabilityReason:availability.reason,versionEvidencePolicy:availability.versionEvidencePolicy,realAcceptance:availability.realAcceptance}];}));
export const operationAcceptance58e2204=upstream58e2204Operations.map((op:any)=>{const override:any=operationAcceptanceOverrides58e2204[op.operationId];const policies:any=acceptancePolicyCatalog;const high=['R2','R3'].includes(op.riskLevel);const auth=dedicatedAuth.has(op.operationId);const scenarios=override.scenarioAcceptance;return {operationId:op.operationId,method:op.method,pathTemplate:op.pathTemplate,upstreamDomain:op.upstreamDomain,primaryRoute:override.primaryRoute,surfaceId:override.surfaceId,uiStrategy:override.uiStrategy,availability:override.availability,availabilityReason:override.availabilityReason,versionEvidencePolicy:override.versionEvidencePolicy,requiredStates:{request:['idle','loading','success','error'],freshness:['fresh','stale','expired','unknown'],support:['supported','unsupported','auth-required','degraded','unknown'],scenarios:Object.entries(scenarios).filter(([,v]:any)=>v.applicable).map(([k])=>k),naRationale:'Non-applicable scenarios retain an explicit rationale in scenarioAcceptance.'},scenarioAcceptance:scenarios,riskLevel:op.riskLevel as Risk,confirmationUX:op.confirmationPolicy,executionMode:auth?'dedicated-flow':high?'preparation-job':'direct',executionDerivation:auth?'Registry executionPolicy=dedicatedFlow binds the dedicated authentication orchestration.':high?'Registry capability=job plus product prepare-confirm-execute policy derives preparation-job orchestration.':'Registry capability plus acceptance policy derives direct structured execution.',executionPolicySource:'Registry supplies risk, confirmation, capability and dedicatedFlow; acceptance policy supplies orchestration.',...Object.fromEntries(['preconditionPolicyId','stalePolicyId','unsupportedPolicyId','retryPolicyId','resultPolicyId'].map(k=>[k,override[k]])),preconditions:policies.preconditionPolicyId[override.preconditionPolicyId],stalePolicy:policies.stalePolicyId[override.stalePolicyId],unsupportedPolicy:policies.unsupportedPolicyId[override.unsupportedPolicyId],retryRecovery:policies.retryPolicyId[override.retryPolicyId],resultDestination:policies.resultPolicyId[override.resultPolicyId],resourceBulk:resourceBulk.has(op.operationId),fleetBatchable:op.operationId==='getHealth',partialAggregationPolicy:op.operationId==='getHealth'?'per-item':resourceBulk.has(op.operationId)?'resource-item':'not-applicable',realAcceptance:override.realAcceptance,evidenceIds:[`registry:${op.operationId}`,...op.sourceEvidence.map((x:string)=>`upstream:${x}`),`fixture:${fixtureById.get(op.operationId)?.runtimeFixtureStatus}`],...(op.sessionSensitive?{sessionSubtype:'session-sensitive'}:{})};});
const flow=(flowId:string,route:string,risk:string,riskSubtype:string,confirmation:string,preconditions:string,result:string,failureRecovery:string,secretPolicy:string,evidence:string)=>({flowId,route,risk,riskSubtype,confirmation,preconditions,result,failureRecovery,secretPolicy,evidence});
export const controlPlaneAcceptance=[
flow('instance-create','/instances/new','R1','configuration','diff-confirm','canonical origin and unique stable ID','created instance revision and audit','retain draft on validation or reconcile failure','secret reference only; never return a value','WF-01 + product policy'),
flow('instance-update','/settings/instances/:id','R1','configuration','revision-diff','current revision','updated revision and audit','409 refreshes diff without losing edits','preserve/set/clear explicit; never return a value','WF-01 + product policy'),
flow('instance-delete','/settings/instances/:id','R3','destructive','strong target restatement','fresh revision and no conflicting job','new jobId with two-phase deleting to tombstone result','before boundary restore; after boundary manual recovery','destroy reference without reading secret value','WF-13'),
flow('secret-set','/settings/instances/:id','R1','secret-reference','explicit set','authorized SecretStore write','new reference metadata and audit','atomic rollback on reference write failure','never return or log secret value','WF-01'),flow('secret-preserve','/settings/instances/:id','R1','secret-reference','explicit preserve','existing reference metadata','unchanged reference metadata and audit','revision conflict refreshes metadata only','never read or return secret value','WF-01'),flow('secret-clear','/settings/instances/:id','R1','secret-reference','explicit clear','fresh revision','reference removed and audit','atomic rollback or explicit recovery state','never return destroyed secret value','WF-01'),
flow('config-import-preview','/settings/instances','R0','preview','none','validated upload and canonical origins','redacted diff/conflict/count preview','fix file and regenerate preview','never include secret values in preview','IA settings import'),flow('config-import-confirm','/settings/instances','R2','bulk-configuration','explicit preview token','fresh unexpired preview','new jobId with per-instance items','retry failed items in new lineage','references only; never import/export secret values','IA settings import'),
flow('credential-verify','/instances/new','R1','session-sensitive','actor initiated','rate limit and registered target','credential metadata-only result','no automatic replay; actor may retry after backoff','ephemeral input, never response/audit value','WF-01'),flow('saved-secret-login','/instances/new','R1','session-sensitive','actor initiated','saved reference and rate limit','session metadata-only result','no automatic replay; return to login flow','resolve server-side; never expose value','WF-12'),flow('temporary-secret-login','/instances/new','R1','session-sensitive','actor initiated','one-shot input and rate limit','session metadata-only result','no automatic replay; require new actor input','memory-only and never saved or returned','WF-12'),flow('logout','/settings/instances/:id','R1','session-sensitive','actor initiated','active session','session cleared and metadata audit','no replay; reconcile auth status','no credential value involved','WF-12'),flow('401-recovery','/instances/:id/overview','R1','session-recovery','actor chooses login','401 evidence and retained stale data','return to owner; retry R0 only','never replay writes; preserve draft for new prepare','temporary/saved secret follows selected login policy','WF-12'),
flow('auth-setup','/instances/new','R3','authentication-change','strong confirmation','fresh dedicated auth preflight','new jobId and metadata-only audit','new lineage after state verification','password never returned or audited','Registry postAuthSetup'),flow('auth-password-change','/settings/instances/:id','R3','authentication-change','strong confirmation','fresh dedicated auth preflight','new jobId and metadata-only audit','new lineage after auth-status verification','old/new password never returned or audited','Registry postAuthPassword'),flow('auth-settings-read','/settings/instances/:id','R0','authentication-read','none','registered instance and actor','structured auth settings','safe actor retry','no password/cookie/token fields','Registry getAuthSettings'),flow('auth-settings-write','/settings/instances/:id','R2','authentication-change','explicit confirmation','fresh dedicated auth preflight','new jobId and metadata-only audit','new lineage; no replay','never return credential values','Registry postAuthSettings'),
flow('job-cancel','/jobs/:jobId','R1','job-control','explicit confirmation','cancelable current phase','immutable cancellation event','show non-cancelable boundary and reconcile','no secret data in event','IA jobs'),flow('job-retry','/jobs/:jobId','R2','job-control','explicit failed-item selection','source terminal state and fresh preflight','new jobId with retryOf/root/source lineage','never mutate source or replay successful items','redacted parameter summary only','WF-10'),flow('audit-export','/audit','R0','data-export','explicit scope','authorized filters','redacted export artifact','regenerate from immutable audit','redaction applies; no sensitiveFields','WF-11'),flow('system-settings-update','/settings/system','R1','configuration','revision-diff','safe bounds and current revision','updated revision and audit','409 refreshes diff; invalid bounds rejected','no secrets accepted','IA settings system')
];
const esc=(v:any)=>String(v).replace(/\|/g,'\\|').replace(/\n/g,' ');
export function renderOperationAcceptanceMatrix(){const controlRows=controlPlaneAcceptance.map(x=>`| \`${x.flowId}\` | \`${x.route}\` | ${x.risk} / ${x.riskSubtype} | ${x.confirmation} | ${esc(x.preconditions)} | ${esc(x.result)} | ${esc(x.failureRecovery)} | ${esc(x.secretPolicy)} | ${esc(x.evidence)} |`).join('\n');const rows=operationAcceptance58e2204.map((x:any)=>{const f:any=fixtureById.get(x.operationId);const scenarios=Object.entries(x.scenarioAcceptance).map(([k,v]:any)=>`${k}:${v.applicable?'Y':'N'} (${v.rationale})`).join('<br>');const policies=`${x.preconditionPolicyId}/${x.stalePolicyId}/${x.unsupportedPolicyId}/${x.retryPolicyId}/${x.resultPolicyId}`;const categories=f.observedCategories.length?[...f.observedCategories].sort().join(','):'none';return `| \`${x.operationId}\` | ${x.method} \`${x.pathTemplate}\` | ${x.upstreamDomain} | \`${x.primaryRoute}\`<br>\`${x.surfaceId}\` | ${x.uiStrategy} | ${x.availability}: ${esc(x.availabilityReason)}<br>${esc(x.versionEvidencePolicy)} | ${scenarios} | ${x.riskLevel}; ${x.confirmationUX}<br>${x.executionMode} | ${policies}<br>${esc(x.preconditions)}<br>${esc(x.stalePolicy)}<br>${esc(x.unsupportedPolicy)}<br>${esc(x.retryRecovery)}<br>${esc(x.resultDestination)} | ${x.realAcceptance} | ${f.runtimeFixtureStatus}; n=${f.fixtureCount}; categories=${categories}; ${esc(f.reason)} | ${x.evidenceIds.map((e:string)=>`\`${e}\``).join('<br>')} |`;}).join('\n');return `# Operation acceptance matrix — upstream 58e2204\n\n> Generated from the structured ledger. Registry is the sole source for risk, confirmation, capability, and dedicated-flow facts; orchestration is bound by acceptance policy. \`registeredOperation\` is not a synonym for preparation Job.\n\nREAL_READ means captured evidence and is restricted to \`captured-readonly\`. REAL_READ_DEFERRED marks denied candidates without a real fixture. Fixture disposition is metadata-only: runtime status, count, safe observed status categories, and reason; it never renders fixture body/response, alias, identity, or URL.\n\n## Control-plane acceptance (independent flows)\n\n| flowId | route | risk / subtype | confirmation | preconditions | result | failure recovery | secret policy | evidence |\n|---|---|---|---|---|---|---|---|---|\n${controlRows}\n\n## Upstream operation acceptance (exact 117)\n\n| operationId | method/path | domain | route/surface | UI | availability/version evidence | scenario applicability | risk/confirmation/execution | policy IDs and resolved policies | real class | fixture disposition (metadata-only: runtime status / n / categories / reason) | evidence |\n|---|---|---|---|---|---|---|---|---|---|---|---|\n${rows}\n`;}
export const fixtureDenyReasons58e2204=DENY_REASONS;