Problem: The NDJSON spawn path had no stdin support, so `M.submit` used
one-shot `vim.system()` with no live feedback. Status events from the
scraper were never surfaced to Neovim.
Solution: Conditionally create a `stdin_pipe` in the NDJSON path and
write `opts.stdin` after spawn. Switch `M.submit` to `ndjson=true`; route
`ev.status` events to a new `on_status` callback and `ev.success` to the
existing `callback`. A `done` flag prevents double-callback on crash.
Problem: vim.json.decode maps JSON null to vim.NIL (userdata), but
cache.set_test_cases validates precision as number|nil, causing a
type error on every scrape where precision is absent.
Solution: guard the precision field when building the callback
table, converting vim.NIL to nil.
Problem: luals flagged undefined-field on uv timer methods because
race_state.timer was untyped, and undefined-field on env_extra/stdin
because they were missing from the run_scraper opts annotation.
Solution: hoist race_state.timer into a typed local before the nil
check so luals can narrow through it; add env_extra and stdin to the
opts inline type in run_scraper.
Problem: problem pages contain floating-point precision requirements and
contest start timestamps that were not being extracted or stored. The
submit workflow also needed a foundation in the scraper layer.
Solution: add extract_precision() to base.py and propagate through all
scrapers into cache. Add start_time to ContestSummary and extract it
from AtCoder and Codeforces. Add SubmitResult model, abstract submit()
method, submit CLI case with get_language_id() resolution, stdin/env_extra
support in run_scraper, and a full AtCoder submit implementation; stub
the remaining platforms.
Problem: vim.loop is deprecated since Neovim 0.10 in favour of vim.uv.
Five call sites across scraper.lua, setup.lua, utils.lua, and health.lua
still referenced the old alias.
Solution: replace every vim.loop reference with vim.uv directly.
Add LuaCATS annotations to the env conversion helper and drop the table.sort call since ordering is not required by uv.spawn.
Co-authored-by: Codex <noreply@openai.com>
Neovim/libuv spawn expects env as a list of KEY=VALUE strings. Passing the map from vim.fn.environ() can fail process startup with ENOENT, which breaks NDJSON test scraping and surfaces as 'Failed to start scraper process'.\n\nConvert env map to a deterministic list before uv.spawn in the NDJSON scraper path.
Co-authored-by: Codex <noreply@openai.com>
Problem: setup_python_env() is called from check_required_runtime()
during config.setup(), which runs on the very first :CP command. The
uv sync and nix build calls use vim.system():wait(), blocking the
Neovim event loop. During the block the UI is frozen and
vim.schedule-based log messages never render, so the user sees an
unresponsive editor with no feedback.
Solution: remove setup_python_env() from check_required_runtime() so
config init is instant. Call it lazily from run_scraper() instead,
only when a scraper subprocess is actually needed. Use vim.notify +
vim.cmd.redraw() before blocking calls so the notification renders
immediately via a forced screen repaint, rather than being queued
behind vim.schedule.
Problem: with debug = true, there is not enough diagnostic output to
troubleshoot environment or execution issues. The resolved python path,
scraper commands, and compile/run shell commands are not logged.
Solution: add logger.log calls at key decision points: python env
resolution (nix vs uv vs discovery), uv sync stderr output, scraper
subprocess commands, and compile/run shell strings. All gated behind
the existing debug flag so they only appear when debug = true.