Expand description
btctax-cli: the CLI + reconciliation library that wires the encrypted vault (btctax-store),
ingest (btctax-adapters), and the pure projection (btctax-core) into the Phase-1 command surface
(spec §11). The library is I/O-explicit and deterministic; the binary (main.rs) is a thin clap
dispatch. PRIVACY: tests use only temp vaults + synthetic fixtures; no real user file is ever read.
Re-exports§
pub use cli::Cli;pub use cmd::tranche::guard_allocation_vs_tranche;pub use cmd::promote::PROMOTE_ACK_PHRASE;pub use cmd::promote::ProvenanceKind;pub use cmd::promote::PROVENANCE_TEXT;pub use cmd::admin::promote_export_gate;pub use cmd::admin::IrsPdfReport;pub use chokepoint::apply_declare;pub use chokepoint::plan_declare;pub use chokepoint::DeclarePlan;pub use chokepoint::Refusal;pub use chokepoint::apply_promote;pub use chokepoint::plan_promote;pub use chokepoint::render_consent;pub use chokepoint::PromotePlan;pub use config::CliConfig;pub use session::BulkFilter;pub use session::BulkIncomeFilter;pub use session::BulkIncomePlan;pub use session::BulkIncomeRow;pub use session::BulkLinkPlan;pub use session::BulkLinkRow;pub use session::BulkReclassifyOutflowPlan;pub use session::BulkReclassifyOutflowRow;pub use session::BulkResolvePlan;pub use session::BulkResolveRow;pub use session::BulkStiFilter;pub use session::BulkStiPlan;pub use session::BulkStiRow;pub use session::BulkVoidPlan;pub use session::BulkVoidRow;pub use session::Frame;pub use session::MatchAction;pub use session::MatchProposal;pub use session::Session;
Modules§
- bulk_
estimated bulk_estimated_proceedsside-table — flags each disposal whose proceeds were derived from an auto-FMV (daily-close market value) by the bulk-reclassify-outflow path, rather than a real user-entered sale price. Keyed by theEventId::canonical()string of thetransfer_out_event, which IS the eventualDisposal.event(fold pushesDisposal{event: eff.id.clone()}using the ORIGINAL TransferOut id — so the Disposals-tab join lands). Modeled ondonation_details.rs/optimize_attest.rsdiscipline (idempotent DDL, defensiveinit_tableguard on every accessor).- chokepoint
- Defensive Filing Wizard, sub-project-2 Phase P-A, Task 1 — the PROMOTE chokepoint: a reusable
plan/confirm/apply pipeline extracted VERBATIM from the shipped CLI verb
(
cmd::promote::promote_tranche, Approach-B Task 10,cmd/promote.rs:364-488) so a future TUI can drive the EXACT SAME gated pipeline as the CLI.cmd::promote::promote_trancheis now a thin driver over this module:Session::open→ build args →plan_promote(mapRefusal→CliError) →println!("{}", render_consent(&plan))→ prompt/collect ack →apply_promote. - cli
- The clap-4 command surface for
btctax, extracted into the library so tooling (thextaskman-page generator) can obtain theCommandviaCli::command()(clap::CommandFactory). The binary (main.rs) is a thin dispatch over these types. - cmd
- config
- The CLI’s persisted projection-config knob (TP8 self-transfer fee treatment + lot method), stored
in a
cli_config(key,value)table inside the vault DB. It is a projection input parameter, not ledger state (NFR6): the event log remains the sole source of truth; this only selects a swappable rule. TP8 default is (c), USER-MANDATED — never default to (b). - donation_
details donation_detailsside-table — persists Form 8283 Section-B appraiser + structured-donee metadata for each donation event. Keyed by the donation’sEventId::canonical()string. Modeled onoptimize_attest.rsdiscipline (idempotent DDL, defensiveinit_tableguard on every accessor, JSON storage via serde_json — same astax_profile.rs). The data is POST-HOC form-completion metadata; it does NOT enter the fold or projection.- eventref
- Parse CLI references back into core types. The primary case is the canonical
EventIdstring the engine prints (EventId::canonical()):import|<src>|<source_ref…>,conflict|<src>|<source_ref…>|<fp>,decision|<seq>.source_refitself may contain|(adapters mint direction-scoped refs likeout|cb-send), so import rejoins parts[2..] and conflict takes the LAST part as the fingerprint. - input_
form_ store - Per-year
return_inputs_draft(year, inputs_json, schema_version, parked)side-table — the input form’s crash-recovery scratch, INVISIBLE toresolve.rs.parked = 1marks a parked committed return (C-1). - optimize_
attest optimize_attestationside-table — persists the user’s per-disposal contemporaneous-ID attestations (a projection input, not ledger state). Theattested_setaccessor feeds thecompliance_overlayas itsattested: &BTreeSet<EventId>argument;getreturns the stored attestation text so the overlay can enforce attested-binds-the-exact-selection (R2-I1: a later divergent pick is NOT covered). Modeled ontax_profile.rsdiscipline (idempotent DDL, defensive guard on every accessor, BTreeSet for NFR4 determinism).- price_
cache - Resolve the local price-cache path (#41 Part C).
dirslives HERE (and inbtctax-update-prices), NOT in btctax-adapters [R0-M2/r2 M-A] — the adapter’sLayeredPricestakes an ALREADY-resolvedcache_pathand stays a pure format/provider crate (nodirs, no network). The cache is a documented LOCAL INPUT the offline projection layers OVER the bundled dataset; it is populated ONLY by the separatebtctax-update-pricesbinary, so btctax-cli itself carries NO network dependency. - render
- Text rendering of CLI outputs (FR9 verify, FR4 report/show) + FR10 CSV export. Pure string-building over engine data — the CLI displays; the engine computes (NFR4/NFR5).
- resolve
- Single profile-source resolver (full-return v1, SPEC §4.12 / G4).
- return_
inputs - Per-year
return_inputs(year, inputs_json)side-table — the full-return v1 input surface (line items + PII + payments). A projection input, not ledger state (NFR6). Mirrorstax_profile.rsexactly (idempotent DDL, robust-to-older-vaults guard, typed error on bad JSON) — one JSON-encodedReturnInputsper tax year, stored inside the encrypted vault. - session
Sessionwraps one openbtctax_store::Vaultand is the single seam every command opens. The passphrase is ALWAYS a parameter — production resolves it inmain(prompt/env); tests inject a constructedPassphrase.project()runs the pure core projection over the bundled price dataset.- tax_
profile - Per-year
tax_profile(year, profile_json)side-table — a projection input, not ledger state (NFR6). Stores one JSON-encodedTaxProfileper tax year. Modeled onconfig.rs’scli_configside-table discipline (idempotent DDL, robust-to-older-vaults guard, typed error on bad JSON). Called bySession::from_fresh_vaultand as a defensive guard at the top of every read/write (same pattern asconfig::init_config_table/config::read_config). - testonly
- Shared synthetic corpora + per-journey fixtures for the worked-example journeys (J1–J9).
Enums§
Constants§
- ATTEST_
PHRASE - The exact phrase a user must affirm to export a form/data file while the ledger is pseudo-reconciled
(sub-project 3). Compared TRIMMED, case-SENSITIVE, exact. The prompt + both error strings are BUILT
from this constant [R0-M1] so there is no drift (a KAT asserts they contain it).
pubso btctax-tui shares it [R0-r2-N2]. - EXPORT_
OUT_ HINT - UX-P4-8 hint: shown when an export
--outdirectory cannot be created (a colliding file, a missing parent, or a permission problem). - VAULT_
OPEN_ HINT - UX-P4-8 hint: shown when a
--vaultcannot be opened (missing/unreadable path).
Functions§
- cli_
io_ with_ path - Re-wrap a pathless I/O failure with the offending PATH + a one-clause hint (UX-P4-8). Enriches
BOTH shapes an export write can produce: a raw
CliError::Io(awrite/flushmid-write) AND aCliError::Store(StoreError::Io)(amkdir_owner_only/open_owner_onlyunderout_dir— e.g. a SUBPATH collision likeout_dir/lots.csvalready existing as a directory, which?-converts throughFrom<StoreError>). ACliError::Csv(a serialization error, not a path problem) and every other variant pass through unchanged. - require_
attestation - PURE exact-compare attestation gate — NO I/O, NO TTY read [R0-I2]. The interactive prompt lives in
the caller (the
export-snapshotmain.rs arm / the btctax-tui export modal); this helper only compares, keeping the library I/O-explicit and the KATs deterministic (no env-dependent branch). - store_
io_ with_ path - Re-wrap a
StoreErrorI/O failure with the offending PATH + a one-clause hint (UX-P4-8). ONLY the pathlessStoreError::Iois enriched; every other variant (WrongPassphrase,Locked,HalfCreatedVault, …) passes through unchanged — each already carries its own precise meaning and must NOT be masked behind a generic path/hint.