Bifrost/tools/epiphany-operator-command-documents.mjs
2026-07-19 18:43:49 +01:00

45 lines
16 KiB
JavaScript

export const operatorRequestType="voidbot.discord.epiphany_operator_request";
export const operatorRequestSchema="voidbot.discord.epiphany_operator_request.v1";
export const operatorAdmissionType="bifrost.operator_command.delivery";
export const operatorAdmissionSchema="bifrost.operator_command.delivery.v1";
export const legacyOperatorAdmissionSchema="bifrost.operator_command.delivery.v0";
export const operatorResultType="epiphany.operator_command.result";
export const operatorResultSchema="epiphany.operator_command.result.v1";
export const legacyOperatorResultSchema="epiphany.operator_command.result.v0";
export const operatorResultReceiptType="epiphany.operator_command.sealed_result";
export const operatorResultReceiptSchema="epiphany.operator_command.sealed_result.v1";
export const legacyOperatorResultReceiptSchema="epiphany.operator_command.sealed_result.v0";
export const operatorTerminalType="bifrost.operator_command.terminal";
export const operatorTerminalSchema="bifrost.operator_command.terminal.v0";
export const operatorDiscordDeliveryType="bifrost.discord.epiphany_operator_delivery";
export const operatorDiscordDeliverySchema="bifrost.discord.epiphany_operator_delivery.v1";
export function buildOperatorDefinitions(defineDocumentType){const make=(type,schemaId,name,parse)=>defineDocumentType({type,schemaName:type,schemaId,schemaVersion:schemaId,contentHash:schemaId,global:false,name,schema:{parse}});return {request:make(operatorRequestType,operatorRequestSchema,"requestId",parseOperatorRequest),admission:make(operatorAdmissionType,operatorAdmissionSchema,"admissionId",value=>parseOperatorAdmission(value,{allowLegacy:true})),result:make(operatorResultType,operatorResultSchema,"resultId",value=>parseOperatorResult(value,{allowLegacy:true})),sealedResult:make(operatorResultReceiptType,operatorResultReceiptSchema,"commandId",value=>parseOperatorResultReceipt(value,{allowLegacy:true})),terminal:make(operatorTerminalType,operatorTerminalSchema,"requestId",parseOperatorTerminal),discordDelivery:make(operatorDiscordDeliveryType,operatorDiscordDeliverySchema,"deliveryId",parseOperatorDiscordDelivery)};}
export function parseOperatorRequest(value){const v=exactRecord(value,["schemaName","schemaVersion","requestId","commandId","nonce","sourceEventId","sourceActorDiscordId","discordGuildId","discordChannelId","discordMessageId","targetRuntimeId","issuedAt","expiresAt","producerId","producerRuntimeId","authorityClass","status","command"],"operator request"); exact(v.schemaName,operatorRequestType,"schemaName");exact(v.schemaVersion,operatorRequestSchema,"schemaVersion"); for(const k of ["requestId","commandId","nonce","sourceEventId","sourceActorDiscordId","discordGuildId","discordChannelId","discordMessageId","targetRuntimeId","producerRuntimeId"])text(v[k],k); exact(v.producerId,"voidbot","producerId");exact(v.authorityClass,"operator_request_only","authorityClass");exact(v.status,"pending","status"); const issued=date(v.issuedAt,"issuedAt"),expires=date(v.expiresAt,"expiresAt");if(expires<=issued||expires-issued>60000)throw new Error("operator request TTL must be positive and at most 60 seconds.");parseCommand(v.command);return v;}
export function parseOperatorAdmission(v,{allowLegacy=false}={}){v=exactRecord(v,["schemaName","schemaVersion","admissionId","packet","packetSha256","sourceObserverId","sourceObserverRuntimeId","provider","bifrostAdmissionReceiptId","authority","providerIdentityId","providerSignature"],"operator admission");exact(v.schemaName,operatorAdmissionType,"schemaName");if(v.schemaVersion!==operatorAdmissionSchema&&!(allowLegacy&&v.schemaVersion===legacyOperatorAdmissionSchema))throw new Error("schemaVersion must be the current admission schema.");for(const k of ["admissionId","packetSha256","sourceObserverRuntimeId","bifrostAdmissionReceiptId","providerIdentityId"])text(v[k],k);exact(v.sourceObserverId,"voidbot","sourceObserverId");exact(v.provider,"bifrost","provider");exact(v.authority,"exact_operator_command_only","authority");v.providerSignature=bytes(v.providerSignature,"providerSignature",64);parsePacket(v.packet);if(v.schemaVersion===legacyOperatorAdmissionSchema&&["reviews","review"].includes(v.packet.command.kind))throw new Error("legacy v0 admission cannot carry Mind review commands.");return v;}
export function parseOperatorResult(v,{allowLegacy=false}={}){const legacy=v?.schemaVersion===legacyOperatorResultSchema;if(legacy&&!allowLegacy)throw new Error("legacy result is replay-only.");v=exactRecord(v,legacy?["schemaVersion","resultId","commandId","packetSha256","targetRuntimeId","disposition","consequenceKind","consequenceRef","completedAt","privateStateExposed","operatorStatus","stateStatus","coordinatorAction","brakeStatus","detail"]:["schemaVersion","resultId","commandId","packetSha256","targetRuntimeId","disposition","consequenceKind","consequenceRef","completedAt","privateStateExposed","operatorStatus","stateStatus","coordinatorAction","brakeStatus","detail","reviews","reviewCandidateId","reviewDecision"],"operator result");if(!legacy)exact(v.schemaVersion,operatorResultSchema,"schemaVersion");for(const k of ["resultId","commandId","packetSha256","targetRuntimeId","disposition","consequenceKind","completedAt"])text(v[k],k);if(!["observed","applied","refused"].includes(v.disposition))throw new Error("result disposition is invalid.");if(v.privateStateExposed!==false)throw new Error("operator result must not expose private state.");for(const k of ["consequenceRef","operatorStatus","stateStatus","coordinatorAction","brakeStatus","detail"]){if(typeof v[k]!=="string")throw new Error(`${k} must be a string.`);if(v[k].length>512)throw new Error(`${k} exceeds 512 characters.`);}if(!legacy){for(const k of ["reviewCandidateId","reviewDecision"]){if(typeof v[k]!=="string")throw new Error(`${k} must be a string.`);if(v[k].length>256)throw new Error(`${k} exceeds 256 characters.`);}if(!Array.isArray(v.reviews)||v.reviews.length>10)throw new Error("operator reviews must be a bounded array.");v.reviews.forEach(parseReviewSummary);if(v.reviewDecision&&!['adopt','refuse','hold'].includes(v.reviewDecision))throw new Error("reviewDecision is invalid.");}date(v.completedAt,"completedAt");return v;}
export function parseOperatorResultReceipt(v,{allowLegacy=false}={}){v=exactRecord(v,["schemaVersion","result","resultPayloadSha256","commandId","packetSha256","targetRuntimeId","completedAt","providerIdentityId","privateStateExposed","executorSignature"],"operator sealed result receipt");const legacy=v.schemaVersion===legacyOperatorResultReceiptSchema;if(legacy&&!allowLegacy)throw new Error("legacy sealed result is replay-only.");if(!legacy)exact(v.schemaVersion,operatorResultReceiptSchema,"schemaVersion");parseOperatorResult(v.result,{allowLegacy});if(legacy!== (v.result.schemaVersion===legacyOperatorResultSchema))throw new Error("sealed result and embedded result versions differ.");for(const k of ["resultPayloadSha256","commandId","packetSha256","targetRuntimeId","completedAt","providerIdentityId"])text(v[k],k);date(v.completedAt,"completedAt");if(v.privateStateExposed!==false)throw new Error("operator sealed result receipt must not expose private state.");v.executorSignature=bytes(v.executorSignature,"executorSignature",64);return v;}
export function parseOperatorTerminal(v){v=exactRecord(v,["schemaVersion","requestId","commandId","status","failureCode","recordedAt","retryable","privateStateExposed"],"operator terminal disposition");exact(v.schemaVersion,operatorTerminalSchema,"schemaVersion");for(const k of ["requestId","commandId","failureCode","recordedAt"])text(v[k],k);exact(v.status,"refused","status");date(v.recordedAt,"recordedAt");if(v.retryable!==false||v.privateStateExposed!==false)throw new Error("operator terminal disposition must be non-retryable and private-state-free.");return v;}
export function parseOperatorDiscordDelivery(v){v=exactRecord(v,["schemaVersion","deliveryId","requestId","requestPayloadSha256","commandId","discordGuildId","discordChannelId","discordInteractionId","targetRuntimeId","status","disposition","failureCode","detail","operatorStatus","stateStatus","coordinatorAction","brakeStatus","reviews","reviewCandidateId","reviewDecision","sealedResultPayloadSha256","executorSignatureSha256","resultProviderIdentityId","recordedAt","privateStateExposed"],"operator Discord delivery");exact(v.schemaVersion,operatorDiscordDeliverySchema,"schemaVersion");for(const k of ["deliveryId","requestId","requestPayloadSha256","commandId","discordGuildId","discordChannelId","discordInteractionId","targetRuntimeId","status","recordedAt"])text(v[k],k);if(!/^sha256-[0-9a-f]{64}$/.test(v.requestPayloadSha256))throw new Error("operator Discord delivery request digest is invalid.");if(!["completed","refused"].includes(v.status))throw new Error("operator Discord delivery status is invalid.");for(const k of ["disposition","failureCode","detail","operatorStatus","stateStatus","coordinatorAction","brakeStatus","reviewCandidateId","reviewDecision","sealedResultPayloadSha256","executorSignatureSha256","resultProviderIdentityId"])if(typeof v[k]!=="string")throw new Error(`${k} must be a string.`);if(!Array.isArray(v.reviews)||v.reviews.length>10)throw new Error("operator Discord delivery reviews must be bounded.");v.reviews.forEach(parseReviewSummary);if(v.reviewDecision&&!['adopt','refuse','hold'].includes(v.reviewDecision))throw new Error("operator Discord delivery reviewDecision is invalid.");for(const k of ["detail","operatorStatus","stateStatus","coordinatorAction","brakeStatus"])if(v[k].length>512)throw new Error(`operator Discord delivery ${k} exceeds 512 characters.`);if(v.status==="completed"&&(!v.disposition||!/^sha256-[0-9a-f]{64}$/.test(v.sealedResultPayloadSha256)||!/^sha256-[0-9a-f]{64}$/.test(v.executorSignatureSha256)||!v.resultProviderIdentityId))throw new Error("completed operator Discord delivery lacks sealed-result binding.");if(v.status==="refused"&&!v.failureCode)throw new Error("refused operator Discord delivery lacks failure code.");date(v.recordedAt,"recordedAt");if(v.privateStateExposed!==false)throw new Error("operator Discord delivery must not expose private state.");return v;}
export function operatorRequestTuple(v){return [v.schemaName,v.schemaVersion,v.requestId,v.commandId,v.nonce,v.sourceEventId,v.sourceActorDiscordId,v.discordGuildId,v.discordChannelId,v.discordMessageId,v.targetRuntimeId,v.issuedAt,v.expiresAt,v.producerId,v.producerRuntimeId,v.authorityClass,v.status,commandTuple(v.command)];}
export function packetTuple(p){return [p.commandId,p.nonce,p.sourceEventId,p.sourceActorId,p.discordGuildId,p.discordChannelId,p.discordMessageId,p.targetRuntimeId,p.issuedAt,p.expiresAt,commandTuple(p.command)];}
export function admissionTuple(a){return [a.schemaVersion,a.admissionId,packetTuple(a.packet),a.packetSha256,a.sourceObserverId,a.sourceObserverRuntimeId,a.provider,a.bifrostAdmissionReceiptId,a.authority,a.providerIdentityId];}
// rmp-serde's compact serializer encodes the nested Rust wire-result struct as
// this positional array inside the signed tuple. The separately hashed result
// payload is encoded with named fields.
export function wireResultTuple(v){const tuple=[v.schemaVersion,v.resultId,v.commandId,v.packetSha256,v.targetRuntimeId,v.disposition,v.consequenceKind,v.consequenceRef,v.completedAt,v.privateStateExposed,v.operatorStatus,v.stateStatus,v.coordinatorAction,v.brakeStatus,v.detail];return v.schemaVersion===legacyOperatorResultSchema?tuple:[...tuple,v.reviews.map(reviewSummaryTuple),v.reviewCandidateId,v.reviewDecision];}
export function resultReceiptTuple(v){return [v.schemaVersion,wireResultTuple(v.result),v.resultPayloadSha256,v.commandId,v.packetSha256,v.targetRuntimeId,v.completedAt,v.providerIdentityId,v.privateStateExposed];}
function parsePacket(v){v=exactRecord(v,["commandId","nonce","sourceEventId","sourceActorId","discordGuildId","discordChannelId","discordMessageId","targetRuntimeId","issuedAt","expiresAt","command"],"operator packet");for(const k of ["commandId","nonce","sourceEventId","sourceActorId","discordGuildId","discordChannelId","discordMessageId","targetRuntimeId"])text(v[k],k);date(v.issuedAt,"issuedAt");date(v.expiresAt,"expiresAt");parseCommand(v.command);return v;}
function parseCommand(v){if(!v||typeof v!=="object"||Array.isArray(v))throw new Error("command must be an object.");if(["status","wake","reviews"].includes(v.kind))return exactRecord(v,["kind"],"command");if(v.kind==="sleep"){exactRecord(v,["kind","reason"],"command");text(v.reason,"reason");if(v.reason.length>512)throw new Error("sleep reason exceeds 512 characters.");return v;}if(v.kind==="directive"){exactRecord(v,["kind","objective"],"command");text(v.objective,"objective");if(v.objective.length>4096)throw new Error("directive objective exceeds 4096 characters.");return v;}if(v.kind==="review"){exactRecord(v,["kind","mindRequestId","candidateId","candidateSha256","expectedModelRevision","expectedModelHash","decision"],"command");for(const k of ["mindRequestId","candidateId"]){text(v[k],k);if(v[k].length>256)throw new Error(`${k} exceeds 256 characters.`);}hex64(v.candidateSha256,"candidateSha256");hex64(v.expectedModelHash,"expectedModelHash");if(!Number.isSafeInteger(v.expectedModelRevision)||v.expectedModelRevision<0)throw new Error("expectedModelRevision must be an unsigned safe integer.");if(!["adopt","refuse","hold"].includes(v.decision))throw new Error("review decision is invalid.");return v;}throw new Error("command kind is invalid.");}
// rmp-serde's compact enum form is the snake-case unit variant string, or a
// two-element [variant, sole-field] tuple for these one-field struct variants.
function commandTuple(v){if(v.kind==="sleep")return ["sleep",v.reason];if(v.kind==="directive")return ["directive",v.objective];if(v.kind==="review")return ["review",[v.mindRequestId,v.candidateId,v.candidateSha256,v.expectedModelRevision,v.expectedModelHash,v.decision]];return v.kind;}
export const commandTupleForInterop=commandTuple;
function parseReviewSummary(v){exactRecord(v,["mindRequestId","candidateId","candidateSha256","modelRevision","modelHash","frontierItemId","requestedAt"],"review summary");for(const k of ["mindRequestId","candidateId","frontierItemId"]){text(v[k],k);if(v[k].length>256)throw new Error(`review ${k} exceeds 256 characters.`);}hex64(v.candidateSha256,"candidateSha256");hex64(v.modelHash,"modelHash");if(!Number.isSafeInteger(v.modelRevision)||v.modelRevision<0)throw new Error("review modelRevision is invalid.");date(v.requestedAt,"requestedAt");return v;}
function reviewSummaryTuple(v){return [v.mindRequestId,v.candidateId,v.candidateSha256,v.modelRevision,v.modelHash,v.frontierItemId,v.requestedAt];}
function hex64(v,label){if(typeof v!=="string"||!/^[0-9a-fA-F]{64}$/.test(v))throw new Error(`${label} must be 64 hexadecimal characters.`);return v;}
function exactRecord(v,keys,label){if(!v||typeof v!=="object"||Array.isArray(v))throw new Error(`${label} must be an object.`);const actual=Object.keys(v).sort(),expected=[...keys].sort();if(actual.join("\0")!==expected.join("\0"))throw new Error(`${label} has unknown or missing fields.`);return v;}
function text(v,label){if(typeof v!=="string"||!v.trim())throw new Error(`${label} is required.`);return v;}
function exact(v,e,label){if(v!==e)throw new Error(`${label} must be ${e}.`);}
function date(v,label){text(v,label);if(!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(v))throw new Error(`${label} must be RFC3339.`);const n=Date.parse(v);if(!Number.isFinite(n))throw new Error(`${label} must be RFC3339.`);return n;}
function bytes(v,label,length){const normalized=v instanceof Uint8Array?v:Array.isArray(v)&&v.every(x=>Number.isInteger(x)&&x>=0&&x<=255)?Uint8Array.from(v):null;if(!normalized||normalized.length!==length)throw new Error(`${label} must be ${length} bytes.`);return normalized;}