release: v1.15.0 - #363
Closed
VijitSingh97 wants to merge 35 commits into
Closed
Conversation
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@9c091bb...3d3c42e) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* fix(tune): runtime HugePages reservation is grow-only (#328) tune_kernel wrote the miner's computed requirement to vm.nr_hugepages absolutely, which shrinks a pool another consumer already reserved (a co-hosted pithead stack's p2pool/monerod share the same 2MB pool) down to its in-use floor — zero free pages on both sides, measured live on the pithead#797 appliance bench. The write is now availability-based: pages the miner can draw on = HugePages_Free + whatever a running miner already holds (it re-uses its pages across a restart). The pool grows by the shortfall only and never shrinks. Fresh single-purpose rigs see the same reservation as before; re-runs that find enough available write nothing. This is the runtime half of #305's co-resident keep-existing guard. The setup --dry-run plan previews the same decision from the same availability check. Closes #328 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(tune): cover the held-pages probe, fallback, and dry-run no-change branches Three lines diff-cover flagged: the real-MainPID HugetlbPages read (now exercised via a stub systemctl reporting a live pid), the no-proposed-grub 3072 fallback (now asserted grow-only too), and the dry-run plan's covered-pool wording. The probe also always prints a number now — a status file without a HugetlbPages line previously produced empty output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ead#797 R1) (#330) * feat(setup): appliance mode — baked deps, /run units, GRUB skip (pithead#797 R1) One opt-in env flag, RIGFORGE_APPLIANCE=1, for running setup on the Pithead appliance image: read-only root, volatile /etc overlay, and a boot leg that re-runs setup every boot instead of relying on persisted state. Under the flag: - dependencies are verified (command -v), never installed — a missing tool fails loudly naming the image-build gap; a prebuilt tree needs envsubst only (the R0 bench re-ran from cache with a half-broken compiler) - the GRUB leg takes the skip branch deliberately: the kernel cmdline, incl. any 1GB-hugepage reservation, is image-owned - units render into /run/systemd/system (SYSTEMD_DIR preset) and enable with systemctl enable --runtime - hugetlbfs mounts at runtime; no fstab or limits.conf appends (the unit already sets LimitMEMLOCK=infinity) - runtime tuning unchanged: modprobe msr, grow-only HugePages sysctl (#328), performance governor setup --dry-run previews the same decisions through the shared helpers, never a second copy. Every decision was proven on the pithead#797 R0 bench. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(appliance): close the two review gaps — jq install and the logrotate drop-in Adversarial review of the appliance flag found two writes that survived the R1 contract: check_prerequisites still apt/brew-installed a missing jq (appliance mode never installs — hard-fail naming the baked-image fix instead), and generate_xmrig_config still wrote /etc/logrotate.d/ xmrig onto the volatile overlay of an image that runs no logrotate (log policy belongs to the integration layer, pithead#797 R2). Tests cover both; the missing-jq case clears bash's command hash table first, since sourcing the script hashes jq's real path and command -v would ignore the emptied PATH. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The appliance full-run asserted --runtime for xmrig.service only; the
other enable sites (timers, api, control) share the same
${ENABLE_RUNTIME:+...} mechanism, but a future call site that forgets
the expansion would persist its enable into the volatile /etc overlay
and silently vanish on reboot. One guard closes the class: no
[systemctl] enable line in the appliance run's call log may lack
--runtime.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…from MSR failure (#333) (#334) * fix(doctor): detect kernel lockdown directly instead of inferring it from MSR failure (#333) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(docs): rewrap line so markdownlint doesn't parse '+ Curve Optimizer' as a list (#333) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ls don't fail (#327) (#337) The apt dependency list named linux-tools-common unconditionally, but that package is Ubuntu-only — Debian ships cpupower as linux-cpupower — and apt's install transaction is all-or-nothing, so the one unknown name failed the ENTIRE dependency install: git, build-essential and cmake never arrived either. Probe with apt-cache show (the same guard the kernel-versioned linux-tools-$(uname -r) package already had) and add whichever name the distro actually ships; when neither exists, warn and carry on — cpupower is a tuning aid, never worth losing the compiler toolchain over. Closes #327 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…y slow (#339) * feat(doctor): surface missing AES-NI / AVX2 instead of mining silently slow (#338) RandomX without AES-NI falls back to XMRig's soft-AES path, roughly 4x slower, and nothing anywhere said why — the last undelivered acceptance criterion from #1 ("unsupported hardware is surfaced rather than silently failing"). setup/apply now warn at configure time when the CPU flags lack aes (and, advisory, avx2 — that one only slows dataset init), and doctor counts a missing AES-NI as an issue. Judged only when an x86-style flags line exists in /proc/cpuinfo (same CPUINFO override util/proposed-grub.sh already uses); macOS, ARM and stubbed sandboxes read as unknown, and unknown never manufactures an issue — the #333 lockdown stance. Never aborts: a knowingly-old rig is a valid choice. Closes #338 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: collapse one-arm case blocks to [[ ]] guards (ponytail-review) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four comments/docs still described the pre-acceptance design — "the rig re-derives latest and refuses anything else" — contradicting accepted D4: the staged body IS the target (the dashboard re-derives latest host-side, over Tor); the rig makes no version check of its own and only BOUNDS the supplied target with the monotonic anti-rollback + reachable-from-main guards. Reworded util/control-server.py (_handle_upgrade comment), systemd/rigforge-control-upgrade.service.template, the ADR 0002 Alternatives bullet, and the control_upgrade() header in rigforge.sh. Comments and docs only; no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lity (#342) pithead#261 shipped: the stack serves TLS on the SAME :3333 (per-connection detect, mixed fleet migrates one rig at a time), generates a self-signed cert on first apply, and prints the lowercase 64-hex SHA-256 fingerprint (pithead status repeats it). Rotation is delete the proxy-tls files + re-pin. Rewrite docs/pithead-integration.md "Stratum over TLS" accordingly: drop the unshipped claim, the :3334 example port, and the "once pithead#261 fixes its port model" caveat; state that the rig side is config-file-not-prompt; point the troubleshooting row at pithead status as the canonical pin source. Ride-along audit one-liners (2026-08-14): - docs/README.md: ADR 0002 status Proposed -> Accepted (D-OPEN-1 signed off); integration row mentions the optional :8081 sister API like the root README - README.md: platform badge Ubuntu 22.04+ -> Ubuntu 22.04+ / Debian 12 (Debian shipped in v1.14.0, #327) - docs/operations.md: drop the word "simply" Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pithead's host runner caps its synchronous /status poll after a
worker-apply at 20s, but control-apply's auto-rollback can take minutes —
the change-history row froze at 'accepted' with no way to catch up short
of a new authenticated dial to the rig's control port (a token the
dashboard container never holds).
The rig now mirrors its own last outcome into the already-open read feed:
_api_control_json reads {change_id, status, reason} from the status.json
_control_status already writes 0644, and _api_rigforge_block serves it as
rigforge.control. Missing, unreadable, or malformed status.json degrades
to control: null — the mirror can never break the feed — and pithead's
parse_worker_control_status filters non-terminal records itself.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…341) XMRig's /2/summary reports "hugepages" as a [loaded, total] pages array; jq's @TSV refuses nested arrays (exit 5), so _status_api_summary's single stats-row fork died on every healthy rig — the || true swallowed the exit but the ERR trap still printed an abort, and the Hashrate/Pool/Uptime/ Shares block never rendered. Serialize the array to "loaded/total" before @TSV; scalar and absent shapes pass through unchanged. Tests: the shared curl stub now emits the real array shape (the old bool-shaped fixture is how this slipped past the suite), the #143 assertion tracks it, and a new #341 section renders status against array, scalar, and absent hugepages bodies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iner (#348) tests/e2e/linux.sh now runs TWO passes, a fresh disposable container each: the standard deploy, then RIGFORGE_APPLIANCE=1. The appliance branch in in-container.sh reuses the shared harness setup (real apt prereqs, /etc seed, stubs, config) and asserts the mode's contracts on the container's real filesystem across a first run and an every-boot re-run: - units render into /run/systemd/system (real envsubst|tee), and nothing lands under /etc/systemd/system; - no package installs: install_dependencies reads the toolchain as baked (new cc stub feeds the command -v probe) and a logging apt-get stub proves apt is never invoked; - /etc/fstab, /etc/security/limits.conf and /etc/default/grub stay byte-identical (grepping for "memlock" would false-fail: the stock ubuntu limits.conf documents it in comments), no modules-load or logrotate drop-ins; - every systemctl enable carries --runtime, pinned non-vacuous by the xmrig enable line and a zero count of enables without it; - hugetlbfs mounted at runtime (argument-level: mount is stubbed, the real mountpoint probe reports not-mounted in a fresh container). Honesty boundary stated in the harness comment: systemctl/mount stay stubbed (no pid-1 systemd, no privileges in the container), so those contracts are proven at the argument level; the filesystem effects are real. To make argument-level assertions readable at all, the container stubs now log "[cmd] args" to $CALL_LOG (run.sh's idiom) — this also turns run 3's previously vacuous "no git clone" assert into real evidence, since the git stub never logged before. CI wiring is the existing e2e job's existing step: make test-e2e runs both passes, so local runs and CI cover appliance identically with no matrix plumbing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed (#347) An interrupted tune --live (or autotune / tune --now) persisted whatever mid-sweep candidate was in flight: _measure_live writes each candidate into tune-overrides.json and restarts the miner on it, but the EXIT trap only cleaned the temp dir and restarted a bench-stopped service — the candidate stayed saved AND running, silently costing hashrate until the next re-tune. Mechanism: tune() snapshots the pre-sweep overrides and marks the file dirty for the duration of a live sweep; the existing EXIT trap (which bash runs on INT/TERM/HUP and on errexit) now restores that snapshot FIRST — through _restore_overrides, the exact restore+apply step the --confirm revert leg already used, factored out so the abort path cannot diverge from the completion path — before any other service handling, so every later restart re-reads the restored file. The winner write clears the flag: a completed decision stands down the abort-restore. autotune gets the same protection via its own EXIT trap: the pre-sweep prefetch mode is re-merged with _autotune_set_prefetch (the sweep's own write path, shared via _autotune_settle with the clean-completion tail), so knobs pinned by an offline tune survive the abort exactly as they survive a completed run. Tests: two black-box sections kill the real process mid-iteration (the fake API flags the candidate window, then blocks; exec makes the backgrounded PID the trap-owning shell) and assert the overrides come back byte-identical (tune --live) / mode-restored with merged knobs intact (autotune), plus a post-kill service restart. All six behavior asserts fail on the unfixed script. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… of assuming it (#343) doctor and apply gave a clean bill of health while the rig mined nothing: with pools[0].url unresolvable, xmrig loops on DNS errors every ~5s, yet doctor printed "all critical checks passed" (no pool check existed) and apply reported "Applied config and restarted xmrig." with no warning. Mechanism: the miner's local API already knows the truth — /2/summary's connection.uptime is positive exactly while a stratum connection is live and 0 while it retries — so both verbs read that rather than dialing the pool from the script (a second dial can disagree with the miner's proxied/TLS view; the miner is the party that has to be connected). - doctor gains a named pool-connection check right after the service check: connected -> ok line (pool, connection age, accepted shares); running-but-disconnected -> counted issue (exit 1 per #149); silent API -> advisory only (the miner may still be starting). Service stopped -> one guarded TCP dial of pools[0] stands in (host/port as positional args, never interpolated into the -c string; timeout-bound). - apply's post-reconcile summary polls the API briefly (APPLY_POOL_TRIES x APPLY_POOL_IVL, default 5x3s, early exit once connected) and WARNS when no live connection appears — warn, never refuse: the pool may be legitimately down at apply time, so the exit code stays 0. tune and autotune are untouched (they restart via _apply_runtime and already verify liveness with _wait_miner_live). The TSV parse places its "?" placeholder jq-side: a disconnected xmrig reports pool "", and since tab is IFS whitespace, a leading empty field would be swallowed by read and shift every later field one left — "failures: 2" would have parsed as a live connection. Tests: a doctor section (connected / disconnected / empty-pool fallback to pools[0] / api-down / stopped+reachable / stopped+unreachable / real closed-port dial) and a black-box apply section (connected report; disconnected warn with rc 0; api-down warn with rc 0); the shared curl stub's /2/summary body gains realistic connection.uptime/failures fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rig has no non-latest check — a newer-but-not-latest target is accepted; the refusal category is a target outside the allowed bound. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ring continuations diff-cover graded the reshaped filter's two continuation lines as 0% — bash coverage marks only the command line, and a quoted string's continuation lines can never execute. Same filter, one physical line; the tests already prove all three hugepages shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pages-array fix(status): render XMRig's array-valued hugepages instead of aborting (#341)
docs: pithead stratum TLS is shipped, same-port — rewrite the stale section (#342)
…nguage docs: stop claiming the rig re-derives latest — five sites, accepted D4 semantics (#352)
…container-pass test(e2e): a second in-container pass with RIGFORGE_APPLIANCE=1 (#348)
…ability # Conflicts: # CHANGELOG.md # tests/run.sh
…bility fix(doctor,apply): read the miner's own pool-connection state (#343)
…tatus-mirror # Conflicts: # CHANGELOG.md
…restore # Conflicts: # CHANGELOG.md
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…atus-mirror feat(api): mirror the control status into the enriched feed (#346)
…estore fix(tune): an interrupted live sweep restores the pre-sweep config (#347)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promote develop to main for the v1.15.0 release. Gates: e2e-real all six phases PASS on miner-2 (2026-08-15, /opt checkout), e2e-pithead worker↔stack PASS against gouda's live stack (stratum-auth + dashboard phases env-skipped, recorded), full suite 1668/0, CI green. Contents: the v2-readiness stability wave — status abort fix (#341), TLS doc reality (#342), pool-reachability in doctor/apply (#343), control status mirror (#346), tune-interrupt restore (#347), appliance-mode CI pass (#348), ADR-0002 language (#352).
🤖 Generated with Claude Code