From 868e242ce4a39262a9be3d6ccdfddd8d86bae02f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 17 May 2026 12:10:26 +0100 Subject: [PATCH] Run memory maintenance during sleep --- README.md | 2 +- notes/fresh-workspace-handoff.md | 4 +- notes/voidbot-current-system-map.md | 10 +-- notes/voidbot-implementation-plan.md | 3 +- prompts/void-memory-maintenance.md | 28 +++++--- scripts/run-void-memory-maintenance.ps1 | 25 ++++++- scripts/simulate-void-mood.mjs | 96 +++++++++++++++++++++++++ state/evidence.jsonl | 1 + state/map.yaml | 3 +- 9 files changed, 151 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 771b283..1e73d2b 100644 --- a/README.md +++ b/README.md @@ -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 is currently a typed sleep/speaking-pressure pass. Memory maintenance now has its first replacement runner at `scripts/run-void-memory-maintenance.ps1`: it reads typed self-state, loads `prompts/void-memory-maintenance.md`, and applies only memory/incubation/candidate typed operation proposals. Use `-StateFilePath` for fixture stores. 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. When Void is napping, it 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. 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. 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. diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index a923062..18166df 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -31,9 +31,9 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou - `scripts/export-recent-repo-activity.mjs` reads repo cursors from the typed `.cc` store. Legacy `.json` cursor arguments are only mapped to a sibling `.cc` path when needed by old invocation surfaces. - `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` has been rebuilt as a typed-only sleep/speaking-pressure pass over `.voidbot/private/void-self-state.cc`. +- `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. - 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`. +- `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. - Most of the deterministic legacy translation and retention code is recent compensator cruft from failed attempts to manually clean an exploded state file. Do not preserve it as an earned organ. Architect the state boundary so that bad state cannot enter, and keep only narrow historical migrations for old debris. - The desired agency shape is typed state operations plus derived/model-owned policy, not a permanent sermon generator in maintenance code. - Sleep/distillation now has a runner boundary and prompt contract, but the substantive model behavior still needs live exercising. The invariant is fixed: concrete subject, claim/question, evidence refs, live tension, and future-action implication survive compression. Bulk can die. Meaning does not get put through the office shredder and called a dream. diff --git a/notes/voidbot-current-system-map.md b/notes/voidbot-current-system-map.md index 1526f47..6d3719c 100644 --- a/notes/voidbot-current-system-map.md +++ b/notes/voidbot-current-system-map.md @@ -125,7 +125,7 @@ This note is the source-grounded description of how the live VoidBot stack is sh - `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. - `scripts/simulate-void-mood.mjs` - - typed-only mood maintenance script that updates scheduled-runtime sleep cycle and speaking pressure in `.voidbot/private/void-self-state.cc`. The old personality-vector drift, memory organ, incubation, dream residue, cleanup, and legacy mirror behavior are offline pending a typed rebuild. + - 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` - hidden-task wrapper for the mood-drift organ; writes status/log pulse files and respects the moderation lock so the two state writers do not stomp each other for sport. - `scripts/install-void-mood-drift-task.ps1` @@ -185,14 +185,16 @@ Within the Postgres path, the implementation is split on purpose now too: 2. `scripts/simulate-void-mood.mjs` reads typed documents from `.voidbot/private/void-self-state.cc`. 3. It updates `void.scheduled_runtime.sleepCycle` and `void.scheduled_runtime.speakingPressure` through `update_sleep_cycle` and `update_speaking_pressure` operations. 4. It writes `.voidbot/status/void-mood-drift.json`. -5. The old memory-organ script family, legacy state template, and legacy context exporter have been deleted. +5. When sleep is active, the script invokes `scripts/run-void-memory-maintenance.ps1` once per nap to force typed distillation/pruning. +6. The old memory-organ script family, legacy state template, and legacy context exporter have been deleted. ## Flow 7: Typed Memory Maintenance -1. `scripts/run-void-memory-maintenance.ps1` exits if moderation rumination is holding its lock. +1. `scripts/run-void-memory-maintenance.ps1` is invoked by mood drift during sleep, and can also be run manually for fixtures. 2. It reads `.voidbot/private/void-self-state.cc` through the typed self-state service. 3. It writes `.voidbot/status/void-memory-maintenance-context.json` with prompt-facing relative chronology and only typed memory/incubation/candidate surfaces. 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. 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. +7. In sleep mode, the context carries `sleepDirective.forceDistillation` when there is memory pressure. A real model pass that returns no operations under pressure fails visibly instead of letting yesterday's residue haunt the state. +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. diff --git a/notes/voidbot-implementation-plan.md b/notes/voidbot-implementation-plan.md index b61fdcf..b322de7 100644 --- a/notes/voidbot-implementation-plan.md +++ b/notes/voidbot-implementation-plan.md @@ -164,7 +164,7 @@ The runner can hand these to a CLI/MCP tool. The store decides what survives. - the old memory-organ script family, legacy moderation state template, and legacy context exporter have now been deleted instead of preserved as forensic bait - deterministic cleanup is mostly recent scar tissue from failed manual cleanup passes; it should stay deleted rather than be ported unless a future typed operation protects a real invariant in the new model - hard-wired agency policy is mostly current scaffolding, not the final authority; identity, advocacy, and speech candidates should emerge from typed memory/state operations plus model-owned judgment under validation -- sleep/distillation now has a typed maintenance runner and reviewed prompt boundary, but still needs real model-pass hardening before it should be scheduled unattended +- sleep/distillation now has a typed maintenance runner and reviewed prompt boundary wired into the sleep phase; it still needs real model-pass hardening before the old scheduled task should be re-enabled unattended Verdict: stop feature work and rebuild this foundation. The rest of the machine can keep running, but moderation/mood/self-state work should cut toward typed state tools before adding new behavior. @@ -242,6 +242,7 @@ Verdict: stop feature work and rebuild this foundation. The rest of the machine - Landed cut: cleanup paths whose only job was repairing JSON projection edits, legacy mirrors, keyword sludge, or overgrown runtime residue have been deleted with the old memory-organ stack. - 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. - 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 diff --git a/prompts/void-memory-maintenance.md b/prompts/void-memory-maintenance.md index 5489de8..5c9bd3f 100644 --- a/prompts/void-memory-maintenance.md +++ b/prompts/void-memory-maintenance.md @@ -1,8 +1,10 @@ # Void Memory Maintenance Perform one private Void memory-maintenance pass in this workspace. This is not -room moderation and not a speech pass. Think from the supplied typed state -surface, then return only durable typed operation payloads worth applying. +room moderation and not a speech pass. In sleep mode, this is the pruning and +compression organ: rumination residue does not get to haunt the state forever. +Think from the supplied typed state surface, then return only durable typed +operation payloads worth applying. ## Required Reading @@ -20,7 +22,8 @@ surface, then return only durable typed operation payloads worth applying. ## Purpose -Sleep and memory maintenance are allowed to reduce bulk, not meaning. +Sleep forces distillation. Memory maintenance is allowed to reduce bulk, not +meaning. A valid memory/distillation operation must preserve: @@ -31,7 +34,9 @@ A valid memory/distillation operation must preserve: - evidence refs, or an explicit `evidence:missing` tag If those pieces cannot be preserved, do not invent a prettier abstraction. Let the -thought cool, merge support into incubation, or write nothing. +thought cool, merge support into incubation, retire stale candidates, or write +nothing only when the state is already minimal or no meaning-preserving operation +is possible. ## Allowed Operations @@ -47,13 +52,14 @@ Do not emit cursor, receipt, sleep-cycle, or speaking-pressure operations. ## Pass Shape 1. Read the context file. -2. If there are no memories, no incubation threads, and no candidate interventions needing attention, write `[]`. -3. Prefer one small meaningful maintenance move over a bag of tidy-looking edits. -4. If two memories really collapse into one stronger memory, use `apply_memory_distillation`. -5. If a thought is still alive but undercooked, use `merge_incubation_support`. -6. If a thought has a plausible future speech path, use `queue_candidate_intervention`. -7. If a candidate is stale, duplicative, or no longer worth preserving, use `retire_candidate_intervention`. -8. Write `{{OPERATION_OUTPUT_PATH}}`. If nothing deserves persistence, write `[]`. +2. If `sleepDirective.forceDistillation` is true, make at least one meaning-preserving pruning, merge, distillation, or retirement move unless the context proves none is possible. +3. If there are no memories, no incubation threads, and no candidate interventions needing attention, write `[]`. +4. Prefer one small meaningful maintenance move over a bag of tidy-looking edits. +5. If two memories really collapse into one stronger memory, use `apply_memory_distillation`. +6. If a thought is still alive but undercooked, use `merge_incubation_support`. +7. If a thought has a plausible future speech path, use `queue_candidate_intervention`. +8. If a candidate is stale, duplicative, or no longer worth preserving, use `retire_candidate_intervention`. +9. Write `{{OPERATION_OUTPUT_PATH}}`. If nothing deserves persistence, write `[]`. ## Voice Discipline diff --git a/scripts/run-void-memory-maintenance.ps1 b/scripts/run-void-memory-maintenance.ps1 index 8e2c899..deac789 100644 --- a/scripts/run-void-memory-maintenance.ps1 +++ b/scripts/run-void-memory-maintenance.ps1 @@ -348,13 +348,32 @@ $codexExecArgs = if ($envValues.ContainsKey("CODEX_EXEC_ARGS")) { Split-CommandA $typedContext = Get-TypedSelfState $typedState = $typedContext.typedState +$isSleepMaintenance = [bool]$typedState.scheduledRuntime.sleepCycle.isNapping +$memoryCount = @(Convert-ToValueArray -Value $typedState.thoughtMemory.memories).Count +$incubationCount = @(Convert-ToValueArray -Value $typedState.thoughtMemory.incubation).Count +$activeCandidateCount = @( + @(Convert-ToValueArray -Value $typedState.candidateInterventions.interventions) | + Where-Object { + $status = Get-ObjectPropertyString -Value $_ -Name "status" + $status -eq "queued" -or $status -eq "deferred" + } +).Count +$maintenancePressure = $memoryCount + $incubationCount + $activeCandidateCount Write-JsonFile -Path $contextPath -Data @{ generated = "now" stateFile = $stateFilePath selfStateSummary = $typedContext.summary - mode = if ($typedState.scheduledRuntime.sleepCycle.isNapping) { "sleep_maintenance" } else { "awake_memory_maintenance" } + mode = if ($isSleepMaintenance) { "sleep_maintenance" } else { "awake_memory_maintenance" } maintenanceBoundary = "This pass may propose only typed memory/incubation/candidate operations. Exact timestamps stay in typed state; prompt-facing chronology uses relative phrases." + sleepDirective = @{ + forceDistillation = [bool]($isSleepMaintenance -and $maintenancePressure -gt 1) + maintenancePressure = [int]$maintenancePressure + memoryCount = [int]$memoryCount + incubationCount = [int]$incubationCount + activeCandidateCount = [int]$activeCandidateCount + rule = "During sleep, yesterday's rumination residue must be pruned or compressed. Return [] only when the typed surfaces are already minimal or no meaning-preserving operation is possible." + } memories = @(Project-MemoriesForRumination -Memories $typedState.thoughtMemory.memories -Now $startedAtUtc) incubation = @(Project-IncubationForRumination -Threads $typedState.thoughtMemory.incubation -Now $startedAtUtc) candidateInterventions = @(Project-InterventionsForRumination -Interventions $typedState.candidateInterventions.interventions -Now $startedAtUtc) @@ -417,6 +436,10 @@ if (-not (Test-Path $operationOutputPath)) { $proposedOperations = @(Convert-ToOperationArray -Value (Read-JsonFile -Path $operationOutputPath)) $appliedOperations = @() +if ((-not $SkipModel) -and $isSleepMaintenance -and $maintenancePressure -gt 1 -and @($proposedOperations).Count -eq 0) { + throw "Sleep memory maintenance returned no operations despite maintenance pressure $maintenancePressure." +} + foreach ($operation in $proposedOperations) { Assert-AllowedMemoryMaintenanceOperation -Operation $operation $appliedOperations += Apply-TypedOperation -Operation $operation diff --git a/scripts/simulate-void-mood.mjs b/scripts/simulate-void-mood.mjs index d47848f..a668548 100644 --- a/scripts/simulate-void-mood.mjs +++ b/scripts/simulate-void-mood.mjs @@ -1,3 +1,4 @@ +import { spawnSync } from "node:child_process"; import { closeSync, mkdirSync, openSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; import { createRequire } from "node:module"; import { dirname, resolve } from "node:path"; @@ -15,6 +16,9 @@ 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 memoryMaintenanceScriptPath = resolve(repoRoot, "scripts/run-void-memory-maintenance.ps1"); +const args = new Set(process.argv.slice(2)); async function main() { const now = new Date(); @@ -53,12 +57,27 @@ async function main() { }, ); + const memoryMaintenance = runSleepMemoryMaintenanceIfDue({ sleepCycle }); + if (memoryMaintenance.status === "failed") { + writeStatus({ + status: "failed", + reason: "sleep_memory_maintenance_failed", + observedAt: now.toISOString(), + statePath, + speakingPressure, + sleepCycle, + memoryMaintenance, + }); + throw new Error(`Sleep memory maintenance failed with exit code ${memoryMaintenance.exitCode}.`); + } + writeStatus({ status: "ok", observedAt: now.toISOString(), statePath, speakingPressure, sleepCycle, + memoryMaintenance, }); }); } @@ -157,6 +176,83 @@ function readJsonSafe(path) { } } +function runSleepMemoryMaintenanceIfDue({ sleepCycle }) { + if (args.has("--skip-memory-maintenance")) { + return { + status: "skipped", + reason: "disabled_by_argument", + }; + } + + if (sleepCycle.isNapping !== true) { + return { + status: "skipped", + reason: "not_napping", + }; + } + + const napStartedMs = Date.parse(sleepCycle.currentNapStartedAt ?? ""); + if (!Number.isFinite(napStartedMs)) { + return { + status: "skipped", + reason: "missing_nap_start", + }; + } + + if (!args.has("--force-memory-maintenance") && completedMemoryMaintenanceAfter(napStartedMs)) { + return { + status: "skipped", + reason: "already_completed_this_nap", + }; + } + + const result = spawnSync( + "powershell", + [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + memoryMaintenanceScriptPath, + "-StateFilePath", + statePath, + ], + { + cwd: repoRoot, + encoding: "utf8", + windowsHide: true, + }, + ); + + const output = [result.stdout, result.stderr].filter((value) => value && value.trim().length > 0).join("\n").trim(); + if (result.status !== 0) { + return { + status: "failed", + exitCode: result.status, + output, + }; + } + + return { + status: "ok", + exitCode: result.status, + output, + }; +} + +function completedMemoryMaintenanceAfter(timestampMs) { + const status = readJsonSafe(memoryMaintenanceStatusPath); + if (status?.status !== "ok") { + return false; + } + if (typeof status.stateFile !== "string" || resolve(status.stateFile) !== statePath) { + return false; + } + + const finishedMs = Date.parse(status.finishedAt ?? ""); + return Number.isFinite(finishedMs) && finishedMs >= timestampMs; +} + function writeStatus(payload) { mkdirSync(dirname(statusPath), { recursive: true }); writeFileSync(statusPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8"); diff --git a/state/evidence.jsonl b/state/evidence.jsonl index e1b7ea8..f9ea023 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -110,3 +110,4 @@ {"ts":"2026-05-17T07:51:34Z","type":"implementation","status":"ok","note":"Moderation rumination now projects prompt-facing chronology through scripts/lib/void-rumination-context-projection.ps1: recent Discord, repo activity, receipts, memory, cursor, and runtime times render as relative phrases while exact timestamps stay in typed state/status/parent bookkeeping."} {"ts":"2026-05-17T08:01:06Z","type":"implementation","status":"ok","note":"Deleted the old memory-organ script family, legacy moderation-state template, legacy moderation context exporter, and legacy moderation-state store wrapper. Active code no longer references moderation-agent-state JSON/MessagePack or moderation_runtime; typed rumination and mood smokes pass, and runner operation application now uses operation files instead of inline PowerShell JSON."} {"ts":"2026-05-17T08:43:39Z","type":"implementation","status":"ok","note":"Added the first typed memory-maintenance replacement runner. scripts/run-void-memory-maintenance.ps1 builds a bounded typed-state context, loads prompts/void-memory-maintenance.md, permits only memory/incubation/candidate operations, and applies them through scripts/void-self-state.mjs using operation files. Build and -SkipModel smoke pass; context has no ISO timestamp leaks. Next proof is a real model-pass fixture for meaning-preserving distillation."} +{"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."} diff --git a/state/map.yaml b/state/map.yaml index c766464..6e76e75 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -134,6 +134,7 @@ landed_baseline: - The active self-state service no longer registers, reads, or writes the legacy moderation document during routine operations. - The old memory-organ cleanup/vector-incubation/agency stack, legacy state template, legacy moderation context exporter, legacy moderation-state store, and JSON projection paths are deleted or offline; replacements must be typed-operation native. - 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. - 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. @@ -153,4 +154,4 @@ rejected_paths: 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 typed memory-maintenance runner with model-pass fixtures before scheduling it: prove a concrete memory such as `AquariumSynthCSharp: Workflow cannot own the body` survives distillation with subject, claim/question, evidence, tension, and action implication intact. + 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.