7b9d84be87
The `alpha-id index --pack` writer logic — store-completeness check, row
collection in corpus order, header derivation (dim/corpus_name/corpus_sha256/
n_rows), and the write — lived inline in main, leaving the header construction
outside library test reach (covered only end-to-end via the pack CLI tests).
This extracts it into packed::pack_from_store, returning
PackOutcome { Packed(PackedHeader), Incomplete { cached, total } }. main's pack
branch now just loads entries, calls the fn, and matches the outcome onto the
same stderr messages and exit code 2 as before.
Behaviour is unchanged: the stderr lines ("store incomplete: N of M entries
embedded; run `index --full --confirm` first" and "packed N rows × D dims →
path") and the exit-2 refusal are byte-identical, and the four existing pack
CLI tests (pack_refuses_incomplete_store_exit_2, pack_writes_file_from_complete_store,
cli_packed_file_loads_back_as_ok_index, cli_packed_rows_are_in_corpus_order)
stay green unchanged as the behaviour-parity guard. Two new unit tests now
exercise the header construction directly without spawning the binary: a
complete store yields PackOutcome::Packed with the expected n_rows/dim/
embed_model/corpus_sha256 and writes the file; an incomplete store yields
PackOutcome::Incomplete { cached, total } and writes nothing.
Minor improvement folded in: the old inline `store.get(...).expect("cached
vector")` is now a propagated AppError inside pack_from_store rather than a
panic (the branch stays unreachable — the complete-store precondition is
checked first — so parity holds).
This is the debt tidy the cycle-close audit deferred (architect [low] finding).
87 tests green.
closes #5
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>