Version: Current
Historical release snapshot. These docs are frozen. Read current docs.
Owner decision map: 2026-10-21
Historical, as of 2026-10-21. This is a dated compilation of the decisions
open on 2026-10-21 and is kept as history. It is not a statement of the current
fleet, host names or open decisions; read definitions/README.md and the
product definitions in definitions/ for current product state.
Compiled: 2026-10-21T22:06Z (23:06 BST) by worker W122 on deepseek/deepseek-flash.
Scope: every open decision that is the owner’s to make — not a worker’s, not a
repo’s — across the estate, as registered at the time of compiling.
Authority: this is the single map. Where it disagrees with a working note, this
map wins until the map is refreshed (see “Expiry”). Where a live probe disagrees
with this map, the probe wins and the row is corrected here.
Decisions: 18 open. Three have a hard external date; the rest expire on a
chosen review date so the map cannot outlive its evidence.
This document is a register, not a plan. It does not assign work, it does not approve spend, and a row being here is not an instruction to act. It exists so that a reader can answer four questions without a session: what is undecided, who decides it, what it blocks, and when this row stops being trustworthy.
0. How to read a row
Section titled “0. How to read a row”Each decision carries the same seven fields.
| Field | Meaning |
|---|---|
| Decision needed | The question, phrased so that one person can answer it in one sentence |
| Options | The real alternatives, with the consequence of each. An option with no cost is not an option |
| Who decides | The single owner. If two names appear, it is not decided yet |
| Blocking | What cannot be claimed, shipped, priced or published until this is answered |
| Evidence | observed (a tool result, cited), derived (from observed facts, stated), unknown (and what would settle it) |
| Default | What happens if nobody decides — every decision has one, and it is usually “the broken thing stays broken” |
| Stale after | The date this row stops being evidence. After it, re-verify before citing |
House vocabulary follows GLOSSARY.md; the claim model follows AGENTS.md
(“Claims”). A gate verdict is evidence about a tree, never proof a feature works,
so no row here claims health from a green gate.
Expiry
Section titled “Expiry”- Each row has its own stale after date.
- The whole map is stale after 2026-11-04 unless refreshed, because the fastest-moving rows (vendor seats, backups, reboot window) cannot be carried further than that without new observation.
- A stale row is not deleted. It is re-observed and re-dated, or marked decided with the answer and the date. Rows are append-only history, like the wayfinder tickets.
What this map is not
Section titled “What this map is not”It is not the wayfinder frontier. The frontier in
docs/wayfinder/map.md is the harness’s own ticket queue; this map is the
owner’s decision debt across products and hosts. A decision here can be
resolved without opening a wayfinder ticket, and a frontier ticket can be
worked without touching this map.
1. Summary
Section titled “1. Summary”| ID | Decision | Owner | Blocks | Stale after |
|---|---|---|---|---|
| D01 | Qwen supply: reseat, retire, or hold | Operator (vendor spend) | Model catalogue honesty, pinned route | 2026-10-28 |
| D02 | Which Grafana is sanctioned; remove the other | Operator (host ownership) | Observability truth, one credential defect | 2026-11-04 |
| D03 | WP1 Path A (regenerate) or Path B (splice) | Massprox owner | Engine-coverage claim, dsh rollout | 2026-10-28 |
| D04 | Mailbox dedupe: four coupled answers | Mailbox owner | PR #12, every dedupe code path | 2026-11-04 |
| D05 | Repair fleet backup; libvirtd stance on core | Operator (core) | “The estate is backed up” claim | 2026-10-24 |
| D06 | dsh reboot window | Operator (live host) | Kernel patch level on dsh | 2026-10-31 |
| D07 | Skills: dedupe, rewrite or retire | Operator (workstation) | Skill catalogue truth, gate baseline | 2026-11-18 |
| D08 | Cleanup register: approve the 146G | Operator (data owner) | Disk headroom, backup semantics | 2026-11-04 |
| D09 | xenode.cloud: claim or abandon | Operator (legal identity) | Brand, product naming, copy | 2026-12-15 |
| D10 | Mint the foxd enrollment token | Operator (panel admin) | First real node, hosting claims | 2026-10-28 |
| D11 | Merchant of record for Relay | Operator (entity) | Any paid checkout | 2026-11-20 |
| D12 | Direct DeepSeek seat: top up, move or retire | Operator (vendor spend) | Price card, reliability claim | 2026-10-31 |
| D13 | gitleaks: allowlist, fix fixtures, or stay red | Operator (security) | “No secrets” claim, CI green | 2026-11-04 |
| D14 | Publish radar on the public edge, or not | Operator (public surface) | Radar as a product, W19’s window | 2026-11-04 |
| D15 | Restart-coordination record (ACR-004) | Operator (acumen) | Restart safety, cap-tracker truth | 2026-10-28 |
| D16 | Open WebUI: keep stock, replace, or licence | Operator (surface owner) | Consumer tier, licence position | 2026-11-20 |
| D17 | One account per platform per person | Operator (identity) | Vendor identity, account recovery | 2026-11-20 |
| D18 | GitHub Actions billing: restore CI or replace it | Operator (payer) | Every PR gate, every CI claim | 2026-10-28 |
Reading the table by consequence rather than by ID:
- Wrong money: D01, D08, D11, D12, D15.
- Something is broken now: D05 (backups, two nights), D13 (scan red).
- Something is dark now: D09 (domain), D10 (node unenrolled), D14 (no edge).
- Nothing is on fire, but a claim is unsupported: D02, D03, D04, D06, D07, D16, D17.
- Found while compiling this map: D18 — the CI that would have gated this very change could not start.
D01 — Qwen supply: reseat, retire, or hold
Section titled “D01 — Qwen supply: reseat, retire, or hold”Decision needed. Does the company buy working Qwen vendor keys, remove Qwen from the catalogue, or keep the seats dark and stop advertising the model?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Reseat | Add working keys for the 11 dark seats (cloud/payg/token) | Restores the cheapest-first tier, but 11 purchases plus a re-verification sweep before any of it is claimable |
| B. Retire | Remove Qwen from the compiled catalogue and drop the pinned route | Honest and small. Loses the cheap tier and rewrites the price card |
| C. Hybrid (recommended) | Keep one Charm seat, retire the ten dead seats, stop advertising charm/qwen3.8-flash until a seat answers |
Smallest blast radius: no spend, no lie, option stays open |
| D. Hold | Change nothing | Circuits stay open; auto avoids the provider; pinned callers keep receiving 503 |
Evidence
Section titled “Evidence”observed(earlier session, SQLite aggregates ontcp, re-quoted in the acumen state-and-recovery research): 11 Qwen seats return vendor 401/403, 286 auth rows in 24 hours; 649 attempts and 0 successes ever between 2026-10-17T22:37Z and 2026-10-21T21:35Z; Charm hypercredit reads 0.0; qwen-cloud-plan-4 disabled.observed: the pinned routecharm/qwen3.8-flashis a single flapping seat — 1,158 ok against 2,655 circuit-open refusals and 994 timeouts, TTFT p95 26.91 s.derived: option D already costs telemetry quality — thousands of refusals and timeouts in the usage table keep any SLO statement unquotable.
Who decides
Section titled “Who decides”Operator, because every option except B spends money or gives up a price tier.
Blocking
Section titled “Blocking”Any copy, price card or comparison that lists Qwen3.8-flash; the pinned-route SLO; closure of acumen #190 (the seat gate that is already live).
Default if nobody decides
Section titled “Default if nobody decides”D. Qwen stays in the catalogue with zero live capacity.
Stale after 2026-10-28 — vendor key state changes faster than any other row.
D02 — Which Grafana is sanctioned; remove the other
Section titled “D02 — Which Grafana is sanctioned; remove the other”Decision needed. The estate runs two independent Grafana instances on two hosts. Which one is the sanctioned fleet Grafana, and does the other get removed or formally scoped?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
A. Sanction tcp (native grafana-server 11.0.0 behind tcp.ts.tcp.systems), remove the dsh container |
Keeps the dashboards the fleet already uses; loses the dsh stack’s VictoriaMetrics/Loki/Alertmanager companions | The container stack carries metrics, logs and alerting — removing only Grafana leaves those orphaned |
B. Sanction dsh (container 13.2.4 with VictoriaMetrics, Loki, Alertmanager, cAdvisor), remove tcp’s |
One modern stack with logs and alerting; retires the tcp vhost and its self-signed cert |
Two hosts’ dashboards must be re-pointed; the tcp dashboards become history |
| C. Keep both, declared | A written split: tcp = fleet availability dashboards, dsh = search/ingest metrics |
Two credential surfaces, two upgrade paths, two failure modes — but no migration |
| D. Hold | Both keep running | Ambiguity persists, and one of them keeps a known credential defect |
Evidence
Section titled “Evidence”observed(2026-10-21, live):tcprunsgrafana-server.service, Grafana 11.0.0 on 127.0.0.1:3000, proxied at thetcp.ts.tcp.systemsvhost with a self-signed certificate valid to 2027-10-20.observed(2026-10-21, live):dshruns containergrafana/grafana:13.2.4on 127.0.0.1:3000 alongsidevictoriametrics,loki,alertmanagerandcadvisor.observed(dashboards record, 2026-10-20):tcp’s Grafana admin account is still the packaged default, and its dashboard folderFleetwas empty before that work. This is a credential defect independent of the choose-one question.derived: whichever instance is retired, the other must own every dashboard query currently documented against it, or the records go stale silently.
Who decides
Section titled “Who decides”Operator. It is a host-ownership and credential decision, not an operations preference.
Blocking
Section titled “Blocking”Any statement that fleet dashboards are authoritative; the observability section of any status page; removing the default admin credential (only meaningful once one instance is chosen).
Default if nobody decides
Section titled “Default if nobody decides”D, plus the default-password defect stays on tcp.
Stale after 2026-11-04.
D03 — WP1 Path A (regenerate) or Path B (splice)
Section titled “D03 — WP1 Path A (regenerate) or Path B (splice)”Decision needed. How does the reviewed engine-coverage set land on dsh —
by regenerating each profile’s full settings.yml, or by splicing only the
engines: section?
The runbook is explicit that nothing has been run and that the two paths are not equivalent. Status at authoring: decided-needed / not deployed; the generator change (WP1 code) is merged, the gateway cache (WP5) is deployed, the engine set is not.
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Regenerate | bin/gen-settings.py writes each profile’s complete file with inactive: false and weights |
Reproducible and converging with the committed copies — but it is a replacement: live hand-tuning inside engines: is discarded, and engines measured hostile from this egress (google, brave, qwant, openalex) return enabled and burn pool budget on failures |
| B. Splice (recommended by the runbook’s own risk ordering) | apply-engines.py replaces only engines: with the reviewed 23-entry set, preserving secret_key, limiter, search: and the egress block; writes a dated backup file; supports --dry-run |
Smallest diff, reversible per file. Leaves github code disabled (its token is supplied per install), which is a deliberate divergence |
| C. Defer | Nothing changes on the host | 83 of 265 engines enabled stays the measured truth; the coverage claim cannot be made |
Evidence
Section titled “Evidence”observed(runbook facts, each re-checkable on the host): all three instances load 265 engine entries, 83 enabled; expected after rollout ~110 enabled (an estimate, measured by Stage 1).observed:rx-proxy-apply.servicerestarts all three containers when it runs, and its timer fires every 15 minutes — so any manual edit races a 15-minute recreation unless the timer is held.observed: the health endpoint (healthz) answers 200 with a dead engine set, so health is not evidence that the rollout worked.derived: a path A run that re-enables hostile engines will look successful on that endpoint and fail in the search-quality numbers, which is the failure mode the pool’s economics cannot absorb.
Who decides
Section titled “Who decides”Massprox owner. The choice changes which engines the company pays to fail.
Blocking
Section titled “Blocking”The engine-coverage claim; the WP1 rollout window on dsh; any benchmark that
compares against the 83-engine baseline.
Default if nobody decides
Section titled “Default if nobody decides”C. 83 engines, no change, no claim.
Stale after 2026-10-28.
D04 — Mailbox dedupe: four coupled answers
Section titled “D04 — Mailbox dedupe: four coupled answers”Decision needed. Issue #9 (M4) proposes keying dedupe on SMTP transaction identity instead of message bytes. Four decisions gate it and they must be made together; the brief is ADR-0006 (merged as a decision brief, status proposed), and it amends ADR-0005 (held inside PR #12) once accepted.
The four decisions
Section titled “The four decisions”| # | Question | Options | Consequence |
|---|---|---|---|
| 1 | Visibility vs silent loss | A silent (current: answer 250, write nothing) · B visible (second membership, new UID over the same block) | B makes every delivery IMAP-visible and grows index rows, not bytes. Current behaviour logs one line per duplicate and nothing durable |
| 2 | Identity derivation | A content hash (ADR-0003) · B Message-ID + Date, else envelope sender + Date · C sender + recipient + queue id |
A is retry-safe but conflates a retry with “same body, different sender”. B needs nothing new from the MTA and is what PR #12 implements. C is strongest but LMTP carries no queue id today |
| 3 | Journal persistence and format version | A additive optional field, V unchanged · B rebuild on replay, persist nothing · C bump the version |
C without an accept-old path makes every existing journal and checkpoint corrupt at first open, because both loaders fail closed on a version mismatch. A is PR #12’s choice |
| 4 | Duplicate: true semantics |
A current (return the first UID) · B distinguish (retry returns the original UID; distinct same-body delivery returns a new UID) | A leaves callers unable to tell a retry from a dropped distinct message |
Two coherent bundles:
- Minimal-risk: 1=B + 4=B on the current content hash (2=A, 3=A/B). Stops the loss being silent; does not fix the conflation.
- Issue #9’s proposal: 2=B (or 2=C where the MTA supplies a queue id) + 4=B + 3=A. Fixes the conflation with no migration. This is what PR #12 does.
No bundle needs 3=C.
Evidence
Section titled “Evidence”observed(issue #9, open,bug):Deliverhashes the normalised message and dedupes per account; the envelope sender and delivery time are not in the key; a hit returnsDuplicate: truewith the first UID and LMTP answers 250. An hourly monitoring job with a stable body and noMessage-IDis delivered once, ever, and every later alert is acknowledged and dropped.observed(ADR-0006, merged 2026-10-21 in PR #14): the numberings are settled — the brief is ADR-0006, the held PR adds ADR-0005, and the two are sequential, not alternatives to be merged side by side.observed: PR #12 is open and held on these answers.unknown: whether the MTA in deployment can supply a queue id out of band (option 2=C). Resolve by reading the maddy/LMTP configuration ontcp.
Who decides
Section titled “Who decides”Mailbox owner. The coupling means a partial answer is not usable.
Blocking
Section titled “Blocking”PR #12; any code on issue #9; the mailbox’s delivery-semantics documentation.
Default if nobody decides
Section titled “Default if nobody decides”Current behaviour: silent, content-hash, V=1, first-UID return. The hourly-alert
loss continues.
Stale after 2026-11-04.
D05 — Repair fleet backup; libvirtd stance on core
Section titled “D05 — Repair fleet backup; libvirtd stance on core”Decision needed. Two separate questions that arrived together on core:
(1) is the nightly fleet backup repaired, re-scoped, or declared
non-authoritative; and (2) is libvirtd deliberately replaced by the modular
daemons, or is masking it a mistake to undo?
Options — backup
Section titled “Options — backup”| Option | What happens | Consequence |
|---|---|---|
| A. Attribute and repair | Run the backup per host with --only until the failing target is named, then fix it |
Restores a seven-day snapshot; costs one diagnostic run. The script accumulates a non-zero exit from any failing host, so one bad target fails the whole unit |
| B. Re-scope | Back up only the targets that succeed; record what is unprotected | Honest and cheap; requires writing down what is not covered, which is the part usually skipped |
| C. Declare non-authoritative | Treat the 43.4G output as history and rely on restic (mail), Sentry’s own backup and release artefacts | Removes a false comfort; leaves hosts without a snapshot |
| D. Hold | Status quo | The unit fails again at 03:34 and the register’s A2 entry (43.4G of output from a failing producer) gets larger |
Options — libvirtd
Section titled “Options — libvirtd”| Option | What happens | Consequence |
|---|---|---|
| A. Adopt modular daemons (recommended) | Keep libvirtd masked, keep virtqemud enabled, fix floki’s probe so it accepts the modular model |
Matches where libvirt is going; needs a probe change before floki check can be believed |
B. Unmask libvirtd |
Restore the monolithic daemon | Reverses a deliberate-looking change made 2026-10-21 01:24, and duplicates the modular daemons |
C. Declare core not a libvirt host |
No VMs on core | Closes the VPS lane on that host; floki’s browser/console work has nowhere to land |
Evidence
Section titled “Evidence”observed(live,core, 2026-10-21):fleet-backup.servicefailed with exit 1 on 2026-10-20 03:45 and 2026-10-21 03:47 (BST); it succeeded on 2026-10-19 03:32; memory peak 7.6G then 2.4G; next timer run 2026-10-22 03:34.observed: the script is rsync-over-ssh with hardlink snapshots, seven retained, and it accumulatesRC=1from any failing host or path — the unit’s exit code names no target. The failing target is therefore unknown until a per-host run names it.observed:libvirtd.serviceis a symlink to/dev/null, created 2026-10-21 01:24;libvirtd.socketandlibvirtd-ro.socketare disabled;virtqemudandvirtqemud.socketare active;virsh -c qemu:///system list --allanswers with zero domains; the QEMU domain directory holds only autostart and networks.observed:nfs-serveris active and exports only to 100.64.0.3 (edge).observed(defect, worth fixing regardless of the decision):core’s fstab carries three remote NFS mounts whose mount points do not match the tailnet map — 100.64.0.3 (edge) is mounted at/fleet/tcp, 100.64.0.4 (core itself) at/fleet/edge, and 100.64.0.5 (tcp) at/fleet/scaleblade. Verified against each host’s own address. Anything reading/fleet/*reads the wrong host. This is a plausible contributor to the backup and verification confusion and must be corrected before either is trusted.corrected: an earlier audit described the cause as “sshfs mounts”. The script uses rsync over ssh; the mounts are NFS automounts with a 120 s idle timeout, which is why they are absent fromfindmntwhen idle. The label was wrong; the failure is real.
Who decides
Section titled “Who decides”Operator, as host owner and data owner. The backup answer also needs the security owner’s view (what is acceptable to lose).
Blocking
Section titled “Blocking”Any claim that the estate is backed up; the cleanup register’s A2 row (43.4G of
fleet-auto output — deleting it hides the failure); floki’s VPS lane on core.
Default if nobody decides
Section titled “Default if nobody decides”D and the current mask: a failing nightly backup, and a floki check that reports
libvirtd available while the probe’s assumptions and the host’s daemon model
disagree.
Stale after 2026-10-24 — a broken backup cannot be carried a week.
D06 — dsh reboot window
Section titled “D06 — dsh reboot window”Decision needed. dsh has a pending kernel image and has been up two days.
When does it reboot?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Named window before 2026-10-31T16:00Z | Reboot in a declared slot, then verify the search stack and the expiry timer | One planned interruption; the kernel is current before the search-preview deadline |
| B. Named window after the cutoff | Reboot once the DeepSeek preview has ended | Same outcome, later patch; the expiry service has already run |
| C. Defer | No reboot | The registered kernel stays unapplied; the pending-reboot state is a standing finding |
| D. Reboot now, unannounced | Drops in-flight bench runs and interrupts the DSH web session — the harness manual forbids restarting the user’s live web process |
Evidence
Section titled “Evidence”observed(live,dsh, 2026-10-21): up 1 day 23 h since 2026-10-19 23:10:56; running kernel 6.12.107; the reboot-required marker is present forlinux-image-6.12.113.observed:searxng-deepseek-expire.timeris armedOnCalendar=2026-10-31 16:00:00 UTCwithPersistent=true, and the unit comment says a host that was down at the cutoff runs it on the next boot.derived(correction to the register’s framing): the reboot is not gated by the DeepSeek cutoff.Persistent=truemeans a reboot before 16:00Z either lets the timer fire on time or catches up at next boot. “Pre-2026-10-31” is a preference, not a constraint.observed:rx-proxy-apply.timerfires every 15 minutes and recreates all three SearXNG containers, so a reboot is not the only restart in that hour.observed:rx-search-bench.timerruns daily at 06:30, anddsh-web.serviceserves the operator’s live session.
Who decides
Section titled “Who decides”Operator, as the owner of the live host and the session it serves.
Blocking
Section titled “Blocking”Any statement about dsh’s patch level; the WP1 rollout window (D03) should be
scheduled against the same calendar so the host is not restarted twice.
Default if nobody decides
Section titled “Default if nobody decides”C. The pending kernel stays unapplied and the host keeps its two-day uptime.
Stale after 2026-10-31 (the cutoff is the natural re-check even though it is not a constraint).
D07 — Skills: dedupe, rewrite or retire
Section titled “D07 — Skills: dedupe, rewrite or retire”Decision needed. Two skill roots advertise overlapping catalogues. Does the company collapse them, rewrite the drifted entries, retire a named list, or keep both roots with a drift check?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. One canonical root (symlink the shared IDs) | ~/.claude/skills stays canonical for Claude, ~/.agents/skills links the shared IDs |
Single source; breaks if either client resolves links differently — the audit’s advice is not to delete either root |
| B. Rewrite the drifted pair, keep both roots (recommended by the audit) | Fix openviking-memory and openviking-skills, add a periodic drift check |
Cheapest correct step; duplicates remain but stop drifting silently |
| C. Retire a named list | Remove skills nothing invokes | Reduces catalogue noise; needs a named list and a restore path, which the audit already provides |
| D. Hold | Duplicates continue | No prompt cost (OpenCode keys by ID) but drift returns, and the gate keeps warning about skills not installed on this host |
Evidence
Section titled “Evidence”observed(skills audit, 2026-10-20): 111 IDs exist in both roots, 109 are byte-identical, 2 differ (openviking-memory,openviking-skills); hiding the winning copy does not reveal the losing one, so precedence mistakes are invisible.observed: 33 IDs were already hidden, not deleted, with a pre-change archive; the audit explicitly recommends against deleting either root.observed(gate, 2026-10-21):skillscheck PASS with a warning that two skills are not installed on this host.unknown: which of the two drifted descriptions is intended. Resolve by reading both and choosing the shorter (the longer one is truncated at 500 characters).
Who decides
Section titled “Who decides”Operator, because the skill catalogue is personal tooling, and a wrong call removes capability from every future session.
Blocking
Section titled “Blocking”Any claim about what the agent can do; the gate’s skills baseline.
Default if nobody decides
Section titled “Default if nobody decides”D. Duplicates stay, drift stays, warnings stay.
Stale after 2026-11-18.
D08 — Cleanup register: approve the 146G
Section titled “D08 — Cleanup register: approve the 146G”Decision needed. The staleness audit produced a three-way register. Which parts are approved for deletion?
- SAFE — 20 items, ≈36.5G. Regenerable or strictly superseded, with a newer copy of the same data already on the host.
- NEEDS-APPROVAL — 19 items, ≈146G. Contains unique data, key material, or an undocumented retention intent.
- KEEP — 22 items. Live or required.
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Approve SAFE as one batch | ~36.5G back, no unique data lost | Needs an executor on each host; the workstation’s guardian preflight blocks rm from an agent session |
| B. Approve SAFE + the four large APPROVAL rows individually | Up to ~178G back | A1 (57.8G pre-migration snapshot) and A2 (43.4G fleet-auto) are irreversible historical state and the live output of a failing service (D05) |
| C. Approve nothing | Status quo | Disk is not critical today (core: 21% used of 929G) but the register ages |
| D. Approve A17/A19 only | Two duplicate-clone decisions | These are not size decisions: A17 is “which tree is canonical when five clones have divergent dirty state” — deleting can destroy unique uncommitted work |
Evidence
Section titled “Evidence”observed(staleness audit, 2026-10-21): SAFE 20 ≈36.5G; APPROVAL 19 ≈146G; KEEP 22. Largest APPROVAL rows: A1 57.8G, A2 43.4G, A4 27.3G (llama weights), A3 13.1G, A10 ~1G, A18 877M.observed(live,core, 2026-10-21): root filesystem 188G used of 929G, 21%. Headroom is not urgent; the register is about honesty and hygiene, not survival.observed: A2 is the live output offleet-backup.sh, whose producing service is failing (D05). Deleting A2 hides a failure rather than fixing it.derived: the two decisions that need a person, not a size, are A17 (duplicate clones with 6–9 dirty files each) and A19 (which tree is canonical on scaleblade). A batch approval that includes them is an approval to destroy uncommitted work.
Who decides
Section titled “Who decides”Operator, as data owner. SAFE can be delegated to a named executor with the register attached; APPROVAL cannot.
Blocking
Section titled “Blocking”Disk-reclamation claims; the backup story (A2’s meaning depends on D05).
Default if nobody decides
Section titled “Default if nobody decides”C. Nothing is deleted, and the register gets older.
Stale after 2026-11-04.
D09 — xenode.cloud: claim or abandon
Section titled “D09 — xenode.cloud: claim or abandon”Decision needed. Is xenode.cloud ours? If it is, renew and move the
registrar before 2026-12-15. If it is not, the product keeps its name and lives
at foxcore.cloud/xenode.
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Claim, renew, transfer | Prove ownership, renew at Spaceship, move the registrar, then use the name | Unblocks the Xenode brand as a front door; costs a renewal and a transfer, and must be done before expiry |
| B. Abandon the name, keep the product | Product lives at foxcore.cloud/xenode; copy never depends on the domain |
Zero cost, zero risk; the name stays a second-class brand |
| C. Wait for expiry | Let 2026-12-15 pass | The domain may be caught by a third party; the copy problem gets worse, not better |
Evidence
Section titled “Evidence”observed(brand architecture record, 2026-10-21): registered 2025-12-15 at Spaceship, expires 2026-12-15, Cloudflare nameservers, proxied A record answering 502, MXmail.postale.io, registrant redacted. Recorded as D-04: not usable; do not put xenode on a domain until ownership is proven and the registration renewed.observed(live DNS, 2026-10-21):xenode.cloudresolves to a Cloudflare anycast address — it is proxied and served by someone, which proves nothing about who holds the registration.observed: two sibling names are parked or third-party (xenode.app,xenode.dev) and must be avoided in copy.unknown: the registrant. Only the registrar account or a whois with a disclosure path settles it; a public RDAP lookup with a redacted registrant does not.
Who decides
Section titled “Who decides”Operator, and the legal entity owner if the answer depends on which entity holds the registration (see D17).
Blocking
Section titled “Blocking”Brand architecture, the Xenode product definition’s front-door decision, and any copy that would read as a promise of a domain the company may not control.
Default if nobody decides
Section titled “Default if nobody decides”C. The domain expires on 2026-12-15 and the copy problem remains.
Stale after 2026-12-15 — the expiry is the hard boundary; this row is dead the day the domain is.
D10 — Mint the foxd enrollment token
Section titled “D10 — Mint the foxd enrollment token”Decision needed. Who mints the first single-use enrollment token, for which
region, and is core the right first node?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
A. Mint on core as the first node |
Operator signs in to the panel’s node admin page, mints a 15-minute token, starts the staged unit | First real node and a live session wire; core is a stopgap host with no root unit and no listener |
| B. Mint on a production node later | Keep core staged and unenrolled |
Nothing is proven end-to-end; the staged install ages |
| C. Do not enroll; remove the staged install | Delete the four staged paths | Clean host, no claim; loses the only prepared node |
Evidence
Section titled “Evidence”observed(fox operator runbook): tokens are short-lived and single-use, TTL is 15 minutes, the plaintext is shown once and only a hash is stored; a failed mint without a session is 401; the node needs the panel origin, not an API path.observed(reversibility record, 2026-10-21):corehasfoxdandflokiinstalled user-scope, unit disabled and inactive, no credential written (the token line is commented out), and starting it without a token fails closed with “no credential” after three bounded restarts.observed:flokiin that revision has no daemon — only acheckprobe.derived: the enrollment is a person’s click. No worker may mint or hold the token, so this cannot be delegated to an agent.
Who decides
Section titled “Who decides”Operator, as panel admin.
Blocking
Section titled “Blocking”The first real node; the enroll-and-session smoke; any hosting or capacity claim.
Default if nobody decides
Section titled “Default if nobody decides”B. The node stays staged and nothing is proven.
Stale after 2026-10-28.
D11 — Merchant of record for Relay
Section titled “D11 — Merchant of record for Relay”Decision needed. Does the operator sign or reject the merchant-of-record and
Connect configuration held in foxcorecloud/ops issue #7?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Sign the recommended configuration | Stripe Connect direct charges for tenant retail, Relay takes an application fee, losses and fees sit on Stripe; Foxcore is merchant of record only for what Foxcore actually sells | Tenant owns retail tax and is liable; onboarding friction and KYC sit with the tenant; low platform risk |
| B. Sign with a full MoR (Paddle, Lemon Squeezy) | The provider is merchant, files and remits in many territories | 5% + 50c; branding and payout control belong to the provider; not a marketplace split, so Relay’s tenant model does not fit |
| C. Reject | No paid rail | Nothing can be sold |
| D. Hold | Issue #7 remains open | Every pricing surface stays hypothetical |
Evidence
Section titled “Evidence”observed(issue #7, open): recommended v2 direct charges + application fee, with losses and fees on Stripe; Connect kept behind an explicit retail decision.observed(issue #80, open, MON-7): supplies the rails comparison and states the ticket-size economics — at a EUR 10 ticket a merchant of record takes 40% of a 25% hosting margin; at EUR 500 it is 5.1% and the tax work becomes worth paying for. Stripe Managed Payments cannot split a marketplace because it does not support Connect.observed(research note, not a decision): the current stance is that Foxcore should be merchant of record only for what Foxcore actually sells.unknown: the Stripe rate for the operating entity’s country — the table carries an unverified label that issue #80 asks to be removed or corrected.
Who decides
Section titled “Who decides”Operator, and only after the entity question is settled enough to name the contracting party.
Blocking
Section titled “Blocking”Any paid checkout; entitlement enforcement; invoicing; the price card.
Default if nobody decides
Section titled “Default if nobody decides”D. No revenue rail exists and no price is real.
Stale after 2026-11-20.
D12 — Direct DeepSeek seat: top up, move or retire
Section titled “D12 — Direct DeepSeek seat: top up, move or retire”Decision needed. The direct DeepSeek seat runs on a small prepaid balance and costs 2.5× the same model elsewhere. Does the company top it up, move the traffic to the cheaper provider, or retire it?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Top up | Add balance to the DeepSeek console account | Keeps the direct relationship; pays 2.5× the deepinfra rate for the same model |
| B. Move and retire (recommended on cost) | Route the model through deepinfra, retire the direct seat | Cheaper per token; loses the direct vendor line and any direct-only feature |
| C. Keep as fallback | Leave the balance and treat the seat as break-glass | It is intermittent already (16 attempts / 10 ok in 48 h) — a weak fallback |
Evidence
Section titled “Evidence”observed(acumen state record, 2026-10-21 21:38Z): direct DeepSeek balance $4.74 (33.88 CNY).observed: the directdeepseek-flashseat is intermittent, not dead — circuit closed, 1 failure, last success 02:19Z, last attempt timed out at the 8 s cap; 16 attempts / 10 ok in 48 h against 956 deepinfra successes in the same window.observed: the same model costs $0.15/$0.60 direct against $0.06/$0.25 at deepinfra.observed: issue #204 (the “serves 502” report) is open and the state record argues against removing the seat on one sample — hence C is a real option, not a straw man.
Who decides
Section titled “Who decides”Operator, as the account holder and budget owner.
Blocking
Section titled “Blocking”The price card and any cost-per-token claim; the reliability statement for the
deepseek provider.
Default if nobody decides
Section titled “Default if nobody decides”C, until the balance reaches zero, at which point the seat fails and the default becomes B by accident rather than by decision.
Stale after 2026-10-31.
D13 — gitleaks: allowlist, fix fixtures, or stay red
Section titled “D13 — gitleaks: allowlist, fix fixtures, or stay red”Decision needed. The secret scan reports pre-existing findings in synthetic test fixtures. Are they allowlisted with a reason, converted to placeholder shapes, or left red?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Allowlist exact path + pattern with a reason | CI goes green; the allowlist is a standing exception | Fast; the exception must be reviewed or it becomes permanent. The repository’s rule is “allowlist an exact path and pattern only with a reason” |
| B. Fix the fixtures | Replace secret-shaped strings with obviously synthetic placeholders | Removes the finding class permanently; touches test files, so the tests must be re-run |
| C. Leave red | The scan keeps failing | Honest, and it blocks any “no secrets” claim and any CI green |
Evidence
Section titled “Evidence”observed(acumen history record atd0c82e4): the WIP files scanned clean; the only 4 findings were pre-existing synthetic test fixtures already on the default branch (credentials_test.go, and telemetry test files).discrepancy: the register carries 3 fingerprints, the record names 4 findings. Resolve by re-running the scan at the current head and recording the actual count — do not reconcile from memory.derived: a fingerprint is only meaningful against the scanner version that produced it; an allowlist written without the version will drift.
Who decides
Section titled “Who decides”Operator, as security owner. A worker can prepare the allowlist but must not self-approve it.
Blocking
Section titled “Blocking”A green CI claim; any statement that the repository holds no credentials; the secret-surface section of any audit.
Default if nobody decides
Section titled “Default if nobody decides”C. The scan stays red and every reader learns to ignore it.
Stale after 2026-11-04.
D14 — Publish radar on the public edge, or not
Section titled “D14 — Publish radar on the public edge, or not”Decision needed. radar runs on tcp behind loopback with no DNS and no
vhost. Is it published to the public edge, exposed on the tailnet only, or left
unpublished?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Public | Add radar.tcp.systems DNS and a Caddy vhost; decide what the health endpoint may expose |
A real product surface; needs the degraded state fixed first or the first impression is a 200 “degraded” |
| B. Tailnet only | Keep loopback, reach it over the tailnet | Safe; no product surface, no analytics |
| C. Unpublished | Leave as is | The service runs, consumes a host, and serves nobody |
Evidence
Section titled “Evidence”observed(reversibility record, 2026-10-21):radar.serviceis enabled and active on 127.0.0.1:4030, NRestarts 0, the health endpoint answers 200 but degraded — the catalogue is from 2026-10-05 andsite/index.htmlis missing; both need a crawl that is not scheduled.observed: the unit’s comment (“public surface is Caddy -> 127.0.0.1:4030”) is aspirational, not implemented.observed(live DNS, 2026-10-21):radar.tcp.systemsanddesk.tcp.systemsreturn no answer.derived: publishing before the crawl means publishing a page that describes data sixteen days old and reports itself degraded.
Who decides
Section titled “Who decides”Operator. A public hostname needs Lead approval under the harness manual’s safety rule, so this row needs both names if the answer is A.
Blocking
Section titled “Blocking”Radar as a product; W19’s deployment window; any analytics or SEO work aimed at it.
Default if nobody decides
Section titled “Default if nobody decides”C. The service runs dark.
Stale after 2026-11-04.
D15 — Restart-coordination record (ACR-004)
Section titled “D15 — Restart-coordination record (ACR-004)”Decision needed. Adopt a written restart-coordination record for acumen — owner, window, pre-checks, post-checks, and the no-second-restart rule — and decide what a restart does to capped spend.
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Write and adopt the record | One page, linked from the acumen operators document; every restart cites it | Restarts stop being improvised; a second restart becomes a decision, not an accident |
| B. Adopt the record and make caps durable first | Same, but key spend moves out of memory before the next restart | Correct order; costs the schema work in #171/#142 before the next window |
| C. Adopt nothing | Restarts continue as they have | The cap-tracker reset stays an undocumented side effect |
Evidence
Section titled “Evidence”observed(acumen state record, 2026-10-21): no such record exists in the repo; the closest is a host document’s “restart and coordination rules” section.observed: key spend is memory-only, so a restart refills caps (ACN-004); tenant budgets are memory-only for the same reason (#142, #171).observed: probes are read once at boot, so enabling them is an env edit plus a second restart — the exact case a no-second-restart rule has to name.observed: circuits are in-memory and a restart loses them; the warm path rebuilds state.
Who decides
Section titled “Who decides”Operator, as acumen’s owner. B is the version that can be defended to a customer.
Blocking
Section titled “Blocking”Any restart that touches billing truth; any SLO statement across a restart; closure of #142/#171.
Default if nobody decides
Section titled “Default if nobody decides”C. Restarts keep silently refilling caps.
Stale after 2026-10-28.
D16 — Open WebUI: keep stock, replace, or licence
Section titled “D16 — Open WebUI: keep stock, replace, or licence”Decision needed. chat.tcp.systems runs Open WebUI. Does it stay stock
(branding intact, internal-only), get replaced, or get a licence that permits
rebranding?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Keep stock, internal-only (recorded position) | No rebranding, no price, no consumer tier | Licence-safe and cheap; the surface stays an internal tool |
| B. Replace with an owned surface | Use acumen’s consumer plane instead | Removes the licence question; costs the UI feature set |
| C. Licence and rebrand | Buy a licence that permits removing the branding | Cost plus a maintenance commitment for a surface with no billing path |
Whichever is chosen, one separate fix is not optional: the container runs a floating tag.
Evidence
Section titled “Evidence”observed(live,tcp, 2026-10-21): containeropen-webuifromghcr.io/open-webui/open-webui:main, healthy, behind thechat.tcp.systemsvhost, pagenoindex,nofollow, title still carries the Open WebUI name.observed(issue #78, open, MON-5): the recorded decision is internal-only, no price, and reversal requires per-user key minting, per-user caps, a licence review, and a measured support cost — in that order.observed: the image carries no licence file in the image, so clause-level reading must come from the upstream repository at the pinned version.unknown: the exact obligation of the licence’s branding clause at the running version. Resolve by reading the upstream licence at the commit the image was built from; do not decide from memory.derived: a floating:maintag means the licence terms and the code both change without a deployment on this side. Pinning is a supply-chain decision that does not need the licence answer.
Who decides
Section titled “Who decides”Operator, as the surface owner.
Blocking
Section titled “Blocking”Any consumer tier on that surface; any copy that offers the product.
Default if nobody decides
Section titled “Default if nobody decides”A plus the floating tag: internal-only, and the image moves under the estate.
Stale after 2026-11-20.
D17 — One account per platform per person
Section titled “D17 — One account per platform per person”Decision needed. Does the estate adopt “one account per platform per person” as a written rule, and if so under which legal identity are new accounts opened and who may open them?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Adopt per-person accounts, register them | Each platform has exactly one account per person; a register names holder, entity and recovery route | Accountable and auditable; means an account can leave with a person |
| B. Adopt per-entity accounts | Accounts belong to the entity, not a person; access is delegated | Survives staff change; most vendors still require a named human, so a delegation record is needed anyway |
| C. Mixed, written rule | Per-entity where the vendor supports it, per-person with delegation elsewhere | Realistic; the rule must be written down or it is not a rule |
| D. No rule | Whatever each session did | Identity claims stay unverifiable, recovery stays improvised |
Evidence
Section titled “Evidence”observed: vendor signups in this estate are human-gated — identity verification, terms acceptance and payment all need a person, so an agent can prepare a signup but cannot complete one.observed: at least one registration is held with a redacted registrant (xenode.cloud), which means the estate cannot currently prove which entity or person holds it — the same gap that makes D09 undecidable.unknown: there is no account register on disk. Nothing in the repositories names, per platform, the holder, the entity and the recovery route. Resolve by compiling that register; it is the artefact the rule needs either way.
Who decides
Section titled “Who decides”Operator, as identity owner, with the entity owner for option B.
Blocking
Section titled “Blocking”Vendor identity claims; account recovery; the entity chain that D11 and D09 both depend on; any statement that the estate “owns” an account.
Default if nobody decides
Section titled “Default if nobody decides”D. Accounts keep being created ad hoc and nobody can prove ownership.
Stale after 2026-11-20.
D18 — GitHub Actions billing: restore CI or replace it
Section titled “D18 — GitHub Actions billing: restore CI or replace it”Decision needed. Actions jobs do not start because the account’s payment or spending limit is blocked. Does the company restore the account, move the gate to a runner it controls, or accept local-only gates?
Options
Section titled “Options”| Option | What happens | Consequence |
|---|---|---|
| A. Restore billing | Fix the failed payment or raise the spending limit | CI resumes; every open PR gets a real gate; costs money per minute of runner time |
| B. Self-host the gate | A runner on core or forge runs node harness/check.mjs |
Predictable cost, no vendor billing dependency; the runner becomes a host to secure and patch |
| C. Local gate only, declared | Every PR carries a local gate record; CI status is not claimed | Honest, and it puts the full review burden on the reviewer — which is the current de facto state anyway |
| D. Hold | PRs open with red CI | Reviewers learn to ignore CI, which is the most expensive outcome available |
Evidence
Section titled “Evidence”observed(2026-10-21T22:09Z, this PR’s run): thedeploy-simjob failed in 2 s and thegatejob was skipped. The run annotation reads: “The job was not started because recent account payments have failed or your spending limit needs to be increased.” No step executed, so this is not a code failure.observed: the same repository’s local gate passes on this branch —node harness/check.mjsexit 0, 11 passed, 4 warnings, 0 failed.derived: while this stands, no PR in the estate can produce CI evidence, so a green gate claim is only ever a local claim. The harness manual already says a gate verdict is evidence about a tree, not proof a feature works — this narrows it further, to one machine.unknown: which account owns the billing and whether the block is payment or limit. Resolve in the organisation’s billing settings; the annotation names both possibilities and does not distinguish them.
Who decides
Section titled “Who decides”Operator, as the payer on the account. Option B also needs a host owner.
Blocking
Section titled “Blocking”Every PR gate in every repository under the organisation; any “CI is green” statement; the review-then-merge rule the working agreement depends on.
Default if nobody decides
Section titled “Default if nobody decides”D, which is C without the honesty: red CI that everyone learns to ignore.
Stale after 2026-10-28.
2. Dependency chains
Section titled “2. Dependency chains”The rows are not independent. Resolving one sometimes changes another’s options.
| Chain | Why it matters |
|---|---|
| D17 → D11, D09 | The contracting identity decides what a merchant-of-record agreement and a domain registration can even name |
| D05 → D08 | A2 is the live output of the failing backup. Approving its deletion before D05 hides a failure |
| D05 → D10 | A node on core inherits a host with a failing backup |
| D06 → D03 | The WP1 rollout needs a window; two reboots in one week is the alternative |
| D01 → D12 | Both are seat-supply decisions on the same catalogue; deciding one without the other leaves a mixed model |
| D15 → D01, D12 | A restart refills caps, so any seat change should ride a coordinated window |
| D02 → D13 | Observability and secret-scan hygiene are the two claims most often made from a green gate |
| D18 → every row | No row’s resolution can be CI-verified while Actions cannot start; each must be verified by a local or self-hosted gate |
3. Appendix — open items referenced but not registered here
Section titled “3. Appendix — open items referenced but not registered here”These are known open items from the same operating session that are not owner decisions in the sense this map records (they are tasks, or they already have a recorded answer). They are listed so the map is not mistaken for the whole queue.
| Item | Why it is not a row here |
|---|---|
| Mail DNS records (SPF/DKIM/DMARC/MTA-STS) | Task with a runbook, not a choice between alternatives |
gcloud auth on core |
Task, one command |
| Scaleblade retirement | Task with a decision recorded elsewhere |
| Pocket ID setup | Task, human-gated |
| Key rotations | Task, already sequenced |
| Mullvad cancellation | Task, single action |
exact_cache |
Answer recorded: OFF in production, DPA corrected; re-enabling needs its own ticket |
| MacroInc jurisdiction | Open, but owned by a research record with its own recommendation; promote it here when the entity question becomes blocking — which D11 and D17 will make it |
If any of these turns into a choice between alternatives with a cost, it earns a row and an ID. Until then it stays a task.
4. How to refresh this map
Section titled “4. How to refresh this map”Each row names what would settle it. A refresh is: re-run the probe, re-date the row, and record the answer if there is one.
| Row | Probe that re-dates it |
|---|---|
| D01 | Acumen usage aggregate: attempts and successes per qwen% provider in the last 48 h |
| D02 | On each host: the Grafana unit or container, its port and its admin-credential state |
| D03 | The engine count on each of the three instances, and the WP1 runbook’s status line |
| D04 | Mailbox ADR-0006 status (proposed until amended) and PR #12’s state |
| D05 | systemctl status fleet-backup.service and the last four journal entries; virsh list --all; the mount map in fstab against each host’s own tailnet address |
| D06 | uptime -s, the running kernel, the reboot-required marker, and the expiry timer’s Persistent= |
| D07 | The duplicate count and the drift loop from the skills audit |
| D08 | The three register counts and the largest APPROVAL rows |
| D09 | A registrar or RDAP lookup with a disclosure path, plus the expiry date |
| D10 | The panel’s node admin page and the staged unit’s state |
| D11 | Issue #7’s state and issue #80’s acceptance boxes |
| D12 | The balance row and the per-provider success counts |
| D13 | A scan at the current head, with the scanner version recorded |
| D14 | DNS for the two candidate names, and the health endpoint for radar |
| D15 | Whether the restart record exists and is linked from the operators document |
| D16 | The running image tag, the page title, and the upstream licence at that version |
| D17 | Whether an account register exists, and its row count |
| D18 | The latest workflow run on any branch: did a job start, or was it refused before step one |
A row that cannot be re-probed is marked unknown with the reason, never carried forward as if it were still observed.
5. Change log
Section titled “5. Change log”| Date | Change |
|---|---|
| 2026-10-21 | First compilation. 17 open decisions, each with options, owner, blocking set, evidence and a stale-after date. Corrections carried in-row: the dsh reboot is not gated by the DeepSeek cutoff (Persistent=true); the core backup script is rsync-over-ssh, not sshfs; the gitleaks count is 4 in the record against 3 in the register. D18 added the |
| same day the map was written: this change’s own CI run was refused before step | |
| one on account billing. |