- Defect 1 (main.py): Replace floating-point stride loop with exact
floor(k * total / cap) index formula so sampling always returns
EXACTLY cap items for any 1 <= cap <= total_usable, including the
stride < 2 regime where the old approach returned cap-1 items.
- Defect 2 (main.py): Validate ollamaMaxSampleLines before computing
the stride; values <= 0 are nonsensical and fall back to 500
(same as the default) rather than raising ZeroDivisionError.
- Defect 3 (test_progress_spinner.py): Rewrite test_non_tty_no_extra_thread
to patch threading.Thread and assert it was never called, so the test
actually fails when the spinner starts a thread in the non-TTY path.
- Defect 4 (test_progress_spinner.py): Simplify test_non_tty_prints_message
to use monkeypatch.setattr instead of the dead mock.patch.object +
manual assign/restore layering; removes two # type: ignore comments.
- docs(README.md): Document ollamaMaxSampleLines alongside ollamaNumCtx /
ollamaTimeout in the Ollama Configuration section.
- tests: Add boundary-case tests for stride < 2 (total==cap, total==cap+1,
total=3/cap=2, cap=1) and zero-cap fallback; make
test_ollama_max_sample_lines_default exercise behaviour rather than
the ambient config value.
Co-Authored-By: Claude <noreply@anthropic.com>
Defect 1 — hcatOllama showed a plain print then blocked silently for
up to 300 s while waiting for the LLM. A new generic context manager
`hate_crack/progress.py::spinner()` now runs a daemon thread that
repaints a single line with a frame + elapsed-seconds counter every
~120 ms. TTY guard ensures non-TTY/test environments get a single
plain print instead of ANSI control characters. The line is erased
with \033[2K\r on exit (normal and exceptional).
Defect 2 — the wordlist path materialised every line in memory and
built a prompt that could massively overflow ollamaNumCtx on large
wordlists. The path now does a two-pass evenly-spaced sample: pass 1
counts usable lines, pass 2 stride-selects up to `ollamaMaxSampleLines`
(default 500, new config key) spread across the full file. When no
capping occurs the message reads "Loaded N passwords"; when capping
occurs it reads "Sampled N of M passwords".
Co-Authored-By: Claude <noreply@anthropic.com>