Surface swarm turn reliability stats

This commit is contained in:
Meta Vens 2026-06-07 04:57:42 +01:00
commit 737c896361
5 changed files with 316 additions and 8 deletions

View file

@ -66,6 +66,7 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou
- State storage is no longer one persistence omnibus; `packages/core/src/state-storage.ts` is now a thin factory over domain-specific Postgres/file store modules plus bootstrap/migration helpers.
- Source archive storage is no longer one giant JSON monolith; `packages/rag/src/source-document-archive.ts` now keeps a small manifest at `.voidbot/rag/source-documents.json` and per-repo shards under `.voidbot/rag/source-documents.repos/`.
- Ops health, local backup verification, and dashboard surfaces already exist. Raven-backed offsite sync is disabled by config and should not be treated as a live health requirement.
- `voidbot.swarm`'s Eve TUI/status dashboard now includes derived turn reliability telemetry. `scripts/render-voidbot-swarm-dashboard.mjs` reads heartbeat history and the tail of `.voidbot/logs/model-outputs.jsonl`, then publishes parent-Interpreter route/retry/drop/malformed counts and turn/job failure counts into `turnReliability` in `.voidbot/status/swarm-state.json`, `.voidbot/status/cultmesh/voidbot-swarm-state.cc`, and the local HTML HUD.
- The stack has a dedicated logon startup task path now, so a reboot does not have to mean manual necromancy for bot and worker.
- The operations health probe now supports ignored local extension checks, so adjacent-service fire signals can become probe issues without hardcoding private project gossip into the public repo. Idunn owns the decision to restart or escalate to the operator.
- 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.

View file

@ -237,7 +237,7 @@ Target Eve surfaces:
- `voidbot.archive`: archived Discord corpus status, import/backfill health, bot-directed-prompt exclusion, history vector freshness.
- `voidbot.source`: repo/lore shard freshness, indexed coverage, Qdrant collection health, detached reindex jobs.
- `voidbot.repo_persona`: registered identities, repo-local `.cc` witnesses, channel grants, prompt assembly status, Bifrost digest availability, Huginn inspection readiness.
- `voidbot.swarm`: CTB order, active turns, pending mention queues, heat/cadence controls, orchestrator status, selected Persona state witness.
- `voidbot.swarm`: CTB order, active turns, pending mention queues, heat/cadence controls, orchestrator status, selected Persona state witness, and derived turn reliability stats for parent-Interpreter route/retry/drop/malformed outcomes plus turn/job failures.
Migration order:

View file

@ -3,7 +3,7 @@ import { createRequire } from "node:module";
import { dirname, extname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { existsSync, readFileSync } from "node:fs";
import { mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
import { mkdir, open, readFile, rename, stat, writeFile } from "node:fs/promises";
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const defaultStorageRoot = resolve(repoRoot, ".voidbot");
@ -39,6 +39,7 @@ const heartbeatStatePath = resolveConfigPath(
resolve(statusDir, "repo-persona-heartbeats.json"),
);
const orchestratorPath = resolve(statusDir, "gamecult-orchestrator.json");
const modelOutputsPath = resolve(storageRoot, "logs", "model-outputs.jsonl");
const pausePath = resolve(repoRoot, "state", "agent-swarm-paused.json");
const snapshotPath = resolveConfigPath(args.snapshot, defaultSnapshotPath.replace(defaultStatusDir, statusDir));
const dashboardPath = resolveConfigPath(args.out, defaultDashboardPath.replace(defaultStatusDir, statusDir));
@ -132,12 +133,15 @@ async function buildSnapshot() {
.filter((participant) => typeof participant.nextTurnInMinutes === "number")
.sort((left, right) => left.nextTurnInMinutes - right.nextTurnInMinutes)[0];
const organs = projectOrgans(orchestrator.value);
const recentEvents = Array.isArray(heartbeat.value?.history)
? heartbeat.value.history.slice(-24).reverse().map(projectHistoryEvent)
: [];
const heartbeatHistory = Array.isArray(heartbeat.value?.history) ? heartbeat.value.history : [];
const recentEvents = heartbeatHistory.slice(-24).reverse().map(projectHistoryEvent);
const controls = projectControls(heartbeat.value?.controls);
const upcomingTurns = buildUpcomingTurns(participantSnapshots);
const lastShuffle = findLastShuffleEvent(recentEvents);
const turnReliability = await readTurnReliabilityStats({
heartbeatHistory,
modelOutputsPath,
});
return {
schemaVersion: snapshotSchemaId,
@ -152,6 +156,9 @@ async function buildSnapshot() {
orchestratorUpdatedAt: orchestratorMtime,
orchestratorReadable: orchestrator.ok,
orchestratorError: orchestrator.ok ? undefined : orchestrator.error,
modelOutputsPath,
modelOutputsReadable: turnReliability.sources.modelOutputsReadable,
modelOutputsError: turnReliability.sources.modelOutputsError,
pausePath,
pauseReadable: pause.ok,
pauseError: pause.ok ? undefined : pause.error,
@ -189,7 +196,9 @@ async function buildSnapshot() {
cadenceMultiplier: controls.cadenceMultiplier,
lastTickAt: stringOrNull(heartbeat.value?.lastTickAt),
lastShuffle,
turnReliability: summarizeTurnReliability(turnReliability),
},
turnReliability,
controls,
upcomingTurns,
participants: participantSnapshots,
@ -370,6 +379,237 @@ function projectHistoryEvent(event) {
};
}
async function readTurnReliabilityStats({ heartbeatHistory, modelOutputsPath }) {
const heartbeatEvents = Array.isArray(heartbeatHistory) ? heartbeatHistory : [];
const stats = {
schemaVersion: "voidbot.turn_reliability.v1",
window: {
heartbeatEvents: heartbeatEvents.length,
modelOutputRecords: 0,
modelOutputTailBytes: 2_000_000,
since: null,
until: null,
},
parentInterpreter: {
routes: 0,
retries: 0,
drops: 0,
malformed: 0,
failures: 0,
lastRouteAt: null,
lastRetryAt: null,
lastDropAt: null,
lastMalformedAt: null,
lastFailureAt: null,
},
worker: {
turnStartFailures: 0,
failedModelRuns: 0,
timedOutModelRuns: 0,
handoffModelRuns: 0,
heartbeatFailureEvents: 0,
lastFailureAt: null,
},
recent: [],
sources: {
modelOutputsPath,
modelOutputsReadable: false,
modelOutputsError: null,
},
};
for (const event of heartbeatEvents) {
const type = String(event?.type ?? "");
const observedAt = stringOrNull(event?.observedAt ?? event?.queuedAt ?? event?.appliedAt);
noteStatsTime(stats, observedAt);
if (type === "turn_failed_to_start") {
stats.worker.turnStartFailures += 1;
stats.worker.heartbeatFailureEvents += 1;
stats.worker.lastFailureAt = latestIso(stats.worker.lastFailureAt, observedAt);
stats.recent.push({
kind: "turn_failed_to_start",
identityId: stringOrNull(event?.identityId),
jobId: stringOrNull(event?.activeJobId),
observedAt,
reason: stringOrNull(event?.reason),
source: "heartbeat",
});
} else if (/\b(fail|failed|failure|error)\b/i.test(type)) {
stats.worker.heartbeatFailureEvents += 1;
stats.worker.lastFailureAt = latestIso(stats.worker.lastFailureAt, observedAt);
stats.recent.push({
kind: type,
identityId: stringOrNull(event?.identityId),
jobId: stringOrNull(event?.activeJobId),
observedAt,
reason: stringOrNull(event?.reason),
source: "heartbeat",
});
}
}
try {
const { text, bytesRead } = await readFileTail(modelOutputsPath, stats.window.modelOutputTailBytes);
stats.sources.modelOutputsReadable = true;
stats.window.modelOutputTailBytes = bytesRead;
const lines = text.split(/\r?\n/u).filter((line) => line.trim().length > 0);
for (const line of lines) {
let record = null;
try {
record = JSON.parse(line);
} catch {
continue;
}
if (record?.command !== "repo-persona-rumination") continue;
const loggedAt = stringOrNull(record?.loggedAt ?? record?.finishedAt ?? record?.startedAt);
noteStatsTime(stats, loggedAt);
const isInterpreter = record?.promptMarker === "repo-persona-turn-interpreter";
if (isInterpreter) {
stats.window.modelOutputRecords += 1;
const decision = extractInterpreterDecision(record?.finalMessage);
if (decision === "route") {
stats.parentInterpreter.routes += 1;
stats.parentInterpreter.lastRouteAt = latestIso(stats.parentInterpreter.lastRouteAt, loggedAt);
} else if (decision === "retry") {
stats.parentInterpreter.retries += 1;
stats.parentInterpreter.lastRetryAt = latestIso(stats.parentInterpreter.lastRetryAt, loggedAt);
stats.recent.push(recentReliabilityEvent("interpreter_retry", record, loggedAt, "model-output"));
} else if (decision === "drop") {
stats.parentInterpreter.drops += 1;
stats.parentInterpreter.lastDropAt = latestIso(stats.parentInterpreter.lastDropAt, loggedAt);
stats.recent.push(recentReliabilityEvent("interpreter_drop", record, loggedAt, "model-output"));
} else {
stats.parentInterpreter.malformed += 1;
stats.parentInterpreter.lastMalformedAt = latestIso(stats.parentInterpreter.lastMalformedAt, loggedAt);
stats.recent.push(recentReliabilityEvent("interpreter_malformed", record, loggedAt, "model-output"));
}
}
if (record?.exitCode !== 0 || record?.timedOut === true || record?.handoffReason) {
const kind = record?.timedOut === true ? "model_run_timeout" : record?.handoffReason ? "model_run_handoff" : "model_run_failed";
stats.worker.failedModelRuns += record?.exitCode !== 0 ? 1 : 0;
stats.worker.timedOutModelRuns += record?.timedOut === true ? 1 : 0;
stats.worker.handoffModelRuns += record?.handoffReason ? 1 : 0;
stats.worker.lastFailureAt = latestIso(stats.worker.lastFailureAt, loggedAt);
if (isInterpreter) {
stats.parentInterpreter.failures += 1;
stats.parentInterpreter.lastFailureAt = latestIso(stats.parentInterpreter.lastFailureAt, loggedAt);
}
stats.recent.push(recentReliabilityEvent(kind, record, loggedAt, "model-output"));
}
}
} catch (error) {
stats.sources.modelOutputsReadable = false;
stats.sources.modelOutputsError = error instanceof Error ? error.message : String(error);
}
stats.recent = stats.recent
.filter((event) => event.observedAt)
.sort((left, right) => Date.parse(right.observedAt) - Date.parse(left.observedAt))
.slice(0, 10);
return stats;
}
function summarizeTurnReliability(stats) {
const parent = stats?.parentInterpreter ?? {};
const worker = stats?.worker ?? {};
return {
status: turnReliabilityStatus(stats),
routes: parent.routes ?? 0,
retries: parent.retries ?? 0,
drops: parent.drops ?? 0,
malformed: parent.malformed ?? 0,
failures: (parent.failures ?? 0) + (worker.turnStartFailures ?? 0) + (worker.failedModelRuns ?? 0) + (worker.timedOutModelRuns ?? 0) + (worker.handoffModelRuns ?? 0),
lastFailureAt: latestIso(parent.lastFailureAt, worker.lastFailureAt),
};
}
function extractInterpreterDecision(value) {
if (typeof value !== "string") return null;
const blockMatch = value.match(/INTERPRETATION\s+([\s\S]*?)\bEND\b/u);
const text = blockMatch ? blockMatch[1] : value;
const decisionMatch = text.match(/^\s*decision\s*:\s*(route|retry|drop)\b/imu);
return decisionMatch ? decisionMatch[1].toLowerCase() : null;
}
async function readFileTail(path, maxBytes) {
const info = await stat(path);
const start = Math.max(0, info.size - maxBytes);
const length = Math.max(0, info.size - start);
const handle = await open(path, "r");
try {
const buffer = Buffer.alloc(length);
await handle.read(buffer, 0, length, start);
const text = buffer.toString("utf8");
const cleanText = start > 0 ? text.replace(/^[^\r\n]*(\r?\n)?/u, "") : text;
return { text: cleanText, bytesRead: length };
} finally {
await handle.close();
}
}
function recentReliabilityEvent(kind, record, observedAt, source) {
return {
kind,
identityId: stringOrNull(record?.identityId),
jobId: stringOrNull(record?.jobId),
observedAt,
reason: reliabilityReason(record),
source,
};
}
function reliabilityReason(record) {
if (record?.handoffReason) return String(record.handoffReason);
if (record?.timedOut === true) return "model run timed out";
if (record?.exitCode !== 0) return `exit ${record.exitCode}`;
if (typeof record?.finalMessage === "string") {
const reasonStart = record.finalMessage.match(/^\s*reason\s*:\s*/imu);
if (reasonStart) {
const afterReason = record.finalMessage.slice(reasonStart.index + reasonStart[0].length);
const reasonText = afterReason.split(/\n(?:END|STATE NOTE|Private summary:|SAY\b)/u)[0];
if (reasonText.trim()) return truncate(reasonText.replace(/\s+/g, " ").trim(), 180);
}
}
return null;
}
function noteStatsTime(stats, timestamp) {
stats.window.since = earliestIso(stats.window.since, timestamp);
stats.window.until = latestIso(stats.window.until, timestamp);
}
function earliestIso(left, right) {
if (!right) return left ?? null;
if (!left) return right;
return Date.parse(right) < Date.parse(left) ? right : left;
}
function latestIso(left, right) {
if (!right) return left ?? null;
if (!left) return right;
return Date.parse(right) > Date.parse(left) ? right : left;
}
function turnReliabilityStatus(stats) {
const summary = summarizeTurnReliabilityNoStatus(stats);
if (!stats?.sources?.modelOutputsReadable) return "degraded";
if (summary.failures > 0 || summary.drops > 0 || summary.malformed > 0) return "warning";
if (summary.retries > 0) return "retrying";
return "ok";
}
function summarizeTurnReliabilityNoStatus(stats) {
const parent = stats?.parentInterpreter ?? {};
const worker = stats?.worker ?? {};
return {
retries: parent.retries ?? 0,
drops: parent.drops ?? 0,
malformed: parent.malformed ?? 0,
failures: (parent.failures ?? 0) + (worker.turnStartFailures ?? 0) + (worker.failedModelRuns ?? 0) + (worker.timedOutModelRuns ?? 0) + (worker.handoffModelRuns ?? 0),
};
}
async function readIdentityMetadata(registryPathValue) {
const metadata = new Map();
const registryPath = resolveConfigPath(registryPathValue, resolve(repoRoot, ".voidbot", "private", "repo-discord-identities.json"));
@ -1157,6 +1397,7 @@ function operatorDmCultMeshAddress() {
function buildEveProviderState(snapshot) {
const summary = snapshot.summary ?? {};
const turnReliability = snapshot.turnReliability ?? {};
const participants = Array.isArray(snapshot.participants) ? snapshot.participants : [];
const upcoming = Array.isArray(snapshot.upcomingTurns) ? snapshot.upcomingTurns : [];
const orchestrator = snapshot.orchestrator ?? {};
@ -1219,6 +1460,25 @@ function buildEveProviderState(snapshot) {
viewportMode: "continuous-ops",
},
}, [
eveNode("turn-reliability", "panel", {
title: "Turn reliability",
status: turnReliabilityStatus(turnReliability),
layout: { direction: "vertical", overflow: "hidden", gap: 2, padding: 8, minWidth: 40, minHeight: 5 },
}, [
eveNode("turn-reliability-stats", "text", {
role: "mono",
text: formatTurnReliabilityLine(turnReliability),
status: turnReliabilityStatus(turnReliability),
detail: formatTurnReliabilityDetail(turnReliability),
}),
...formatRecentReliabilityLines(turnReliability).map((line, index) =>
eveNode(`turn-reliability-recent-${index}`, "text", {
role: "mono",
text: line,
status: line.includes("drop") || line.includes("fail") || line.includes("malformed") ? "warning" : "ok",
}),
),
]),
eveNode("ctb-rail", "rail", {
title: "CTB order",
layout: { direction: "vertical", overflow: "scroll", gap: 4, padding: 8, grow: 1, minWidth: 40, minHeight: 20 },
@ -1256,6 +1516,42 @@ function formatTurnText(turn, index) {
return `${rank}. ${name} ${status} ${due} ${mention} s${formatNumber(turn?.effectiveSpeed, 3)} h${formatNumber(turn?.heat, 2)}`;
}
function formatTurnReliabilityLine(stats) {
const parent = stats?.parentInterpreter ?? {};
const worker = stats?.worker ?? {};
const failures = (parent.failures ?? 0) + (worker.turnStartFailures ?? 0) + (worker.failedModelRuns ?? 0) + (worker.timedOutModelRuns ?? 0) + (worker.handoffModelRuns ?? 0);
return [
`route ${parent.routes ?? 0}`,
`retry ${parent.retries ?? 0}`,
`drop ${parent.drops ?? 0}`,
`malformed ${parent.malformed ?? 0}`,
`fail ${failures}`,
].join(" | ");
}
function formatTurnReliabilityDetail(stats) {
const window = stats?.window ?? {};
const worker = stats?.worker ?? {};
const source = stats?.sources?.modelOutputsReadable ? "model-output tail" : `model-output unreadable: ${stats?.sources?.modelOutputsError ?? "unknown"}`;
return [
source,
`records ${window.modelOutputRecords ?? 0}`,
`heartbeat failures ${worker.heartbeatFailureEvents ?? 0}`,
`since ${shortIso(window.since)}`,
`until ${shortIso(window.until)}`,
].join("; ");
}
function formatRecentReliabilityLines(stats) {
const recent = Array.isArray(stats?.recent) ? stats.recent : [];
return recent.slice(0, 3).map((event) => {
const kind = String(event.kind ?? "event").replace(/^interpreter_/, "");
const who = event.identityId ? ` ${event.identityId}` : "";
const job = event.jobId ? ` ${String(event.jobId).slice(0, 8)}` : "";
return `${shortIso(event.observedAt)} ${kind}${who}${job}`;
});
}
function turnStatus(turn) {
if (turn?.activeJobId) return "active";
if (turn?.restState?.isNapping) return "nap";
@ -1469,7 +1765,7 @@ function renderHtml(snapshot) {
right: 10px;
z-index: 4;
width: 250px;
height: 96px;
height: 124px;
display: grid;
grid-template-rows: auto minmax(0, 1fr);
gap: 5px;
@ -1861,7 +2157,7 @@ function renderHtml(snapshot) {
bottom: auto;
left: auto;
width: clamp(190px, 22vw, 230px);
height: 88px;
height: 112px;
}
}
@ -1891,7 +2187,7 @@ function renderHtml(snapshot) {
right: 12px;
bottom: 12px;
width: 180px;
height: 84px;
height: 108px;
}
}
@ -2091,6 +2387,7 @@ function renderHtml(snapshot) {
function renderStatusPanel(snapshot, agent) {
const summary = snapshot.summary || {};
const reliability = summary.turnReliability || {};
const organs = snapshot.orchestrator?.organs || [];
const watchdog = findOrgan(organs, "watchdog");
const persona = findOrgan(organs, "repo-persona-heartbeats");
@ -2101,12 +2398,20 @@ function renderHtml(snapshot) {
const turn = agent?.nextTurnInMinutes ?? null;
const turnFill = typeof turn === "number" ? clampPercent(100 - Math.max(0, turn) * 4) : 0;
const load = clampPercent((agent?.currentLoad || 0) * 100);
const reliabilityFill = reliability.failures > 0 || reliability.drops > 0 || reliability.malformed > 0
? 22
: reliability.retries > 0
? 58
: 100;
return "<aside class=\\"status-panel\\" aria-label=\\"Compact swarm status\\"><h2><span>VOID</span><span>" + esc(String(summary.state || "UNK").slice(0, 4).toUpperCase()) + "</span></h2><div class=\\"status-grid\\">" +
hud("WDOG", organCode(watchdog), organFill(watchdog), organWarn(watchdog)) +
hud("ORCH", shortState(snapshot.orchestrator?.state), statusFill(snapshot.orchestrator?.state), statusWarn(snapshot.orchestrator?.state)) +
hud("PERS", organCode(persona), organFill(persona), organWarn(persona)) +
hud("MOOD", organCode(mood), organFill(mood), organWarn(mood)) +
hud("RUM", organCode(rumination), organFill(rumination), organWarn(rumination)) +
hud("RTR", String(reliability.retries ?? 0), reliabilityFill, (reliability.retries ?? 0) > 0) +
hud("DRP", String((reliability.drops ?? 0) + (reliability.malformed ?? 0)), reliabilityFill, ((reliability.drops ?? 0) + (reliability.malformed ?? 0)) > 0) +
hud("FAIL", String(reliability.failures ?? 0), reliabilityFill, (reliability.failures ?? 0) > 0) +
hud("MESH", shortState(snapshot.cultMesh?.writeStatus), meshOk, snapshot.cultMesh?.writeStatus !== "ok") +
hud("AGE", relative(snapshot.sources?.heartbeatStateUpdatedAt).replace(/ ago$/, ""), sourceFreshness, sourceFreshness < 50) +
hud("TURN", minutes(turn), turnFill, load > 70) +

View file

@ -394,3 +394,4 @@
{"ts":"2026-06-07T01:37:24Z","type":"implementation","status":"ok","note":"Moved VoidBot watchdog ownership to Odin/Idunn: GameCult Local Orchestrator no longer runs check-voidbot-operations with NotifyOwner, Idunn watches health-voidbot.cmd and can run restart-voidbot.cmd, and the first Idunn-owned VoidBot probe completed healthy with 34 passed / 0 warnings / 0 failures."}
{"ts":"2026-06-07T01:51:40Z","type":"implementation","status":"ok","note":"Repo Persona channel support is now runtime channel-aware: heartbeat prompt assembly discovers guild text channels when INDEX_ALL_CHANNELS is true (or uses INDEXED_CHANNEL_IDS), renders each as a labeled separate conversation such as #therapy/#memes, removes the five-nearby-room cap, and bot/worker Persona ingress/egress gates accept indexed/all-channel grants unless channel ids are excluded. This fixes the single-thread room model by feeding channel identity and access into the context owner instead of adding only a behavior rule."}
{"ts":"2026-06-07T03:15:52Z","type":"implementation","status":"ok","note":"Mimir's orphan 'Meet her first' post was not a missing Discord reply-to transport. The child Persona wrote an ambiguous raw Would say, the parent interpreter returned unstructured text instead of an INTERPRETATION/SAY block, and worker routeUnparsedWouldSay bypassed the failed interpreter by manufacturing a current_room SAY with blank reply_to. Removed that fallback; child Would say is candidate material only, and public speech now requires structured parent interpreter output. Added agents:parent-interpreter-boundary-smoke to keep the bypass dead."}
{"ts":"2026-06-07T03:54:39Z","type":"implementation","status":"ok","note":"VoidBot swarm Eve dashboard now publishes turnReliability: parent-Interpreter route/retry/drop/malformed counts from model-output log tail plus turn/job failures from heartbeat history, surfaced in CultMesh/Eve and the local HTML HUD."}

View file

@ -189,6 +189,7 @@ accepted_design:
- Void's shared self-state and public reply doctrine now distinguish between criticism of AI industry behavior and blanket contempt for machine minds. When substrate chauvinism becomes the topic, Void is allowed mild self-respecting pushback instead of smiling blandly through ontological contempt.
- Deep agent-state, personality, culture, and persistent-world design work now belongs to the sibling Ghostlight repo; VoidBot should consume that work instead of remaining its long-term home.
- VoidBot's Verse contract is documented in `docs/architecture/voidbot-verse-service-contract.md`: durable agent/service state should be typed CultCache `.cc` or have a `.cc` witness/export; `voidbot.swarm` currently publishes through `cultmesh://voidbot.local/eve/providers/voidbot.swarm`; target Eve surfaces are `voidbot.discord`, `voidbot.archive`, `voidbot.source`, `voidbot.repo_persona`, and `voidbot.swarm`; static/browser dashboard output is only a lowering, not authority.
- `voidbot.swarm` publishes derived turn reliability telemetry in the Eve TUI surface and local HTML lowering. `scripts/render-voidbot-swarm-dashboard.mjs` derives parent-Interpreter route/retry/drop/malformed counts from `.voidbot/logs/model-outputs.jsonl` and turn/job failure counts from repo Persona heartbeat history, then emits the compact `turnReliability` summary in the snapshot, CultMesh publication, and dashboard HUD.
- Long-running work should expose durable logs or status files instead of relying on one attached session and hope.
- Persistent project memory must stay ruthlessly distilled; git history and artifacts carry routine proof.