Reliability Diagnostics¶
Status: experimental, built in, default off, goal and session scoped. This package implements the prototype components described by the RFC's P0 roadmap phase: the L1 shadow-observer contract and its first DSH event-source adapter. It does not claim the P0 exit gate; an eligible C1 observer run, C0 adapter-fidelity evidence, and measured overhead are still required.
An L1 observer sees a long-running agent session and writes an independent
diagnostic record about it. It may never influence that session. This
capability makes that promise a machine contract rather than a policy: the
envelope schema cannot express a command, the receipt records the empty set of
outbound endpoints, observer failure is counted and quarantines the evidence,
and the projection carries mode: read_only and authority: none.
flowchart LR
H["DSH agent loop"] -->|"read-only events"| O["observer.ts (dsh-session-events)"]
O -->|"envelopes + stats, NDJSON"| L["reliability_diagnostics/<goal>.ndjson"]
L --> R["integrity receipt"]
L --> P["read-only projection"]
O -. "no send, schedule, gate, tool, or worker-state path" .-> H
The dashed edge is an asserted absence. The observer ships as its own Cordis
plugin entry with no Driver or Agent injection, consumes only session-log
publication events, and is absent from the Driver and package-root bundles.
Tests reject control-shaped fields, and the receipt turns invalid if any
outbound endpoint or scheduler/worker-context path appears. This is module and
hook isolation, not an OS-process-isolation claim.
Placement Rationale¶
- Capability id
reliability-diagnostics(built in, providerloopx-core). The caller outcome is "is this run admissible passive evidence, and what does it say about stage, stall, repetition, and recovery?" No existing capability owns diagnostics without authority. Session runtime is a runtime-authority projection, so the diagnostic ledger and projection are siblings of it, never merged into it. Ids are kebab-case like every other catalog id; the package directory isreliability_diagnostics. - Provider id
dsh-session-events(originextension). It is delivered by the npm packagepackages/dsh-loopx-pluginthrough the explicitdsh-loopx-plugin/observerentry and its ownloopx-shadow-observerCordis row, separate fromdriver.ts. Because an npm plugin has no Pythonextension.tomllifecycle, the capability declares the provider on its catalog entry and the registry reports itdeclared=true,installed=enabled=ready=false. The precedent isrepository_change_window, which declares itsgit-hookprovider the same way. - Helpers stay local. Ledger, receipt, and projection reducers live inside
this package. The only shared imports are the public-safe value validator
and the
SOURCE_ID_KEYSidentity tuple; the session-runtime substring classifier is deliberately not reused.
Relationship To The RFCs¶
- Long-Running Agent Reliability Diagnostics
owns this capability. This slice is the P0 contract checkpoint recorded in
its roadmap; the
dshevent source is the recorded answer to owner decision 2, and the C1 run, overhead report, and retention profile remain open before P0 exit. - Desktop Execution Frontends Mode B is the managed runtime this observer is built for: the Desktop-owned runtime supervisor may consume the receipt and projection as diagnostic inputs, while the observer keeps no supervisor authority.
Contract¶
Observer envelope (reliability_observer_envelope_v0)¶
| Field | Type | Rule |
|---|---|---|
schema_version |
literal | reliability_observer_envelope_v0 |
capability_id |
literal | reliability-diagnostics |
provider_id |
identity token | e.g. dsh-session-events |
observer_id |
identity token | stable for one observer instance and linked to stats |
goal_id, session_id |
identity token | ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,120}$ |
agent_id |
identity token, optional | |
sequence |
integer >= 0 | observer-assigned, monotonic per session; gaps are counted as loss |
observed_at |
ISO-8601 with timezone | |
clock.source |
enum | harness_event_time, observer_wall_clock, fixture |
clock.uncertainty_ms |
integer >= 0 | declared, never inferred |
event_kind |
enum | session_started, turn_started, turn_ended, step_started, step_ended, user_message, tool_called, tool_completed, agent_status, agent_pre_step, agent_error, session_disposed, unsupported |
summary |
object | only turn, step (integers) and reason, status, tool_name, error_class, source_event_type, message_source_kind (compact tokens) |
source_refs |
object | only id keys: event_id, event_seq, tool_call_id, message_id, outcome_id, gate_id, approval_id, artifact_id, run_id, ref_id |
Any other field is rejected with a typed reason: control_field_rejected
(command, send, prompt, schedule, retry, stop, resume, gate,
tool_call, worker_state, ...), raw_material_field_rejected
(transcript, messages, content, text, arguments, output,
stdout, stderr, log, cwd, token, ...), or
unsupported_field_rejected. Every provider applies the equivalent recursive
public-safe value contract before its first append, and LoopX ingest applies
it again. Absolute local paths and credential-like tokens fail closed without
reaching ledger bytes; the producer counts them as public_safety_violation.
Observer stats (reliability_observer_stats_v0)¶
Written by every observer implementation next to its envelopes. It pins
worker_id, model_id, task_id, environment_id, tools_id, budget_id,
adapter_revision, and observer_revision under run_identity; declares
event_sources and source_fields_consumed; and records timestamps, accepted
and rejected counts, typed rejection totals, buffer bound, drops, failures,
peak buffered events, flush attempts, clock source, outbound endpoints, and
both worker-context and scheduler-input influence flags. Counts must satisfy
observed = accepted + rejected + dropped, timestamps must be timezone-aware,
and every accepted envelope must link to matching provider/observer stats.
Stats are cumulative per observer instance; the receipt keeps the latest
record per observer_id and sums across instances.
Integrity receipt (reliability_integrity_receipt_v0)¶
| Field | Meaning |
|---|---|
status |
valid, degraded, quarantined, invalid (total, ordered) |
reason_codes |
typed list; empty only when valid |
observed_event_count, accepted_event_count, persisted_event_count |
source attempts, accepted count from stats, and linked envelopes in the ledger |
lost_event_count, duplicate_sequence_count |
per-session sequence gaps and repeats |
ledger_invalid_record_count |
malformed or foreign records found in the ledger |
rejected_event_count, rejected_by_reason |
refusals reported by observers |
buffer_bound, backpressure_drop_count, observer_failure_count |
bounded-failure evidence |
clock.sources, clock.max_uncertainty_ms |
declared clocks; > 1000 ms degrades |
outbound_endpoints, worker/scheduler influence flags |
must be [] / false / false |
run_identities, event_sources, source_fields_consumed |
pinned treatment identity and declared adapter coverage |
event_kinds_consumed, summary_fields_consumed |
the event kinds and compact summary fields actually persisted |
Status rules: invalid when there are no observations, stats are absent or do
not link exactly to persisted envelopes, an identity was rejected, the ledger
contains invalid input, any outbound endpoint exists, or observation entered
worker context or scheduler inputs. Otherwise quarantined covers observer
failure, control-shaped input, or a producer-side public_safety_violation.
Event gaps, drops, duplicates, raw or unsupported fields, and excess clock
uncertainty are degraded; otherwise the receipt is valid.
Diagnostic projection (reliability_diagnostic_projection_v0)¶
| Field | Meaning |
|---|---|
mode, authority, write_scope, worker_influence |
read_only, none, diagnostic_ledger_only, none |
stage |
unknown, idle, running, tool_running, errored, disposed from the last event kind |
counts |
turns started/ended, steps, tool calls, errors |
stall |
detected only while active and silent for threshold_ms (default 300000) relative to --as-of |
repetition |
longest run of consecutive identical tool_name calls; detected at 3 |
recovery |
errors followed by a later completed step or non-error turn end count as recovered |
signals |
stall_suspected, repetition_suspected, unrecovered_error, event_loss, integrity_not_valid |
integrity |
the receipt status and reason codes |
Use It¶
# Enable the DSH provider for one predeclared goal and one exact DSH session.
export LOOPX_DSH_SHADOW_OBSERVER_GOAL_ID=<goal-id>
export LOOPX_DSH_SHADOW_OBSERVER_SESSION_ID=<session-id>
export LOOPX_DSH_SHADOW_OBSERVER_RUN_IDENTITY_JSON='{"worker_id":"<worker>","model_id":"<model>","task_id":"<task>","environment_id":"<environment>","tools_id":"<tools>","budget_id":"<budget>","adapter_revision":"<adapter-revision>","observer_revision":"<observer-revision>"}'
# Optional: LOOPX_DSH_SHADOW_OBSERVER_LEDGER_DIR, LOOPX_DSH_SHADOW_OBSERVER_BUFFER_BOUND
loopx reliability-diagnostics receipt --goal-id <goal-id> --format json
loopx reliability-diagnostics status --goal-id <goal-id> --format json
loopx reliability-diagnostics status --goal-id <goal-id> --with-receipt --format json --as-of "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
loopx reliability-diagnostics ingest --goal-id <goal-id> --input observer.ndjson --format json
For live age/stall evaluation, pass the current timezone-aware --as-of as in
the POSIX-shell example. Without it, historical replay uses the last event time
and reports zero last-event age. This does not establish current liveness.
Explicit --as-of values must be ISO-8601 timestamps with Z or a UTC offset.
Empty, malformed, or timezone-free values exit with code 2, even when the ledger
is missing, empty, or corrupt; this applies with or without --with-receipt.
status --with-receipt returns both existing contracts from one ledger read.
Omit the option to retain projection-only output. It grants no control authority
and does not enable the observer. Concurrent appends are not atomic snapshots;
partial records remain integrity failures. See the
DSH/Pi assessment
before wiring this full-ledger CLI into a polling surface.
The ledger lives at <runtime-root>/reliability_diagnostics/<goal-id>.ndjson;
the default runtime root is the same one the rest of LoopX uses and the CLI
prints only the relative ledger_ref. ingest re-validates every line. A
clean ingest is a transparent copy; any malformed or rejected input appends a
durable reliability_ingest_violation_v0 marker, making subsequent receipts
invalid instead of losing the failed gate at process exit.
Unless all three required variables are valid, the observer row registers no
hooks and writes no files (feature-off parity). When enabled, observer.ts
observes only session/created, session/event, and session/disposed.
Events from any other session are rejected as identity_invalid, so they can
never be silently attributed to the configured goal. Token-level
assistant/chunk events are not consumed.
Validation¶
python3 examples/reliability_diagnostics/dsh-shadow-observer-fixture-smoke.py
python3 -m pytest tests/capabilities/test_reliability_diagnostics.py tests/capabilities/test_reliability_diagnostics_dsh_provider.py -q
cd packages/dsh-loopx-plugin && pnpm typecheck && pnpm test -- observer
The fixture is a fixed DSH-shaped stream with one missing sequence, one event
stamped with 1500 ms clock uncertainty, one raw-material-bearing record, and a
burst that overflows a 20-record buffer. Its receipt is degraded with exactly
sequence_gap, backpressure_drop, raw_material_rejected, and
clock_uncertainty_exceeded; the projection reports repetition on read, one
recovered error, and no stall.
Non-Goals In This Slice¶
No dashboard surface, no L2 recommendations, no automatic recovery, no
writeback into goals, todos, gates, or session runtime, and no change to the
loopx status first screen. The adapter requires an externally pinned
goal/session/run identity; it does not discover bindings through the Driver or
LoopX CLI. This prototype also does not provide matched native/L1 execution,
observer CPU/I/O/latency/storage measurement, or an eligible C1 run.