Files
vdm/core/include/vdm
samiandClaude Sonnet 5 5d81b4cdae core: segment/segmenter + segment/budget (stage 6)
vdm/ids.hpp — TaskId, an opaque engine handle (DAEMON keeps the wire
UUID <-> TaskId map; the engine never sees the UUID).

segment/segmenter — per-download range management (docs/04 §3). Initial
lazy split; assign_slot() splits the largest remaining range when the
budget grants a slot; on_complete(may_steal) either *steals* the second
half of the largest remaining range for the same worker (slot-neutral) or
returns nullopt so the caller *yields* the slot (ADR 0011 A1); on_failed()
returns requeue only on the 3rd consecutive connection error with a mirror
present — the remaining range is orphaned and re-split. Non-resumable or
unknown-size => exactly 1 segment; never split below min_segment_bytes
(1 MiB). Resume ctor rebuilds from a persisted table (falls back to a
fresh layout if it doesn't tile [0,total)). One mutex == "the task lock";
segment fields are std::atomic and the store is a std::deque so a steal's
append never moves a worker's record.

segment/budget — the global allocator (ADR 0011). Owns exactly one
ceiling (maxActiveSegments) and min-1-before-seconds fairness: a two-pass
allocation (guarantee pass gives every wanting task 1 slot in DAEMON's
priority order, then a growth pass round-robins the rest up to each
task's effective cap = min(per_task_cap, host cap, 1 if non-resumable)),
recomputed from scratch on every edge so a live set_max_active_segments
cut naturally yields the excess lowest-priority-first, never a
mid-segment kill. DAEMON-facing surface exactly as promised in
daemon/docs/core-requests-m1.md / ADR 0011: budget(), segments_active(),
starved_tasks(), starved_since(), set_max_active_segments (drain),
set_host_segment_cap, set_task_order, on_budget_changed (a jthread
coalesces at <=4 Hz; the tasks_starved 0<->nonzero edge fires
immediately). Callbacks are copied out and run after the lock is
dropped.

Tests: segmenter split/steal/requeue/resume math + a concurrent
steal-and-advance run; budget min-1 under a tight budget, round-robin
growth, host-cap and non-resumable clamps, live-lower shedding
lowest-priority-first, starvation below the task count, starved-edge
notification, and a concurrent set_want hammer. Green under ASan/UBSan;
the steal path and the budget green under TSan.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HPPSGhiArbvQgwC2DNiURS
2026-09-10 15:14:14 +04:00
..

libveloxcore — public API

Status: M1 in progress. Only util/ is landed. The download-facing API (DownloadSpec, DownloadTask, probe, typed callbacks) arrives with later stages and is reviewed by DAEMON before M2 (AGENT-CORE DoD).

Layering (CLAUDE.md §3): this library knows nothing about JSON, SQL, Qt, or RPC. Input is a spec value; output is bytes on disk plus typed callbacks. DAEMON projects engine state onto the wire contract's TaskSummary / TaskDetail / events — see core/docs/proto-requests-m1.md for the shapes that projection needs frozen.

Every header under core/include/vdm/ compiles standalone (-Wall -Wextra -Wpedantic -Werror, C++23). Clean under ASan/UBSan and TSan.


util/ — foundations

vdm/util/error.hpp

enum class Error — the engine-wide failure taxonomy (network / HTTP / content / local I/O / metadata / probe / retry / internal). This is CORE's own vocabulary; it is not a wire type. error_name(Error) gives a stable snake_case string; is_retryable(Error) is the advisory retry hint the task policy consults.

struct ErrorInfo { Error code; std::string context; int http_status; bool retryable; Error cause; } — the payload carried by every failed Result. .to_string() renders "<name>: <context> (HTTP <n>)".

vdm/util/result.hpp

Result<T> — return-based error channel, a thin wrapper over std::expected<T, ErrorInfo>. Errors are returned, never thrown, on anything that runs during a transfer.

  • Result<int> r = 42; / Result<int> r = Err{Error::timeout, "..."}; / Result<T> r = Error::not_found;
  • r.has_value(), explicit operator bool, r.value() / *r / r->, r.error(), r.code(), r.value_or(x)
  • monadic and_then / transform / transform_error (forward to std::expected)
  • Result<void> specialization; vdm::ok() success sentinel
  • VDM_TRY(expr) — return the error if expr failed
  • VDM_TRY_ASSIGN(auto x, expr) — bind the value or return the error

vdm/util/bytes.hpp

Byte / ByteSpan / ConstByteSpan aliases; as_bytes(string_view) / as_chars(span). Little-endian fixed-width codec load_le<T> / store_le<T> and a bounds-checked sequential ByteReader (.u8/.u16/.u32/.u64, .raw(n), .lp_string(), .overran()). Built for the .veloxpart.meta reader and the 4-byte NM framing; every read is bounds-checked and latches on overrun (reader-first, fuzz-ready).

vdm/util/event_bus.hpp

EventBus — typed, thread-safe in-process pub/sub. subscribe<E>(fn) -> Token, publish<E>(ev) (synchronous, calling thread, registration order), unsubscribe(Token), and RAII subscribe_scoped<E> returning a Subscription. Handlers may (un)subscribe or publish during dispatch. Handlers must not throw. Not a hot-path structure — progress is coalesced to ≤4 Hz upstream.

vdm/util/thread_pool.hpp

ThreadPool — fixed-size std::jthread pool for bounded off-loop work (hashing, fsync batches, DNS pre-resolve). submit(fn, args...) -> std::future<R>; propagates exceptions through the future; drains already-queued tasks on destruction. Not the transfer loop — net/ will own one curl_multi per dedicated worker.

vdm/util/log.hpp

Sink interface — core does no I/O itself. LogSink abstract base; DAEMON installs one via set_log_sink(), default discards. CallbackSink adapter (with a min-level filter). VDM_LOG_{TRACE,DEBUG,INFO,WARN,ERROR}(category, fmt, args...)std::format syntax, only formatted when a sink is installed and wants the level.