Stage 8 of the CORE build order: the bodies behind the DownloadSpec /
callback API reviewed in core/docs/engine-api-m1.md. Wires probe -> segment
workers -> WriteBuffer -> SparseFile -> .veloxpart.meta -> retry/backoff ->
SegmentBudget -> RateLimiter -> callbacks into one event-driven machine.
- Engine (src/engine.cpp): owns HttpClient, Prober, SegmentBudget,
RateLimiter and one timer jthread (min-heap of scheduled fns). start()
builds a task and returns a DownloadHandle; ~Impl quiesces every task
before joining the timer so no callback fires during teardown.
- DownloadTaskState (src/task/download_task.cpp): one `mu` task lock; a
shared_mutex over the worker map for the curl write path; callbacks
collected under `mu` and fired after release via a separate deferred
queue; weak_from_this() in every async hop. State machine over the
CORE-owned EngineState subset, auto-pause on 401/407 and on a 200 where
206 was expected, validated resume via If-Range.
- digest (src/task/digest.cpp): OpenSSL EVP hash_file() for the optional
post-download checksum; links OpenSSL::Crypto PRIVATE.
- Segmenter::release_segment(): hand a paused segment back to the pool
unassigned so resume's assign_slot() picks it up instead of splitting a
still-"assigned" range and orphaning its front half.
- DownloadHandle now names the real control block (vdm::task::
DownloadTaskState, defined only in the engine TU) via a namespace-scope
fwd decl and a public-but-effectively-engine-only ctor, replacing the
nested State/friend pair. Every public signature is unchanged; DAEMON
(vdm-79) confirmed sched/ names only the public API.
Fixes found while building the end-to-end suite (tests/task/engine_test.cpp,
9 cases against tools/testserver, green under ASan/UBSan and TSan):
- a dropped connection lost its unflushed WriteBuffer tail while advance()
had already counted those bytes as done -> a retry resumed past an
unwritten hole. Flush on the failure path.
- when the byte counters hit total while other workers were still live,
teardown dropped their buffered tails. Now: cancel them and let each
worker's own seg_finished drain it (the `assembling` state), last one
starts verification -- no cross-thread buffer access.
- seg_head() let a 401 with credentials present abort before libcurl's
resend; now it proceeds once and acts on the final status.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HPPSGhiArbvQgwC2DNiURS
Lays out Velox Download Manager (IDM-class download manager for Ubuntu
26.04) as a monorepo ready for parallel lane development. No implementation
code by design.
- docs/: architecture, roadmap M0-M7, IDM-parity GUI spec, engine design,
Firefox extension spec, risks/spikes, packaging
- contracts/: wire-contract skeleton (JSON Schema + fixture templates) —
the single synchronization point between lanes
- docs/agents/: one brief per lane (PROTO, CORE, DAEMON, GUI, EXT, PKG/QA)
with owned directories, build order and definition of done
- CLAUDE.md: rules of engagement — lane ownership, layering, non-negotiables
- CMake scaffolding with dev/tsan/release/ci presets
Two environment findings shape the design: Firefox here is the Mozilla snap
(native-messaging risk, so the extension carries a loopback-WebSocket
fallback), and Wayland forbids passive clipboard monitoring (so clipboard
capture is explicit-action-first).
Co-Authored-By: Claude Opus 5 <[email protected]>