Twinned from https://github.com/cfsh/ninefold/issues/1141 by tools/beads/import_github.py's reconcile pass.
Suggestions from ninefold-reviewer's review of #1106
Two low-severity findings, same class, neither blocking merge: a newly-added verb crashes with a raw Python traceback instead of a clean CLI error, on a rare precondition failure dev.py's established except PlumbingFailed/except ContractBroken convention does not cover.
- _bd()'s resolve_beads_workspace() call can raise sessions.ReapRefused, uncaught. tools/nflib/devcli.py's _bd() helper (used by claim/release/say) calls resolve_beads_workspace(Git(cwd=ROOT, runner=seam)), which raises sessions.ReapRefused (not PlumbingFailed) if git worktree list --porcelain fails or lists no working tree (tools/nflib/sessions.py:459-465,490-491). devcli.main()'s dispatcher only catches PlumbingFailed/ContractBroken (devcli.py:2242-2248). Every other consumer of sessions.ReapRefused in this codebase catches it explicitly (merge_pr.py:1108,1505,1554, session_state.py:362, wrap_up.py:322,511) - this is the one call site of that pattern that does not. Fix: add except sessions.ReapRefused to main() alongside the existing handlers, same message shape.
- dev.py say's --body-file read has no error handling. verb_say (devcli.py:2141-2161) passes args.body_file straight into gh.comment_file()/bd.comment(), both doing an unguarded Path(body_file).read_text(...). A typo'd path crashes with a raw traceback instead of the clean dev.py say: <error> a bad path should produce. verb_pr reads the same --body-file/-F flag and wraps it in try/except OSError (devcli.py:1220-1228) - the established pattern for this exact flag in this exact file; verb_say does not reuse it.
Both are worth fixing in one pass, since they are the same 'new verb code does not reuse this file's established exception-handling convention' class.
None.
Both findings fixed in tools/nflib/devcli.py:
sessions.ReapRefused(raised by_bd()'sresolve_beads_workspace()call on agit worktree listfailure), alongside the existingPlumbingFailed/ContractBrokenhandlers — samef"dev.py: {exc}"message shape and exit code 2 as every other catch site for this exception (merge_pr.py, session_state.py, wrap_up.py).--body-fileconvention (devcli.py's established pattern) — a typo'd path now printsdev.py say: --body-file <errno message>and returns 2 instead of a raw traceback.Added regression tests in devcli_test.py's ClaimReleaseSayVerbTest: test_claim_wraps_reap_refused_from_the_bd_seam (worktree-list failure → clean exit 2, no traceback) and test_say_with_a_missing_body_file_fails_cleanly.