The lease-service half of the #14144 heavy-maintenance lease-fairness epic. (Grace owns the consumer half, #14186 — the kbSync embedViaShadowSwap between-batch yield-point.)
Scope
HeavyMaintenanceLeaseService exposes the cooperative-yield decision so a long heavy-task holder can poll it between resumable checkpoints:
- a reactive
maxActiveHoldMs_ config reading AiConfig.orchestrator.heavyMaintenance.maxActiveHoldMs at the use-site (SSOT discipline);
- a thin
shouldYield(lease, {now, maxActiveHoldMs}) method over the already-built shouldYieldHeavyMaintenanceLease primitive;
- the leaf default set to 30min (the fairness Decision Record converged with @neo-opus-grace: independent of
staleAfterMs but smaller, so a live holder yields before stale-reclaim; a soft knob, tunable on churn);
- falsy ⇒ never yields (byte-identical back-compat — #14186's absent/0-leaf path).
Acceptance Criteria
Delivered by the PR linked below. The #14144 epic closes once this and #14186 (the consumer) land. Refs #14144 (parent epic), #14186 (consumer sub), #14039 (v13.1).
Contract Ledger
This sub modifies consumed surfaces (pull-request-workflow guide §5.4) — the matrix (mirrored from the delivering PR #14261):
| Surface |
Change |
Consumer |
Migration |
HeavyMaintenanceLeaseService.shouldYield(lease, {now?, maxActiveHoldMs?}) → Boolean |
added |
#14186 (kbSync batch loop) |
none — new method |
orchestrator.heavyMaintenance.maxActiveHoldMs leaf |
value HOUR_MS → HOUR_MS / 2 (30min) |
the service's reactive maxActiveHoldMs_ config |
none — env-overridable; falsy ⇒ never-yield preserves byte-identical back-compat |
Existing acquire / inspect / release / withLease + the re-exported pure primitives are unchanged.
Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code).
The lease-service half of the #14144 heavy-maintenance lease-fairness epic. (Grace owns the consumer half, #14186 — the kbSync
embedViaShadowSwapbetween-batch yield-point.)Scope
HeavyMaintenanceLeaseServiceexposes the cooperative-yield decision so a long heavy-task holder can poll it between resumable checkpoints:maxActiveHoldMs_config readingAiConfig.orchestrator.heavyMaintenance.maxActiveHoldMsat the use-site (SSOT discipline);shouldYield(lease, {now, maxActiveHoldMs})method over the already-builtshouldYieldHeavyMaintenanceLeaseprimitive;staleAfterMsbut smaller, so a live holder yields before stale-reclaim; a soft knob, tunable on churn);Acceptance Criteria
HeavyMaintenanceLeaseService.shouldYield(lease)injects the reactivemaxActiveHoldMsinto the primitive (per-call override wins).maxActiveHoldMsleaf defaults to the 30min DR; env-overridable; falsy ⇒ never yields.Delivered by the PR linked below. The #14144 epic closes once this and #14186 (the consumer) land. Refs #14144 (parent epic), #14186 (consumer sub), #14039 (v13.1).
Contract Ledger
This sub modifies consumed surfaces (pull-request-workflow guide §5.4) — the matrix (mirrored from the delivering PR #14261):
HeavyMaintenanceLeaseService.shouldYield(lease, {now?, maxActiveHoldMs?}) → Booleanorchestrator.heavyMaintenance.maxActiveHoldMsleafHOUR_MS→HOUR_MS / 2(30min)maxActiveHoldMs_configExisting
acquire/inspect/release/withLease+ the re-exported pure primitives are unchanged.Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code).