Verify sleep memory maintenance fixture
This commit is contained in:
parent
5df282e6b4
commit
29f68626cd
10 changed files with 276 additions and 22 deletions
|
|
@ -633,7 +633,7 @@ That gives the loop a compact digest of recent commit motion across every tracke
|
|||
|
||||
The moderator state is now typed CultCache state, not an editable Ghostlight-shaped JSON projection. The typed documents own profile, moderation cursor/open cases, speech receipts, thought memory/incubation, scheduled runtime, and candidate interventions. The old JSON projection, state template, and context exporter are gone.
|
||||
The typed rumination runner can still think about GameCult projects, archived Discord seams, indexed repos, recent cross-repo commit motion, and lore, but durable changes must come back as typed operation payloads. The child does not edit state.
|
||||
The mood-drift task owns the sleep transition. Rumination writes short-term memory only; when Void is napping, mood drift invokes `scripts/run-void-memory-maintenance.ps1` once per nap unless the pass already completed for that nap. Memory maintenance reads typed self-state, loads `prompts/void-memory-maintenance.md`, and applies only memory/incubation/candidate typed operation proposals. Short-term memories do not survive sleep unless promoted into durable memory or merged into incubation; the runner fails a real sleep pass that leaves short-term residue behind. Use `-StateFilePath` for fixture stores, and `--skip-memory-maintenance` on `simulate-void-mood.mjs` for smoke runs that must not invoke Codex. Dream residue, identity crystallization, value pressure, and other agency behavior still have to come back through that operation boundary. No compatibility séance.
|
||||
The mood-drift task owns the sleep transition. Rumination writes short-term memory only; when Void is napping, mood drift invokes `scripts/run-void-memory-maintenance.ps1` once per nap unless the pass already completed for that nap. Memory maintenance reads typed self-state, loads `prompts/void-memory-maintenance.md`, and applies only memory/incubation/candidate typed operation proposals. Short-term memories do not survive sleep unless promoted into durable memory or merged into incubation; the runner fails a real sleep pass that leaves short-term residue behind. Use `-StateFilePath` for fixture stores, `--skip-memory-maintenance` on `simulate-void-mood.mjs` for smoke runs that must not invoke Codex, and `npm run moderation:memory-maintenance:sleep-fixture` to exercise the non-skip model branch with a fake Codex child. Dream residue, identity crystallization, value pressure, and other agency behavior still have to come back through that operation boundary. No compatibility séance.
|
||||
Directly invoked live replies read the same typed private self-state as a distilled self-state attachment. When the sleep projection says Void is napping, the direct reply path skips the expensive room-read sidecar, avoids normal attentive service-work, and answers in brief sleepy grumbles instead.
|
||||
The moderation loop now speaks through the local bot token instead of approval-gated side-effecting MCP tools, so unattended runs can DM or post without making Codex stop and ask your permission every time it finds a mouthful of words.
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
|
|||
- `scripts/run-void-moderator-rumination.ps1` has been rebuilt as a typed rumination runner. It builds a typed context packet, loads `prompts/void-moderator-rumination.md`, runs Codex rumination, and applies only the JSON operation payloads that come back through `scripts/void-self-state.mjs`. Cursor and receipt bookkeeping remain parent-owned.
|
||||
- Prompt-facing rumination chronology is projected by `scripts/lib/void-rumination-context-projection.ps1`. Exact timestamps stay in typed state/status/cursors; the child context gets relative phrases like `5 minutes ago`, including recent Discord messages, repo activity, receipts, memory timestamps, and sleep/speech timing.
|
||||
- `scripts/simulate-void-mood.mjs` owns typed sleep/speaking-pressure over `.voidbot/private/void-self-state.cc`. During sleep, it invokes typed memory maintenance once per nap unless that nap already completed a pass; use `--skip-memory-maintenance` for smoke runs that must not call Codex.
|
||||
- `npm run moderation:memory-maintenance:sleep-fixture` now proves the non-skip sleep path without spending a live model call: it seeds a temporary `.cc`, forces mood drift through sleep maintenance, uses a fake Codex child to propose `apply_memory_distillation`, and verifies short-term residue is gone while the durable memory keeps subject, claim, tension, action implication, and evidence.
|
||||
- The local scheduled task `Void Mood Drift` has been reinstalled/enabled against the typed runner and manually started once with Last Result `0`. `Void Moderator Rumination` remains disabled until its model-pass fixture earns unattended runtime.
|
||||
- The old memory-organ script family, legacy moderation-state template, and legacy moderation context exporter have been deleted. Do not revive their cleanup, agency, dream, vector-incubation, or mirror-repair behavior as compatibility scaffolding.
|
||||
- `scripts/run-void-memory-maintenance.ps1` is the first replacement memory-maintenance organ. It builds a bounded context from typed memories/incubation/candidates/runtime, loads `prompts/void-memory-maintenance.md`, and applies only allowed memory/incubation/candidate typed operation proposals through `scripts/void-self-state.mjs`. In sleep mode, memory pressure sets `sleepDirective.forceDistillation`; a real model pass returning no operations under pressure fails visibly.
|
||||
- Rumination does not write durable memory. It can only emit `record_short_term_memory`; sleep maintenance must promote short-term records with `apply_memory_distillation`, merge them into incubation and prune them, or prune them outright. A real sleep pass that leaves short-term records behind fails.
|
||||
|
|
|
|||
|
|
@ -122,8 +122,14 @@ This note is the source-grounded description of how the live VoidBot stack is sh
|
|||
- typed self-state operation CLI. It applies strict operation payloads such as cursor updates, open-case changes, delivery receipts, repo cursor updates, short-term memory records, sleep-owned distillations, incubation merges, candidate interventions, sleep-cycle updates, and speaking-pressure updates through `packages/core/src/void-self-state-service.ts` against the CultCache `.cc` store.
|
||||
- `scripts/run-void-memory-maintenance.ps1`
|
||||
- typed memory-maintenance runner. It builds a bounded prompt-facing context from typed short-term memories, durable memories, incubation, candidates, receipts, and scheduled runtime; loads `prompts/void-memory-maintenance.md`; asks Codex for memory/incubation/candidate operation proposals; then applies only allowed typed operations through `scripts/void-self-state.mjs`. It accepts `-StateFilePath` so fixture passes can use a throwaway `.cc` store.
|
||||
- `scripts/smoke-void-memory-maintenance-sleep-fixture.ps1`
|
||||
- sleep-maintenance fixture. It seeds a temporary CultCache `.cc` store with a napping sleep cycle and one short-term memory, runs mood drift with a fake Codex child through the non-skip maintenance branch, and verifies the source short-term record is gone while one durable meaning-preserving memory remains.
|
||||
- `scripts/install-moderation-rumination-task.ps1`
|
||||
- installs the local 15-minute scheduled task that runs the moderation/participation loop through the hidden PowerShell launcher shim.
|
||||
- Scheduled task `Void Mood Drift`
|
||||
- enabled typed mood/sleep runner. It invokes `scripts/run-void-mood-drift.ps1`, which calls `scripts/simulate-void-mood.mjs`; when the typed sleep cycle is napping, that path invokes memory maintenance once per nap.
|
||||
- Scheduled task `Void Moderator Rumination`
|
||||
- disabled pending its own model-branch fixture. Its script is typed-only, but unattended speech/thought is still too behaviorally sharp to re-enable on smoke tests alone.
|
||||
- `scripts/simulate-void-mood.mjs`
|
||||
- typed mood maintenance script that updates scheduled-runtime sleep cycle and speaking pressure in `.voidbot/private/void-self-state.cc`. It owns the sleep transition and invokes typed memory maintenance once per nap unless that nap already completed a maintenance pass. The old personality-vector drift, memory organ, incubation, dream residue, cleanup, and legacy mirror behavior are offline pending typed replacements.
|
||||
- `scripts/run-void-mood-drift.ps1`
|
||||
|
|
@ -196,5 +202,5 @@ Within the Postgres path, the implementation is split on purpose now too:
|
|||
4. It loads `prompts/void-memory-maintenance.md` and asks Codex for operation proposals unless `-SkipModel` is set.
|
||||
5. The parent runner rejects any operation outside memory, incubation, or candidate-intervention maintenance.
|
||||
6. The parent runner applies allowed operations through `scripts/void-self-state.mjs`.
|
||||
7. In sleep mode, the context carries `sleepDirective.forceDistillation` when there is short-term memory pressure. A real model pass that returns no operations under pressure fails visibly, and any real sleep pass that leaves short-term memory behind fails instead of letting yesterday's residue haunt the state.
|
||||
7. In sleep mode, the context carries `sleepDirective.forceDistillation` when there is short-term memory pressure. A real model pass that returns no operations under pressure fails visibly, and any real sleep pass that leaves short-term memory behind fails instead of letting yesterday's residue haunt the state. The fixture smoke exercises this path with a fake Codex child so the parent validation and application machinery are tested without relying on live inference.
|
||||
8. This is the replacement path for sleep/distillation and agency work: model-owned proposals crossing the typed operation boundary, not deterministic repair code editing state.
|
||||
|
|
|
|||
|
|
@ -232,9 +232,10 @@ Verdict: stop feature work and rebuild this foundation. The rest of the machine
|
|||
|
||||
### Commit 6.5: Keep Old Scripts Offline
|
||||
|
||||
- Confirm `Void Moderator Rumination` and `Void Mood Drift` remain disabled while their replacement behavior is rebuilt.
|
||||
- Do not reinstall or re-enable old scheduled scripts as compatibility surfaces.
|
||||
- Verification: scheduled-task query shows both disabled; direct dry runs of the rebuilt scripts operate only on `.voidbot/private/void-self-state.cc`.
|
||||
- `Void Mood Drift` has been deliberately reinstalled after the typed sleep-maintenance fixture passed. It runs `scripts/run-void-mood-drift.ps1`, which calls the typed `scripts/simulate-void-mood.mjs` path.
|
||||
- Keep `Void Moderator Rumination` disabled until its typed operation path has a model-branch fixture comparable to the sleep-maintenance fixture.
|
||||
- Do not reinstall or re-enable deleted legacy scripts as compatibility surfaces.
|
||||
- Verification: scheduled-task query shows mood enabled with Last Result `0`, moderation disabled, and rebuilt direct dry runs operate only on `.voidbot/private/void-self-state.cc`.
|
||||
|
||||
### Commit 7: Harden Scheduled Runner As A Phase Machine
|
||||
|
||||
|
|
@ -261,6 +262,7 @@ Verdict: stop feature work and rebuild this foundation. The rest of the machine
|
|||
- Landed cut: hard-wired agency paths that turned heuristic scores into doctrine, advocacy, or speech candidates without an explicit typed-state contract have been deleted.
|
||||
- Landed replacement boundary: `scripts/run-void-memory-maintenance.ps1` asks the model for memory/incubation/candidate typed operation proposals using `prompts/void-memory-maintenance.md`, rejects non-maintenance operations, and applies the rest through `scripts/void-self-state.mjs`.
|
||||
- Landed sleep integration: `scripts/simulate-void-mood.mjs` invokes memory maintenance once per nap, and the maintenance runner fails a real sleep pass that returns no operations while memory pressure is present.
|
||||
- Landed verification: `npm run moderation:memory-maintenance:sleep-fixture` exercises the non-skip model branch with a fake Codex child, proving `AquariumSynthCSharp: Workflow cannot own the body` promotes from short-term into durable memory while preserving subject, claim, evidence, tension, and action implication.
|
||||
- Treat legacy brain mush as a migration problem, not the design center. New memory writes must cross the meaning-preserving typed operation schema before they reach CultCache.
|
||||
- Redesign sleep/distillation around an explicit contract:
|
||||
- preserve the claim/question/fascination target
|
||||
|
|
@ -270,7 +272,7 @@ Verdict: stop feature work and rebuild this foundation. The rest of the machine
|
|||
- preserve why the memory should affect future action
|
||||
- never replace a concrete thought with a prettier generic principle unless the operation records what was lost and why that loss is acceptable
|
||||
- Make distillation emit typed candidate memories first; the state service applies only candidates that satisfy the contract.
|
||||
- Remaining verification: model-pass fixtures such as `AquariumSynthCSharp: Workflow cannot own the body` survive sleep with their subject, claim, evidence, and tension intact.
|
||||
- Remaining work: rebuild agency behavior through typed operations and add the same model-branch fixture discipline to moderation rumination before scheduling it unattended.
|
||||
|
||||
### Commit 10: Resume Product Hardening
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"moderation:random-history": "node scripts/export-random-discord-history.mjs",
|
||||
"moderation:recent-repo-activity": "node scripts/export-recent-repo-activity.mjs",
|
||||
"moderation:memory-maintenance": "powershell -ExecutionPolicy Bypass -File scripts/run-void-memory-maintenance.ps1",
|
||||
"moderation:memory-maintenance:sleep-fixture": "powershell -ExecutionPolicy Bypass -File scripts/smoke-void-memory-maintenance-sleep-fixture.ps1",
|
||||
"moderation:mood-drift": "node scripts/simulate-void-mood.mjs",
|
||||
"rag:scrub-bot-prompts": "tsx scripts/scrub-bot-prompts-from-history.ts",
|
||||
"rag:index-sources": "tsx scripts/index-source-repos.ts",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -113,3 +113,4 @@
|
|||
{"ts":"2026-05-17T11:09:32Z","type":"implementation","status":"ok","note":"Sleep now owns memory distillation. simulate-void-mood.mjs invokes typed memory maintenance once per nap, can skip it for smoke, and records the result in mood status. run-void-memory-maintenance.ps1 marks sleep-mode pressure with sleepDirective.forceDistillation and fails real sleep passes that return no operations while memory pressure exists. Fixture smoke confirmed napping context with two concrete AquariumSynthCSharp memories sets forceDistillation=true without leaking raw timestamps."}
|
||||
{"ts":"2026-05-17T11:16:42Z","type":"implementation","status":"ok","note":"Made sleep distillation a state invariant instead of a prompt preference. Typed thought memory now has shortTerm plus durable memories; rumination may only emit record_short_term_memory, while durable promotion happens through sleep-owned apply_memory_distillation. Sleep maintenance now fails a real pass if short-term memories remain afterward. Fixture smoke verified record_short_term_memory creates only short-term state and apply_memory_distillation promotes it while clearing the source."}
|
||||
{"ts":"2026-05-17T11:24:20Z","type":"implementation","status":"ok","note":"Closed the durable-memory side door: removed append_distilled_memory from the typed operation schema/service, kept rumination limited to record_short_term_memory, and verified direct durable append is rejected while sleep-owned apply_memory_distillation promotes and clears short-term sources."}
|
||||
{"ts":"2026-05-17T11:49:21Z","type":"verification","status":"ok","note":"Added and ran the sleep-maintenance model-branch fixture. The fixture seeds a temporary CultCache .cc with a napping sleep cycle and one short-term memory, routes mood drift through run-void-memory-maintenance without -SkipModel using a fake Codex child, and verifies the source short-term record is consumed into one durable memory preserving summary, claim, tension, action implication, and evidence. Reinstalled the typed Void Mood Drift scheduled task, manually started it once, and confirmed Last Result 0 while Void Moderator Rumination remains disabled."}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ data_flow:
|
|||
active_subgoals:
|
||||
- Make the new project-state surfaces the default continuity path for nontrivial VoidBot work.
|
||||
- Rebuild the moderation/self-state foundation so canonical CultCache `.cc` documents are mutated only through typed operations, never through an editable JSON working projection.
|
||||
- Keep the old moderation and mood scheduled tasks offline until their typed replacements are deliberately reinstalled; typed rumination exists as a direct runner again, but not as an enabled legacy task.
|
||||
- Keep the old moderation scheduled task offline until its typed replacement is deliberately proven; typed mood drift is reinstalled against the typed runner after fixture verification.
|
||||
- Keep legacy moderation mirrors, whole-state projection commits, and deleted memory-organ compensators from re-entering the active path before adding more moderation, mood, agency, or public-lane behavior.
|
||||
- Keep public-lane limits, moderation, and provider behavior constrained enough that one 4060 Ti box does not get flayed for sport.
|
||||
- Preserve boring observability and startup discipline around Postgres, Qdrant, Ollama, Docker, backups, scheduled tasks, watchdogs, and any private local fire-signal extensions.
|
||||
|
|
@ -136,6 +136,8 @@ landed_baseline:
|
|||
- Memory maintenance now has a typed runner boundary: `scripts/run-void-memory-maintenance.ps1` builds prompt-facing typed context, loads `prompts/void-memory-maintenance.md`, rejects non-maintenance operations, and applies allowed memory/incubation/candidate proposals through `scripts/void-self-state.mjs`.
|
||||
- Sleep is the forcing function for memory distillation. `scripts/simulate-void-mood.mjs` invokes typed memory maintenance once per nap, and a real sleep pass with memory pressure must return at least one operation instead of letting yesterday's rumination residue linger.
|
||||
- Rumination writes short-term memory only through `record_short_term_memory`. Durable memory is sleep-owned: short-term residue must be promoted with `apply_memory_distillation`, merged into incubation and pruned, or pruned outright before sleep completes.
|
||||
- The sleep-maintenance path has a model-branch fixture: `npm run moderation:memory-maintenance:sleep-fixture` seeds a temporary `.cc`, forces mood drift into sleep maintenance, routes the non-skip Codex branch through a fake child, and verifies short-term memory is consumed into one durable meaning-preserving record.
|
||||
- The local `Void Mood Drift` scheduled task is reinstalled/enabled against the typed runner and has completed one manual scheduled-task start with Last Result 0. `Void Moderator Rumination` remains disabled pending its own model-branch fixture.
|
||||
- Memory cleanup now has to be meaningfully destructive. Sleep-side consolidation should translate old thought fossils into the live claim/question/fascination surface, drop templated slogan-slop, trim repo/archive/runtime residue down to a small recent evidence surface, and keep the freshest surviving records instead of accidentally embalming the oldest ones after a sort.
|
||||
- Durably weird semantic kinds are guilty until proven useful. `recent-preoccupation`, `quiet-room-status`, person-singleton labels, and `live seam` boilerplate are state poison, not doctrine; typed memory ingress should reject or avoid them instead of relying on cleanup to mop later.
|
||||
|
||||
|
|
@ -154,5 +156,5 @@ rejected_paths:
|
|||
reason: sleep/distillation that collapses concrete claims into generic abstraction creates memory nonsense and then forces later cleanup compensators
|
||||
|
||||
current_status:
|
||||
summary: VoidBot's ordinary bot/worker/provider/RAG/Postgres/Qdrant structure is still conceptually sound, and the private self-state path has been cut to a typed CultCache `.cc` store at `.voidbot/private/void-self-state.cc`. The active typed service no longer loads or mirrors the legacy moderation monolith. The old memory-organ compensator stack has been deleted. Typed rumination and typed memory maintenance now exist as reviewed prompt runners that return operation payloads for the parent to validate/apply.
|
||||
next_action: Exercise the sleep-invoked typed memory-maintenance runner with model-pass fixtures before re-enabling scheduled mood drift: prove a concrete memory such as `AquariumSynthCSharp: Workflow cannot own the body` survives distillation with subject, claim/question, evidence, tension, and action implication intact.
|
||||
summary: VoidBot's ordinary bot/worker/provider/RAG/Postgres/Qdrant structure is still conceptually sound, and the private self-state path has been cut to a typed CultCache `.cc` store at `.voidbot/private/void-self-state.cc`. The active typed service no longer loads or mirrors the legacy moderation monolith. The old memory-organ compensator stack has been deleted. Typed rumination and typed memory maintenance now exist as reviewed prompt runners that return operation payloads for the parent to validate/apply. The sleep-maintenance model branch has a fixture smoke that proves short-term memory is consumed into durable meaning-preserving memory, and typed mood drift is reinstalled as a scheduled task.
|
||||
next_action: Build a model-branch fixture for typed moderation rumination before re-enabling its scheduled task, then rebuild agency through typed operations instead of legacy compensators.
|
||||
|
|
|
|||
Loading…
Reference in a new issue