CSV Cleaver

Assumptions

Every assumption found in the code and the tests, from a deliberate audit (2026-08-05), with what guards it or why it is accepted. An assumption is not a defect — software cannot be written without them — but an unexamined one is how every defect this project shipped got out. This file is where they stop being unexamined.

Three kinds of entry:

Found wrong by this audit

AssumptionRealityFix
The banner warning covers every mode that lets a caller name a pathIt tested = :path exactly, so both — which grants everything path grants — carried no warningWarns on #{:path :both}; tested from R64's reasoning, per mode
The header question panel rendersNo test had ever constructed the :unsure + unanswered state; the panel was 19 uncovered linesRendered and both answers asserted; answering makes it disappear
The Trash accounting renders:trashed / :left-behind result lines never rendered in any test, in any languageRendered, counts asserted, plural forms exercised in fr/zh/ja
The scanner's quote-exit branches are covered by the fixturesThe :quote-seen → delimiter/CR/EOF transitions were the least-covered lines in the one namespace where a miss is silent corruptionEach exit exercised explicitly

Guarded

AssumptionWhereGuard
A multi-byte character straddling the 64 KiB sniff boundary is truncation, not corruptionencoding/detectEnd-to-end test with é split across byte 65,536; misreading demotes UTF-8 to windows-1252
Numbers are written and read in the interface language, and rewritten at the moment it changesformat/restate, state/with-languageR80 tests + mutations
Stored settings never hold locale-formatted textprefs, state/remembered-valuesR81 tests + every-remembered-setting-is-classified, which fails when a new setting is added unclassified
The bundled runtime contains locale datapackaging scriptsR83: parsed from --add-modules, checked inside the built image, binary launched before wrapping
Comma wins delimiter ties; nothing separator-like falls back to commacsv/detect-delimiterExplicit tie and fallback tests
A stale folder-inspection reply cannot overwrite the current folder'sstate/::out-dir-inspectedTest with mismatched dir
An unrecognised charset label means "detected", never nilstate/charset-for-labelRound-trip through every language + fallback test
The window geometry survives a restart, and nonsense geometry is ignoredapp/session-settings, view/remembered-windowR55/R58: read from a real (never-shown) Stage, sanity bounds tested
Every picker label maps back to the value it stands for, in every languageapp/handle-eventRouting tests over all six languages
A split that cannot write reports a failure event, never a bare exceptionapp/split-workerTest against an impossible output folder
The service reports a job that threw as failed, with the reasonapi.jobs/start!Test with a file deleted between survey and execution

Accepted

AssumptionReasoningBlast radius if wrong
64 KiB of head is enough to sniff encoding and delimiterA file that switches encoding or delimiter after 64 KiB is corrupt in a way no sniff length fixesWrong delimiter → visibly wrong preview; the user can override both
"MB" means MiB (×1,048,576)Matches what file managers show for the resulting files, which is the number users will compare againstSizes ~5% larger than a decimal reading; consistent in both directions
Index padding is fixed at max(4, digits of planned count) before writing startsWidth must be chosen before file 1 is written; a byte-mode plan is an estimateA byte-mode split whose reality exceeds 9,999 files against a smaller estimate sorts _10000 before _9999 in file managers. Requires the user to have confirmed a >10,000-file split first. Names remain unique and correct
zh serves Traditional-script readers with Simplified stringsOne Chinese translation; normalise-tag takes the primary subtagReadable but non-native script for zh-TW/zh-HK users; a Traditional bundle can be dropped into the languages folder
Finished API jobs expire only when a new job starts or the service stopsA poll-only client holds at most its own finished jobs for the 30-minute windowBounded memory (one map entry per job), reclaimed at the next start
The token is printed to stdoutThe user asked for a service; the terminal is theirs. Documented in SECURITY.mdAnything reading the process's stdout could read the token — a process that can do that can read .nvd-api-key too
free-space may be unknown (nil) on exotic filesystems; an unknown never blocks a splitRefusing to split because the filesystem would not answer would be a worse failure than trusting the userThe disk-full refusal degrades to the OS's own write error, which is caught and shown
split/terminated's fallback branch is unreachable through execute!A header row with no terminator means the header is the file's last line, which means no data rows, which plan refusesDefensive only; unit-tested directly so a refactor that makes it reachable finds it working
Drag events, file dialogs and System/exit are untestedDragEvent/chooser dialogs cannot be constructed headlessly; exit! ends the test JVM. All are behind vars or thin wrappers so everything around them is testedThe wiring layer; a break is visible on first manual launch, which bb package performs

Assumptions the tests make

These are about the suite itself — the ones rule 3 of the testing standard is aimed at.

What coverage cannot say

Coverage of the remaining gap is concentrated in app.clj's display-bound wiring (dialogs, drag, renderer mounting) and desktop.clj's calls into java.awt.Desktop. These run only with a display and real user gestures. The guard for them is not a unit test: it is bb package, which launches the packaged binary, and the shots harness, which renders every screen. 100% line coverage of this layer would mean mocking the exact APIs whose real behaviour is the risk — a test that can only agree with itself, which is the kind this project has resolved not to write.