Skip to content

Record Claude StopFailure events - #330

Closed
myobie wants to merge 2 commits into
mainfrom
agent/stop-failure-records
Closed

Record Claude StopFailure events#330
myobie wants to merge 2 commits into
mainfrom
agent/stop-failure-records

Conversation

@myobie

@myobie myobie commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Append every Claude StopFailure event to one private JSONL file per st2 identity.
  • Store UTC timestamp, identity, normalized error_type, and the sanitized provider payload.
  • Read the current provider error field and the legacy error_type field.
  • Redact sensitive fields, bearer values, known token prefixes, JWTs, and opaque credential-shaped strings before writing.
  • Bound a large sanitized payload to a 16,384-character preview.
  • Record invalid JSON without copying its raw bytes.
  • Record before presence and notification filters.
  • Keep record, presence, and notification failures fail-open.

The record path is:

${XDG_STATE_HOME:-$HOME/.local/state}/st2/hook-events/stop-failure/<safe-identity>.jsonl

The directory uses mode 0700. Each record file uses mode 0600.

Why

The prior hook changed presence and could notify a declared supervisor. It wrote no durable evidence.

An agent without a supervisor produced no notification. Filtered error types also left no record. Operators could not count repeated provider failures without scanning transcripts.

User impact

A deployed hook set creates a queryable local failure history without changing the Claude hook response. Existing presence and supervisor actions remain.

The hook-set hash changes. Operators must select it through the normal st2 hooks install flow during deployment.

Proof

Commit 411dbe4 contains the red regression. Its exact test fails because the successful hook creates no JSONL file.

The green tests prove:

  • one append per event;
  • no supervisor requirement;
  • exact private modes;
  • current and legacy error fields;
  • reaction filtering after recording;
  • recursive field and token redaction;
  • invalid-input suppression;
  • fail-open behavior on an unwritable state path.

Checks:

  • bash -n hooks/claude-stop-failure.sh
  • cargo test --test claude_hooks — 9 passed.
  • cargo test --test hooks — 11 passed.
  • cargo test --test codex_hooks — 5 passed.
  • cargo test --lib — 451 passed.
  • Scoped strict Clippy passes after allowing current-main library lints.
  • git diff --check origin/main...HEAD

The full workspace run reaches the current-main incomplete_apply_marker_blocks_declarations_but_not_the_state_plane failure. The exact test fails unchanged on origin/main. The current-main native-surface test and rustfmt drift also reproduce unchanged on origin/main.

Hosted Nix run 32746034451 passed at 6086795.

This PR stays draft. Nathan owns the ready-for-review and merge gates.

@myobie
myobie force-pushed the agent/stop-failure-records branch from 636bb01 to 6086795 Compare August 24, 2026 15:37
@schickling-assistant

Copy link
Copy Markdown
Contributor

Superseded by merged first-class Claude harness state and unified OpenTelemetry diagnostics. A separate StopFailure JSONL would create another telemetry source of truth.

Posted on behalf of @schickling
field value
agent_identity dev3.direct.omp.jmg9x29x
session dev3.jmg9x29x
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.11
agent_runtime OMP 18.0.11
tooling_profile dotfiles@2161b9c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants