Split moderation heartbeat from Void rumination

This commit is contained in:
Meta Vens 2026-06-08 23:34:35 +01:00
commit a055cc286e
12 changed files with 843 additions and 75 deletions

View file

@ -17,7 +17,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
## Current Shape
- Discord bot and worker are live.
- The unattended repo Face / CTB swarm is live again as of 2026-05-21 after the teardown/restart pass. `GameCult Local Orchestrator` is enabled and owns the single hidden pulse for repo Face CTB turns, Void mood drift, Void moderation rumination, and the watchdog. Bifrost dispatch is present but disabled by default behind `BIFROST_DISPATCH_ENABLED=false`.
- The unattended repo Face / CTB swarm is live again as of 2026-05-21 after the teardown/restart pass. `GameCult Local Orchestrator` is enabled and owns the single hidden pulse for repo Face CTB turns, Void moderation heartbeat, Void mood drift, Void moderation rumination, and the watchdog. Bifrost dispatch is present but disabled by default behind `BIFROST_DISPATCH_ENABLED=false`.
- The teardown authority remains `notes/agent-swarm-teardown-plan-2026-05-21.md`, but it is now a restart checklist and smell ledger rather than a stop sign. Keep using it when a Face/Bifrost/CTB boundary smells like prompt/parser/transport Jenga.
- The repo-controlled pause flag is `state/agent-swarm-paused.json`. While it is missing or has `"paused": false`, swarm runners may operate. While it has `"paused": true` or is malformed, the Face heartbeat runner skips and the orchestrator skips agent-swarm organs. This is the brake. Do not route around it.
- Postgres owns jobs, audit events, interaction memory, and rate-limit state.
@ -37,7 +37,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
- 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 anchor.
- The live local pulse is now one hidden scheduled task: `GameCult Local Orchestrator`. It invokes repo Face CTB heartbeats, Void mood drift, Void moderation rumination, and the operations watchdog with one lock, one status surface, per-organ logs, and per-organ timeouts. The Bifrost dispatch organ remains wired but is skipped unless `BIFROST_DISPATCH_ENABLED=true`. The old per-organ tasks are disabled and should remain disabled unless testing one organ in isolation.
- The live local pulse is now one hidden scheduled task: `GameCult Local Orchestrator`. It invokes repo Face CTB heartbeats, Void moderation heartbeat, Void mood drift, Void moderation rumination, and the operations watchdog with one lock, one status surface, per-organ logs, and per-organ timeouts. The Bifrost dispatch organ remains wired but is skipped unless `BIFROST_DISPATCH_ENABLED=true`. The old per-organ tasks are disabled and should remain disabled unless testing one organ in isolation.
- `scripts/start-voidbot-stack.ps1` now treats the local Bifrost container stack as a startup dependency. It reads `BIFROST_ROOT` and `BIFROST_HEALTH_URL`, runs `E:\Projects\Bifrost\compose.local.yaml` when the health endpoint is down, and records the result under `runtime-stack.json` as `bifrost`.
- `npm run moderation:rumination:fixture` proves the non-skip typed rumination branch without spending a live model call: it seeds a temporary `.cc`, routes the runner through a fake Codex child, and verifies short-term memory, incubation, agency pressure, and candidate intervention proposals are parent-applied typed operations with no exact timestamp leakage in the prompt-facing context.
- `npm run moderation:rumination:speech-fixture` proves queued speech has a parent-owned action loop: fake Codex queues one candidate with a delivery target, fake Discord send writes a receipt, and the parent runner marks the candidate spoken through typed state. The child prompt now forbids direct send-script calls.
@ -51,8 +51,8 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
- Long-term memory is durable, not immutable. `revise_durable_memory`, `retire_durable_memory`, and `crystallize_memory_into_identity` make memory reconsolidation explicit; `npm run moderation:memory-lifecycle:fixture` proves a short-term thought can promote, revise, retire superseded durable records, and crystallize into an identity memory plus self-profile value.
- Agency has a typed pressure surface now: `upsert_agency_pressure` / `retire_agency_pressure` own discomforts, active tensions, self-advocacy requests, and world-advocacy requests. Candidate interventions are possible speech/actions emerging from pressure, not the pressure itself. `npm run moderation:agency-pressure:fixture` verifies the pressure enters `.cc`, renders in self-state summary, and affects mood speaking pressure.
- 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.
- Severe safety evidence now has the same no-silent-advance wall. The rumination runner projects `urgentModerationWitnesses` from recent Discord history for credible violence, weapon, robbery, stalking, or sexual-boundary evidence, and the parent rejects silent `[]` unless an existing open case or new moderation operation accounts for the witness. `npm run moderation:rumination:urgent-safety-fixture` uses the archived 2026-06-08 Lobo threat sequence to prove the guard.
- Urgent safety handling can now enforce through a parent-owned Discord action path. `VOID_MODERATION_ENFORCEMENT_MODE=log_only` is the non-destructive default, `notify_owner` sends an owner DM, and `timeout` calls `scripts/moderate-discord-user.mjs` to apply a Discord member timeout for the first non-owner urgent witness author after the model/open-case operation passes validation. The child prompt still does not own raw sanction authority.
- Severe safety evidence now has the same no-silent-advance wall. The moderation heartbeat projects `urgentModerationWitnesses` from recent Discord history for credible violence, weapon, robbery, stalking, or sexual-boundary evidence, and the parent rejects silent `[]` unless an existing open case or new moderation operation accounts for the witness. `npm run moderation:rumination:urgent-safety-fixture` still covers the older rumination guard, while `npm run moderation:heartbeat:policy-fixture` proves the heartbeat-only policy path.
- Urgent safety handling can now enforce through a parent-owned Discord action path. `VOID_MODERATION_ENFORCEMENT_MODE=policy` enables instant bans and three-strike bans according to the explicit table in `config/discord-server-rules.md`; the child only opens typed cases with `infringement:<type>` plus one moderation disposition tag. The child prompt still does not own raw sanction authority.
- 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.
@ -74,7 +74,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
- Source repo discovery now reconciles automatically during `npm run stack:start` and through the watchdog path, so new repos under `SOURCE_REPO_ROOT` stop waiting for manual hook folklore before they get indexed.
- Bot-directed prompts now stay in the raw Discord archive but are excluded from default semantic history indexing and lexical fallback, so repeated summons stop teaching the bot its own call-and-response loops.
- Source-grounding hints are advisory now; the owner and local lanes can decide when repo or lore tool use is actually warranted instead of obeying a lexical front-door veto.
- The moderation rumination organ is invoked by `GameCult Local Orchestrator` against `.voidbot/private/void-self-state.cc` without reviving the legacy projection path. The prompt lives in `prompts/void-moderator-rumination.md`; treat that file as a sensitive behavior surface, not incidental script text.
- The moderation heartbeat organ is invoked every orchestrator pulse against `.voidbot/private/void-self-state.cc` with `prompts/void-moderation-heartbeat.md`, which exposes only rules, recent history, urgent witnesses, and infringement history. The moderation rumination organ is still invoked by `GameCult Local Orchestrator` for Void's slower person-shaped participation and possible announcement turns; its prompt lives in `prompts/void-moderator-rumination.md`. Treat both files as sensitive behavior surfaces, not incidental script text.
- The moderation loop now uses the typed context packet from `scripts/run-void-moderator-rumination.ps1`; legacy Ghostlight-shaped JSON runtime fields are not the active memory surface.
- Repo-weather sweeps are now incremental rather than a rolling four-day scrapbook. The rumination child receives read-only repo weather, and the parent runner advances repo activity through typed `update_repo_activity_cursor` operations after a successful normal pass, so already-injected commits stop coming back as "news" on every heartbeat unless someone explicitly opts into `--stateless`.
- Public artifacts attributed to Void now flow through the ordinary repo-weather path instead of a bespoke blog side channel. `repoActivity.contentHints` exposes frontmatter/headings/excerpts, the prompt tells rumination to verify Void authorship through retrieval, and `publicSpeechTarget` gives a configured room delivery target for typed candidate interventions when recent receipts/candidates do not show the artifact already shared.

View file

@ -140,16 +140,20 @@ Verse-facing service contract: `docs/architecture/voidbot-verse-service-contract
- parent-owned speech fixture. It queues one deliverable candidate through fake Codex, routes delivery through a fake Discord sender, then verifies the parent runner writes a delivery receipt and marks the candidate spoken through typed state.
- `scripts/smoke-void-rumination-nap-skip-fixture.ps1`
- nap-skip fixture. It seeds a napping typed state with no room debt, points `CODEX_EXECUTABLE` at a bogus command, then verifies the runner exits with `napping_without_room_debt` and writes no operation proposals before invoking the model.
- `scripts/smoke-void-moderation-heartbeat-policy-fixture.ps1`
- rules-only moderation heartbeat fixture. It routes the heartbeat through a fake Codex child, verifies the prompt excludes rumination/memory/repo surfaces, writes a tagged instant-ban infringement case, and proves parent policy enforcement would call a Discord ban in dry-run mode.
- `scripts/install-moderation-rumination-task.ps1`
- legacy installer for isolating the moderation/participation loop. The live scheduled pulse is now `GameCult Local Orchestrator`; keep this per-organ task disabled unless testing the organ in isolation.
- `scripts/run-gamecult-orchestrator.ps1`
- local pulse owner for agent transport/runtime chores. It runs Bifrost dispatch, repo Face CTB heartbeats, Void mood drift, Void moderation rumination, and the operations watchdog from one hidden scheduled task with one lock, per-organ status/log files, and per-organ timeouts.
- local pulse owner for agent transport/runtime chores. It runs Bifrost dispatch, repo Face CTB heartbeats, Void moderation heartbeat, Void mood drift, Void moderation rumination, and the operations watchdog from one hidden scheduled task with one lock, per-organ status/log files, and per-organ timeouts.
- `scripts/install-gamecult-orchestrator-task.ps1`
- installs scheduled task `GameCult Local Orchestrator` through the hidden PowerShell launcher and can disable the old per-organ tasks: `Bifrost Agent Dispatch`, `VoidBot Repo Face Heartbeats`, `Void Mood Drift`, `Void Moderator Rumination`, and `VoidBot Operations Watchdog`.
- Scheduled organ `Void Mood Drift`
- typed mood/sleep runner invoked by the orchestrator. It calls `scripts/simulate-void-mood.mjs`; when the typed sleep cycle is napping, that path invokes memory maintenance once per nap.
- Scheduled organ `Void Moderation Heartbeat`
- rules-only moderation loop invoked every orchestrator pulse. It uses `prompts/void-moderation-heartbeat.md`, recent Discord history, urgent witnesses, and typed infringement/open-case history; it may emit only `upsert_open_case` or `close_open_case`, then parent enforcement applies the explicit instaban/three-strike policy through `scripts/enforce-discord-moderation-policy.mjs`.
- Scheduled organ `Void Moderator Rumination`
- typed-only moderation/participation runner invoked by the orchestrator; it has model-branch plus parent-owned speech fixtures.
- typed-only participation/announcement runner invoked by the orchestrator or CTB queue; it has model-branch plus parent-owned speech fixtures. It is no longer the every-heartbeat rules authority.
- Live sleep maintenance
- passed once on real state after a manual typed nap. The maintenance runner consumed the scheduled rumination short-term memory with one `apply_memory_distillation` operation, leaving short-term memory empty and preserving one durable identity seam with target, claim, tension, action implication, and anchors.
- Sleep brake