Skip to content

docs: the lab is disposable, and that is the boundary (#196, #733) - #879

Merged
stephrobert merged 1 commit into
mainfrom
decide/733-on-merged-main
Nov 11, 2026
Merged

stephrobert merged 1 commit into
mainfrom
decide/733-on-merged-main

Conversation

@stephrobert

Copy link
Copy Markdown
Owner

Summary

Two current texts said opposite things and neither cited the other.

docs/roadmap.md:829 put persistent hardware on the far side of this project's boundary — "a small IaaS above Incus answers a different question from the one this project answers, and answering both in one binary is how a repository acquires two products and does neither well." Three milestones planned durable state, a reconciler and volumes holding real bytes inside this binary. The decision that would say which superseded which was filed as #196 and never written, so a reader of either text was right and wrong at once, and had been for two months.

It is written now, and the answer is the roadmap's: feint never manages a resource whose loss would matter.

Why this is a safety property, not a scope preference

What makes feint safe to point at an operator's own station is one sentence: it only touches what it made, and what it made is disposable.

Both halves carry weight. The first is enforced — everything is labelled, the driver answers ownership before shape, feint clean sweeps exactly its own work. The second is what makes the first affordable. A sweep that could destroy something irreplaceable would need a confirmation, a backup story and a recovery path, and an emulator that grows those is one nobody dares aim at a real directory.

An audit already turned a crafted snapshot into incus delete --force and network delete incusbr0 on a host. Ownership checks refused both. The reason that refusal is sufficient rather than merely necessary is that nothing feint owns was worth keeping.

The nuance the decision adds, which is its whole content

The boundary is a resource whose loss would matter, not persistence as such.

The emulator's own record may survive a restart — that is #551, and an apply, a kill -9 and a restart leaving the plan empty is a convenience for the person using the lab, not a promise about anybody's bytes. Three properties keep it on this side, and breaking any one is a change of product rather than a feature:

  • the record is explicitly rebuildable: losing it costs a re-apply, never data;
  • it is never authoritative: what the runtime holds decides, the record describes, and a restored record is an untrusted input revalidated at the boundary;
  • nothing in it is a user's content.

What it refuses, by name

The refusal is of the work landing here, not of the work. A homelab that materialises durable resources is a legitimate product; it is a different one, and that line is now written where a reader meets it.

#551 and #552 stay in scope.

Where it lives, and why not an ADR

docs/limits.md, this repository's home for a decision carrying its measurement, and the destination #733 itself accepts provided the roadmap points at it. docs/adr/ does not exist — that is #722 — and blocking a two-month-old decision on a journal nobody has built yet is how it stays unwritten for two more.

docs/roadmap.md's section keeps its text and gains a clarifying block, per the never-delete rule the journal issue asks for: the sentence stands, and the one nuance is named rather than left for a reader to infer.

Type of change

  • A route added or changed
  • Bug fix
  • Refactor
  • Documentation
  • Chore / tooling
  • Security / supply chain

Checklist

Always

  • mise run check passes
  • No new external Go dependency
  • internal/core still knows no provider — no Go file is touched
  • Nothing in the diff could be written identically for another provider: it is a decision about this product's boundary, not about a cloud
  • mise run testplan was run, and what it printed was run — docs:check and limits:check for a prose diff, both green

When a model wrote a substantive part of this

  • An Assisted-by: trailer names the tool and the model version
  • No conformance suite is touched and none is claimed. The decision itself is the maintainer's, taken explicitly; what is model-written is the text, the citations and the consistency pass over the two documents
  • No provider field name is added or changed

When a route is added or changed

N/A.

When behaviour a client can observe changes

  • No behaviour changes. docs/limits.md gains the section; both READMEs move by one line each because the safety banner counts the sections it vouches for, and feint docs --check refuses until they agree
  • docs/limits.md updated — it is the subject

When .github/workflows/ is touched

N/A.

When a machine runtime is involved

N/A — though the decision is about what the runtime may ever hold.

Related issues

Closes #733. Closes #196 — it is the decision that issue asks for, written rather than filed.

Refuses #553, #554 and #555, each closed with this reason rather than left open under a milestone the roadmap says should not exist. The milestones Reality wins and The homelab is not disposable close with them.

🤖 Generated with Claude Code

Two current texts said opposite things and neither cited the other.
`docs/roadmap.md:829` put persistent hardware on the far side of this
project's boundary; three milestones planned durable state, a reconciler and
volumes holding real bytes inside this binary. The decision that would say
which superseded which was filed as #196 and never written — so a reader of
either text was right and wrong at once, and had been for two months.

It is written now, and the answer is the roadmap's: **feint never manages a
resource whose loss would matter.**

## Why it is a safety property, not a scope preference

What makes feint safe to point at an operator's own station is one sentence:
it only touches what it made, and what it made is disposable. Both halves
carry weight. The first is enforced — everything is labelled, the driver
answers ownership before shape, `feint clean` sweeps exactly its own work. The
second is what makes the first affordable: a sweep that could destroy
something irreplaceable would need a confirmation, a backup story and a
recovery path, and an emulator that grows those is one nobody dares aim at a
real directory.

An audit already turned a crafted snapshot into `incus delete --force` and
`network delete incusbr0`. Ownership checks refused both. The reason that
refusal is *sufficient* rather than merely necessary is that nothing feint
owns was worth keeping.

## The nuance the decision adds, which is its whole content

The boundary is a resource whose **loss would matter**, not persistence as
such. The emulator's own record may survive a restart — that is #551, and an
apply, a `kill -9` and a restart leaving the plan empty is a convenience for
the person using the lab, not a promise about anybody's bytes.

Three properties keep that on this side, and breaking any one is a change of
product rather than a feature: the record is explicitly rebuildable, losing it
costs a re-apply and never data; it is never authoritative, since what the
runtime holds decides and the record describes; and nothing in it is a user's
content.

So #551 and #552 stay in scope. #553, #554 and #555 are refused by name, with
the reason: a reconciler that converges the host toward a declaration is the
other project's control loop, and volumes whose bytes survive a host reboot
are the resource this decision refuses.

The refusal is of the work landing **here**, not of the work. A homelab that
materialises durable resources is a legitimate product; it is a different one,
and that line is now written where a reader meets it.

## Where it lives, and why not an ADR

`docs/limits.md`, which is this repository's home for a decision carrying its
measurement, and which #733 accepts as the destination provided the roadmap
points at it. `docs/adr/` does not exist — that is #722 — and blocking a
two-month-old decision on a journal nobody has built yet is how it stays
unwritten for two more.

`docs/roadmap.md`'s section keeps its text and gains a clarifying block, per
the never-delete rule the journal issue asks for: the sentence stands, and the
one nuance is named rather than left for a reader to infer.

Assisted-by: Claude Code (claude-opus-5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant