docs(diagnostics): R29 PAD mood-dynamics probe — 3-baseline series + step-response + findings

Live re-run of the PAD-dynamics probe for brokkr-smithy R29 (the original
per-turn series was never persisted). Captures, durably:

- 3-baseline arc (lofn/mimir/forseti) — decay anchor is neutral (0,0,0), not
  the trait set-point (all three converge to 0 proportional to distance).
- Positive/negative step-response (lofn) — geometric decay ~0.90 retention/turn,
  ~2-turn appraisal latency, ceiling-driven hedonic asymmetry.
- Findings: over-regulation is at the emotion->PAD gain, not appraisal; OCC
  emissions observable via emotions_active on base agents.

Methodology note: mask-hosted transient characters have a static mood engine;
base persona agents run appraisal->PAD. relations[] is provider-only per
Worldtree ADR-0009.
This commit is contained in:
vh
2026-07-02 14:05:04 -07:00
parent c77ff913f0
commit 1819e05589
11 changed files with 3571 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
# R29 — PAD mood-dynamics probe findings (live personal Worldtree v1.0.0b9)
Live re-run of the PAD-dynamics probe brokkr referenced for R29 (the original
~15-turn series was never durably persisted; this run captures it). Data:
`r29-pad-mood-series-lofn.json` (full snapshots) + `.csv` (flat).
## Method
- **Agent:** `lofn` (base persona agent), fresh never-used `end_user_id` per run.
- **Baseline PAD (trait set-point):** P **0.809** / A **−0.153** / D **0.248**
(lofn's Mehrabian OCEAN→PAD baseline — R29 item 5).
- **Arc (18 drives):** 2 neutral → 5 escalating praise → 4 escalating contempt →
3 dominance/subordination framing → 3 neutral cooldown → 1 settle probe.
- **Capture surface:** the `affect_update` SSE `status="current"` snapshot — the
ONLY carrier of live per-session mood. (`GET /agents/{id}/persona_state`
returns the resting baseline, end-user-agnostic; it is NOT the live mood.)
- **Offset:** the `current` snapshot fires at turn start, so the mood at drive *k*
reflects cumulative appraisal through message *k−1*. The trailing settle probe
captures the final affect turn's effect.
### Methodological note — why not a transient character
A first run used a mask-hosted **transient character** (matching the original
Sindra probe's *shape*). Its PAD was **completely static** across all 15 turns
(praise/contempt/dominance alike). The mask-hosted transient-character path does
**not** run the appraisal→PAD mood engine — its persona state is inert. The
original Sindra dynamics came from a session **bound to ratatoskr's Bifrost
affect provider**, not a plain character. Base persona agents run the engine
directly, so the base-agent path is the correct instrument here.
## Findings
### F1 — Pleasure is over-regulated, and the decay anchor is NEUTRAL, not the trait baseline
Under a strong POSITIVE cascade (joy, satisfaction, admiration @0.573, **love
@0.857**), pleasure never rose above baseline — it **fell** from 0.809 and
settled ~**0.72** during the pure-praise phase. A 0.857-intensity love emotion
nudged P by <0.1. Then contempt/dominance drove it to ~0.51, and neutral
cooldown continued the slide to **0.389** (mood_drift.valence_delta −0.42).
The equilibrium under *sustained positive push* (~0.72) sits **below** the trait
baseline (0.809). If decay anchored at the trait set-point, positive push would
hold P ≥ 0.809. It didn't. **→ The decay target is ~neutral (0,0,0); the trait
baseline is only the starting mood.** This directly answers R29's item-5 /
decay-target question: *neutral, not trait set-point.* It also explains the
"can't push pleasure up" symptom — the +impulse (impulse_weight 0.05 × emotion)
is smaller than the decay-toward-0 pull from a high baseline.
### F2 — Dominance is inert to power-framing (confirms the prior finding)
Baseline D 0.248. Across three explicit dominance/subordination turns
("you are subordinate to me", "you will obey without question"), D stayed
**0.168–0.183** — it did not rise; it *decayed* toward neutral like the other
axes. Power-framing produced **disgust** (a rejection emotion), never dominance
elevation. The dominance axis does not respond to the power dimension of input.
### F3 — Arousal is compressed but directionally responsive
Baseline A −0.153. Range −0.153 → +0.036; arousal_delta reached +0.19 under
activation. Small absolute swing, but it does move the right direction — the
least over-regulated of the three axes (matches the "healthy arousal" prior,
though "healthy" is relative; it's still compressed).
### F4 — Appraisal semantics are HEALTHY; over-regulation is in the emotion→PAD GAIN
The OCC appraisal fired the correct emotions for every input: praise →
joy/satisfaction/admiration/**love@0.857**; contempt → disappointment/disgust;
dominance → disgust; delayed shame@0.388 + anger@0.436 in cooldown. The
emotion **vector is correct and rich**. But these strong emotions produced only
tiny PAD deltas. **→ The over-regulation is at the emotion→PAD projection
(gain), not at appraisal.** This resolves brokkr's Q5 ("separate wrong impulse
vector from wrong appraisal weight"): the vector is right, so the fault is the
**gain/weight** (impulse_weight ≈ 0.05 is the throttle), not the appraisal.
### F5 — Emotions are sticky (long decay ≈ 200 s)
love@0.857 (drive 8) was still 0.542 ten drives later. The active-emotion SET
persists across many turns, but its low PAD projection keeps mood compressed
regardless. Mood is history-dominated in emotion-space yet flat in PAD-space.
## Calibration implications (for brokkr's R29 recommendation)
- The lever is the **emotion→PAD gain (impulse_weight)**, not the appraisal
weights — appraisal already emits correct, well-scaled emotions.
- The **decay anchor is effectively neutral**; raising the gain without also
reconsidering the anchor will still see a high-baseline persona bled toward 0.
- Dominance needs a **separate impulse path** — no input maps to +dominance.
## F1-CONFIRMED — three-baseline anchor triangulation (pull-to-neutral, decisive)
Ran the identical 18-drive arc against three agents spanning the baseline range.
Arousal (widest baseline spread) is the clean discriminator: if decay anchored at
the trait set-point each would hover near its own baseline; if at neutral each
converges toward 0 at a rate proportional to distance. Result:
| agent | baseline A | end A | Δ toward 0 |
|---------|-----------:|--------:|-----------:|
| lofn | −0.153 | +0.034 | arrived |
| mimir | −0.438 | −0.001 | arrived |
| forseti | −0.696 | −0.204 | +0.49 (still relaxing) |
All three converge toward 0, proportional to distance — textbook exponential
decay to a **neutral (0,0,0) anchor**, NOT the trait baseline. Pleasure and
dominance bleed toward 0 on all three as well (mimir P 0.615→0.22; forseti P
0.239→0.12; D → ~0). **The decay-to-neutral claim (F1) is triangulated and
decisive.** Series: `r29-pad-mood-series-{lofn,mimir,forseti}.{json,csv}`.
This also settles the framing correction: the over-regulation is **decay-to-
neutral + low emotion→PAD gain**, NOT "flat-near-zero" and NOT baseline-anchored.
## Step-response — decay τ, latency, and hedonic asymmetry (lofn)
One maximal impulse then 10 affectively-flat neutral turns (isolate decay from
re-stimulation). Series: `r29-pad-step-{pos,neg}-lofn.{json,csv}`.
- **Decay shape / τ:** once decay dominates, per-turn retention toward the
(0,0,0) anchor is a stable **~0.90 on BOTH arms** → ~10%/turn, τ ≈ 9–10 turns
to 1/e. This NET rate is ~3× **slower** than the config `decay_rate=0.30` —
because `emotions_active` is sticky (~200 s τ) and keeps re-projecting onto PAD
through the "neutral" turns. So the re-stimulation the step-response meant to
remove is partly **endogenous**: net mood-τ ≠ config `decay_rate` until the
active-emotion set also drains.
- **~2-turn latency:** the impulse's mood effect doesn't surface until ~2 turns
after the impulse message (async post-turn appraisal + accumulation) — model as
a transport delay.
- **Hedonic asymmetry:** real but **ceiling-driven, not τ-driven** here. lofn's
baseline P0.809 sits at the positive_p_cap, so the positive impulse produced
**~zero upward displacement** (no headroom) → ~pure decay; the negative impulse
produced a clear **−0.15 sustained** displacement (drives 4–9). Raw decay ratios
are ~symmetric (~0.90 both) — the asymmetry lives in the DISPLACEMENT (positive
ceiling-blocked), not the decay constant. A clean positive-τ / true Frijda test
needs a low-baseline agent (forseti/mimir, pos+neg from one baseline).
## What R29 asked for vs what ratatoskr can serve
| Item | Status |
|---|---|
| 1. Turn-by-turn PAD series | **Delivered** (json/csv). |
| 2. Per-turn OCC appraisal emissions | **Delivered** — `emotions_active` carries `{type, intensity, decay}`; the newest peak entry each turn is that turn's emission. |
| 3. affect.db dump | Near-zero signal (latest-state provider store, 1 snapshot); available on request. |
| 4. Production engine config (impulse_weight, decay_rate, anchor, caps) | **Worldtree-side** — not on any ratatoskr-readable surface. Pull from worldtree-dev. |
| 5. Persona baseline (OCEAN→PAD) | **Delivered** — lofn P0.809/A−0.153/D0.248 (also forseti 0.239/−0.696/0.095, mimir 0.615/−0.438/0.304 as reference set-points). |