Skip to content

Moral Tension

Robert Malczyk edited this page Jun 25, 2026 · 1 revision

Moral Tension (M-J)

An opt-in overlay that gives an NPC a conscience: guilt, secrets, lies, accusation, suspicion, and betrayal — all as the same kind of coupled-integrator dynamics as the rest of the engine, plus a small bookkeeping ledger of what is hidden and what was lied about.

It is strictly opt-in. With no moral config, a persona is byte-identical to a non-moral build, and the whole base believability corpus renders identically across the merge. You turn it on by adding a moral overlay (calibration/moral_overlay.yaml) and moral traits/secrets to a persona.

What it models

  • Guilt core — a wrong raises guilt; confessing relieves it, staying silent lets it sit. A litmus confessremain_silent decision emerges from the state, not a rule.
  • Lie loop — lying or deflecting buys short-term relief but accrues cognitive_load_from_lies (a self-limiting noose): the more you lie, the heavier it gets.
  • Repair & ruminationapologize (empathic repair) and a rumination replay loop.
  • Secrets & exposure — a MoralLedger of Secrets (each with a moral_weight) and LieRecords. An active secret drips salience/stress; being caught spikes exposure anxiety and guilt.
  • Accusation & suspicion — being falsely accused raises a grievance (perceived_injustice) and routes to blame_other / avoid; being watched with suspicion (innocent) raises a suspicion relation dimension toward the watcher.
  • Witness fan-out — built on Architecture (multi-event per tick): one event can be perceived by several NPCs at once.

Minor vs serious guilt

The engine has one guilt state with one half-life, but a serious wrong should weigh longer than a minor one. Rather than a second state, an active secret re-injects guilt proportional to its authored moral_weight × salience. So a serious unconfessed secret keeps guilt alive against decay (it lingers), a minor one barely does (it fades), and confession/exposure inactivates the secret → the drip stops → relief. Judge-validated timescales: minor ≈ 18h, serious ≈ 72h.

How it is tested

There is no PASS/FAIL rate for the moral layer — unlike the base corpus, moral behaviour is judged on a fuzzy 1–5 quality scale (believability + curve_plausibility). Testing is three blind-judge surfaces on top of a deterministic pre-filter (no LLM until the hard gates pass):

  • Deterministic pre-filter — Jury + litmus gates over an 81-point magnitude grid (18/81 survive).
  • Litmus judge — 12 single-situation vignettes: 4.83/5 after calibration.
  • Gate-C corpus — 126 observable vignettes (7 personas × situations): weak situations lifted to 4.0/4.0, full sweep mean 3.93.
  • Multi-day judge — half-life persistence; serious-guilt 72h scored 5/5, suspicion set to 24h.

All blind judging is paced (single agents over time, never one large parallel burst).

Read the report

  • eval/MORAL_REPORT.md — the full moral test report (HTML twin: eval/MORAL_REPORT.html).
  • Plan + spec: docs/moral_tension_PLAN.md, docs/moral_tension_impl_spec.md, docs/moral_calibration_plan.md; block diagram: docs/diagrams/moral_tension.md.

Clone this wiki locally