Files
vdm/daemon/docs/deferrals.md
T
samiandClaude Sonnet 5 d93c8e10a0 daemon: sched/scheduler — governor <-> store <-> engine, against an EnginePort seam
The Scheduler that D4 was waiting on. Built against CORE's engine
HEADERS (now in main); the real EnginePort and the veloxd wiring wait
for lane/core's stage-8 bodies to reach main (deferrals.md D4a/D4b) —
core/src/task/ is still .gitkeep there, so linking vdm::Engine now
would be an unresolved symbol.

- sched/engine_port — the abstract seam: start/pause/resume/cancel/
  provide_auth/decide/refresh_url + the ADR 0011 admission config
  (set_task_order / set_max_active_segments / set_host_segment_cap).
  Keeps the Scheduler testable without a live engine and the daemon
  unbound from the concrete vdm::Engine.
- sched/fake_engine_port — a recording impl for tests.
- sched/scheduler:
  * owns the wire-UUID <-> vdm::TaskId map.
  * tick(): snapshot queues (schedule window evaluated with an
    injectable clock) + non-terminal tasks -> governor.evaluate ->
    apply. to_start builds a vdm::task::DownloadSpec from the row and
    calls EnginePort::start; to_resume -> resume(); to_pause ->
    pause() + writes the pause_reason; priority_order -> set_task_order
    over the mapped engine ids. `new` tasks are parked (startMode
    manual) and skipped.
  * on_engine_state(wire_id, state, err): projects an engine
    transition onto the store row (state, pause_reason='auto' when an
    error rides a paused transition per ADR 0013 §2, flattened error
    columns) so the next tick sees ground truth. This is also the hook
    event.task.state will fire from (D5).
  * reconcile_after_restart(): CORE-owned states -> queued, paused
    keeps its reason (ADR 0013 §5).
  * reload_config(): reads connection.maxConcurrentDownloads /
    maxActiveSegments + a daemon-local host-cap map, pushes caps to
    the engine, updates the governor.
  * Deps: injectable local-now clock and a post_to_loop marshaller
    (engine callbacks arrive on engine threads; default runs inline
    for tests).

Test veloxd.sched_scheduler (ASan+UBSan and TSan clean): admission +
ordering, a slot freeing on completion, queue-stop -> pause
(queue_stopped) then queue-restart -> resume (not a fresh start),
engine auto-pause -> pause_reason 'auto' + never auto-resumed,
reconcile_after_restart, reload_config caps push. 35 daemon/cli tests
green.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Upd9WhG9oppieig5nRDLig
2026-09-10 20:29:37 +04:00

2.1 KiB

DAEMON — deferred work, tracked

Things that are deliberately incomplete in daemon/ right now, with why and when they close. Kept here (not buried in commit messages) so the next pass can see them at a glance.

# What Where Why deferred Closes when
D1 Pairing prompt is EnvAutoApprover (needs VELOX_PAIR_AUTO=1) rpc/pairing.hpp, main.cpp A GUI dialog / org.freedesktop.Notifications approver is integration work Build step 7 (systemd + notifications)
D2 download.probe-32603 rpc/dispatcher.cpp download.add is wired (fs/safepath + store, real -32011); download.probe needs the engine's probe path for -32013 probe with the engine link (CORE stage 3 is landed; wire Engine::probe)
D3 Stub handlers for everything except session.*, download.add/list/get rpc/dispatcher.cpp No store behind them yet (categories/queues/rules/settings/limiter/schedule) Per method, as the store query modules land behind them
D4a sched/scheduler is built and unit-tested against FakeEnginePort, but there is no real EnginePortCore (wraps vdm::Engine + SegmentBudget) and it is not wired into veloxd sched/ CORE stage 8 is on lane/core, not yet in main (core/src/task/ is still .gitkeep there) — linking vdm::Engine would be an unresolved symbol lane/core merges to main: add engine_port_core.{hpp,cpp} (~100 lines) + construct Engine/Scheduler in main.cpp, run tick() on the timer thread and on RPC-driven changes
D4b no timer thread driving Scheduler::tick(); download.add/pause/resume/queue handlers don't nudge the scheduler daemon/src/main.cpp, rpc/dispatcher.cpp depends on D4a with D4a
D5 event.* fan-out not implemented; session.subscribe accepts and echoes but nothing is emitted rpc/uds_server.cpp, rpc/ws_server.cpp No task state to broadcast until the engine is wired. Scheduler::on_engine_state is the hook it will fire from With D4a — the same engine-state callback feeds both the store and event.task.state