Require speech accountability for agency pressure

This commit is contained in:
Meta Vens 2026-05-17 19:22:52 +01:00
commit 0851e41cb3
10 changed files with 383 additions and 6 deletions

View file

@ -44,6 +44,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
- Short-term rumination memory is clustered at the typed service boundary now. When a new `record_short_term_memory` operation repeats the same target/topic pressure, the service keeps one provisional memory, merges anchors/tags, preserves a stable source id for sleep, and updates the thought instead of stacking duplicates. This is meant to protect deepening, not suppress it: low-saturation or newly anchored thoughts should keep developing inside the cluster until they stop changing. `npm run moderation:short-term-clustering:fixture` proves the guard.
- 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` for high-intensity active self/world advocacy pressures with no matching candidate. A pass may queue/defer a candidate or cool/retire the pressure, but silent `[]` fails visibly. `npm run moderation:rumination:speech-pressure-fixture` covers the guard.
- 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.
@ -101,7 +102,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
## Likely Next Bounded Move
- First bounded move after the current commit: let the enabled loop run under ordinary scheduling after the short-term clustering guard, then inspect the next unattended awake rumination and sleep cycle for repeated thought clusters, stale short-term residue, or ungrounded memory writes before calling the system broadly stable.
- First bounded move after the current commit: let the enabled loop run under ordinary scheduling after the short-term clustering and speech-pressure guards, then inspect the next unattended awake rumination and sleep cycle for repeated thought clusters, stale short-term residue, muted advocacy pressure, or ungrounded memory writes before calling the system broadly stable.
- The immediate duplicate-rumination follow-up is to inspect the next ordinary rumination after the clustering guard and confirm repeated AquaSynth/Aquarium pressure folds into the existing cluster or redirects to underworked terrain instead of producing another short-term variant.
- Next cuts should delete unstable foundations early: do not revive `legacyJsonPath`, working projections, top-level mirror fields, or cleanup code that only compensated for those broken boundaries.
- Keep sleep/distillation under watch. Fixture check: a memory like `AquariumSynthCSharp: Workflow cannot own the body` must survive sleep with its concrete subject, claim, anchor, tension, and implication intact.

View file

@ -201,6 +201,7 @@ Within the Postgres path, the implementation is split on purpose now too:
7. If posting is enabled and the child queued a candidate intervention with a delivery target, the parent runner sends at most one newly proposed candidate, records the delivery receipt, and marks the candidate spoken through typed state. The child prompt forbids direct send-script calls.
8. The runner writes `.voidbot/status/moderation-rumination.json` and `.voidbot/logs/moderation-rumination.log`.
9. It intentionally does not materialize `.json`, load `.msgpack`, read the legacy moderation monolith, or let the child edit state directly.
10. Before applying model output, the runner enforces speech-pressure accountability. High-intensity active self/world advocacy pressures with no matching queued/deferred candidate are projected as `speechPressureObligations`; model output must queue/defer a candidate or cool/retire the pressure instead of returning silent `[]`.
## Flow 6: Mood And Sleep Runtime
@ -236,3 +237,4 @@ Within the Postgres path, the implementation is split on purpose now too:
2. The typed service validates that each pressure has a concrete target, claim or question, action implication, intensity, and either anchors/source memory ids or an explicit `anchor:missing` tag.
3. The self-state summary renders active agency pressure separately from queued speech candidates.
4. Mood drift reads active and ready agency pressure into speaking pressure, but it does not manufacture speech text from it.
5. The rumination runner bridges desire-to-speak without manufacturing text: strong advocacy pressure becomes an obligation for the model to queue/defer a candidate or explicitly cool/retire the pressure. The parent rejects silent output for those obligations.

View file

@ -60,6 +60,7 @@ CultCache does not need a separate physical store per state type; it is already
- read stable self profile
- update scheduled runtime pressure/sleep fields
- request memory maintenance through typed operations
- expose desire-to-speak as pressure, while rumination owns the model-written candidate text
Runtime context dies at the end of the pass unless an explicit typed mutation preserves a durable fact.
@ -283,6 +284,7 @@ Verdict: the foundation is coherent enough for cautious live operation. Do not a
- Make distillation emit typed candidate memories first; the state service applies only candidates that satisfy the contract.
- Landed agency ingress: `upsert_agency_pressure` / `retire_agency_pressure` store discomforts, active tensions, self-advocacy requests, and world-advocacy requests separately from candidate speech.
- Landed agency verification: `npm run moderation:agency-pressure:fixture` proves agency pressure enters typed state, appears in the self-state summary, and contributes to mood speaking pressure.
- Landed agency-to-speech accountability: strong active self/world advocacy pressure now appears as `speechPressureObligations` in rumination context. The parent runner rejects silent `[]` unless the model queues/defers a candidate intervention or cools/retires the pressure. `npm run moderation:rumination:speech-pressure-fixture` proves both the muzzle-failure path and the deferred-candidate path.
- Landed rumination verification: `npm run moderation:rumination:fixture` routes the non-skip rumination branch through a fake Codex child and proves short-term memory, incubation, agency-pressure, and candidate-intervention proposals cross the parent-applied typed operation boundary without timestamp leakage.
- Landed controlled live rumination review: the first real-model `-NoPost` pass produced valid but self-orbiting readiness-test residue, which was pruned/retired and folded into a prompt guard; the second real-model `-NoPost` pass sampled non-VoidBot repo pressure, used retrieval, and correctly wrote `[]` when nothing earned persistence.
- Landed parent-owned speech closure: candidate interventions can include `deliveryTarget`, the prompt forbids child-side send scripts, the parent runner delivers at most one newly queued deliverable candidate per pass, records the receipt, and marks the candidate spoken with `mark_candidate_intervention_spoken`. `npm run moderation:rumination:speech-fixture` proves the loop with fake Codex and fake Discord send helpers.