Skip to main content

Module chokepoint

Module chokepoint 

Source
Expand description

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_tranche is now a thin driver over this module: Session::open → build args → plan_promote (map RefusalCliError) → println!("{}", render_consent(&plan)) → prompt/collect ack → apply_promote.

Gate ordering (DFW-D2) MUST match cmd/promote.rs:378-485 exactly: resolve-live → BG-D5 provenance → BG-D7 Part II → BG-D3 floor/coverage → BG-D6 consent_terms → synthetic-promote advisory → gift-only relabel → consent render (incl. wide_window_note) → ack inside apply_promote, fail-closedwould_conflict → append.

I-1 (byte-parity): the shipped verb prints, IN ORDER (promote.rs:443-455), the synthetic-promote ADVISORY (pre-consent) → render_consent(&terms, &gift_only_years) → the wide_window_note (post-consent). PromotePlan therefore carries THREE ordered pieces (advisory_lines, gift_only_years, post_consent_note) so this module’s render_consent(&plan) reproduces advisory → consent → note byte-for-byte when printed via a single println! — a single flat Vec cannot place terms BETWEEN the pre-advisory and the note; do NOT collapse the three. The shipped render_consent(terms, gift_only_years) stays in cmd::promote (still pub — external KATs in tests/promote_cli.rs call it directly — and is invoked from here); gift_only_flagged_years/ wide_window_note move HERE.

DFW-D6 (the ONE intended behavior change — the sub-1 pseudo-off fix): plan_promote forces cfg.pseudo_reconcile = false on its own COPY (ProjectionConfig is Copy) before consent_terms / promote_prior_year_advisory / gift_only_flagged_years — mirroring would_conflict (project/mod.rs:118). Without this, a pseudo-active vault’s consent screen — and the RECORDED Acknowledgment.shown_terms, the §6664(c) good-faith artifact — could fold in a synthetic default that was never persisted, misstating what the filer actually acknowledged.

arch-m-6/tax-N-1: Refusal::Target covers the resolve-live gate — unknown/voided/wrong-type target only (resolve_live_tranche). Already-promoted (a DOUBLE promote) is NOT caught here; it surfaces as would_conflict at APPLY time (a CliError, never a plan Refusal) — mirroring promote.rs:475-483.

arch-m-new-3: plan_promote takes no Session/state — the shipped pipeline rebuilds everything from events (promote.rs:364-488) — so a caller (CLI or future TUI) supplies its own already-loaded events/prices/cfg.

Task 2 — the DECLARE chokepoint: plan_declare/apply_declare, extracted from the shipped cmd::tranche::declare_tranche (tranche.rs:120-175). plan_declare gates on the shipped set (sat>0, ws<=we, guard_tranche_vs_allocation — the LAST one stays defined in cmd::tranche, not duplicated here) ALWAYS; iff target_shortfall = Some(id) it ALSO runs the DFW-D5.2 target-scoped clearance shadow: append the candidate DeclareTranche → re-project (pseudo FORCED off, mirroring would_conflict) → assert no BlockerKind::UncoveredDisposal remains on id; else Refusal::Coverage. target_shortfall = None (the CLI free-form path) is the shipped declare_tranche gate set, BYTE-FOR-BYTE (DFW-D8/SPEC §5) — no clearance shadow runs at all. apply_declare is a plain append+save (declaring is $0/revocable/no-Form-8275 — DFW-D8 — so unlike promote there is no acknowledgment gate and no would_conflict pre-check; the shipped verb never ran one either).

Refusal-variant note: the shared Refusal enum stays CLOSED at the four Task-1 variants (the plan review explicitly rejected adding a new Conflict variant for this task). The shipped-set gates (sat/window/allocation) have no promote-shaped variant of their own, so — like the new clearance failure the brief names explicitly — they map to Refusal::Coverage. Every variant collapses to the identical CliError::Usage(msg) via From<Refusal> (below), so this is a pure internal-taxonomy choice: the filer-facing message text is unchanged from the shipped verb either way.

Structs§

DeclarePlan
Everything needed to append a DeclareTranche decision. Unlike PromotePlan, declaring has no acknowledgment gate or consent screen (DFW-D8 — a plain $0, revocable confirmation) — so there is nothing else to carry beside the payload itself.
PromotePlan
Everything computed BEFORE the filer types the acknowledgment phrase (the PromoteTranche decision id, target, is not yet known — it is assigned at apply_promote’s append_decision). ★ I-1: the three ordered fields (advisory_lines, gift_only_years, post_consent_note) let render_consent reproduce the shipped verb’s advisory → consent → note byte order — do NOT collapse them into one Vec or pre-render gift_only_years into a string.

Enums§

Refusal
A plan_promote refusal — fail-closed, BEFORE any computation past the failing gate. Each variant carries the exact filer-facing message (byte-identical to the shipped verb’s CliError::Usage text), so mapping to CliError (the thin CLI driver) or a distinct TUI error surface is trivial either way.

Functions§

apply_declare
Apply a planned declare: append + save. No acknowledgment gate and no would_conflict pre-check (DFW-D8 — declaring is a plain $0, revocable confirmation, unlike promote’s typed-phrase tier; the shipped verb never ran a would_conflict check either — cmd/tranche.rs:166-174 appends immediately once guard_tranche_vs_allocation passes).
apply_promote
Apply a planned promote: the acknowledgment gate (BG-D6, fail-closed, INSIDE apply) → would_conflict pre-check (BG-D9 — a second live promote on this target, or any other resolver-level conflict; refuses BEFORE appending, NOT last-wins) → append + save. Reloads events/cfg fresh from session (arch-m-new-3: plan_promote took no Session) — a single synchronous CLI/TUI invocation cannot append anything between plan_promote and apply_promote, so this is behavior-preserving.
plan_declare
Plan a DeclareTranche decision. Gates on the shipped set ALWAYS — sat>0, ws<=we, guard_tranche_vs_allocation (cmd::tranche, the single source of that guard for all four allocation append sites — NOT duplicated here) — replicating cmd/tranche.rs:134-154 exactly (arch-m-new-3: no Session — the caller supplies its own already-loaded events/prices/cfg, mirroring plan_promote).
plan_promote
Plan a PromoteTranche decision — the DFW-D2 gate order, everything computable BEFORE the filer types the acknowledgment phrase: resolve-live → BG-D5 provenance → BG-D7 Part II → BG-D3 floor/coverage → BG-D6 consent_terms → synthetic-promote advisory → gift-only relabel. events/prices/cfg are the caller’s own already-loaded state (arch-m-new-3: no Session here — the CLI’s thin driver and a future TUI each supply their own).
render_consent
Re-emit the shipped verb’s ordered filer-visible text: advisory_lines → the shipped render_consent(&plan.terms, &plan.gift_only_years) (cmd::promote) → post_consent_note — ★ I-1: byte-identical to promote.rs:443-455 when the RESULT is printed via a single println!("{}", render_consent(&plan)) (the shipped verb instead used three separate println! calls; a single combined string reproduces the exact same stdout bytes because println! always adds exactly one trailing \n). Do NOT collapse this into plan.terms/plan.gift_only_years alone — the pre-advisory must land BEFORE the consent screen and the note AFTER it.