fabro/lib/crates
fabro-sh-0530[bot] 01892185ff
Replace bare unwrap() with documented expect() across production runtim… (#415)
Audit and remediation pass enforcing the project's
no-panic-in-production policy. Every `unwrap()` on a mutex/RwLock in
reachable runtime code is replaced with `expect()` carrying a message
that explains *why* the lock cannot be poisoned (no code panics while
holding it). Bare `unreachable!()` and `panic!()` calls are updated with
messages that name the invariant being asserted. One genuine bug is
fixed in the process.

## What changed

**`unwrap()` → `expect()` on locks** (`fabro-core`, `fabro-oauth`,
`fabro-util`, `fabro-workflow/*`, `fabro-server`): Every
`Mutex`/`RwLock` `.unwrap()` in production paths now carries the
standard justification pattern: `"<name> mutex/RwLock should not be
poisoned: no code panics while holding this lock"`.

**`unreachable!()` and `panic!()` message quality**: Bare
`unreachable!()` calls in `subagent.rs`, `wait.rs`, `condition.rs`,
`event/convert.rs`, and `server.rs` now name the structural invariant
(e.g. "outer match arm already verified…"). The `panic!` in `tools.rs`
now includes the offending name and the expected format, making it
actionable.

**`sha_newtype` / `short_sha_newtype` in `run_files.rs` — actual bug
fix**: These helpers previously called `unwrap_or_else(|e| panic!(…))`
on git output, meaning a malformed SHA from a real git subprocess would
panic in a request handler. They now return `Result<T, ApiError>` and
propagate errors to callers, which in turn propagate with `?`. This is
the only change that alters observable behavior under failure.

**Demo-only panics in `fabro-server/src/demo/mod.rs`**: Panic messages
updated to clarify that these paths operate on hardcoded compile-time
constants, so the panic is a programming-error guard rather than a
runtime failure guard.

## Design note

The lock-poisoning `expect` messages all follow a single template so
reviewers can quickly verify the claim: if you ever add code that can
panic inside a lock guard scope, the message becomes a lie and that must
be caught in review. The uniformity is intentional.


### Fabro Details

<details>
<summary>Ran 0 stages in 64m 54s for $14.28</summary>

| Stage | Duration | Cost | Retries |
|---|---|---|---|
| **Total** | **64m 54s** | **$14.28** | **0** |

</details>

<details>
<summary>Ran <code>Goal.fabro</code> (4 nodes and 5 edges)</summary>

```dot
digraph Goal {
    graph [
        goal="Complete the user-provided goal",
        rankdir=LR,
        max_node_visits=30
    ]

    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare, label="Exit"]

    work [
        label="Work",
        thread_id="goal",
        fidelity="full",
        max_visits=12,
        prompt="@prompts/continue.md"
    ]

    audit [
        label="Completion Audit",
        thread_id="goal",
        fidelity="full",
        goal_gate=true,
        retry_target="work",
        output_schema="routing",
        output_retries=2,
        max_visits=12,
        prompt="@prompts/audit.md"
    ]

    start -> work -> audit

    audit -> exit [label="Done", condition="outcome=succeeded"]
    audit -> work [label="Continue", condition="outcome=failed || preferred_label=Continue"]
    audit -> work [label="No clear verdict"]
}

```

</details>

⚒️ Generated with [Fabro](https://fabro.sh)

---------

Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
2026-05-26 17:46:39 -04:00
..
build-support fix(build): refresh embedded git sha on branch commits 2026-05-09 14:10:04 -04:00
fabro-acp fix(workflow): capture configured artifacts once (#337) 2026-05-21 10:52:22 -04:00
fabro-agent Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-api Add provider-backed sandbox inventory API and rename SandboxProvider to… (#409) 2026-05-25 22:41:57 -04:00
fabro-auth refactor: rationalize server secret scopes (vault-only for optional int… (#401) 2026-05-25 17:26:01 -04:00
fabro-checkpoint Make git metadata sandbox-native 2026-04-27 21:43:15 -07:00
fabro-cli Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-client feat: Add approve/deny run controls to MCP and CLI (#400) 2026-05-25 15:49:57 -04:00
fabro-config refactor: rationalize server secret scopes (vault-only for optional int… (#401) 2026-05-25 17:26:01 -04:00
fabro-core Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-dev feat: add [run.agent] fabro_tools opt-in for worker run tools (#348) 2026-05-22 09:41:27 -04:00
fabro-devcontainer refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-dump Add provider-backed sandbox inventory API and rename SandboxProvider to… (#409) 2026-05-25 22:41:57 -04:00
fabro-github fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-graphviz fix(graph): support dotted Fabro graph attributes (#324) 2026-05-20 09:31:08 -04:00
fabro-hooks Add event-sourced todo tools for OpenAI and Anthropic profiles (#353) 2026-05-22 13:44:42 -04:00
fabro-http refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-install Add provider-backed sandbox inventory API and rename SandboxProvider to… (#409) 2026-05-25 22:41:57 -04:00
fabro-interview Migrate sandbox config to named environments; add InterviewOption metad… (#372) 2026-05-23 15:47:33 -04:00
fabro-llm Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-macros refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-manifest Replace run-scoped sandbox config with named environments (#360) 2026-05-23 13:03:21 -04:00
fabro-mcp Add legacy SSE MCP transport support (#386) 2026-05-24 15:29:01 -04:00
fabro-mcp-server feat: Add approve/deny run controls to MCP and CLI (#400) 2026-05-25 15:49:57 -04:00
fabro-model fix(model): retire GPT-5.2 and GPT-5.3 catalog entries (#412) 2026-05-26 00:06:50 -04:00
fabro-oauth Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-options-metadata refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-proc refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-redact refactor(integrations): make chat integrations Slack-only 2026-05-09 11:43:16 -04:00
fabro-sandbox Add provider-backed sandbox inventory API and rename SandboxProvider to… (#409) 2026-05-25 22:41:57 -04:00
fabro-server Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-slack Improve Slack setup and lifecycle notifications (#391) 2026-05-24 16:54:25 -04:00
fabro-spa feat(dev): gitignore embedded spa assets 2026-04-26 21:31:11 -04:00
fabro-static refactor: rationalize server secret scopes (vault-only for optional int… (#401) 2026-05-25 17:26:01 -04:00
fabro-store Add provider-backed sandbox inventory API and rename SandboxProvider to… (#409) 2026-05-25 22:41:57 -04:00
fabro-telemetry refactor(workflow): remove retro stage (#230) 2026-05-09 10:18:20 -04:00
fabro-template feat(template): resolve template error locations (#333) 2026-05-20 20:15:04 -04:00
fabro-test fix(skills): Ensure the local server can access project skills (#383) 2026-05-24 13:22:00 -04:00
fabro-tool feat: Add approve/deny run controls to MCP and CLI (#400) 2026-05-25 15:49:57 -04:00
fabro-tracker fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-types Add provider-backed sandbox inventory API and rename SandboxProvider to… (#409) 2026-05-25 22:41:57 -04:00
fabro-util Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-validate fix(graph): support dotted Fabro graph attributes (#324) 2026-05-20 09:31:08 -04:00
fabro-vault refactor: rationalize server secret scopes (vault-only for optional int… (#401) 2026-05-25 17:26:01 -04:00
fabro-workflow Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00