Skip to content

release: v1.16.0 - #402

Merged
VijitSingh97 merged 9 commits into
mainfrom
develop
Aug 23, 2026
Merged

release: v1.16.0#402
VijitSingh97 merged 9 commits into
mainfrom
develop

Conversation

@VijitSingh97

Copy link
Copy Markdown
Contributor

Promote develop to main for the v1.16.0 release. Restart-free control-apply fast path (#397/#381) and the HugePages pool-ceiling contract (#399/#398, pithead#1103). This promotion also folds back the topology guard + e2e-dashboard leg + msr-test PATH fix that had drifted onto main-only, restoring the main-ancestor-of-develop invariant. Gate: full e2e-real on a loaner rig all phases PASS (perf 36866 H/s within 5%), e2e-pithead 19/0 vs the live stack, merged-tree make test 1827/0. Landing via fast-forward push per RELEASING.md.

VijitSingh97 and others added 9 commits August 21, 2026 14:23
control_apply re-ran the entire apply() pipeline for every accepted
change -- regenerate XMRig's config, re-render its unit, restart the
service, then poll for a live pool connection -- even for a change
that never touches XMRig at all. A live walkthrough (#344 item 1)
measured a single watchdog_interval_min change taking ~62s round-trip
because of this.

CONTROL_FAST_PATH_KEYS is a closed allowlist (watchdog_interval_min,
max_temp_c), checked as a subset match so an unrecognised key --
including any future CONTROL_WRITABLE_KEYS addition nobody has
re-proven restart-free here -- takes the full path by construction.
Both keys are proven restart-free from generate_xmrig_config and
install_watchdog's own comments, not asserted. The fast path reuses
install_watchdog verbatim (the same call apply() already makes on
every run) instead of re-implementing unit rendering, per the #344
constraint that this must not fork a second apply implementation that
can drift from the real one; it stamps config_meta provenance the same
way apply() does. A fast-path failure falls through to the same
full-pipeline rollback a failed full apply already uses.

Closes #381.
…e alone (#381)

An independent security review of the fast path found a HIGH-severity
gap: gating success on a bare `systemctl is-active` reads a
legitimately stopped rig -- a watchdog thermal hold, or an operator's
manual stop -- as a fast-path failure. control_apply's rollback then
discards the operator's change and calls the full apply() pipeline,
which unconditionally restarts the service, force-restarting a rig
that was deliberately offline. Worst case: changing max_temp_c during
a thermal hold, the exact case this fast path exists for.

Fix: capture is-active before the watchdog reconcile and again after.
Success is "the run-state did not degrade" -- inactive-before is
success regardless of after (the fast path never touches the xmrig
unit, so it can't have caused whatever state the rig is in either
way); only active-before/inactive-after is a real regression and
still rolls back. No thermal-hold-marker special-casing needed.

Tests use a stateful systemctl stub (the generic always-succeeds stub
elsewhere never exercised the inactive branch) driving control_apply
end to end through the real _control_do_apply_fast body.

ADR 0001's D12 paragraph updated to state the run-state criterion in
place of the original is-active-alone claim.
…-path

feat(control): restart-free fast path for /apply on watchdog-only keys
…e-counting

The grow-only runtime write (_ensure_hugepages) computes
current + required - avail, where required already includes any declared
hugepages_reserve_extra_mb (the co-resident stack's headroom) but avail gives
no credit for pages that same stack already holds — only free pages and pages
the RigForge-managed miner itself holds. The stack's reservation therefore
lands in the write twice: once via required's declared headroom, once again
because avail doesn't cancel it back out. Re-derived independently (not from
the write-up that first reported it) against an 8 GiB reduced-tier appliance
box: the write comes out to 6118 pages (~12 GiB) instead of the honest 3782
(rigforge#398, pithead#1103).

hugepages_reserve_extra_mb can't fix this — no declared value cancels a
double count in the arithmetic that combines it. A new config key,
hugepages_pool_ceiling_mb (default 0, inert), caps the WRITE itself instead:
when declared, vm.nr_hugepages is never grown past the ceiling regardless of
what required/avail compute. Absent, the write is byte-for-byte unchanged
(proved by a regression test against the same 8 GB fixture).

Closes #398
Security review on fix/398-hugepages-ceiling found that ceiling_pages was
computed as ceil(HUGEPAGES_POOL_CEILING_MB / 2) — the same rounding rule
EXTRA_2MB_PAGES uses for headroom, which is right for a value being ADDED but
wrong for a cap: an odd declared ceiling (5121 MB) rounded up to 2561 pages
(5122 MB), one page past the declared ceiling, contradicting the "never grown
past the ceiling" contract. All three existing fixtures used even MB values
so the suite couldn't see it.

Floor instead (bash integer division already truncates toward zero for
positive operands, so dropping the "+ 1" is the whole fix). Added an odd-MB
fixture (5121 -> 2560 pages) that kills the ceil mutation: restoring "+ 1"
flips it to write vm.nr_hugepages=2561 and drops the "already at its declared
ceiling" WARN, confirmed by hand before this commit. Updated the two
in-code comments and the CHANGELOG entry to state the floor behavior.
…eiling

feat(hugepages): a declared pool ceiling caps the grow-only write
Restart-free control-apply fast path (#397/#381) and the HugePages pool-ceiling
contract that closes the co-resident double-count (#399/#398, pithead#1103).
Recovers the topology guard, e2e-dashboard leg, and msr-test PATH fix that had
landed on main only (back-merge restoring the main-ancestor invariant).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U189N8GtbdUVtm8UtVNcDw
@VijitSingh97
VijitSingh97 merged commit 4ce29b3 into main Aug 23, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant