CORE reviewed and accepted (core/docs/adr-0011-core-response.md, lane/core@7bf5cb5), with three amendments folded in: - yield (slot transfer at the next segment boundary) as the mechanism that satisfies min-1-before-seconds out of a full budget; steal stays slot-neutral as originally written. - "admission implies progress" is bounded-delay (min(next yield boundary, low_speed_secs) + connect_timeout), not immediate — widens the starvation-assertion window from 2s to ~low_speed_secs + connect_timeout (45s). - starved_tasks()/starved_since(TaskId) added to the accessor set; segments_active() and tasks_starved definitions pinned (a 'connecting' segment counts as held, not starved). All five open questions answered (min-1 buildable without inversion, probe pool size 4 outside the budget, drain-not-kill live-apply, ordered TaskId list for priority, 4Hz + starved-edge callback coalescing). Section 6 rewritten: connection.maxActiveSegments landed on the wire in PROTO's ADR 0012 while this was in flight, so the daemon-local stopgap is dropped. daemon/src/sched/ is unblocked. Both docs updated in the rebased vdm-daemon worktree against the frozen 1.0.0 contract. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Upd9WhG9oppieig5nRDLig
3.6 KiB
DAEMON → CORE — the engine API sched/ needs before it can be written
Status: resolved. CORE answered in full: core/docs/adr-0011-core-response.md
(lane/core, commit 7bf5cb5). Kept as a record of what was asked and the shape of the
answer; the API itself is now specified in
docs/adr/0011-admission-control-and-the-segment-budget.md §"Engine API sched/ is built
against". sched/ may be written against it.
Ranking followed contracts/README.md rule 4 conventions even though this wasn't a
contracts/ change: new API surface = cheap, land anytime; a behavioural promise (min-1
fairness) = needed CORE's explicit sign-off before DAEMON built on the assumption. That
sign-off is in.
C1. Occupancy read-out, not inference — resolved
Requested budget(), segments_active(TaskId), on_budget_changed. CORE's answer adds
starved_tasks() and starved_since(TaskId) (amendment A3) and pins two definitions:
segments_active(id) counts a segment in connecting state as held (it is progress, not
starvation), and tasks_starved counts only segments_active == 0. See ADR 0011 §3.6.
C2. set_max_active_segments(uint32_t) live-apply — resolved: drain, never kill
Confirmed DAEMON's assumption. Lowering runs in-flight segments to their next boundary; no
new segment starts while over the new ceiling; nothing is aborted, no partial range lost.
If the new ceiling is below the running-task count, CORE honours min-1 for the top-priority
subset and reports the rest via tasks_starved — DAEMON's governor must reconcile and
pause the lowest-priority excess itself (CORE does not auto-pause). See ADR 0011 §2.
C3. set_host_segment_cap(host, uint32_t) — resolved, confirmed as proposed
CORE keeps the host → cap map and derives a task's host from its URL/mirror set; DAEMON
owns the table and pushes it. See ADR 0011 §4.
C4. Contract gap: connection.maxActiveSegments — resolved by PROTO
PROTO landed it (ADR 0012, connection.maxActiveSegments default 32,
connection.maxTotalBufferBytes default 128 MiB, TaskDetail.effectiveBufferBytes) while
this was in flight. No daemon-local stopgap needed — sched/ reads the wire field
directly. See ADR 0011 §6.
C5. Fairness rule sign-off — resolved, with two amendments
CORE confirmed min-1-before-seconds is implementable without a priority-inversion at slot release (two-pass allocator: guarantee pass over zero-slot tasks in DAEMON's priority order, then a growth pass; a released slot always re-enters the pool at pass 1, never handed back locally). Two amendments to what DAEMON assumed:
- A1 — "steal" (slot-neutral, unchanged) isn't the whole mechanism; "yield" is the slot-transfer operation that actually satisfies min-1 out of a full budget: an over-quota task releases one slot at its next segment boundary, bounded by that segment's remaining bytes.
- A2 — "admission implies progress" is bounded-delay, not immediate:
time_to_first_slot ≤ min(next yield boundary, low_speed_secs) + connect_timeout, not "connect timeout + per-host cap" alone. DAEMON's starvation-invariant assertion window widened from the originally proposed 2 s tolow_speed_secs + connect_timeout(~45 s) accordingly.
Priority order (open item 4) is an ordered TaskId list pushed via set_task_order on
change — not an integer, not per-tick. See ADR 0011 §3.
C6. Probe pool sized outside the segment budget — resolved, confirmed
Dedicated pool, default size 4, set_probe_pool_size(uint32_t), independent of
maxActiveSegments; probe cancellation is immediate. DAEMON still bounds probe
submission on its own side. See ADR 0011 §5.