# Technical Debt Log Append-only log of known technical debt. Maintained by `.claude/agents/qa-tech-debt.md`. Do not delete paid-down entries — mark them resolved instead. | Date | Item | Type (unintentional/unavoidable/deliberate) | Impact ("interest rate") | Status | Resolution | |---|---|---|---|---|---| | 2026-09-08 | `EnvelopeRenderer.Cli` exits `64` ("render not implemented") for any argument-valid run, since the Debenu render engine isn't wired in yet. Self-documenting and expected to disappear once "Render text-only PDFs through Debenu Quick PDF" (Sprint 1 Batch 2) lands and exit `0` becomes reachable. | Deliberate | Low | Paid Down | `RenderNotImplemented` branch removed from `Program.cs`; exit `0` is now reachable and exit `1` covers all template/CSV/render failures (see `code/CLI_CONTRACT.md`). | | 2026-09-08 | `DebenuPdfRenderer` always embeds TrueType fonts fully (`AddTrueTypeFont(..., Embed: 1)`), cached once per unique font name per document. Fine at today's scale (one sample render: ~1.3 MB for 392 pages, one font) but full embedding could add up if a template ever uses many distinct fonts/styles at very high page counts, working against the sub-2GB PDF constraint. | Deliberate | Low | Open | Revisit if the "Time-box the first high-volume benchmark" story (not in this sprint) shows file size becoming an issue; Debenu also exposes `AddSubsettedFont` as a smaller-footprint alternative if needed. Sprint 3's batching mitigation made this concern concrete: each batch now re-embeds the font from scratch (see the 2026-09-21 entry below). | | 2026-09-08 | `EnvelopeRenderer.Desktop`'s Render button re-enables as soon as the CLI process is confirmed *started* (`CliProcessLauncher.LaunchAsync` returning), not once it finishes rendering — this story (Sprint 1 Batch 4) intentionally does not track render completion. An operator can click Render again (e.g. against the same output path) while a prior render is still in progress, since nothing yet observes the child process's lifetime or exit code. | Unavoidable (scope boundary of this story) | Low | Resolved | Sprint 1 Batch 5 ("Show render progress and completion summary") replaced `CliProcessLauncher.LaunchAsync`/`Launch` with `RunAsync`/`Run`, which stream the CLI's redirected stdout/stderr, wait for the process to actually exit, and return exit code + final progress event. `MainForm.OnRenderClick` now only re-enables the Render button in the `finally` block after that awaited call completes, not when the process starts — verified with a real launch against the sample CSV (button stayed disabled for the full render, both success and forced-failure runs). | | 2026-09-14 | The render path's actual high-volume throughput badly misses the product's stated "100,000 records at 300 DPI in under 10 minutes" target: a real (not simulated) 100k-record benchmark run showed throughput degrading monotonically from ~399 rec/s to ~15 rec/s (and still falling) by record 4,827 of 100,352, isolated with reasonable confidence to Debenu Quick PDF Library 10.13's in-memory document model rather than this repo's own O(1)-per-record merge/CSV code. Projected full-run time is on the order of 45-90+ minutes — 5x-10x+ over target. Full methodology, raw data, and root-cause investigation in `code/BENCHMARK.md`. | Unavoidable (external vendor library characteristic, not yet confirmed fixable) | High (directly threatens a hard product constraint — `project_config.md`'s "render 100,000 records at 300 DPI in under 10 minutes" — and would be worse at the stated 1,000,000-record ceiling) | Resolved (for the 100,000-record target) | Sprint 3 story "Investigate and address high-volume render throughput degradation" confirmed the Debenu-internal-document-model hypothesis (a scaled-down probe showed the per-page cost reliably resets after a save+release/reopen cycle) and implemented a batching mitigation in `DebenuPdfRenderer` (save+release/reopen every 300 pages, merged via Debenu's `MergeFileListFast`). The full 100k-record benchmark was re-run to completion (not time-boxed): 315 seconds, ~47.5% under the 10-minute budget, valid 100,352-page PDF, 397 MB. Full results in `code/BENCHMARK.md`'s "Sprint 3 follow-up" section. This closes the 100,000-record risk but opens a new, narrower one at the 1,000,000-record ceiling -- see the next entry. | | 2026-09-21 | The Sprint 3 batching mitigation for the above throughput issue (save+release/reopen every 300 pages, merged via `MergeFileListFast`) fixes the 100,000-record/10-minute target with margin, but introduces a new file-size risk at the product's stated 1,000,000-record ceiling: each batch re-embeds the template's TrueType font from scratch (~1.05 MB per extra batch, measured directly), so linear extrapolation of the 100k run's real numbers (397 MB, ~350 MB of which is batching overhead) to 1,000,000 records suggests a combined output size in the neighborhood of 4.5-5 GB -- over the product's sub-2GB final PDF constraint (`project_config.md`). Not yet observed directly (no 1,000,000-record run has been performed); this is a qualitative, evidence-informed extrapolation, not a confirmed failure. Full analysis in `code/BENCHMARK.md`'s "Re-assessment of the 1,000,000-record ceiling" section. | Unintentional (side effect of the chosen mitigation, not present in this form before it) | Medium (only threatens the stated ceiling's extreme end, not the tested and confirmed 100,000-record target; no story currently commits to rendering 1,000,000 records) | Open | Not fixed as part of this story (out of scope: the story's AC2 asks for one mitigation sized against the 100k target). Two candidate directions identified, not yet attempted: a batch size that scales with total record count, or switching to Debenu's `AddTrueTypeSubsettedFont` so each batch only re-embeds the glyphs actually used instead of the full font. Should be revisited before any story commits to rendering at or near the 1,000,000-record ceiling. | | 2026-09-04 | `EnvelopeRenderer.Cli` only read `DEBENU_LICENSE_KEY` from the process environment. That's fine for `dotnet run --project ... --` (the CLI inherits the invoking shell's env directly), but `EnvelopeRenderer.Desktop` launches the CLI as a child process, which only inherits whatever environment variables were already present in whatever launched the desktop app itself (a double-clicked `.exe` or Start Menu shortcut typically has none) — so every desktop-launched render failed with Debenu error 999 regardless of a valid key existing on disk. Real-user-reported: the operator correctly guessed a `key.txt` dropped next to the exe should work (matching how the CLI's own test helper already resolved keys), but production code had no such fallback. This is a real Definition-of-Done verification gap from Sprint 1 Batches 4-5: the "real success run" verification used an in-process test harness with the env var set directly in that process, never the actual built `.exe` launched the way an operator would, so the gap wasn't caught before Sprint Review. | Unintentional | High (silently broke the desktop app's core success path for any non-`dotnet run` launch) | Resolved | Added `DebenuLicenseKeyResolver` (`code/src/EnvelopeRenderer.Cli/DebenuLicenseKeyResolver.cs`) to the shipped CLI: env var first, then a `key.txt` walked up from the executable's own directory — the same rule the test-only helper already used, now shared via delegation instead of duplicated. Documented in `CLI_CONTRACT.md`'s "Debenu license key" section and `code/README.md`'s desktop-app instructions. Verified by running the actual built `EnvelopeRenderer.Cli.exe` from the Desktop app's own output folder with no environment variable set at all, `key.txt` sitting next to it: exit `0`, valid 1.3 MB `%PDF-1.4` output, all 392 records. 5 new unit tests added (`DebenuLicenseKeyResolverTests.cs`); full suite 111/111 passing. |