| import type { |
| SkynetCausalEpisode, |
| SkynetCausalValenceLabel, |
| } from "../causal-valence/episode-ledger.js"; |
| import { deriveSkynetWorldTransitionFeatures } from "../causal-valence/world-transition.js"; |
|
|
| export type SkynetRuntimeTrajectorySample = { |
| id: string; |
| sessionKey: string; |
| recordedAt: number; |
| lookbackCount: number; |
| historyEpisodes: SkynetCausalEpisode[]; |
| currentEpisode: SkynetCausalEpisode; |
| targetLabel: SkynetCausalValenceLabel; |
| }; |
|
|
| export type SkynetRuntimeTrajectoryFeatures = { |
| historyCount: number; |
| historyProgressRatio: number; |
| historyReliefRatio: number; |
| historyStallRatio: number; |
| historyFrustrationRatio: number; |
| historyDamageRatio: number; |
| historyOkRatio: number; |
| historyErrorRatio: number; |
| historyEnvironmentalFailureRatio: number; |
| historyCognitiveFailureRatio: number; |
| historyMixedFailureRatio: number; |
| historyMutationRatio: number; |
| historyAverageRecoveryBurden: number; |
| historyAverageCollateralDamage: number; |
| currentOperationCount: number; |
| currentUniquePathCount: number; |
| currentCreateRatio: number; |
| currentEditRatio: number; |
| currentDeleteRatio: number; |
| currentRenameRatio: number; |
| currentNoopRatio: number; |
| currentTargetCoverage: number; |
| currentCollateralRatio: number; |
| currentFailureStreak: number; |
| currentValidationIntensity: number; |
| currentFreshRatio: number; |
| currentAgingRatio: number; |
| currentStaleRatio: number; |
| currentMissingRatio: number; |
| currentOkRatio: number; |
| currentErrorRatio: number; |
| currentTimeoutRatio: number; |
| currentEnvironmentalFailure: number; |
| currentCognitiveFailure: number; |
| currentMixedFailure: number; |
| currentTargetSatisfied: number; |
| currentValidationPassed: number; |
| currentContinuityDelta: number; |
| currentRecoveryBurden: number; |
| }; |
|
|
| function clamp01(value: number): number { |
| return Math.max(0, Math.min(1, value)); |
| } |
|
|
| function ratio(count: number, total: number): number { |
| return total > 0 ? clamp01(count / total) : 0; |
| } |
|
|
| export function buildSkynetRuntimeTrajectorySamples(params: { |
| episodes: SkynetCausalEpisode[]; |
| lookback?: number; |
| }): SkynetRuntimeTrajectorySample[] { |
| const lookback = Math.max(1, Math.min(8, params.lookback ?? 3)); |
| const sortedEpisodes = [...params.episodes].sort((left, right) => { |
| if (left.sessionKey !== right.sessionKey) { |
| return left.sessionKey.localeCompare(right.sessionKey); |
| } |
| return left.recordedAt - right.recordedAt; |
| }); |
| const bySession = new Map<string, SkynetCausalEpisode[]>(); |
| for (const episode of sortedEpisodes) { |
| const bucket = bySession.get(episode.sessionKey) ?? []; |
| bucket.push(episode); |
| bySession.set(episode.sessionKey, bucket); |
| } |
|
|
| const samples: SkynetRuntimeTrajectorySample[] = []; |
| for (const [sessionKey, sessionEpisodes] of bySession) { |
| for (let index = 1; index < sessionEpisodes.length; index += 1) { |
| const historyStart = Math.max(0, index - lookback); |
| const historyEpisodes = sessionEpisodes.slice(historyStart, index); |
| const currentEpisode = sessionEpisodes[index]; |
| samples.push({ |
| id: `${sessionKey}:${currentEpisode.id}`, |
| sessionKey, |
| recordedAt: currentEpisode.recordedAt, |
| lookbackCount: historyEpisodes.length, |
| historyEpisodes, |
| currentEpisode, |
| targetLabel: currentEpisode.bootstrapLabel, |
| }); |
| } |
| } |
| return samples; |
| } |
|
|
| export function deriveSkynetRuntimeTrajectoryFeatureSummary( |
| sample: SkynetRuntimeTrajectorySample, |
| ): SkynetRuntimeTrajectoryFeatures { |
| const historyEpisodes = sample.historyEpisodes; |
| const historyCount = historyEpisodes.length; |
| const labelCount = (label: SkynetCausalValenceLabel): number => |
| historyEpisodes.filter((episode) => episode.bootstrapLabel === label).length; |
| const okCount = historyEpisodes.filter((episode) => episode.outcome.status === "ok").length; |
| const errorCount = historyEpisodes.filter((episode) => episode.outcome.status !== "ok").length; |
| const environmentalFailureCount = historyEpisodes.filter( |
| (episode) => episode.outcome.failureDomain === "environmental", |
| ).length; |
| const cognitiveFailureCount = historyEpisodes.filter( |
| (episode) => episode.outcome.failureDomain === "cognitive", |
| ).length; |
| const mixedFailureCount = historyEpisodes.filter( |
| (episode) => episode.outcome.failureDomain === "mixed", |
| ).length; |
| const mutationCount = historyEpisodes.filter((episode) => |
| episode.transition.operations.some((operation) => operation.kind !== "noop"), |
| ).length; |
| const averageRecoveryBurden = |
| historyCount > 0 |
| ? historyEpisodes.reduce((sum, episode) => sum + episode.outcome.recoveryBurden, 0) / |
| historyCount |
| : 0; |
| const averageCollateralDamage = |
| historyCount > 0 |
| ? historyEpisodes.reduce((sum, episode) => sum + episode.outcome.collateralDamage, 0) / |
| historyCount |
| : 0; |
| const currentTransition = deriveSkynetWorldTransitionFeatures(sample.currentEpisode.transition); |
|
|
| return { |
| historyCount, |
| historyProgressRatio: ratio(labelCount("progress"), historyCount), |
| historyReliefRatio: ratio(labelCount("relief"), historyCount), |
| historyStallRatio: ratio(labelCount("stall"), historyCount), |
| historyFrustrationRatio: ratio(labelCount("frustration"), historyCount), |
| historyDamageRatio: ratio(labelCount("damage"), historyCount), |
| historyOkRatio: ratio(okCount, historyCount), |
| historyErrorRatio: ratio(errorCount, historyCount), |
| historyEnvironmentalFailureRatio: ratio(environmentalFailureCount, historyCount), |
| historyCognitiveFailureRatio: ratio(cognitiveFailureCount, historyCount), |
| historyMixedFailureRatio: ratio(mixedFailureCount, historyCount), |
| historyMutationRatio: ratio(mutationCount, historyCount), |
| historyAverageRecoveryBurden: clamp01(averageRecoveryBurden), |
| historyAverageCollateralDamage: clamp01(averageCollateralDamage), |
| currentOperationCount: currentTransition.operationCount, |
| currentUniquePathCount: currentTransition.uniquePathCount, |
| currentCreateRatio: currentTransition.createRatio, |
| currentEditRatio: currentTransition.editRatio, |
| currentDeleteRatio: currentTransition.deleteRatio, |
| currentRenameRatio: currentTransition.renameRatio, |
| currentNoopRatio: currentTransition.noopRatio, |
| currentTargetCoverage: currentTransition.targetCoverage, |
| currentCollateralRatio: currentTransition.collateralRatio, |
| currentFailureStreak: sample.currentEpisode.context.failureStreak, |
| currentValidationIntensity: sample.currentEpisode.context.validationIntensity, |
| currentFreshRatio: sample.currentEpisode.context.continuityFreshness === "fresh" ? 1 : 0, |
| currentAgingRatio: sample.currentEpisode.context.continuityFreshness === "aging" ? 1 : 0, |
| currentStaleRatio: sample.currentEpisode.context.continuityFreshness === "stale" ? 1 : 0, |
| currentMissingRatio: sample.currentEpisode.context.continuityFreshness === "missing" ? 1 : 0, |
| currentOkRatio: sample.currentEpisode.outcome.status === "ok" ? 1 : 0, |
| currentErrorRatio: sample.currentEpisode.outcome.status === "error" ? 1 : 0, |
| currentTimeoutRatio: sample.currentEpisode.outcome.status === "timeout" ? 1 : 0, |
| currentEnvironmentalFailure: |
| sample.currentEpisode.outcome.failureDomain === "environmental" ? 1 : 0, |
| currentCognitiveFailure: sample.currentEpisode.outcome.failureDomain === "cognitive" ? 1 : 0, |
| currentMixedFailure: sample.currentEpisode.outcome.failureDomain === "mixed" ? 1 : 0, |
| currentTargetSatisfied: sample.currentEpisode.outcome.targetSatisfied ? 1 : 0, |
| currentValidationPassed: sample.currentEpisode.outcome.validationPassed ? 1 : 0, |
| currentContinuityDelta: clamp01(sample.currentEpisode.outcome.continuityDelta), |
| currentRecoveryBurden: clamp01(sample.currentEpisode.outcome.recoveryBurden), |
| }; |
| } |
|
|
| export function encodeSkynetRuntimeTrajectoryFeatures( |
| sample: SkynetRuntimeTrajectorySample, |
| ): number[] { |
| const summary = deriveSkynetRuntimeTrajectoryFeatureSummary(sample); |
| return [ |
| clamp01(Math.min(summary.historyCount, 4) / 4), |
| summary.historyProgressRatio, |
| summary.historyReliefRatio, |
| summary.historyStallRatio, |
| summary.historyFrustrationRatio, |
| summary.historyDamageRatio, |
| summary.historyOkRatio, |
| summary.historyErrorRatio, |
| summary.historyEnvironmentalFailureRatio, |
| summary.historyCognitiveFailureRatio, |
| summary.historyMixedFailureRatio, |
| summary.historyMutationRatio, |
| summary.historyAverageRecoveryBurden, |
| summary.historyAverageCollateralDamage, |
| clamp01(Math.min(summary.currentOperationCount, 8) / 8), |
| clamp01(Math.min(summary.currentUniquePathCount, 8) / 8), |
| summary.currentCreateRatio, |
| summary.currentEditRatio, |
| summary.currentDeleteRatio, |
| summary.currentRenameRatio, |
| summary.currentNoopRatio, |
| summary.currentTargetCoverage, |
| summary.currentCollateralRatio, |
| clamp01(Math.min(summary.currentFailureStreak, 4) / 4), |
| clamp01(summary.currentValidationIntensity), |
| summary.currentFreshRatio, |
| summary.currentAgingRatio, |
| summary.currentStaleRatio, |
| summary.currentMissingRatio, |
| summary.currentOkRatio, |
| summary.currentErrorRatio, |
| summary.currentTimeoutRatio, |
| summary.currentEnvironmentalFailure, |
| summary.currentCognitiveFailure, |
| summary.currentMixedFailure, |
| summary.currentTargetSatisfied, |
| summary.currentValidationPassed, |
| summary.currentContinuityDelta, |
| summary.currentRecoveryBurden, |
| ]; |
| } |
|
|