If `graphify extract --backend claude` runs without the `anthropic`
package installed (pip install graphifyy doesn't pull it in), every
semantic chunk fails inside extract_corpus_parallel. The per-chunk
errors print to stderr but the function returns the empty merged
accumulator anyway, so extract proceeds to write an AST-only graph.json
and exit 0. CI that checks exit status sees success even though the
requested semantic pass produced no nodes.
Track per-chunk success via the existing on_chunk_done callback, which
only fires after a chunk succeeds. If fresh extraction was requested
(uncached_paths non-empty) and zero chunks completed, abort before the
merge/cluster/write phase with exit 1 and a message naming the backend.
The same shape covers other backends with optional SDK deps (openai,
google-generativeai). Cached-only runs are unaffected: uncached_paths
is empty and the guard does not fire.
Tests in tests/test_extract_cli.py simulate the all-failed and
one-succeeded paths by patching extract_corpus_parallel directly.