The tracking lives in Issues.
This file is the shape of the work — what is outstanding, what gates it, and
why it is in this order. Whether a thing is started, blocked or done is on its
issue. What happened, and what it found, is in
changelog.md, dated. Two places holding the same checkbox is
how a checkbox stops being true, and for a month this file was the second
place — #577 moved the history
out.
The order is the seven milestones, each of which states what closes it. This file adds what a milestone cannot say: the order between them, and inside each the order and the gate where an issue cannot carry it alone.
What an entry here may contain:
- A link, the gate, its place in the order, and why. Nothing else. No date except a gate that is a date.
- When the issue closes, the entry leaves. Anything worth keeping goes to
changelog.mdas a dated entry, in the same PR. - An accepted ADR with work behind it has an issue in a milestone. One that does not is the bug, not a section here.
- A PR that implies a purchase edits Everything still to buy in the same commit. That section is the one place a purchase enters or leaves, and the README's count of outstanding purchases is checked against it.
- Nothing blocks these — first because nothing gates them, and three of them carry a date.
- trinity — the return on the box closes 2026-10-08, and the rehearsal is the step that ends it.
- NAS and
Saruman: the domain, then the SOC
— side by side, with no order between them. The domain, which everything
else on
Sarumanpoints at, is built and closed; the NAS's first issue, the one-disk mirror, is done. - automation — the
pipeline that populates the domain; it runs from
phoenix, which exists. - last — gated on the domain, on a household observation, or on something to publish.
- Tier extras — decision-gated, and outside the order until one is decided.
Closes when it is empty.
- #444 Swap the MokerLink
for the CRS326. Decided by
ADR-0041.
Gate: Phase 1 at the bench, then a rack window outside working hours —
neocarries every VLAN, so the swap cannot share the day with anyone working on them. → runbook - #84 Retire the MokerLink's previous SNMP community. Closes with #444: the row cannot be verified, so it is retired by the hardware leaving, not by a measurement. → runbook
- #574 Shut down on the
UPS's signal. Decided by
ADR-0049.
Steps 0–4 were built on 2026-09-23: NUT on
morpheus, its rules, andSarumanandsmaugsubscribed. The sequence is armed and not proved. The gate is a rack visit, which proves the order withupsmon -c fsdand pulls the mains once to replace the card's 47-minute claim with a number. Shares a window with #444 if its parts have landed. → runbook
The rest of the milestone has no order between its issues.
Closes when the nine services serve from trinity and the firewall restore
has been rehearsed on it.
-
#92 Rehearse the firewall restore — done 2026-09-27. The machine was proved on 2026-09-26, inside the return window that closed 2026-10-08 (#674). The rehearsal restored
config-20260926T043704Z— taken fromoracle, schema24.6, 112 rules — onto pfSense CE 2.9.0 ontrinityin 42 minutes, and it booted with no interface-assignment prompt: WAN onem0, LAN onigc0, all six VLANs, 112 rules, the four tripwires, the twelveTunnel_Peersrules and six Kea scopes, and a laptop tagged into VLAN 99 leased10.0.99.100. Three things asked questions the runbook had not answered — Secure Boot (and HP's four-digit confirmation code), a kernel panic from the undisclosed Wireless-AC 9560 underiwm(fixed withhint.iwm.0.disabled), and an installer that needs the internet — and all three are now in §3. The box went to #404 with the I226 card still fitted. It was recorded as in the drawer until the build found it in the slot on 2026-09-28, and it stays there, unconfigured, for the daytrinityhas to be the firewall. → runbook -
#404 Build the tier's host. Built and deployed 2026-09-28 (ADR-0034, → runbook). What is left:
- the DNS failure test, which proves
AdGuardNotAnsweringpages (and closes #135); - the step 10 gate, which the first real photos passed on 2026-09-28
while most of it was still open: the second age recipient, the
off-estate copy, ADR-0022's identity-provider record and ADR-0023's
Independent test. The Immich restore rehearsal is done
(#132, →
runbook). Until
#455 exists, the
originals' only copy beyond the USB disk is the nightly one to
oracle, in the same room (ADR-0064).
#533's converge timer is authored and installs report-only; it closes when
trinityapplies and a Dependabot bump tostacks/sensitivelands with nobody at a shell (→ runbook). #534's CI re-check is already done (#646). - the DNS failure test, which proves
-
The nine services, each authored ahead of the hardware and each open until it serves from the host: #129 Caddy and #130 step-ca first, because everything else sits behind the one and is issued by the other (ADR-0037 — → runbook); then #135 AdGuard Home, serving since 2026-09-28 with
morpheusforwarding to it alone (ADR-0010, ADR-0055) and both probes live, open only for the failure test (→ runbook); #131 Vaultwarden; #132 Immich; #133 Paperless-ngx; #134 Home Assistant (ADR-0035); #136 ntfy — authored, with the decision taken both ways at once: the in-house topics replace ntfy.sh for all three real channels, andurgentandsecuritypage ntfy.sh as well, because a phone away from home cannot reach the tier. The deploy and the observed end-to-end check remain (→ runbook); and #137 Homepage, authored on 2026-09-28 against the running tier:home.matrix.elysium, a directory and not a status page, with live numbers only where a read-only token can read them (Immich, Paperless-ngx) or none is needed (Prometheus), and its widget path measured through Caddy with placeholder tokens before the real ones exist. Deployed and reading real numbers since; on 2026-09-29 it took Tokyo Night, groups by VLAN, and four more tiles read from Prometheus (UPS, firewall, iLO, NAS) with no new rule or credential. The restore path is rehearsed already: → runbook. -
#455 The off-estate copy. The drive is here. It was bought 2026-09-22 and arrived 2026-09-29 (
hardware.md). The key is decided: on 2026-10-01 ADR-0073 settled the first of ADR-0023's two conditions. The copy is encrypted to the household holder's key, with ADR-0024's second recipient as a fallback. The keys are kept instacks/sensitive/household.recipientsand not in a sops rule. The drive holds age archives on exFAT. The copy is built:make household-copycarries it,HouseholdCopyStalewatches it, and the holder's page isopen-the-household-copy.md. The drive was formatted and rehearsed on 2026-10-01. What is left is a person: choosing the holder, and the holder opening the copy once from their own device, without the operator present. Both were meant to come before the tier held real data, and they did not. ADR-0022's first trigger, the first real photo, fired on 2026-09-28. Until this lands, ADR-0064's nightly copy tooraclestands in for the library, off-host and not off-estate. When this lands, it supersedes ADR-0064.
Closes when a workstation can mount the share. Its other condition, the
faulted Exos replaced and the mirror resilvered, is met and is in
changelog.md.
Closes when it is empty. Both things its name names are done. The domain was built by hand on 2026-09-24 and 25, and #414 closed on 2026-10-02 with its authentication generator running and §10 read from Hicks. The SOC followed: Wazuh and Velociraptor reported the six agents in on 2026-09-27.
- #671 Prove the lab's
second key.
secrets/lab.sops.yamlis encrypted to the offline technical second as well asalexander's key since 2026-10-07. What remains ismake secrets-verify-backup STACK=lab KEY=…with the offline copy. - #920 One on-demand VM
per dotfiles OS layer. It ships in four phases
(ADR-0090):
- Debian, Fedora and Windows
(
test-the-dotfiles-layers.md); - openSUSE and Arch;
- Alpine and Gentoo, from their published images;
- NixOS.
- Debian, Fedora and Windows
(
- #921
garuda, an analyst workstation. Kali Purple without its SOC, always on besideodin, and the home ofdotfiles-Defense(ADR-0091). It ships in three phases:- Template 910, the guest, its tools and dotfiles
(
build-the-analyst-workstation.md). - Enrolling it in Wazuh and Velociraptor, the first Linux guest in either (ADR-0092).
- OpenVAS on demand, scoped to the domain's six by nftables (ADR-0093).
- Template 910, the guest, its tools and dotfiles
(
- #538, #529, #562 and #576 are the host's own blind spots, with no order between them. #576 watches the Proxmox firewall that #566 turned on, so it is the one of the four that has already lost its excuse for waiting.
Closes on BloodHound running where nothing attacks it.
- A chain, in this order:
#440 Packer (done
2026-10-03,
ADR-0074:
901 Ubuntu, 911 Windows 11 and 912 Server 2025 built from
smaug-iso, each clone passingscripts/packer-smoke.sh, SSH included, → runbook; Kali's template waits forifrit, #790) → #445 OpenTofu (done 2026-10-03, ADR-0076: state encrypted, escrowed, and both proofs run against a real apply, → runbook) → #448 Ansible and ADR-0029's six guests from the pipeline (written, ADR-0077, →ansible/; applied to the hand-built six on 2026-10-03, with a second run ofchanged=0andverify.ymlpassing on all six; closes on atofu destroyand rebuild, so it waits for the six to be declared intofu/with pinned MACs; #440's templates exist since 2026-10-03) → #449 users and deliberate weaknesses (the population and the authentication generator are--tags population,authgen, ADR-0078; what remains is the rest ofbuild-the-lab-domain.md§5, which covers the tiers, the SPN account, the Tier 0 GPO and the shares, and then the weaknesses, each its own tag on top of the population) and #450 Sysmon and Pktmon (ADR-0080) → #451 BloodHound (ADR-0081, → runbook), which closes the milestone. All of it runs fromphoenix(ADR-0043, → runbook). #440's templates read their installers fromsmaug-iso, the ISO store ADR-0072 put onerebor/iso. Every file there is hashed daily onSarumanagainst the list inscripts/collect-iso-store-state.sh, andIsoChecksumMismatchpages if one changes, because the export trusts an address and Packer does not check an ISO it is handed from storage. Copying the installers there, listing their hashes and installing the check isbuild-the-lab-templates.md§2b.
Gated on the domain, on a household observation, or on something to publish.
- #421 Buy
ifritand build the range. Gated on #414 and the SOC: an attack VM pointed at an uninstrumented estate teaches nothing. Both are met. What gates the build now is its RAM kit and NVMe drive, in Everything still to buy, and its place in the #919 rack move. → runbook - #447 A cloud relay — only if there is ever something to publish; the day it exists it replaces the dynamic DNS record (ADR-0044).
Beyond ADR-0008's nine: each needs its own decision before it is authored, and none is in the order until one is taken.
- #147 Miniflux — decided by ADR-0057, deployed on
trinity2026-09-29. What remains is committing the encryptedsecrets/sensitive.sops.yamlthat carries its two keys, and seeingminiflux-db-datain a nightly set. - #145 Memos — decided by
ADR-0059
and deployed on
trinity2026-09-29, and reachable from Hicks by name the same day. The admin registered and closed registration on 2026-10-02. Nothing is left; #145 closes with this. It holds no real notes until ADR-0023's Durable condition is met, which is the tier's condition and not this issue's. - #146 Mealie, as
recipes.matrix.elysium. Decided by ADR-0060 and deployed ontrinity2026-09-29. It is the one service here meant for the household to open rather than to benefit from. It uses no new firewall rule and no SOPS secret, and it has no second factor, which is named alongside Immich and AdGuard. The default admin was renamed and re-passworded the same day. Nothing is left. - #144 linkding — decided by ADR-0061 and authored in
stacks/sensitive. Deployed ontrinity2026-09-29, with its host override, and the operator's first login with the superuser password from SOPS is done. Nothing is left. - #143 Stirling-PDF is
deployed on
trinity2026-09-29 (ADR-0063): behind Caddy atpdf.matrix.elysium, login from SOPS, and its documents held on a tmpfs so none reaches a disk. Thepdfoverride onmorpheusis in, and TOTP is enrolled on the admin. Nothing is left; #143 closes with this.
The one list, because purchases kept appearing one at a time in issues, ADRs
and runbooks until one box had been bought for two jobs
(ADR-0034).
Nothing enters the table without a decision the operator made, and a PR that
implies a purchase edits this section in the same commit. Parts on hand are
in hardware.md; a part in transit is its issue's to track.
smaug's memory and the off-estate drive both left this table on 2026-09-22
by that rule, bought rather than dropped
(#599,
#455) — and it
was bought to a different shape than the row described, which is in
hardware.md and in
changelog.md rather than here.
The two Windows 11 Pro keys left it on 2026-09-25 by the same rule. They were
bought and activated on the lab domain's two endpoints, carbuncle and
siren (ADR-0029,
#414). The replacement for
smaug's faulted Exos never entered it. The eBay return came back as a
refund rather than a new drive, and the drive was bought outright on
2026-09-24, the day the choice was known
(#558). It is in
hardware.md.
Buy these, and the estate as decided is fully bought. The table was empty
from 2026-09-25 until ifrit was bought on 2026-10-05, short of the spec its
ADR set; its last two rows are what it still needs. On 2026-10-13 the move
into the 32U rack (#919) put
its parts here, which had been listed only in its runbook's §0.1, and
Saruman's memory joined them. Already on hand, so not listed: the frame,
the VESA mount, trinity's ProDesk tray and the velcro.
| Item | For | Decided by | When it is needed |
|---|---|---|---|
| Four-post shelf, adjustable to 29", at least 17" deep, rated for 50 lb or more. StarTech ADJSHELFHDV fits: 19.5–38", 27.5" tray, 330 lb | smaug on its side, U5–U9 |
hardware.md, 2026-10-12 |
Before the #919 window |
| 2 × 1U four-post vented shelf, adjustable to 29" | prometheus U10, oracle U12 |
hardware.md |
Before the #919 window |
| 1U sliding keyboard drawer, front-rail mount | The console, U24 | hardware.md |
Before the #919 window |
| 1U mount made for a ThinkCentre Tiny, holding its brick | ifrit, U18 |
hardware.md |
Before the #919 window |
| 1U horizontal cable manager | U20, between switch and panel | hardware.md |
Before the #919 window |
| 1U vented blank | U22, the air gap over the CRS326 | hardware.md |
Before the #919 window |
| One factory-made Cat6 patch cable, long enough for the run | The XB7's striped 2.5G port to morpheus's em0, replacing the hand-crimped patch |
#923 | Now: it should not wait for the move |
| Short factory-made Cat6 patch cables, a pack, in the ADR-0009 VLAN colours | Switch to patch panel in the new rack | move-into-the-32u-rack.md §6.1 |
Before the #919 window |
| Spare M6 cage nuts and screws, a pack | The frame | move-into-the-32u-rack.md §0.1 |
Before the #919 window |
| 8 × 16 GB DDR4 RDIMM, dual-rank, matched to a fitted stick's label (2Rx4 or 2Rx8, PC4-2400) | Saruman, 128 GB to 256 GB, one more per channel on both CPUs |
The operator, 2026-10-13: headroom | In the #919 window, while the DL360 is out of the rack |
| 2 × 16 GB DDR4 SO-DIMM kit | ifrit, replacing the 8 GB it shipped with |
ADR-0017: 32 GB socketed | Before build-the-playground.md §1 |
| 1 TB NVMe SSD | ifrit's range and its snapshot reverts |
ADR-0017: NVMe | Before build-the-playground.md §1 |
The last one, bought 2026-10-05: ifrit, the range host — a quiet
SFF box, NVMe, two socketed DIMM slots with 32 GB fitted, one NIC
(ADR-0017,
#421). The box is a
refurbished ThinkCentre M80q, and it arrived on 2026-10-14. It shipped with
8 GB and a 256 GB SSD, so the two rows above are still to buy and fit.
hardware.md records the box.
Only if a decision is taken, and none is pending — these are not on the list, and each names what would put it there:
- A dedicated firewall cold spare: deferred by ADR-0034 until the tier
holding real data makes an hour of firewall downtime unacceptable. There is
one ProDesk, not two —
trinityis the tier's host and the firewall's spare hardware — and the reserved namezionbelongs to the box this bullet would buy (ADR-0038). - A Zigbee or Z-Wave coordinator for Home Assistant: only if a device needs one, and nothing on Skids does today — Ring is cloud, Hue has its own bridge, the assistants are Wi-Fi (#134).
- More memory for
ifritthan ADR-0017's 32 GB: only if 32 GB proves short. Reaching 32 GB is above, in the purchase itself. - A Coral TPU and RTSP cameras: declined with Frigate (ADR-0032).
- A reachable address for the WireGuard endpoint, in either of its paid forms: ADR-0044 answers it with a free dynamic DNS record instead. A static address is not sold on the residential service the house buys and enters only if that service changes; a VPS relay is #447's purchase, entered when there is something to publish.
Never, and the documents say so: anything to make prometheus or oracle
faster or bigger, and any disk or memory on account of Wazuh — ADR-0030 sizes
it to what Saruman has. A 2012 MacBook running the whole observability stack
is the point, not a problem to spend money on.
The one exception, and it narrows this line rather than reversing it: a
consumable whose failure is a safety or availability event is not an
upgrade. prometheus's cell was that case and is replaced
(#454); so is oracle's,
fitted 2026-09-29 (#531).
Nothing else about either machine is.
The mirror of the roadmap, and recorded for the reason turned around: a service rejected for good reasons with nothing written down is indistinguishable from one nobody thought of. It gets proposed again, evaluated again, and can be deployed on the second pass because the first pass left no trace (#150).
These are declines, not bans. Each records what was weighed, so a later proposal argues with the reasoning rather than restarting from nothing — and several of them name the condition that would change the answer.
- Nextcloud — the obvious "one app for everything" answer, and declined
because it overlaps three services already chosen: Immich
(#132) for photos,
Paperless-ngx (#133) for
documents, and file sync. It is more surface and more upkeep than all three
together, and its app ecosystem is a second, unpinned supply chain operating
outside
compose.yaml— the same objection that rules out Home Assistant add-ons in #134. If the want is file sync rather than a suite, Syncthing does that with no server-side application at all, and would be the thing to evaluate instead. - The *arr stack — Sonarr, Radarr, Lidarr and the indexer and subtitle services around them. Five or more services, each holding indexer credentials and each with a standing outbound appetite, added to the tier ADR-0008 deliberately defined as low consequence. The media tier's whole justification is that its compromise costs a film night; this raises what is at stake there while adding the most moving parts of anything on the list. Declined for now rather than permanently — but it should be its own decision with its own reasoning, not a footnote to the NAS build.
- YunoHost-class installers — YunoHost, Tipi, HomelabOS, StartOS and similar. They own the compose file, the update path and often the reverse proxy, which conflicts with essentially everything this repository does on purpose: one compose stack per host (ADR-0004), every image pinned by tag and digest, configuration validated in CI, secrets rendered from SOPS at deploy time. Adopting one trades the properties that make this estate reproducible for a faster first install. Wrong trade here — and the trade, not the software, is the reason.
- Guacamole — a clientless browser-reachable RDP/VNC gateway. Convenient, and a larger concession on the management segment than SSH already is: it turns any browser session on Hicks into a potential path to every console in the estate, and it stores connection credentials to do it. The estate already has a KVM in U6 for physical console access. Declined. The remote-access question it gestured at is answered differently by ADR-0042: WireGuard to the lab jumpbox, terminating on ImaginationLAN and reaching the lab only. That is not a softening of this decline — it stores no connection credentials at a gateway, it never touches Winterfell, and the boundary is the firewall's rather than an application's. Guacamole's objection was about the management segment, and nothing about ADR-0042 goes near it.
- Frigate — locally-processed object detection on camera streams, and the
one service on the shortlist that would change the network's shape rather
than its population: continuous RTSP from every camera through the
99 → 20rule ADR-0008 authorised for Home Assistant's occasional control traffic, a clip archive that is the most sensitive data store in the house on the management segment, and a Coral or GPU the sensitive tier does not have. Declined by ADR-0032 on a fact that comes before all four: every camera on Skids is a Ring device, and Ring exposes no local stream, so Frigate has nothing to consume. Adopting it is a camera replacement first, which is its own decision. Reopened by RTSP cameras, an accelerator, and a separate row in ADR-0008's table for the continuous rule — all three, each decided on its own (#149). - Plex — the media server the household already knows, with polished
clients, and ADR-0008 listed it beside Jellyfin for that reason. It is also
the one proprietary service on the shortlist: clients authenticate through
plex.tveven on a local network, nobody outside the vendor can read the image that digest pinning fixes, and features have moved behind a subscription before. ADR-0016 deferred it against one test, whether any screen on CasaBonita lacks a working Jellyfin client, and the test was run by 2026-09-28: the LG OLED, a console, and the phones and tablets all play from Jellyfin, and the Xumo box is not used for the library. Declined by ADR-0056. Reopened by a screen the household uses for library media that has no working Jellyfin client, with Remote Access off even then (#139). - HomeBox — a home inventory with items, locations, warranties and receipts
as attachments. It was proposed for the sensitive tier as the place for the
serials
hardware.mdwithheld. By the time it was argued,hardware.mdcarried the serials and warranty dates itself. Paperless-ngx already held the receipts and manuals, and a licence key is Vaultwarden's. What remained was a list of household objects, which does not earn a place on the segment ADR-0008 calls its real cost, and which would be a second inventory that drifts from the first. Declined by ADR-0058. Reopened by a household need to track non-infrastructure possessions that Paperless's tags cannot meet, with the proposal saying what leaveshardware.mdso there is still one inventory (#148). - Proxmox clustering — joining
Sarumanandifritinto one cluster once #421 makes them two Proxmox hosts on VLAN 30: one pane of glass, guest migration, shared storage. The first entry here that is a capability rather than a service, and declined by ADR-0039 because a cluster is one/etc/pve, one realm and one quorum across exactly the boundary ADR-0007 draws — root on the attacker's host becomes root on the estate's — and cannot be built without the second NIC or VLAN-aware bridge ADR-0014 names as grounds to reopen it, on a host that is off between sessions by design and would take the estate's hypervisor's quorum down with it. Reopened by a third host that is neither attacker nor defended estate, a live-migration need that snapshot-and-rebuild does not serve, orifritceasing to hold attack tooling — each its own decision (#443). - Authelia / Authentik — already decided, and listed only so the next shortlist does not present it as new. ADR-0008 defers SSO knowingly for two users with no external access; ADR-0022 gives that deferral an expiry, which is what #103 closed on. An identity provider is also the only route to a second factor for Grafana, Immich and AdGuard Home, none of which can carry one themselves — so this decline has a known end, unlike the others here. Pocket ID, the lighter passkey-only provider, has been weighed and changes nothing until a reopen condition fires. It is the first candidate when one does (#860, the note on ADR-0075).
What closed, when, and what it found is in changelog.md,
newest first. An entry leaves this file on the day its issue closes and goes
there with the date.