docs: the install-variant tree, for tomorrow's decision
Enumerates the forty-seven prompts the two scripts actually ask and sorts them into branches, consents and values — the distinction that decides what a generated leaf can remove. Four real branches (OS, role, tailnet state, which half), fourteen consents that let a leaf omit a section entirely, and a set of values that must stay prompts because baking them in would mean publishing somebody's hostname. Names the two things that need deciding rather than deciding them: Whether a leaf strips dead code or sets constants and calls the base. They are different artifacts and the plan rests on which one is meant — the first is what makes it auditable by being short, the second is what keeps it maintainable. And the combinatorics: 4 OS x 3 roles x 3 tailnet states is 36 leaves before consents, so the tree cannot be the full product. Publishing a few opinionated leaves keeps the static-file-anyone-can-diff property; generating on demand does not, which is the property per-leaf scripts existed for. Also notes that --unattended and a generated leaf are the same mechanism seen twice, and that install_config's existing behaviour — keep the user's file when there is no tty — is the conservatism every unattended answer needs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# The install page, and the scripts behind it
|
||||
|
||||
**Status: for discussion, 2026-08-13.** Nothing here is built. It exists so tomorrow's conversation
|
||||
is about real branches rather than sketched ones — every question below is one the scripts already
|
||||
ask today.
|
||||
|
||||
## The shape agreed
|
||||
|
||||
- One **source** — the interactive scripts as they are.
|
||||
- A **build script** that compiles them into single files, because `curl | bash` cannot fetch libs.
|
||||
- The build emits **one script per leaf** of the question tree, not one script with pre-seeded
|
||||
answers. A person auditing before running reads only their own path.
|
||||
- Verification is of the **generator**, once: anyone regenerates the leaves from source and diffs
|
||||
them against what is published. One thing to trust rather than N.
|
||||
|
||||
---
|
||||
|
||||
## The questions that actually exist
|
||||
|
||||
Forty-seven prompts across the two scripts. Almost none of them should become a branch — the
|
||||
distinction that matters is:
|
||||
|
||||
**A branch** changes which *code* runs. Removing it makes a script genuinely shorter.
|
||||
|
||||
**A value** changes a *string*. Removing it makes a script no shorter — it just moves the answer
|
||||
from a prompt to a constant.
|
||||
|
||||
**A consent** is a yes/no about doing a step at all. These are the interesting middle: pre-answering
|
||||
one lets the build delete the section entirely.
|
||||
|
||||
### Branches — these change what code exists
|
||||
|
||||
| question | answers | what it eliminates |
|
||||
| --- | --- | --- |
|
||||
| operating system | macOS · Debian/Ubuntu · Arch · Fedora | 17 of 26 machine-setup sections on macOS; the whole `case $PM` ladder collapses to one arm |
|
||||
| machine role | homelab · vps · dev | swap, ballast, earlyoom, sleep/suspend, boot-hang, static addressing — each is role-gated today |
|
||||
| tailnet | already connected · set one up · none | the entire Tailscale section, its four sub-options and the offscale explanation |
|
||||
| which half | machine + officer · officer only · machine only | one of the two scripts disappears |
|
||||
|
||||
### Consents — pre-answering deletes a section
|
||||
|
||||
Docker · fail2ban · unattended-upgrades · Neovim · agent CLIs · shell config · firewall · SSH
|
||||
hardening · DNS · swap · ballast · earlyoom · inotify · boot-on-start.
|
||||
|
||||
Fourteen sections that a leaf script can simply not contain.
|
||||
|
||||
### Values — never a branch
|
||||
|
||||
Username · install path · git name and email · port · public URL · Postgres connection · timezone ·
|
||||
locale · LAN CIDR · swap size · swappiness.
|
||||
|
||||
These stay as prompts even in a generated script, or arrive as environment variables. Baking them
|
||||
into a published file would mean publishing somebody's hostname.
|
||||
|
||||
---
|
||||
|
||||
## Where this collides with `--unattended`
|
||||
|
||||
`--unattended` and a generated leaf are the *same mechanism seen twice*: both are "answer these in
|
||||
advance". The difference is only whether the answer is baked in at build time or supplied at run
|
||||
time.
|
||||
|
||||
Worth deciding tomorrow whether a leaf script is literally `base.sh --unattended` with a header of
|
||||
constants, or whether the build truly strips the dead branches. The second is what makes it
|
||||
auditable-by-being-short; the first is what makes it maintainable. **They are not the same artifact,
|
||||
and the whole plan rests on which one we mean.**
|
||||
|
||||
One thing that already exists and should be preserved either way: with no tty, `install_config`
|
||||
keeps the user's file rather than replacing it. Every unattended answer needs to be conservative in
|
||||
that same way, and that is a property of each prompt, not of the flag.
|
||||
|
||||
---
|
||||
|
||||
## The combinatorics
|
||||
|
||||
4 OS × 3 roles × 3 tailnet states = **36 leaves** before any consent is considered, and consents
|
||||
multiply it past anything anyone would publish.
|
||||
|
||||
So the tree the install page walks cannot be the full product. Two ways out, to choose between:
|
||||
|
||||
1. **Publish a few opinionated leaves** — "Ubuntu VPS, new tailnet", "macOS dev machine", "Ubuntu
|
||||
homelab, existing tailnet" — and send everything else to the full interactive script.
|
||||
2. **Generate on demand** — the page composes the leaf when the questions are answered. Stronger, but
|
||||
the artifact is no longer a static file anyone can diff against the repo, which costs the
|
||||
verification property the whole design was for.
|
||||
|
||||
My inclination is (1), because (2) quietly trades away the thing that made per-leaf scripts worth
|
||||
building. But it is a real trade and it is yours.
|
||||
|
||||
---
|
||||
|
||||
## Open, for tomorrow
|
||||
|
||||
- Does a leaf strip dead code, or set constants and call the base?
|
||||
- How many leaves get published, and what happens to the rest?
|
||||
- Does the install page show the script before running it? It should — that is the moment auditing
|
||||
is cheap and nobody will do it afterwards.
|
||||
- The report from `install-report.md` names a script commit. A generated leaf needs to name the
|
||||
source commit it was generated from, or the report cannot be checked against anything.
|
||||
Reference in New Issue
Block a user