TODO cleanup

This commit is contained in:
Emil Lerch 2026-06-24 11:08:11 -07:00
parent bd0483b26e
commit 545fda4c52
Signed by: lobo
GPG key ID: A7B62D657EF764F8

120
TODO.md
View file

@ -539,80 +539,6 @@ Once decisions are made, sweep all four sites + add a regression
alignment test per table that mixes a fully-populated row with alignment test per table that mixes a fully-populated row with
an em-dash-heavy row and verifies `displayCols` matches. an em-dash-heavy row and verifies `displayCols` matches.
## TUI: numeric keypad input not handled — priority LOW
Numeric-keypad keys (Num0-Num9, decimal point, minus) don't reach
the modal text-input handlers. Reproduced on the projections tab
as-of date prompt (`d`): typing the date with the numpad produces
no input, while the digit keys on the main keyboard row work fine.
Affects every modal that takes numeric input — symbol-input is
unaffected because it's letters.
Likely cause: the modal handlers route through `vaxis.Key.codepoint`
matching, but vaxis emits keypad keys with a distinct keycode (kitty
keyboard protocol) rather than the codepoint of the equivalent ASCII
digit. The fix is in the modal key paths (`handleDateInputKey` in
`src/tui/projections_tab.zig` and the symbol-input handler in
`src/tui.zig` — though that one is letters-only in practice) and
possibly the shared `input_buffer.zig` if that's where character
gathering lives. Worth surveying both files plus any other tab that
will grow numeric input (the CLI options command's near-the-money
strike count would be a candidate if migrated to a modal).
Verification: open the TUI, press `d` on projections, try to type a
date with the keypad. Then try the keyboard row. Both should commit
identical input.
## TUI: memory leaks somewhere — priority MEDIUM
User reported leaks while doing a detailed TUI walkthrough; no
specific tab or interaction yet identified. The TUI uses a mix
of arena allocators (frame-scoped) and persistent tab state, so
likely culprits:
- Per-tab `State` structs that hold `[]const u8` slices duped
from a long-lived allocator but not freed when the tab
reloads or the symbol changes.
- Cached service-fetch results stored in tab state that aren't
`result.deinit()`-ed before being replaced.
- ArrayList accumulators that get appended to across multiple
draw cycles without an intervening clear.
- Vaxis event/dialog closures that capture strings into
arena-allocated lambdas but escape the arena's lifetime.
### Investigation plan
1. Run the TUI under `std.testing.allocator` (a debug
allocator that panics on leak). The current binary uses a
gpa, which silently tolerates leaks. A test-mode TUI run
with a leak-detecting allocator would surface the
offending alloc sites with file/line info.
2. Walk each tab's `State.deinit` (and `tab.deactivate` /
`tab.reload` hooks) against the `State` field list — every
owned field needs a free path on every state-change boundary.
3. Pay specific attention to `classification_map` and any
per-symbol caches (option chains, candle snapshots) — those
are the biggest fixed-size strings.
No reproducer yet. When the user has a more specific lead
(which tab, which interaction), this entry should narrow.
### `etf <SYMBOL>` warns `failed to serialize ETF profile: WriteFailed` — priority LOW
Every `zfin etf VTI` invocation prints
`warning(cache): VTI: failed to serialize ETF profile: WriteFailed`
to stderr before the foreground output. The ETF profile renders
correctly; just the cache write fails.
`src/cache/store.zig:209` calls `serializeEtfProfile` which fails
on the `aw.writer.print(...)` call inside it (line 1007). Likely
a Zig 0.16 stdlib quirk in the SRF writer path or a missing
`flush()` somewhere in the writer chain.
Investigate by replacing the `print` with a manual `print` +
`flush` to see if it's a buffer-not-flushed issue, or by
serializing a known-good fixture in isolation.
## Analysis: dividend equity / income-shaped equity — think about it ## Analysis: dividend equity / income-shaped equity — think about it
Dividend-equity ETFs (SCHD, VYM, DGRO, NOBL, SDY, VIG, etc.) Dividend-equity ETFs (SCHD, VYM, DGRO, NOBL, SDY, VIG, etc.)
@ -660,52 +586,6 @@ If a fix lands, it's probably a separate analysis section (yield
breakdown, income coverage) — not a change to the asset-class breakdown, income coverage) — not a change to the asset-class
taxonomy. taxonomy.
## Analysis: umbrella-insurance exposure — future enhancements — priority LOW
**v1 shipped (May 2026)**: `analysis` command and TUI tab now show an
"Umbrella exposure" section that splits the liquid portfolio into
Shielded vs Exposed dollars based on per-account `tax_type` from
`accounts.srf`, with an optional per-account `shielded:bool:false`
(or `:true`) override for cases the tax-type default gets wrong
(e.g. pre-tax deferred-comp accounts that aren't ERISA-protected).
The shielding decision is intentionally simple: tax_type != taxable
defaults to shielded; the `shielded` field overrides per-account.
That covers the realistic cases (401k vs taxable brokerage; DCP-style
non-ERISA pre-tax accounts) without a state-by-state lookup table.
### What's deferred
These were in the original v1 design but skipped to keep the
shipping scope tight. Pick up only if real user demand surfaces.
- **State-by-state IRA protection lookup table**. Civil-judgment IRA
shielding varies by state (TX/FL full, some none, most partial).
v1 punts to the manual override; users in weak-state IRA
jurisdictions add `shielded:bool:false` on their IRA accounts
themselves. A built-in state table would automate this — needs a
`state` field at the user level (per-portfolio-file or global
config) and a maintained taxonomy. Doable but high-friction relative
to the manual override.
- **`account_type` distinction**. v1 uses `tax_type` (taxable / roth
/ traditional / hsa) as the umbrella proxy because that's what
exists. A more granular `account_type` (`401k`, `403b`, `roth_ira`,
`traditional_ira`, `sep_ira`, `inherited_ira`, ...) would let the
default shielding decision be more nuanced (e.g. inherited_ira
defaults to NOT shielded post-Clark v. Rameker). Not necessary
while the override exists.
- **Joint-account / community-property nuance**. State-specific.
v1 treats each account holistically. Probably never needed.
- **Inherited-IRA flag**. Currently the user adds
`shielded:bool:false` on inherited IRAs as the workaround. A
dedicated flag would let the section call them out by name in
the output. Cosmetic.
The following items are acknowledged but not prioritized. Listed here The following items are acknowledged but not prioritized. Listed here
so they don't get lost; pick up opportunistically. so they don't get lost; pick up opportunistically.