From 8e4dfffc3f14c7d15bc468c381a884a396fedd6f Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Mon, 18 May 2026 17:16:41 -0700 Subject: [PATCH] update todo --- TODO.md | 112 -------------------------------------------------------- 1 file changed, 112 deletions(-) diff --git a/TODO.md b/TODO.md index 4e2d96c..6676e14 100644 --- a/TODO.md +++ b/TODO.md @@ -156,77 +156,6 @@ Out of scope for V1: file-format alternatives (SVG, PDF), themed color overrides for export (always uses the active terminal theme), non-chart command output as PNG. -## CLI architecture overhaul — priority MEDIUM - -The CLI surface has grown to 21 top-level commands and the dispatch -machinery in `src/main.zig` is starting to bloat. Three related gaps, -all best addressed together because they share the same refactor -vehicle: - -1. **No per-command `--help`.** `zfin help` shows a wall of every - command and every flag. There's no way to ask "what does - `projections` accept?" without grepping the top-level usage. - Every command should support `zfin --help` printing - just that command's synopsis, flags, and a few examples. -2. **`usage` text is roughly chronological-by-feature.** Re-group it - into workflow sections so users can scan for what they need: - - **Per-symbol lookups:** `perf`, `quote`, `history` (symbol - mode), `divs`, `splits`, `options`, `earnings`, `etf` - - **Portfolio analysis:** `portfolio`, `analysis`, `history` - (portfolio mode), `projections`, `milestones` - - **Time-series & journaling:** `snapshot`, `compare`, - `contributions` - - **Data hygiene:** `audit`, `enrich`, `lookup` - - **Infra:** `cache`, `version`, `interactive` -3. **Per-command flag parsing lives inline in `runCli`.** It's - ~500 lines now. The `projections`, `contributions`, and `compare` - branches each carry ~50 lines of inline flag parsing plus their - own conflict-detection. Each command module should own its own - `parseArgs()`; `runCli` should be pure dispatch. - -The natural mechanism for all three is a **command registry table** -mirroring the `tab_modules` registry in `src/tui.zig`: - -```zig -// src/main.zig -const command_registry = .{ - .perf = @import("commands/perf.zig"), - .quote = @import("commands/quote.zig"), - // ... -}; - -// each command module exposes: -// pub const meta = .{ -// .help = "perf Show trailing returns ...", -// .group = .symbol_lookup, -// .takes_symbol = true, -// .needs_portfolio_path = false, -// }; -// pub fn parseArgs(allocator, args, today) !ParsedArgs -// pub fn run(io, allocator, *DataService, parsed, today, color, *Writer) !void -``` - -A comptime walk over the registry produces: -- The grouped `usage` text (sort by `meta.group`, render section - headers). -- Per-command help dispatch (`zfin --help` prints - `meta.help` plus the parsed flag descriptors). -- The dispatch chain itself (replace the giant `if-else if`). -- The "does this command take a symbol?" / "does it need a - portfolio path?" decisions currently scattered across `runCli`. - -**Driver:** the per-command `--help` is the loudest user-facing gap; -the registry refactor is the cleanest way to land it without -scattering help text across more files. Also unblocks `zfin doctor` -(below) and the unified time-range parser (below) by giving them -a clean module shape to plug into. - -**Open question for when this is picked up:** how to handle the -`history` command's two modes (symbol vs portfolio) under a single -registry entry. Probably one entry with a parser that branches on -`args[0]`, same as today — but the registry shape should accommodate -that without ceremony. - ## `zfin doctor` health-check command — priority LOW Front-door command for the file constellation and environment. @@ -327,47 +256,6 @@ README still says "six tabs," actual count is eight (Portfolio, Quote, Performance, Options, Earnings, Analysis, History, Projections). -## Unified time-range flag parser — priority LOW - -`compare`, `contributions`, `projections --vs`, and `projections ---as-of` all accept overlapping but slightly different time-range -inputs. Today there are two helpers in `src/commands/common.zig` -(`parseAsOfDate`, `parseCommitSpec`) and the conflict-detection -logic (`since != null and before_spec != null`, etc.) is duplicated -across each command's flag-parsing block in `main.zig`. - -### Sketch - -```zig -// src/commands/common.zig -pub const TimeRange = struct { - before: Endpoint, - after: Endpoint, - pub const Endpoint = union(enum) { - date: Date, - commit_spec: CommitSpec, - live, - head, - }; -}; -pub fn parseTimeRange(args: ...) !TimeRange { ... } -``` - -Each command consumes a `TimeRange` and decides which endpoint -combinations make sense: -- `compare` rejects `live`-on-both-sides. -- `contributions` rejects `live` entirely (no meaningful "live - contributions diff"). -- `projections --vs` accepts `live` on either side. - -### Naturally folds into the CLI architecture overhaul - -Once each command has its own `parseArgs()` (per the CLI overhaul -entry above), the time-range parser becomes a shared utility those -parsers call. Could either land standalone or be pulled in as part -of the overhaul. If the overhaul lands first, this is one of its -follow-ups; if this lands first, the overhaul inherits it for free. - ## Split `audit.zig` into per-broker reconcilers — priority LOW `src/commands/audit.zig` is 3438 lines — the largest command file