Verify sleep memory maintenance fixture
This commit is contained in:
parent
5df282e6b4
commit
29f68626cd
10 changed files with 276 additions and 22 deletions
|
|
@ -15,8 +15,16 @@ $stateFilePath = if ([string]::IsNullOrWhiteSpace($StateFilePath)) {
|
|||
} else {
|
||||
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($StateFilePath)
|
||||
}
|
||||
$statusDir = Join-Path $repoRoot ".voidbot\status"
|
||||
$logDir = Join-Path $repoRoot ".voidbot\logs"
|
||||
$statusDir = if (-not [string]::IsNullOrWhiteSpace($env:VOID_MEMORY_MAINTENANCE_STATUS_DIR)) {
|
||||
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($env:VOID_MEMORY_MAINTENANCE_STATUS_DIR)
|
||||
} else {
|
||||
Join-Path $repoRoot ".voidbot\status"
|
||||
}
|
||||
$logDir = if (-not [string]::IsNullOrWhiteSpace($env:VOID_MEMORY_MAINTENANCE_LOG_DIR)) {
|
||||
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($env:VOID_MEMORY_MAINTENANCE_LOG_DIR)
|
||||
} else {
|
||||
Join-Path $repoRoot ".voidbot\logs"
|
||||
}
|
||||
$statusPath = Join-Path $statusDir "void-memory-maintenance.json"
|
||||
$summaryLogPath = Join-Path $logDir "void-memory-maintenance.log"
|
||||
$lastMessagePath = Join-Path $statusDir "void-memory-maintenance-last-message.txt"
|
||||
|
|
@ -341,10 +349,34 @@ foreach ($requiredPath in @($contextProjectionScriptPath, $selfStateScriptPath,
|
|||
}
|
||||
|
||||
$envValues = Read-DotEnv -Path (Join-Path $repoRoot ".env")
|
||||
$codexExecutable = if ($envValues.ContainsKey("CODEX_EXECUTABLE") -and -not [string]::IsNullOrWhiteSpace($envValues["CODEX_EXECUTABLE"])) { $envValues["CODEX_EXECUTABLE"] } else { "codex" }
|
||||
$codexModel = if ($envValues.ContainsKey("CODEX_MODEL") -and -not [string]::IsNullOrWhiteSpace($envValues["CODEX_MODEL"])) { $envValues["CODEX_MODEL"] } else { "gpt-5.4" }
|
||||
$codexReasoningEffort = if ($envValues.ContainsKey("CODEX_MODEL_REASONING_EFFORT") -and -not [string]::IsNullOrWhiteSpace($envValues["CODEX_MODEL_REASONING_EFFORT"])) { $envValues["CODEX_MODEL_REASONING_EFFORT"] } else { "medium" }
|
||||
$codexExecArgs = if ($envValues.ContainsKey("CODEX_EXEC_ARGS")) { Split-CommandArgs -Value $envValues["CODEX_EXEC_ARGS"] } else { @() }
|
||||
$codexExecutable = if (-not [string]::IsNullOrWhiteSpace($env:CODEX_EXECUTABLE)) {
|
||||
$env:CODEX_EXECUTABLE
|
||||
} elseif ($envValues.ContainsKey("CODEX_EXECUTABLE") -and -not [string]::IsNullOrWhiteSpace($envValues["CODEX_EXECUTABLE"])) {
|
||||
$envValues["CODEX_EXECUTABLE"]
|
||||
} else {
|
||||
"codex"
|
||||
}
|
||||
$codexModel = if (-not [string]::IsNullOrWhiteSpace($env:CODEX_MODEL)) {
|
||||
$env:CODEX_MODEL
|
||||
} elseif ($envValues.ContainsKey("CODEX_MODEL") -and -not [string]::IsNullOrWhiteSpace($envValues["CODEX_MODEL"])) {
|
||||
$envValues["CODEX_MODEL"]
|
||||
} else {
|
||||
"gpt-5.4"
|
||||
}
|
||||
$codexReasoningEffort = if (-not [string]::IsNullOrWhiteSpace($env:CODEX_MODEL_REASONING_EFFORT)) {
|
||||
$env:CODEX_MODEL_REASONING_EFFORT
|
||||
} elseif ($envValues.ContainsKey("CODEX_MODEL_REASONING_EFFORT") -and -not [string]::IsNullOrWhiteSpace($envValues["CODEX_MODEL_REASONING_EFFORT"])) {
|
||||
$envValues["CODEX_MODEL_REASONING_EFFORT"]
|
||||
} else {
|
||||
"medium"
|
||||
}
|
||||
$codexExecArgs = if (-not [string]::IsNullOrWhiteSpace($env:CODEX_EXEC_ARGS)) {
|
||||
Split-CommandArgs -Value $env:CODEX_EXEC_ARGS
|
||||
} elseif ($envValues.ContainsKey("CODEX_EXEC_ARGS")) {
|
||||
Split-CommandArgs -Value $envValues["CODEX_EXEC_ARGS"]
|
||||
} else {
|
||||
@()
|
||||
}
|
||||
|
||||
$typedContext = Get-TypedSelfState
|
||||
$typedState = $typedContext.typedState
|
||||
|
|
|
|||
|
|
@ -11,14 +11,16 @@ const {
|
|||
loadVoidSelfStateTypedDocuments,
|
||||
} = require(resolve(repoRoot, "packages/core/dist/index.js"));
|
||||
|
||||
const statePath = resolve(repoRoot, ".voidbot/private/void-self-state.cc");
|
||||
const statusPath = resolve(repoRoot, ".voidbot/status/void-mood-drift.json");
|
||||
const lockPath = resolve(repoRoot, ".voidbot/status/void-mood-drift.lock");
|
||||
const lastSpeechPath = resolve(repoRoot, ".voidbot/status/void-last-speech.json");
|
||||
const moderationLockPath = resolve(repoRoot, ".voidbot/status/moderation-rumination.lock");
|
||||
const memoryMaintenanceStatusPath = resolve(repoRoot, ".voidbot/status/void-memory-maintenance.json");
|
||||
const rawArgs = process.argv.slice(2);
|
||||
const args = new Set(rawArgs);
|
||||
const statePath = resolveArgPath("--state-path", ".voidbot/private/void-self-state.cc");
|
||||
const statusDir = resolveStatusDir();
|
||||
const statusPath = resolve(statusDir, "void-mood-drift.json");
|
||||
const lockPath = resolve(statusDir, "void-mood-drift.lock");
|
||||
const lastSpeechPath = resolve(statusDir, "void-last-speech.json");
|
||||
const moderationLockPath = resolve(statusDir, "moderation-rumination.lock");
|
||||
const memoryMaintenanceStatusPath = resolveMemoryMaintenanceStatusPath();
|
||||
const memoryMaintenanceScriptPath = resolve(repoRoot, "scripts/run-void-memory-maintenance.ps1");
|
||||
const args = new Set(process.argv.slice(2));
|
||||
|
||||
async function main() {
|
||||
const now = new Date();
|
||||
|
|
@ -313,3 +315,28 @@ function clamp(value, min, max) {
|
|||
}
|
||||
|
||||
await main();
|
||||
|
||||
function getArgValue(name) {
|
||||
const index = rawArgs.indexOf(name);
|
||||
if (index < 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const value = rawArgs[index + 1];
|
||||
return typeof value === "string" && !value.startsWith("--") ? value : undefined;
|
||||
}
|
||||
|
||||
function resolveArgPath(name, fallbackRelativePath) {
|
||||
const value = getArgValue(name);
|
||||
return value ? resolve(value) : resolve(repoRoot, fallbackRelativePath);
|
||||
}
|
||||
|
||||
function resolveStatusDir() {
|
||||
const value = process.env.VOID_STATUS_DIR;
|
||||
return resolve(value && value.trim().length > 0 ? value : resolve(repoRoot, ".voidbot/status"));
|
||||
}
|
||||
|
||||
function resolveMemoryMaintenanceStatusPath() {
|
||||
const statusDir = process.env.VOID_MEMORY_MAINTENANCE_STATUS_DIR;
|
||||
return resolve(statusDir && statusDir.trim().length > 0 ? statusDir : resolveStatusDir(), "void-memory-maintenance.json");
|
||||
}
|
||||
|
|
|
|||
181
scripts/smoke-void-memory-maintenance-sleep-fixture.ps1
Normal file
181
scripts/smoke-void-memory-maintenance-sleep-fixture.ps1
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
$repoRoot = Split-Path -Parent $PSScriptRoot
|
||||
Set-Location -LiteralPath $repoRoot
|
||||
|
||||
$tempRoot = Join-Path $env:TEMP ("void-memory-maintenance-fixture-" + [guid]::NewGuid().ToString("n"))
|
||||
$stateFilePath = Join-Path $tempRoot "void-self-state.cc"
|
||||
$fakeCodexPath = Join-Path $tempRoot "fake-codex-memory-maintenance.mjs"
|
||||
$recordOperationPath = Join-Path $tempRoot "record-short-term.json"
|
||||
$sleepOperationPath = Join-Path $tempRoot "sleep-cycle.json"
|
||||
$fixtureStatusDir = Join-Path $tempRoot "status"
|
||||
$fixtureLogDir = Join-Path $tempRoot "logs"
|
||||
$statusOperationPath = Join-Path $fixtureStatusDir "void-memory-maintenance-operations.json"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $tempRoot | Out-Null
|
||||
|
||||
try {
|
||||
$fakeCodexSource = @'
|
||||
import { mkdirSync, writeFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
|
||||
const operationOutputPath = resolve(process.env.VOID_MEMORY_FIXTURE_OPERATION_OUTPUT);
|
||||
const lastMessageIndex = process.argv.indexOf("-o");
|
||||
const lastMessagePath = lastMessageIndex >= 0 ? process.argv[lastMessageIndex + 1] : undefined;
|
||||
|
||||
let prompt = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => {
|
||||
prompt += chunk;
|
||||
});
|
||||
process.stdin.on("end", () => {
|
||||
if (!prompt.includes("Sleep forces distillation")) {
|
||||
console.error("fixture prompt did not contain the sleep distillation contract");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const operation = {
|
||||
operation: "apply_memory_distillation",
|
||||
proposalId: "fixture-sleep-distillation",
|
||||
sourceMemoryIds: ["fixture-short-term-memory"],
|
||||
memory: {
|
||||
memoryId: "fixture-durable-memory",
|
||||
kind: "project_seam",
|
||||
target: {
|
||||
kind: "repo",
|
||||
id: "AquariumSynthCSharp",
|
||||
label: "AquariumSynthCSharp",
|
||||
},
|
||||
summary: "Workflow cannot own the body.",
|
||||
claim: "Runtime state should be owned by the implementation boundary rather than by workflow scripts.",
|
||||
tension: "Workflow scripts can orchestrate a pass, but they become compensators when they own the organism's body.",
|
||||
actionImplication: "Move authority into typed runtime state before adding more maintenance scripts.",
|
||||
evidenceRefs: [
|
||||
{
|
||||
ref: "fixture:aquarium-body-workflow",
|
||||
kind: "fixture",
|
||||
summary: "Seeded short-term memory for the sleep-maintenance fixture.",
|
||||
},
|
||||
],
|
||||
createdAt: "2026-05-17T00:00:00.000Z",
|
||||
updatedAt: "2026-05-17T01:00:00.000Z",
|
||||
tags: [],
|
||||
},
|
||||
appliedAt: "2026-05-17T01:00:00.000Z",
|
||||
};
|
||||
|
||||
mkdirSync(dirname(operationOutputPath), { recursive: true });
|
||||
writeFileSync(operationOutputPath, `${JSON.stringify([operation], null, 2)}\n`, "utf8");
|
||||
|
||||
if (lastMessagePath) {
|
||||
mkdirSync(dirname(resolve(lastMessagePath)), { recursive: true });
|
||||
writeFileSync(lastMessagePath, "fixture memory maintenance wrote one sleep distillation operation\n", "utf8");
|
||||
}
|
||||
|
||||
process.stdout.write(JSON.stringify({ type: "fixture", operationCount: 1 }) + "\n");
|
||||
});
|
||||
'@
|
||||
[System.IO.File]::WriteAllText($fakeCodexPath, $fakeCodexSource, [System.Text.UTF8Encoding]::new($false))
|
||||
|
||||
$recordOperation = @{
|
||||
operation = "record_short_term_memory"
|
||||
memory = @{
|
||||
memoryId = "fixture-short-term-memory"
|
||||
kind = "project_seam"
|
||||
target = @{
|
||||
kind = "repo"
|
||||
id = "AquariumSynthCSharp"
|
||||
label = "AquariumSynthCSharp"
|
||||
}
|
||||
summary = "Workflow cannot own the body."
|
||||
claim = "Runtime state should be owned by the implementation boundary rather than by workflow scripts."
|
||||
tension = "Workflow scripts can orchestrate a pass, but they become compensators when they own the organism's body."
|
||||
actionImplication = "Move authority into typed runtime state before adding more maintenance scripts."
|
||||
evidenceRefs = @(
|
||||
@{
|
||||
ref = "fixture:aquarium-body-workflow"
|
||||
kind = "fixture"
|
||||
summary = "Seeded short-term memory for the sleep-maintenance fixture."
|
||||
}
|
||||
)
|
||||
createdAt = "2026-05-17T00:00:00.000Z"
|
||||
updatedAt = "2026-05-17T00:00:00.000Z"
|
||||
tags = @()
|
||||
}
|
||||
}
|
||||
$sleepOperation = @{
|
||||
operation = "update_sleep_cycle"
|
||||
sleepCycle = @{
|
||||
isNapping = $true
|
||||
currentNapStartedAt = "2026-05-17T00:00:00.000Z"
|
||||
currentNapEndsAt = "2099-05-17T01:00:00.000Z"
|
||||
nextNapStartsAt = "2099-05-17T04:00:00.000Z"
|
||||
activeDreamThemes = @("fixture-distillation")
|
||||
}
|
||||
}
|
||||
|
||||
$recordOperation | ConvertTo-Json -Depth 32 | Set-Content -LiteralPath $recordOperationPath -Encoding UTF8
|
||||
$sleepOperation | ConvertTo-Json -Depth 32 | Set-Content -LiteralPath $sleepOperationPath -Encoding UTF8
|
||||
|
||||
node .\scripts\void-self-state.mjs apply-operation --canonical $stateFilePath --operation-file $recordOperationPath | Out-Null
|
||||
node .\scripts\void-self-state.mjs apply-operation --canonical $stateFilePath --operation-file $sleepOperationPath | Out-Null
|
||||
|
||||
$previousCodexExecutable = $env:CODEX_EXECUTABLE
|
||||
$previousCodexExecArgs = $env:CODEX_EXEC_ARGS
|
||||
$previousFixtureOutput = $env:VOID_MEMORY_FIXTURE_OPERATION_OUTPUT
|
||||
$previousStatusDir = $env:VOID_STATUS_DIR
|
||||
$previousMaintenanceStatusDir = $env:VOID_MEMORY_MAINTENANCE_STATUS_DIR
|
||||
$previousMaintenanceLogDir = $env:VOID_MEMORY_MAINTENANCE_LOG_DIR
|
||||
|
||||
try {
|
||||
$env:CODEX_EXECUTABLE = "node"
|
||||
$env:CODEX_EXEC_ARGS = $fakeCodexPath
|
||||
$env:VOID_MEMORY_FIXTURE_OPERATION_OUTPUT = $statusOperationPath
|
||||
$env:VOID_STATUS_DIR = $fixtureStatusDir
|
||||
$env:VOID_MEMORY_MAINTENANCE_STATUS_DIR = $fixtureStatusDir
|
||||
$env:VOID_MEMORY_MAINTENANCE_LOG_DIR = $fixtureLogDir
|
||||
|
||||
node .\scripts\simulate-void-mood.mjs --state-path $stateFilePath --force-memory-maintenance | Out-Null
|
||||
} finally {
|
||||
$env:CODEX_EXECUTABLE = $previousCodexExecutable
|
||||
$env:CODEX_EXEC_ARGS = $previousCodexExecArgs
|
||||
$env:VOID_MEMORY_FIXTURE_OPERATION_OUTPUT = $previousFixtureOutput
|
||||
$env:VOID_STATUS_DIR = $previousStatusDir
|
||||
$env:VOID_MEMORY_MAINTENANCE_STATUS_DIR = $previousMaintenanceStatusDir
|
||||
$env:VOID_MEMORY_MAINTENANCE_LOG_DIR = $previousMaintenanceLogDir
|
||||
}
|
||||
|
||||
$stateJson = node -e "const core=require('./packages/core/dist/index.js'); core.loadVoidSelfStateTypedDocuments({canonicalPath: process.argv[1]}).then((state)=>console.log(JSON.stringify(state))).catch((error)=>{ console.error(error); process.exit(1); })" $stateFilePath
|
||||
$state = $stateJson | ConvertFrom-Json
|
||||
$shortTermCount = @($state.thoughtMemory.shortTerm).Count
|
||||
$durableCount = @($state.thoughtMemory.memories).Count
|
||||
|
||||
if ($shortTermCount -ne 0) {
|
||||
throw "Sleep fixture left $shortTermCount short-term memories behind."
|
||||
}
|
||||
if ($durableCount -ne 1) {
|
||||
throw "Sleep fixture expected one durable memory, found $durableCount."
|
||||
}
|
||||
|
||||
$durableMemory = @($state.thoughtMemory.memories)[0]
|
||||
if ($durableMemory.summary -ne "Workflow cannot own the body.") {
|
||||
throw "Sleep fixture distorted the memory summary."
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($durableMemory.claim) -or [string]::IsNullOrWhiteSpace($durableMemory.tension) -or [string]::IsNullOrWhiteSpace($durableMemory.actionImplication)) {
|
||||
throw "Sleep fixture produced a durable memory without claim, tension, and action implication."
|
||||
}
|
||||
if (@($durableMemory.evidenceRefs).Count -lt 1) {
|
||||
throw "Sleep fixture produced a durable memory without evidence refs."
|
||||
}
|
||||
|
||||
@{
|
||||
status = "ok"
|
||||
shortTermCount = $shortTermCount
|
||||
durableCount = $durableCount
|
||||
durableSummary = $durableMemory.summary
|
||||
} | ConvertTo-Json -Compress
|
||||
} finally {
|
||||
Remove-Item -LiteralPath $tempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Loading…
Reference in a new issue