Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a35ed7af19 |
@@ -0,0 +1,64 @@
|
||||
# R30 gap-injection — deployed-run harness (BANKED, not run)
|
||||
|
||||
**Status:** CLOSED — not executed. On 2026-07-04 the operator steered **close R30 on
|
||||
offline-tests + human face-validity**, no deployed harness build, no endpoint. No
|
||||
`(agent, N, Δt, observed p/a/d)` series was collected. This harness + brokkr's protocol
|
||||
are **banked / drop-in** for the parked powered true-τ perceptual study if it is ever
|
||||
commissioned.
|
||||
|
||||
**Spec pin:** brokkr R30.10 protocol `de8357f` —
|
||||
`brokkr-smithy/research/R30-ocean-derived-mood-dynamics/empirics/r30-gap-injection-protocol.md`.
|
||||
|
||||
## Why it was closed (not built)
|
||||
|
||||
The deployed gap-injection run was **confirmatory, not measuring** (brokkr's §0 reframe:
|
||||
against a deployed system the fade is `exp(−Δt/τ_shipped)` by construction, so a fit
|
||||
returns τ_shipped tautologically — the run graduates the interim coefficients, it does not
|
||||
measure them). Given that:
|
||||
|
||||
- The repo's **offline tests already cover the OU formula + BOTH directions**
|
||||
(`high_N_fades_slower_than_low_N` decay, `phenotype_high_n_bigger_negative_excursion` gain).
|
||||
- **b17 is deployed-clean** on demo + personal.
|
||||
- The ①-approved **mood-holds-within-conversation** IS the face-validity call.
|
||||
|
||||
…the interim coefficients **graduate validated-as-shipped** with no deployed run needed.
|
||||
|
||||
The build cost that would have been required (and was declined):
|
||||
|
||||
- No deployed write affordance exists; the in-memory `_user_moods` cache **shadows** raw
|
||||
`persona_mood.db` writes, so a clean inject needs an in-service **set-mood/back-date
|
||||
endpoint** (set p/a/d + `updated_at` + evict cache).
|
||||
- `moody-lofn N=+0.8` **does not exist** (only lofn `N=−0.5`; tier-3 empty OCEAN → N=0), so
|
||||
the gain half would have needed a new high-N tier-1 agent + deploy — dropped as the
|
||||
expensive, offline-redundant half.
|
||||
|
||||
## What is validated (harness self-check)
|
||||
|
||||
`harness.py::predict()` reproduces brokkr's stated N=0 P-axis retention anchors **exactly**:
|
||||
|
||||
| Δt | predicted | brokkr stated |
|
||||
|---|---|---|
|
||||
| 1h (3600s) | 0.904837 | 0.905 |
|
||||
| 10h/overnight (36000s) | 0.367879 | 0.368 |
|
||||
| 1 week (604800s) | 5.06e-08 | 5e-08 |
|
||||
|
||||
Per-axis τ confirms arousal fades ~1.9× faster (N=0: τ_P = τ_D = 10h, τ_A = 5.26h).
|
||||
|
||||
## Personal `:8081` b17 baseline survey (candidate N-grid agents, all at rest)
|
||||
|
||||
| agent | baseline p/a/d | note |
|
||||
|---|---|---|
|
||||
| lofn | 0.809 / −0.153 / 0.248 | production, N=−0.5 |
|
||||
| mask | 0.0 / 0.0 / 0.0 | zero baseline → zero-N candidate |
|
||||
| forseti | 0.239 / −0.696 / 0.095 | production |
|
||||
| mimir | 0.615 / −0.438 / 0.304 | production |
|
||||
|
||||
(sindra 404s — owner-scoped tier-3, expected.)
|
||||
|
||||
## To un-bank (if the powered study is commissioned)
|
||||
|
||||
1. Worldtree builds the in-service **set-mood/back-date endpoint** (set p/a/d + `updated_at`
|
||||
+ evict `_user_moods`), or the read-only fade-preview variant if that satisfies D1.
|
||||
2. Wire `harness.py::freeze_start()` + `backdate()` to that endpoint (near-zero rebuild).
|
||||
3. Run the 3×8 grid (frozen start p=−0.6/a=+0.5/d=−0.3 × Δt grid), hand brokkr the
|
||||
`(agent, N, Δt, observed p/a/d)` table + per-agent `baseline_pad()`; he runs D1/D2/D3.
|
||||
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
"""R30 gap-injection probe harness (ratatoskr instrument).
|
||||
|
||||
Throwaway probe per the R30.10 protocol
|
||||
brokkr-smithy/research/R30-ocean-derived-mood-dynamics/empirics/r30-gap-injection-protocol.md (de8357f)
|
||||
|
||||
Deliverable: the (agent, N, Δt, observed p/a/d) table + per-agent baseline_pad + the
|
||||
frozen start vector, handed to brokkr who runs D1/D2/D3 graduation. This harness does NOT
|
||||
own the verdict; the predicted/residual columns are a sanity aid only.
|
||||
|
||||
READ + PREDICT + RECORD are fixed by the spec. freeze_start() + backdate() are the WRITE
|
||||
side and are STUBBED pending worldtree's mechanism on personal :8081 (direct persona_mood
|
||||
DB write vs a test affordance). Data lands on a diag/ branch; NOT ratatoskr production code.
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
BASE = os.environ.get("WORLDTREE_API_URL", "http://10.250.50.152:8081")
|
||||
KEY = os.environ["WORLDTREE_API_KEY"]
|
||||
|
||||
# --- R30.10 spec constants (FIXED) ---
|
||||
TAU_BASE_S = 36000.0 # τ_base = 10h
|
||||
BETA_N = 0.25 # τ_P = τ_base · exp(β_N · N)
|
||||
R_A = 1.9 # τ_A = τ_P / r_A ; τ_D = τ_P
|
||||
FROZEN_START = {"pleasure": -0.60, "arousal": +0.50, "dominance": -0.30}
|
||||
DT_GRID = [0, 60, 600, 3600, 14400, 36000, 86400, 604800] # s
|
||||
AXES = ("pleasure", "arousal", "dominance")
|
||||
EPS = 1e-3 # D1 tolerance (PAD units)
|
||||
|
||||
|
||||
def tau(axis, N):
|
||||
tau_p = TAU_BASE_S * math.exp(BETA_N * N)
|
||||
return {"pleasure": tau_p, "arousal": tau_p / R_A, "dominance": tau_p}[axis]
|
||||
|
||||
|
||||
def retention(axis, dt, N):
|
||||
"""ρ_k(Δt,N) = exp(−Δt / τ_k(N)) — predicted deviation-retention fraction."""
|
||||
return math.exp(-dt / tau(axis, N))
|
||||
|
||||
|
||||
def _get(path):
|
||||
req = urllib.request.Request(BASE + path, headers={"Authorization": f"Bearer {KEY}"})
|
||||
with urllib.request.urlopen(req, timeout=8) as r:
|
||||
return json.load(r)
|
||||
|
||||
|
||||
def read_pad(agent):
|
||||
"""get_state read: returns (pad, baseline_pad). pad == peek_relaxed(now), OU-faded, non-mutating."""
|
||||
d = _get(f"/agents/{agent}/persona_state")
|
||||
return d["pad"], d["baseline_pad"]
|
||||
|
||||
|
||||
# --- WRITE SIDE: STUBBED pending worldtree mechanism (msg 01KWNVHTFP…) ---
|
||||
def freeze_start(agent, pad):
|
||||
"""Set persona_mood pad directly to the displaced vector (no live appraisal)."""
|
||||
raise NotImplementedError("worldtree mechanism pending: freeze displaced start mood pad")
|
||||
|
||||
|
||||
def backdate(agent, dt_s):
|
||||
"""Set persona_mood.updated_at = now − dt_s so peek_relaxed fades by exactly Δt."""
|
||||
raise NotImplementedError("worldtree mechanism pending: back-date persisted updated_at")
|
||||
|
||||
|
||||
def predict_selfcheck():
|
||||
"""Validate retention() against brokkr's stated N=0 P-axis anchors (spec §2 D3)."""
|
||||
print("predict() self-check — N=0 P-axis retention vs brokkr's stated anchors:")
|
||||
expect = {"1h": (3600, 0.905), "10h(overnight)": (36000, 0.368), "1wk": (604800, 5e-8)}
|
||||
ok = True
|
||||
for label, (dt, want) in expect.items():
|
||||
got = retention("pleasure", dt, 0.0)
|
||||
match = abs(got - want) < (want * 0.01 + 1e-9) # 1% or float-floor
|
||||
ok = ok and match
|
||||
print(f" {label:>16}: got {got:.6g} expect {want:.6g} {'OK' if match else 'MISMATCH'}")
|
||||
# per-axis τ at a couple N points (informational)
|
||||
print("τ (hours) by axis × N:")
|
||||
for N in (-0.6, 0.0, 0.8):
|
||||
taus = {a: tau(a, N) / 3600 for a in AXES}
|
||||
print(f" N={N:+.1f}: P={taus['pleasure']:.2f}h A={taus['arousal']:.2f}h D={taus['dominance']:.2f}h")
|
||||
return ok
|
||||
|
||||
|
||||
def run_cell(agent, N, dt, baseline):
|
||||
"""One (agent, Δt) cell: freeze start → back-date by Δt → read faded pad → record row.
|
||||
Blocked until freeze_start()/backdate() are wired to worldtree's mechanism."""
|
||||
freeze_start(agent, FROZEN_START)
|
||||
backdate(agent, dt)
|
||||
pad, _ = read_pad(agent)
|
||||
row = {"agent": agent, "N": N, "dt_s": dt}
|
||||
for k in AXES:
|
||||
obs = pad[k]
|
||||
dev0 = abs(FROZEN_START[k] - baseline[k])
|
||||
pred_dev = dev0 * retention(k, dt, N)
|
||||
obs_dev = abs(obs - baseline[k])
|
||||
row[f"obs_{k[0]}"] = obs
|
||||
row[f"pred_dev_{k[0]}"] = pred_dev
|
||||
row[f"resid_{k[0]}"] = obs_dev - pred_dev
|
||||
return row
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "read":
|
||||
agent = sys.argv[2]
|
||||
pad, base = read_pad(agent)
|
||||
print(json.dumps({"agent": agent, "pad": pad, "baseline_pad": base}, indent=2))
|
||||
else:
|
||||
predict_selfcheck()
|
||||
Reference in New Issue
Block a user