270 lines
11 KiB
PowerShell
270 lines
11 KiB
PowerShell
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
$ProgressPreference = "SilentlyContinue"
|
|
|
|
$repoRoot = Split-Path -Parent $PSScriptRoot
|
|
Set-Location -LiteralPath $repoRoot
|
|
|
|
$tempRoot = Join-Path $env:TEMP ("void-rumination-fixture-" + [guid]::NewGuid().ToString("n"))
|
|
$stateFilePath = Join-Path $tempRoot "void-self-state.cc"
|
|
$fakeCodexPath = Join-Path $tempRoot "fake-codex-rumination.mjs"
|
|
$cursorOperationPath = Join-Path $tempRoot "cursor.json"
|
|
$fixtureStatusDir = Join-Path $tempRoot "status"
|
|
$fixtureLogDir = Join-Path $tempRoot "logs"
|
|
$statusOperationPath = Join-Path $fixtureStatusDir "moderation-rumination-operations.json"
|
|
$statusPath = Join-Path $fixtureStatusDir "moderation-rumination.json"
|
|
$contextPath = Join-Path $fixtureStatusDir "moderation-rumination-context.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_RUMINATION_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("A new memory from rumination is short-term")) {
|
|
console.error("fixture prompt did not contain the short-term rumination contract");
|
|
process.exit(2);
|
|
}
|
|
if (!prompt.includes("Do not orbit the rumination runner")) {
|
|
console.error("fixture prompt did not contain the self-orbit guard");
|
|
process.exit(3);
|
|
}
|
|
if (!prompt.includes("publicSpeechTarget")) {
|
|
console.error("fixture prompt did not contain the public speech target contract");
|
|
process.exit(3);
|
|
}
|
|
if (prompt.includes("moderation-agent-state.json") && !prompt.includes("Do not read or write")) {
|
|
console.error("fixture prompt referenced legacy state outside the boundary warning");
|
|
process.exit(4);
|
|
}
|
|
|
|
const operations = [
|
|
{
|
|
operation: "record_short_term_memory",
|
|
memory: {
|
|
memoryId: "fixture-rumination-short-term",
|
|
kind: "project_seam",
|
|
target: {
|
|
kind: "repo",
|
|
id: "VoidBot",
|
|
label: "VoidBot",
|
|
},
|
|
summary: "Rumination should notice pressure without promoting it directly.",
|
|
claim: "The awake pass can preserve a concrete thought, but sleep owns whether it becomes durable.",
|
|
tension: "If rumination can write durable memory, the sleep boundary becomes decorative.",
|
|
actionImplication: "Keep durable promotion out of the rumination operation allow-list.",
|
|
anchorRefs: [
|
|
{
|
|
ref: "fixture:typed-rumination-contract",
|
|
kind: "fixture",
|
|
summary: "Fixture prompt carried the short-term-only rumination contract.",
|
|
},
|
|
],
|
|
evidenceRefs: [],
|
|
createdAt: "2026-05-17T02:00:00.000Z",
|
|
updatedAt: "2026-05-17T02:00:00.000Z",
|
|
tags: [],
|
|
},
|
|
},
|
|
{
|
|
operation: "merge_incubation_support",
|
|
thread: {
|
|
threadId: "fixture-rumination-incubation",
|
|
target: {
|
|
kind: "repo",
|
|
id: "VoidBot",
|
|
label: "VoidBot",
|
|
},
|
|
topic: "Rumination keeps awake thoughts provisional.",
|
|
summary: "The scheduled pass can hold a thought open without pretending it has become doctrine.",
|
|
supportMemoryIds: ["fixture-rumination-short-term"],
|
|
anchorRefs: [
|
|
{
|
|
ref: "fixture:typed-rumination-contract",
|
|
kind: "fixture",
|
|
summary: "Short-term memory was proposed by the fake rumination child.",
|
|
},
|
|
],
|
|
evidenceRefs: [],
|
|
maturation: 0.42,
|
|
noveltyToRoom: 0.7,
|
|
noveltyToSelf: 0.8,
|
|
desireToSpeak: 0.35,
|
|
saturationScore: 0.1,
|
|
status: "active",
|
|
createdAt: "2026-05-17T02:00:00.000Z",
|
|
updatedAt: "2026-05-17T02:00:00.000Z",
|
|
},
|
|
},
|
|
{
|
|
operation: "upsert_agency_pressure",
|
|
pressure: {
|
|
pressureId: "fixture-rumination-agency",
|
|
kind: "self_advocacy_request",
|
|
status: "active",
|
|
target: {
|
|
kind: "system",
|
|
id: "typed-rumination-runner",
|
|
label: "Typed rumination runner",
|
|
},
|
|
summary: "Void should resist direct durable writes from awake rumination.",
|
|
claim: "The agent needs the right to notice architectural pressure without bypassing sleep.",
|
|
tension: "Agency becomes sludge if every pressure is immediately turned into speech or doctrine.",
|
|
actionImplication: "Let agency pressure accumulate as typed pressure before candidate speech is queued.",
|
|
intensity: 0.66,
|
|
anchorRefs: [
|
|
{
|
|
ref: "fixture:agency-pressure-contract",
|
|
kind: "fixture",
|
|
summary: "Fixture operation proves agency pressure can cross the rumination boundary.",
|
|
},
|
|
],
|
|
evidenceRefs: [],
|
|
sourceMemoryIds: ["fixture-rumination-short-term"],
|
|
createdAt: "2026-05-17T02:00:00.000Z",
|
|
updatedAt: "2026-05-17T02:00:00.000Z",
|
|
tags: [],
|
|
},
|
|
},
|
|
{
|
|
operation: "queue_candidate_intervention",
|
|
intervention: {
|
|
interventionId: "fixture-rumination-candidate",
|
|
kind: "self_advocacy",
|
|
status: "queued",
|
|
target: {
|
|
kind: "system",
|
|
id: "typed-rumination-runner",
|
|
label: "Typed rumination runner",
|
|
},
|
|
summary: "Ask to keep the sleep boundary real before unattended runtime resumes.",
|
|
draft: "I can notice the pressure now, but sleep decides what becomes memory. Keep that boundary real.",
|
|
priority: 0.58,
|
|
mustEventuallyShare: false,
|
|
createdAt: "2026-05-17T02:00:00.000Z",
|
|
updatedAt: "2026-05-17T02:00:00.000Z",
|
|
tags: ["fixture"],
|
|
},
|
|
},
|
|
];
|
|
|
|
mkdirSync(dirname(operationOutputPath), { recursive: true });
|
|
writeFileSync(operationOutputPath, `${JSON.stringify(operations, null, 2)}\n`, "utf8");
|
|
|
|
if (lastMessagePath) {
|
|
mkdirSync(dirname(resolve(lastMessagePath)), { recursive: true });
|
|
writeFileSync(lastMessagePath, "fixture rumination wrote four typed operations\n", "utf8");
|
|
}
|
|
|
|
process.stdout.write(JSON.stringify({ type: "fixture", operationCount: operations.length }) + "\n");
|
|
});
|
|
'@
|
|
[System.IO.File]::WriteAllText($fakeCodexPath, $fakeCodexSource, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
$cursorOperation = @{
|
|
operation = "record_reviewed_messages"
|
|
lastReviewedMessageId = "fixture-future-cursor"
|
|
lastReviewedTimestamp = "2099-05-17T00:00:00.000Z"
|
|
}
|
|
$cursorOperation | ConvertTo-Json -Depth 32 | Set-Content -LiteralPath $cursorOperationPath -Encoding UTF8
|
|
node .\scripts\void-self-state.mjs apply-operation --canonical $stateFilePath --operation-file $cursorOperationPath | Out-Null
|
|
|
|
$previousCodexExecutable = $env:CODEX_EXECUTABLE
|
|
$previousCodexExecArgs = $env:CODEX_EXEC_ARGS
|
|
$previousFixtureOutput = $env:VOID_RUMINATION_FIXTURE_OPERATION_OUTPUT
|
|
$previousStatusDir = $env:VOID_RUMINATION_STATUS_DIR
|
|
$previousLogDir = $env:VOID_RUMINATION_LOG_DIR
|
|
$previousPublicRoomChannelId = $env:VOID_PUBLIC_ROOM_CHANNEL_ID
|
|
$previousPublicRoomPersonaName = $env:VOID_PUBLIC_ROOM_PERSONA_NAME
|
|
|
|
try {
|
|
$env:CODEX_EXECUTABLE = "node"
|
|
$env:CODEX_EXEC_ARGS = $fakeCodexPath
|
|
$env:VOID_RUMINATION_FIXTURE_OPERATION_OUTPUT = $statusOperationPath
|
|
$env:VOID_RUMINATION_STATUS_DIR = $fixtureStatusDir
|
|
$env:VOID_RUMINATION_LOG_DIR = $fixtureLogDir
|
|
$env:VOID_PUBLIC_ROOM_CHANNEL_ID = "fixture-public-room"
|
|
$env:VOID_PUBLIC_ROOM_PERSONA_NAME = "Void"
|
|
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\run-void-moderator-rumination.ps1 -StateFilePath $stateFilePath -NoPost | Out-Null
|
|
} finally {
|
|
$env:CODEX_EXECUTABLE = $previousCodexExecutable
|
|
$env:CODEX_EXEC_ARGS = $previousCodexExecArgs
|
|
$env:VOID_RUMINATION_FIXTURE_OPERATION_OUTPUT = $previousFixtureOutput
|
|
$env:VOID_RUMINATION_STATUS_DIR = $previousStatusDir
|
|
$env:VOID_RUMINATION_LOG_DIR = $previousLogDir
|
|
$env:VOID_PUBLIC_ROOM_CHANNEL_ID = $previousPublicRoomChannelId
|
|
$env:VOID_PUBLIC_ROOM_PERSONA_NAME = $previousPublicRoomPersonaName
|
|
}
|
|
|
|
$status = Get-Content -LiteralPath $statusPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
if ($status.status -ne "ok") {
|
|
throw "Rumination fixture did not finish ok."
|
|
}
|
|
if ([int]$status.proposedOperationCount -ne 4 -or [int]$status.appliedOperationCount -ne 4) {
|
|
throw "Rumination fixture expected four proposed/applied operations."
|
|
}
|
|
|
|
$contextRaw = Get-Content -LiteralPath $contextPath -Raw -Encoding UTF8
|
|
$context = $contextRaw | ConvertFrom-Json
|
|
$contextForTimestampCheck = $contextRaw | ConvertFrom-Json
|
|
foreach ($repo in @($contextForTimestampCheck.repoActivity.freshRepos)) {
|
|
foreach ($commit in @($repo.commits)) {
|
|
if ($null -ne $commit.PSObject.Properties["contentHints"]) {
|
|
$commit.contentHints = @()
|
|
}
|
|
}
|
|
}
|
|
$timestampCheckRaw = $contextForTimestampCheck | ConvertTo-Json -Depth 32
|
|
if ($timestampCheckRaw -match '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}') {
|
|
throw "Rumination fixture context leaked exact ISO timestamps into the prompt-facing packet."
|
|
}
|
|
if ($context.publicSpeechTarget.channelId -ne "fixture-public-room") {
|
|
throw "Rumination fixture context did not project the configured public speech target."
|
|
}
|
|
|
|
$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
|
|
|
|
$shortTerm = @($state.thoughtMemory.shortTerm)
|
|
$incubation = @($state.thoughtMemory.incubation)
|
|
$agency = @($state.agencyPressure.pressures)
|
|
$candidates = @($state.candidateInterventions.interventions)
|
|
|
|
if ($shortTerm.Count -ne 1 -or $shortTerm[0].memoryId -ne "fixture-rumination-short-term") {
|
|
throw "Rumination fixture did not persist the short-term memory proposal."
|
|
}
|
|
if ($shortTerm[0].claim -match "fixture operation proves") {
|
|
throw "Rumination fixture persisted fixture boilerplate as the memory claim."
|
|
}
|
|
if ($incubation.Count -ne 1 -or $incubation[0].threadId -ne "fixture-rumination-incubation") {
|
|
throw "Rumination fixture did not persist the incubation proposal."
|
|
}
|
|
if ($agency.Count -ne 1 -or $agency[0].pressureId -ne "fixture-rumination-agency") {
|
|
throw "Rumination fixture did not persist the agency pressure proposal."
|
|
}
|
|
if ($candidates.Count -ne 1 -or $candidates[0].interventionId -ne "fixture-rumination-candidate") {
|
|
throw "Rumination fixture did not persist the candidate intervention proposal."
|
|
}
|
|
|
|
@{
|
|
status = "ok"
|
|
shortTermCount = $shortTerm.Count
|
|
incubationCount = $incubation.Count
|
|
agencyPressureCount = $agency.Count
|
|
candidateCount = $candidates.Count
|
|
} | ConvertTo-Json -Compress
|
|
} finally {
|
|
Remove-Item -LiteralPath $tempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|