Unhappy Path Audit
Audit failure behavior in order. Reachability comes before severity.
Task
$ARGUMENTS
First Principles
| Gate |
Question |
Common failure |
| R0: changed path |
What code path changed? |
Auditing stale or unrelated code |
| R1: reachability |
Can the path execute under current config/capabilities/modes? |
Filing dead code as a bug |
| R2: correctness |
When reached, does error/state/resource handling do the right thing? |
Misclassification, dropped error, leak, hang |
| R3: consequence |
What concrete behavior breaks? |
Wrong severity |
Resource safety is a subset of R2:
| Check |
Proposition |
| Q1 |
Every created resource has a guaranteed cleanup path |
| Q2 |
Every blocking wait has a guaranteed release/cancel/timeout path |
| Q3 |
Every accumulation has a bound, backpressure, or recycling point |
Only apply Q1-Q3 to resources touched by the change.
Step 1: Establish R0
git status --short
git diff --stat
git diff --name-only
For branch or commit targets, use the requested range and inspect the full diff.
Group changed paths by owner:
- Runtime/server/delegation/run lifecycle.
- Services/storage/journal/tasks/restore/sync.
- Turn/tool/prompt/skill selection.
- CLI/TUI/SDK/frontend.
- Tests and docs.
Step 2: Prove R1 Reachability
For every candidate finding, trace:
entrypoint -> caller -> changed branch -> config/capability/feature/mode gate -> execution path
Astra gates to check:
- capability surface and tool visibility;
- runtime config/env defaults;
- feature flags and mode switches;
- session/run/task status;
- delegation pause/cancel/retry state;
- cloud/local/offline DB availability;
- skill source visibility (
.claude, .agent, server HOME, skills_registry).
If no current entrypoint reaches the code, report it as a dead-path note, not a bug.
Step 3: Audit R2 Correctness
Classification:
- Are error categories preserved across boundaries?
- Are retryable, user-fixable, and fatal errors distinguished?
- Does a fallback hide the original cause?
Propagation:
- Does the caller see enough context to recover or report accurately?
- Are journal events, task status, and HTTP/CLI status consistent?
State:
- Are transitions valid from every previous state?
- Are duplicate, stale, out-of-order, and cancellation cases handled?
- Is persistent state written atomically enough for restore/sync?
- Can any consumer derive terminal state from a child/transport event, lookup
miss, timeout, or cached projection instead of the producer-owned lifecycle?
- For grouped work, can one slot transition trigger parent analysis before the
fixed-size group settles, or can several slot transitions schedule duplicate
wakes?
Resource:
- Are tasks joined/cancelled?
- Are channels bounded or drained?
- Are locks held across await points?
- Is accumulation bounded by size, count, time, or compaction?
Step 4: Assign R3 Severity
Use severity only after R1 and R2 are proven.
| Severity |
Bar |
| Critical |
Reachable in default/common config and causes incorrect behavior, data loss, security issue, hang, or unrecoverable task/session state |
| Important |
Reachable under a real configuration and causes user-visible failure or missing recovery evidence |
| Low / note |
Reachable but minor, or unreachable design debt worth tracking |
Group causally related symptoms into one finding. Do not split one root cause into multiple findings.
Output Contract
Critical:
- <file:line> <reachable path> -> <failure> -> <consequence>
Important:
- <file:line> ...
Low / Notes:
- <dead path or low-impact issue>
Verified OK:
- <risky path checked and why it is safe>
Unknowns:
- <missing evidence, if any>
Every finding must include the reachability chain or it does not belong in the report.
1---2name: unhappy-path-audit3description: Reachability-first unhappy-path audit for changed Astra code paths: dead paths, error propagation, state consistency, resource leaks, hung waits, and unbounded accumulation.4---56# Unhappy Path Audit78Audit failure behavior in order. Reachability comes before severity.910## Task1112$ARGUMENTS1314## First Principles1516| Gate | Question | Common failure |17| --- | --- | --- |18| R0: changed path | What code path changed? | Auditing stale or unrelated code |19| R1: reachability | Can the path execute under current config/capabilities/modes? | Filing dead code as a bug |20| R2: correctness | When reached, does error/state/resource handling do the right thing? | Misclassification, dropped error, leak, hang |21| R3: consequence | What concrete behavior breaks? | Wrong severity |2223Resource safety is a subset of R2:2425| Check | Proposition |26| --- | --- |27| Q1 | Every created resource has a guaranteed cleanup path |28| Q2 | Every blocking wait has a guaranteed release/cancel/timeout path |29| Q3 | Every accumulation has a bound, backpressure, or recycling point |3031Only apply Q1-Q3 to resources touched by the change.3233## Step 1: Establish R03435```bash36git status --short37git diff --stat38git diff --name-only39```4041For branch or commit targets, use the requested range and inspect the full diff.4243Group changed paths by owner:4445- Runtime/server/delegation/run lifecycle.46- Services/storage/journal/tasks/restore/sync.47- Turn/tool/prompt/skill selection.48- CLI/TUI/SDK/frontend.49- Tests and docs.5051## Step 2: Prove R1 Reachability5253For every candidate finding, trace:5455```text56entrypoint -> caller -> changed branch -> config/capability/feature/mode gate -> execution path57```5859Astra gates to check:6061- capability surface and tool visibility;62- runtime config/env defaults;63- feature flags and mode switches;64- session/run/task status;65- delegation pause/cancel/retry state;66- cloud/local/offline DB availability;67- skill source visibility (`.claude`, `.agent`, server HOME, `skills_registry`).6869If no current entrypoint reaches the code, report it as a dead-path note, not a bug.7071## Step 3: Audit R2 Correctness7273Classification:7475- Are error categories preserved across boundaries?76- Are retryable, user-fixable, and fatal errors distinguished?77- Does a fallback hide the original cause?7879Propagation:8081- Does the caller see enough context to recover or report accurately?82- Are journal events, task status, and HTTP/CLI status consistent?8384State:8586- Are transitions valid from every previous state?87- Are duplicate, stale, out-of-order, and cancellation cases handled?88- Is persistent state written atomically enough for restore/sync?89- Can any consumer derive terminal state from a child/transport event, lookup90 miss, timeout, or cached projection instead of the producer-owned lifecycle?91- For grouped work, can one slot transition trigger parent analysis before the92 fixed-size group settles, or can several slot transitions schedule duplicate93 wakes?9495Resource:9697- Are tasks joined/cancelled?98- Are channels bounded or drained?99- Are locks held across await points?100- Is accumulation bounded by size, count, time, or compaction?101102## Step 4: Assign R3 Severity103104Use severity only after R1 and R2 are proven.105106| Severity | Bar |107| --- | --- |108| Critical | Reachable in default/common config and causes incorrect behavior, data loss, security issue, hang, or unrecoverable task/session state |109| Important | Reachable under a real configuration and causes user-visible failure or missing recovery evidence |110| Low / note | Reachable but minor, or unreachable design debt worth tracking |111112Group causally related symptoms into one finding. Do not split one root cause into multiple findings.113114## Output Contract115116```text117Critical:118- <file:line> <reachable path> -> <failure> -> <consequence>119120Important:121- <file:line> ...122123Low / Notes:124- <dead path or low-impact issue>125126Verified OK:127- <risky path checked and why it is safe>128129Unknowns:130- <missing evidence, if any>131```132133Every finding must include the reachability chain or it does not belong in the report.