Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a12bc99
chore(deps): Bump actions/checkout from 7.0.0 to 7.0.1 (#326)
dependabot[bot] Jul 24, 2026
c383b03
fix(tune): runtime HugePages reservation is grow-only (#328) (#329)
VijitSingh97 Aug 1, 2026
32be3a4
feat(setup): appliance mode — baked deps, /run units, GRUB skip (pith…
VijitSingh97 Aug 1, 2026
256bc71
test(appliance): every systemctl enable must be --runtime (#797) (#331)
VijitSingh97 Aug 1, 2026
98ef9ac
release: v1.13.0
VijitSingh97 Aug 1, 2026
6d26898
chore(perf): record miner-0 baseline for v1.13.0
VijitSingh97 Aug 1, 2026
37acb86
fix(doctor): detect kernel lockdown directly instead of inferring it …
VijitSingh97 Aug 1, 2026
25abe9b
release: v1.13.1
VijitSingh97 Aug 1, 2026
fb5ecdb
chore(perf): record miner-0 baseline for v1.13.1
VijitSingh97 Aug 1, 2026
5ee5af9
fix(setup): probe the distro's cpupower package name so Debian instal…
VijitSingh97 Aug 2, 2026
c96ff74
feat(doctor): surface missing AES-NI / AVX2 instead of mining silentl…
VijitSingh97 Aug 2, 2026
ffbf759
release: v1.14.0
VijitSingh97 Aug 2, 2026
dea38d7
chore(perf): record miner-0 baseline for v1.14.0
VijitSingh97 Aug 2, 2026
0fa4e7b
docs(#352): align four sites with accepted ADR 0002 D4 semantics
VijitSingh97 Aug 15, 2026
8d15988
docs: stack-side stratum TLS shipped — rewrite the TLS section to rea…
VijitSingh97 Aug 15, 2026
d5c8656
feat(api): mirror the last control outcome into the enriched feed (#346)
VijitSingh97 Aug 15, 2026
f28020e
fix(status): serialize the hugepages array so the stats row renders (…
VijitSingh97 Aug 15, 2026
a0396d3
test(e2e): prove the appliance contracts against a real /etc in-conta…
VijitSingh97 Aug 15, 2026
3e2fea3
fix(tune): restore pre-sweep overrides when a live sweep is interrupt…
VijitSingh97 Aug 15, 2026
561cfed
fix(doctor,apply): read the miner's own pool-connection state instead…
VijitSingh97 Aug 15, 2026
ac477be
docs: CHANGELOG entry for the status abort fix (verifier catch)
VijitSingh97 Aug 15, 2026
122454d
docs: fifth 'non-latest' instance in D6's refusal list (verifier catch)
VijitSingh97 Aug 15, 2026
1dcc8df
chore: keep the jq filter on its executed line — kcov cannot cover st…
VijitSingh97 Aug 15, 2026
cc05922
Merge pull request #355 from p2pool-starter-stack/fix/341-status-huge…
VijitSingh97 Aug 15, 2026
d6c4c1e
Merge pull request #356 from p2pool-starter-stack/docs/342-tls-reality
VijitSingh97 Aug 15, 2026
2481c9f
Merge pull request #360 from p2pool-starter-stack/docs/352-adr0002-la…
VijitSingh97 Aug 15, 2026
e6c3be8
Merge pull request #361 from p2pool-starter-stack/test/348-appliance-…
VijitSingh97 Aug 15, 2026
7823889
Merge remote-tracking branch 'origin/develop' into fix/343-pool-reach…
VijitSingh97 Aug 15, 2026
ea7aac5
Merge pull request #357 from p2pool-starter-stack/fix/343-pool-reacha…
VijitSingh97 Aug 15, 2026
f69d3bc
Merge remote-tracking branch 'origin/develop' into feat/346-control-s…
VijitSingh97 Aug 15, 2026
86b5e8a
Merge remote-tracking branch 'origin/develop' into fix/347-tune-live-…
VijitSingh97 Aug 15, 2026
aace7c5
chore: collapse the double blank line the changelog merge left
VijitSingh97 Aug 15, 2026
b43832f
Merge pull request #358 from p2pool-starter-stack/feat/346-control-st…
VijitSingh97 Aug 15, 2026
8ff692d
Merge pull request #359 from p2pool-starter-stack/fix/347-tune-live-r…
VijitSingh97 Aug 15, 2026
ab69af7
release: v1.15.0
VijitSingh97 Aug 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
name: Lint (yamllint)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
# pipx is preinstalled on ubuntu-24.04 (same path as diff-cover/zizmor); pin the version so the
Expand Down Expand Up @@ -49,7 +49,7 @@ jobs:
name: Lint (markdownlint)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
# node is preinstalled on ubuntu-24.04; `make lint-md` runs the version-pinned markdownlint-cli2
Expand All @@ -66,7 +66,7 @@ jobs:
SHFMT_VERSION: "3.13.1"
SHFMT_SHA256: "fb096c5d1ac6beabbdbaa2874d025badb03ee07929f0c9ff67563ce8c75398b1"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # no pushes from CI; don't leave the token in .git/config (zizmor: artipacked)
# Install PINNED, checksum-verified shellcheck + shfmt instead of the runner's preinstalled
Expand Down Expand Up @@ -98,7 +98,7 @@ jobs:
name: Test suite
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
# Ubuntu is RigForge's supported target. The suite still exercises the macOS code path here via
Expand All @@ -111,7 +111,7 @@ jobs:
name: Test suite (macOS)
runs-on: macos-14 # Apple silicon; pinned (not macos-latest) to avoid image drift
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
# The Linux job only SIMULATES macOS (STUB_UNAME_S=Darwin + stubbed sed/launchctl). Here the suite
Expand All @@ -137,11 +137,14 @@ jobs:
name: End-to-end (Docker)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
# Runs the real script end-to-end inside a disposable Ubuntu container (RigForge's documented
# Linux target), exercising the genuine Linux deploy path and /etc idempotency with real tools.
# linux.sh runs TWO passes (a fresh container each): the standard deploy, then
# RIGFORGE_APPLIANCE=1 (#348) proving the appliance contracts against a real /etc — units in
# /run/systemd/system, no package installs, no fstab/limits/logrotate writes, --runtime enables.
- name: Run end-to-end suite
run: make test-e2e

Expand All @@ -156,7 +159,7 @@ jobs:
# so fall back to the pushed branch itself — that's an empty diff that trivially passes.
BASE_REF: ${{ github.base_ref || github.ref_name }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # diff-cover needs history to diff the PR against its base branch
persist-credentials: false # the fetch below is read-only on a public repo (zizmor: artipacked)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/links.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
# lychee uses GITHUB_TOKEN to make authenticated GitHub requests and dodge the anon rate limit.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
- name: Install pinned lychee
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Releasing goes through `gh` with GH_TOKEN below, not `git push`, so the checkout never
# needs the token left in .git/config (zizmor: artipacked).
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
GITLEAKS_VERSION: "8.30.1"
GITLEAKS_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # scan EVERY commit, not just the tip — a secret is still a leak once pushed
persist-credentials: false # zizmor: artipacked
Expand All @@ -60,7 +60,7 @@ jobs:
env:
ZIZMOR_VERSION: "1.25.2"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked
# pipx is preinstalled on ubuntu-24.04; same install path as diff-cover in ci.yml's coverage job.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tool-bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # zizmor: artipacked; the push authenticates explicitly below
- name: Check every pinned tool, open one PR per stale pin
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/xmrig-bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
pull-requests: write
actions: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# zizmor: artipacked — never persist the token in .git/config; the push step below
# authenticates explicitly with the job token instead.
Expand Down
119 changes: 119 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,125 @@ All notable changes to RigForge are documented here. The format is based on

## [Unreleased]

## [1.15.0] - 2026-08-15

### Added

- **The enriched feed mirrors the last control outcome (#346).** Pithead's host runner caps its
synchronous `/status` poll after a worker-apply, so a slow auto-rollback outruns it and the change
history row froze at `accepted`. The sister API's `rigforge` block now carries `control` —
`{change_id, status, reason}` read from the control status file — so the next routine poll of the
open read feed catches the terminal outcome without a new authenticated dial to the control port.
A rig that never took a control change, or an unreadable/malformed status file, serves
`control: null`; the mirror never breaks the feed.

- **`doctor` and `apply` now notice when the rig isn't mining at all (#343).** With `pools[0].url`
pointed at an unresolvable host, XMRig loops on DNS errors forever — and `doctor` still said "all
critical checks passed" while `apply` said "Applied config and restarted". Both now ask the miner
itself: its local API's `connection.uptime` is positive exactly while a stratum connection is
live. `doctor` gains a pool-connection check — connected reports the pool, connection age and
accepted shares; running-but-disconnected counts as an issue (the rig is not mining); a silent
API is advisory only; and with the service stopped, one guarded TCP dial of `pools[0]` stands in.
`apply` polls briefly after the restart 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.

### Fixed

- **An interrupted live sweep no longer persists the mid-sweep candidate (#347).** `tune --live`
(and `tune --now --long`) applies every candidate straight into `tune-overrides.json` and restarts
the miner on it, but the cleanup trap only restored the temp dir and the service — a Ctrl+C, a
dropped SSH session, or an error mid-sweep left an arbitrary half-measured candidate saved and
running, silently costing hashrate until the next re-tune. The trap now restores the pre-sweep
overrides and restarts the miner on them, through the same restore step the `--confirm` revert leg
uses. `autotune` (and `tune --now`) had the same gap with its per-trial prefetch merges; its trap
restores the pre-sweep mode via the same merge the sweep uses, so knobs pinned by an offline
`tune` survive the abort too.

- **`status` no longer aborts on a healthy rig (#341).** XMRig's `/2/summary` reports
`"hugepages"` as an array (`[pages, total]`); the status renderer fed it to jq's `@tsv`,
which rejects arrays — so the operator's first command printed an abort line instead of
the stats block, on every rig running v1.14.0. The renderer now joins the pair as
`HugePages: N/N`, scalars pass through, and the suite's shared fixture carries the real
array shape so the class can't return.

## [1.14.0] - 2026-08-02

### Added

- **Missing AES-NI / AVX2 is surfaced 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. `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`; 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.

### Fixed

- **Debian: dependency install no longer fails on `linux-tools-common` (#327).** 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 install: git, build-essential and cmake never arrived either. `setup` now
probes with `apt-cache show` (the same guard the kernel-versioned `linux-tools-$(uname -r)`
package already had) and adds whichever name the distro actually ships; when neither exists it
warns and moves on — cpupower is a tuning aid, never worth losing the compiler toolchain over.

## [1.13.1] - 2026-08-01

### Fixed

- **`doctor` detects kernel lockdown directly instead of inferring it from MSR failure (#333).**
When kernel lockdown is active (distro kernels — Ubuntu, RHEL, Debian — enable it automatically
under UEFI Secure Boot), every `/dev/cpu/*/msr` write is denied and the MSR prefetcher mod
silently can't apply, costing ~5–15% RandomX. `doctor` only reacted after something downstream had
already failed, and its remedy for the most common cause was wrong: `msr.allow_writes=on` is dead
code under lockdown, because the kernel checks `security_locked_down(LOCKDOWN_MSR)` and returns
before the `allow_writes` filter is ever consulted (`arch/x86/kernel/msr.c`). `doctor` now reads
the actual state from `/sys/kernel/security/lockdown` *before* the MSR probes — cause before
symptom — and flags active lockdown (`integrity` and `confidentiality` both block the write) as a
counted issue naming the level, the cost, and the real fix (disable Secure Boot, with the
board-specific menu path). Reading beats inferring from `mokutil`: Secure-Boot-implies-lockdown is
a distro patch, not upstream behaviour. The three messages that guessed between causes now name
the one that applies, the missing-`msr`-module hint no longer blames Secure Boot (the in-tree
signed module loads fine under it — that's a modprobe/packaging problem), and `secure_boot` joins
the guided `bios` checklist (#80), leading it, verified against the same securityfs probe so
`doctor` and `bios` can't disagree. Unreadable securityfs stays advisory — unknown, never a
manufactured issue.

## [1.13.0] - 2026-08-01

The pithead#797 appliance release: an opt-in setup mode for the read-only appliance image —
baked deps, runtime units, image-owned kernel cmdline — plus a grow-only runtime HugePages
reservation so a co-resident stack's pool is never shrunk out from under it.

### Added

- **Appliance mode: `RIGFORGE_APPLIANCE=1` (pithead#797 R1).** One opt-in env flag for running
`setup` on the Pithead appliance image, whose root filesystem is read-only and whose `/etc` is a
volatile overlay — every write there vanishes at reboot, and the image's boot path re-runs setup
each boot instead of relying on persisted state. Under the flag, setup installs no packages (the
toolchain is baked at image build; if a required tool is absent, setup fails naming it), skips the
GRUB leg deliberately (the kernel cmdline, including any 1 GB-hugepage reservation, is
image-owned), renders its systemd units into `/run/systemd/system` and enables them with
`--runtime`, mounts `hugetlbfs` at runtime instead of appending to `fstab`, and skips the
`limits.conf` memlock append (the unit already sets `LimitMEMLOCK=infinity`). Runtime tuning is
unchanged: `modprobe msr`, the grow-only HugePages sysctl (#328), and the performance governor all
work on a read-only root — each decision proven on the pithead#797 R0 bench. `setup --dry-run`
previews the same decisions. Everything else (a normal Linux install, macOS) behaves exactly as
before.

### Fixed

- **Runtime HugePages reservation is grow-only (#328).** `tune_kernel`'s runtime sysctl wrote the
miner's computed requirement 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 = free + whatever a running miner already holds;
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, and it applies with or without
`hugepages_reserve_extra_mb` set. The `setup --dry-run` plan previews the same decision.

## [1.12.0] - 2026-07-19

The pithead#597 producer release: the control-upgrade `/status` contract a one-click worker
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

[![CI](https://github.com/p2pool-starter-stack/rigforge/actions/workflows/ci.yml/badge.svg)](https://github.com/p2pool-starter-stack/rigforge/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
![Platform: Ubuntu 22.04+](https://img.shields.io/badge/Platform-Ubuntu%2022.04%2B-E95420?logo=ubuntu&logoColor=white)
![Platform: Ubuntu 22.04+ / Debian 12](https://img.shields.io/badge/Platform-Ubuntu%2022.04%2B%20%2F%20Debian%2012-E95420?logo=ubuntu&logoColor=white)
[![Miner: XMRig](https://img.shields.io/badge/Miner-XMRig-F26822?logo=monero&logoColor=white)](https://github.com/xmrig/xmrig)
[![Companion: Pithead](https://img.shields.io/badge/Companion-Pithead-F26822)](https://github.com/p2pool-starter-stack/pithead)

Expand Down Expand Up @@ -51,8 +51,8 @@ you like to your stack's single endpoint.
`autotune` in `config.json` re-tunes on a monthly schedule.
- An opt-in `watchdog` restarts a wedged miner (alive but hashing 0 H/s), and with `max_temp_c` set
it stops the miner above that temperature and resumes once it cools.
- `doctor` health-checks HugePages, the MSR mod, the governor, and the service; `status` shows live
hashrate, pool, uptime, and shares.
- `doctor` health-checks HugePages, the MSR mod, the governor, the service, and the pool
connection (the miner's own view of it); `status` shows live hashrate, pool, uptime, and shares.
- `bios` is a guided, resumable walkthrough of the BIOS/UEFI changes RigForge can't make itself
(XMP/EXPO, SMT, PBO/Eco Mode), and re-verifies what took after the reboot.
- `backup` and `restore` snapshot your config and tuning; `support-bundle` collects a redacted
Expand Down Expand Up @@ -147,7 +147,7 @@ sudo ./rigforge.sh apply # regenerate config + restart (no rebuild)
git pull && sudo ./rigforge.sh upgrade # rebuild + restart if the XMRig pin moved

sudo ./rigforge.sh tune --now # run a live tune now — keep the best prefetch mode
sudo ./rigforge.sh doctor # health check: HugePages, MSR, governor, service
sudo ./rigforge.sh doctor # health check: HugePages, MSR, governor, service, pool connection
./rigforge.sh logs # follow live logs, no root needed (also: status; sudo for start / stop / restart)
sudo ./rigforge.sh # provision (or re-provision) the worker — idempotent
```
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.12.0
1.15.0
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ individual topics once you're up and running.
| [Configuration](configuration.md) | Every `config.json` key and default, minimal vs. advanced setups, and how the XMRig config is generated. |
| [Operations & Maintenance](operations.md) | The full command reference, service management, logs, upgrades, and troubleshooting. |
| [How It Works](how-it-works.md) | What the script actually does: dependencies, compile-from-source, HugePages, MSR, NUMA, the governor, and the systemd service. |
| [Pithead Integration](pithead-integration.md) | The worker ↔ dashboard contract: discovery via `:3333`, the read-only HTTP API on `:8080`, and the token rules. |
| [Pithead Integration](pithead-integration.md) | The worker ↔ dashboard contract: discovery via `:3333`, the read-only API on `:8080` (plus the optional enriched sister API on `:8081`), and the token rules. |
| [FAQ](faq.md) | Common questions, plus why RigForge vs. setting XMRig up by hand. |

For how RigForge is versioned and released, see [`RELEASING.md`](../RELEASING.md) and
Expand All @@ -27,7 +27,7 @@ For how RigForge is versioned and released, see [`RELEASING.md`](../RELEASING.md
Significant, cross-cutting decisions are recorded as ADRs under [`adr/`](adr/):

- [ADR 0001: Writable worker-config control path](adr/0001-writable-worker-config-control-path.md) — *Accepted.* How the stack applies config changes through RigForge without breaking the read-only sister API.
- [ADR 0002: Remote worker-upgrade control path](adr/0002-remote-worker-upgrade.md) — *Proposed.* Opt-in remote RigForge upgrade for the stack (#308), extending ADR 0001 from a tuning surface to a code-update one; hash-only trust, no signing.
- [ADR 0002: Remote worker-upgrade control path](adr/0002-remote-worker-upgrade.md) — *Accepted.* Opt-in remote RigForge upgrade for the stack (#308), extending ADR 0001 from a tuning surface to a code-update one; hash-only trust, no signing.

## Quick links

Expand Down
Loading