feat(goose): instrument goose_json.ask() failures + triage failure counter (failure-record schema v1) #248
Labels
No labels
burndown-2026-06
coherence-core
consult
headless
interactive
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
coilyco-flight-deck/agentic-os#248
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Goose's tool-use error rate is the motivating pain, and it is currently unmeasurable by construction. Two layers of masking:
Layer 1 - the wrapper discards the evidence.
scripts/goose_json.pyask()is the single boundary every triage call passes through. It runs:It captures
.stderrand.returncodeand throws both away, keeping only.stdout. Every distinct failure (provider 5xx, rate-limit, panic, malformed envelope, schema-invalid reply, timeout) collapses into one undifferentiatedreturn None.GOOSE_BASEalso passes--no-session, so none of it lands in~/.local/share/goose/sessions/sessions.dbeither.Layer 2 - triage launders the
Noneinto a plausible default.scripts/goose-triage.pyfail-softs everyNone:"unscored -> default 30",MODE_DEFAULT = "consult", runoff failure keeps issue order. A failed model call surfaces as a wrong-but-valid label, not a failure. The cached report'sfailed: 0measures label-write success, not Goose-call success.Why this issue is the foundation
Goose here is already 100% ward-routed (every call is a ward-exec'd subprocess), and the failure data is already in hand at one Python function. The fix is to stop discarding
.returncode/.stderr. This issue also defines the failure-record schema v1 that the Claude-transcript drain (issue B) and the GlitchTip shipper (issue C) both consume.Scope
goose_json.ask(). Keep.returncodeand.stderr. Classify each failure into the taxonomy already latent in the code:timeout(TimeoutExpired)nonzero_exit(returncode != 0 - currently ignored; likely where provider / rate-limit / panic errors hide in Goose's stderr)bad_envelope(JSONDecodeErroron the envelope)no_schema_valid_message(envelope parsed, nothing satisfied the schema)exhausted_retries(all N attempts failed)~/.cache/agentic-os/tool-failures/<repo-slug>.jsonl. No network in this issue - local buffer only.goose-triage. The fail-soft defaults stay as resilience, but the substitution must be counted: add agoose_failuresblock to the report, per pass (P0-confirm / urgency / runoff / mode), separate from the label-writefailed.failure-record schema v1 (proposed)
One JSON object per line:
fingerprintcollapses a flood of identical failures into one counted bucket - the field that finally answers "which failure mode dominates."Done condition
ask()failure path writes one classified failure-record to the buffer.goose-triagereport carries a realgoose_failurescount per pass.ward exec testgreen; the failure-record schema documented indocs/goose-triage.md.Out of scope (separate issues)
sessions.dbdrain for the interactive Goose slice.Origin: design session 2026-06-18. Hooks were empirically ruled out as a failure source (Claude Code PostToolUse does not fire on failure and carries no exit code); the harness-specific sources are the transcript (Claude) and the wrapper boundary (Goose).