1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
//! 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.
pub use Cli;
// Re-exported at the crate root so the TUI editor (`btctax-tui-edit`) can call it WITHOUT the `cmd::`
// token its KAT-G1 source gate forbids in non-test code. That gate exists to keep session-lifecycle /
// lock-holding `cmd::` fns out of the held-session editor; `guard_allocation_vs_tranche` is a PURE
// `&[LedgerEvent] -> Result` predicate — no `Session`, no lock, no I/O — so the gate's intent is honored,
// not evaded. Any FUTURE addition here must be equally pure (do NOT re-export a session-opening fn).
pub use guard_allocation_vs_tranche;
// Re-exported at the crate root mirroring `ATTEST_PHRASE` (below): a plain, distinct consent-phrase
// constant, not a `cmd::`-scoped session/lock fn, so it belongs beside the other top-level phrase gates.
pub use PROMOTE_ACK_PHRASE;
// Re-exported at the crate root (Defensive Filing Wizard Task 9) alongside `PROMOTE_ACK_PHRASE`: the
// TUI Promote flow (`btctax-tui-edit`'s `edit/promote_flow.rs`) needs `ProvenanceKind::Purchase` to call
// `plan_promote` WITHOUT the `cmd::` token its KAT-G1 source gate forbids in non-test code, and
// `PROVENANCE_TEXT` to show the filer what BG-D5 attestation is being made on their behalf. Both are
// plain data (a `Copy` enum; a `&'static str`) — no `Session`, no lock, no I/O.
pub use ;
// Re-exported at the crate root so the TUI export path (`btctax-tui::export::do_export`) can call the
// BG-D8 completeness gate WITHOUT the `cmd::` token its KAT-E10 source gate forbids in non-test code
// (Approach-B Task 17). Like `guard_allocation_vs_tranche` above, this is a PURE
// `(&LedgerState, &[LedgerEvent], Option<i32>) -> Result` predicate — no `Session`, no lock, no I/O — so
// the gate's intent (keep session-lifecycle `cmd::` fns out of the held-session viewer) is honored, not
// evaded. Any FUTURE addition here must be equally pure (do NOT re-export a session-opening fn).
pub use promote_export_gate;
// Re-exported at the crate root (Defensive Filing Wizard Task 3, ★ arch-n-1) so a future TUI export
// surface (`btctax-tui-edit`'s `persist.rs`, Task 10) can name `IrsPdfReport` WITHOUT the `cmd::` token
// its KAT-G1 source gate forbids in non-test code (mirrors `promote_export_gate` above). `IrsPdfReport`
// is a plain data struct (no `Session`, no lock, no I/O) — the gate's intent is honored, not evaded.
pub use IrsPdfReport;
// Re-exported at the crate root (Defensive Filing Wizard Task 8, ★ C-3) so the TUI Declare flow
// (`btctax-tui-edit`'s `edit/declare_flow.rs` + `edit/persist.rs`) can drive the DECLARE chokepoint
// WITHOUT the `cmd::` token its KAT-G1 source gate forbids in non-test code — mirrors
// `promote_export_gate`/`IrsPdfReport` above. `plan_declare` is a pure `(events, prices, cfg, ...) ->
// Result` planner (no `Session`, no lock, no I/O); `DeclarePlan`/`Refusal` are plain data types.
// `apply_declare` DOES touch the mutation surface (`append_decision` + `session.save()`) — it is
// re-exported here ONLY so `edit/persist.rs`'s `persist_declare_tranche` wrapper can reach it (KAT-G1's
// `persist_only_tokens` confines the LITERAL `apply_declare(` call token to that one file crate-wide;
// re-exporting the name itself does not weaken that confinement — the gate scans call sites, not
// import lists). Any FUTURE addition here must be equally justified (do NOT re-export a second
// session-opening or unconfined-write fn).
pub use ;
// Re-exported at the crate root (Defensive Filing Wizard Task 9, ★ C-3) so the TUI Promote flow
// (`btctax-tui-edit`'s `edit/promote_flow.rs` + `edit/persist.rs`) can drive the PROMOTE chokepoint
// WITHOUT the `cmd::` token its KAT-G1 source gate forbids in non-test code — mirrors the
// `plan_declare`/`DeclarePlan`/`apply_declare` re-export directly above. `plan_promote`/`render_consent`
// are pure `(events, ...) -> Result` / `(&PromotePlan) -> String` fns (no `Session`, no lock, no I/O);
// `PromotePlan` is a plain data type; `Refusal` is ALREADY re-exported above (the SAME shared enum both
// `plan_declare` and `plan_promote` return). `apply_promote` DOES touch the mutation surface — it is
// re-exported here ONLY so `edit/persist.rs`'s `persist_promote_tranche` wrapper can reach it (KAT-G1's
// `persist_only_tokens` confines the LITERAL `apply_promote(` call token to that one file crate-wide;
// re-exporting the name itself does not weaken that confinement — the gate scans call sites, not import
// lists). Any FUTURE addition here must be equally justified (do NOT re-export a second session-opening
// or unconfined-write fn).
pub use ;
// (The composed multi-year EXPORT chokepoint — `plan_export`/`apply_export`/`ExportPlan`/`ExportOutcome`
// /`ExportOutcomes` — was re-exported here for the TUI wizard's export step. Both the wizard and the trio
// were removed in 0.13.0: the owner ruled that amending several prior years at once is not a real
// workflow, and after the wizard's deletion the trio had zero callers from any shipped surface. Single-year
// export is unchanged and lives where it always did, in `cmd::admin`'s `export_irs_pdf`. Note that
// `btctax_core::conservative::flagged_years` — which the trio composed over — is a SEPARATE, still-live
// symbol: `btctax defensive status` reports its year set so a filer knows which years to re-export by hand.)
pub use CliConfig;
pub use ;
/// UX-P4-8 hint: shown when a `--vault` cannot be opened (missing/unreadable path).
pub const VAULT_OPEN_HINT: &str =
"check the --vault path, or run `btctax init` to create a new vault";
/// UX-P4-8 hint: shown when an export `--out` directory cannot be created (a colliding file, a
/// missing parent, or a permission problem).
pub const EXPORT_OUT_HINT: &str =
"choose an --out path that does not already exist as a file and whose parent is writable";
/// Re-wrap a `StoreError` I/O failure with the offending PATH + a one-clause hint (UX-P4-8). ONLY the
/// pathless `StoreError::Io` is 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.
/// 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` (a `write`/`flush` mid-write) AND a
/// `CliError::Store(StoreError::Io)` (a `mkdir_owner_only`/`open_owner_only` under `out_dir` — e.g. a
/// SUBPATH collision like `out_dir/lots.csv` already existing as a directory, which `?`-converts
/// through `From<StoreError>`). A `CliError::Csv` (a serialization error, not a path problem) and
/// every other variant pass through unchanged.
/// 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). `pub` so btctax-tui
/// shares it [R0-r2-N2].
pub const ATTEST_PHRASE: &str = "I attest this is true";
/// PURE exact-compare attestation gate — NO I/O, NO TTY read [R0-I2]. The interactive prompt lives in
/// the caller (the `export-snapshot` main.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).
///
/// - `attest.map(str::trim) == Some(ATTEST_PHRASE)` → `Ok(())`.
/// - `Some(_)` non-matching → `Err(AttestationFailed)` (a wrong phrase FAILS regardless of env) [R0-I1].
/// - `None` → `Err(AttestationRequired)`.
///
/// `pub` so btctax-tui shares the exact-compare [R0-r2-N2].