diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 7769ffe..6cb0bcd 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -47,6 +47,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou - Strong advocacy pressure now has to account for its own mouth. The rumination runner derives `speechPressureObligations` once active self/world advocacy reaches 0.55 intensity, and only a live queued candidate counts as release for that obligation. A pass may queue/defer a candidate or cool/retire the pressure, but silent `[]` fails visibly and an older spoken candidate does not buy permanent absolution. `npm run moderation:rumination:speech-pressure-fixture` covers the silent, spoken-history, and queued-candidate paths. - Deferred candidates are not delivered speech and no longer satisfy active advocacy pressure by themselves. The runner now delivers existing queued candidates with delivery targets, not only candidates proposed by the current model pass. The first live repair used Metacrat's explicit channel permission to move the stranded AquariumSynthHost candidate from deferred/no-target to queued/channel-target, then delivered it through the normal bot transport and recorded a typed speech receipt. - Parent-owned delivery now also checks canonical typed speech receipts before using the mouth. If a queued candidate targets a Discord reply that already has a receipt, the runner retires it instead of answering the same message twice in slightly different prose. Typed state writes also normalize historical receipts to keep the earliest canonical reply per `channelId + replyToMessageId`. `scripts/smoke-void-rumination-speech-fixture.ps1` now seeds a prior receipt and proves both same-pass sibling retirement and already-answered target retirement. +- Speaking pressure is allowed to refresh while moderation is active. `scripts/simulate-void-mood.mjs` still skips sleep-cycle mutation and memory maintenance under a recent moderation lock, but it now reloads typed state and applies `update_speaking_pressure` first, so fresh canonical speech receipts update `lastSpokeAt`, damping, and `needToSpeak` even during long rumination runs. - 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, prompt contract, fixture coverage, and one live-state pass. The invariant is fixed: concrete subject, claim/question, anchors, 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/scripts/run-void-moderator-rumination.ps1 b/scripts/run-void-moderator-rumination.ps1 index c981b5f..9e64c2e 100644 --- a/scripts/run-void-moderator-rumination.ps1 +++ b/scripts/run-void-moderator-rumination.ps1 @@ -995,6 +995,12 @@ if ($SkipModel) { $combinedText = (($execution.StdOut, $execution.StdErr) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) -join [Environment]::NewLine } +if ([string]::IsNullOrWhiteSpace($combinedText)) { + [System.IO.File]::WriteAllText($tracePath, "Codex rumination produced no stdout/stderr trace." + [Environment]::NewLine, [System.Text.UTF8Encoding]::new($false)) +} else { + [System.IO.File]::WriteAllText($tracePath, $combinedText + [Environment]::NewLine, [System.Text.UTF8Encoding]::new($false)) +} + if ($exitCode -ne 0) { $failureMessage = if ([string]::IsNullOrWhiteSpace($combinedText)) { "Codex rumination failed with exit code $exitCode." } else { $combinedText } throw $failureMessage diff --git a/scripts/simulate-void-mood.mjs b/scripts/simulate-void-mood.mjs index 2be2c97..453a038 100644 --- a/scripts/simulate-void-mood.mjs +++ b/scripts/simulate-void-mood.mjs @@ -26,16 +26,33 @@ async function main() { const now = new Date(); await withLock(async () => { + const typedState = await loadVoidSelfStateTypedDocuments({ canonicalPath: statePath }); + if (isRecentLockPresent(moderationLockPath, 20 * 60 * 1000)) { + const speakingPressure = updateSpeakingPressure({ + typedState, + previous: typedState.scheduledRuntime.speakingPressure, + sleepCycle: typedState.scheduledRuntime.sleepCycle, + now, + }); + await applyVoidSelfStateOperation( + { canonicalPath: statePath }, + { + operation: "update_speaking_pressure", + speakingPressure, + }, + ); writeStatus({ status: "skipped", reason: "moderation_loop_active", observedAt: now.toISOString(), + statePath, + speakingPressure, + sleepCycle: typedState.scheduledRuntime.sleepCycle, }); return; } - const typedState = await loadVoidSelfStateTypedDocuments({ canonicalPath: statePath }); const sleepCycle = updateSleepCycle(typedState.scheduledRuntime.sleepCycle, now); const speakingPressure = updateSpeakingPressure({ typedState, diff --git a/state/evidence.jsonl b/state/evidence.jsonl index b679330..0bce11a 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -160,3 +160,4 @@ {"ts":"2026-05-19T07:04:25Z","type":"implementation","status":"ok","note":"Repo Face CTB now requires a real Void moderation launch handshake before marking Void queued. Direct spawn failures are recorded as turn_failed_to_start instead of fake completed turns; PowerShell Start-Process launch reached the moderation lock and current Void runner is active."} {"ts":"2026-05-19T07:13:47Z","type":"implementation","status":"ok","note":"Repo Face heartbeat prompt now carries a jurisdiction-dive cadence; Nibu gets a hotter AetheriaLore-specific pressure to inspect lore/history and turn source-grounded dystopia/ship-mind/reset-loop findings into state, proposals, essay seeds, agency pressure, or speech instead of private summaries."} {"ts":"2026-05-19T10:52:57Z","type":"implementation","status":"ok","note":"Repo Face mentions now queue into the CTB heartbeat state instead of creating direct repo-identity jobs: role/display-name-addressed prompts become pendingMentions, the scheduler prioritizes the addressed Face and attaches reply targets to the next repo-face-rumination job. Void's rumination doctrine now names GameCult website/blog herald jurisdiction and queues article-proposal candidates for essay-shaped pressures."} +{"ts":"2026-05-19T11:14:00Z","type":"implementation","status":"ok","note":"Mood drift now refreshes scheduledRuntime.speakingPressure from canonical speech receipts even when a moderation lock makes it skip deeper sleep/mood work; live state was repaired to lastSpokeAt=2026-05-19T10:47:05.937Z with recentSpeechDamping=0.888. The moderation runner now overwrites the advertised tracePath with current Codex stdout/stderr so stale legacy JSON-projection traces stop misleading inspection."} diff --git a/state/map.yaml b/state/map.yaml index b00dce5..7d05991 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -169,6 +169,7 @@ landed_baseline: - The agency-to-speech seam now has an accountability gate. `scripts/run-void-moderator-rumination.ps1` projects `speechPressureObligations` once active self/world advocacy reaches 0.55 intensity, rejects silent operation output unless those pressures become live queued candidate interventions or are explicitly cooled/retired, and does not treat old spoken candidates as ongoing satisfaction. `npm run moderation:rumination:speech-pressure-fixture` proves the silent-failure path, the spoken-history failure path, and the queued-candidate path. - Deferred candidate interventions are not speech. A pressure is not resolved until it becomes a queued/spoken candidate or is explicitly cooled/retired, and the rumination runner now delivers already-queued candidates with delivery targets instead of only delivering candidates proposed in the current pass. - Parent-owned candidate delivery must trust canonical speech receipts more than fresh enthusiasm. If a queued candidate points at a Discord reply target that already has a typed receipt, the runner should retire it before delivery instead of answering the same message twice with a slightly different haircut. Typed state writes also normalize receipts to keep only the earliest canonical receipt per `channelId + replyToMessageId`. + - Speaking-pressure freshness must not depend on a full mood-drift window. Mood drift now refreshes `scheduledRuntime.speakingPressure` from canonical speech receipts even when it skips deeper sleep/mood work because the moderation lock is active, so long moderation runs cannot leave `lastSpokeAt` stale against delivered speech. - `npm run moderation:agency-pressure:fixture` verifies typed agency pressure enters CultCache, renders in the self-state summary, and contributes to mood speaking pressure without reviving hard-wired agency behavior. - 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 anchor 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.