ADR-0086: ICN deployment profiles and public/private infrastructure boundary
Status
accepted (2026-09-15). The four-profile decision and the public/private
boundary are in force; new deployment work must conform. Accepted by the decider
named above, as a deliberate act — merging this record did not perform it, and
ADR-0018 is explicit that the decision lifecycle moves only when the project
decides.
Frozen Alpha profile revision: 860c6f6c22f18de0f7bc4cfb55e35b1143b3b4f1.
That is the exact main revision at which the Profile A artifacts were reviewed
and witnessed. The profile means those bytes, not "whatever deploy/ currently
contains".
What acceptance settles, and what it does not:
- it settles the classification — appliance as canonical sovereign-node artifact, Compose devnet as disposable, Kubernetes/K3s as optional operator infrastructure, native Linux as an advanced install form — and the public/private repository boundary;
- it settles that the native service consumes the configuration the institution was provisioned with, at the frozen revision, across every shipped profile override;
- it does not certify production readiness, authorize a production deployment, or adopt any profile for pilot or partner use;
- it does not convert an incomplete item into a complete one. Every non-claim below still holds, and item 7 of the Profile A contract remains open.
implementation_status: partially implemented is unchanged and is a separate
axis from the decision status (ADR-0018 § "Decision status is separate from
implementation status"). Repository paths exist for all four profiles, but only
the assembled Debian appliance has a current, retained build-and-boot witness.
Independent restoration, artifact signing, reproducibility, two-node
institutional operation, and generic Kubernetes reconciliation remain
incomplete.
What the freeze added since this record was written
At the frozen revision, and witnessed against the shipped artifacts rather than hand-composed invocations:
- the native unit and every shipped
icnddrop-in pass the provisioned configuration, so the effective ledger treasury is the institutional principal and not a node-DID fallback (icn#2755); <data_dir>/icn.tomlis the single canonical native configuration path, owned byicn_core::config::config_file_path;- both units that create
icnd's files —icnd.serviceandicn-appliance-firstboot.service— pinUMask=0077; <data_dir>/config.tomlis deprecated and not migrated. There is no legacy upgrade path: when the canonical configuration is absent and a legacyconfig.tomlsits beside it,icndrefuses to start and names both remedies. It does not read the legacy file, and no dual-path discovery exists.
Context
ICN currently exposes several overlapping ways to run icnd: a Debian appliance
builder, multiple Docker Compose stacks, a generic OCI Dockerfile, two
Kubernetes trees, a Helm chart, and native Linux instructions. Until PR #2455,
the public repository also had a workflow that automatically deployed to a
specific private K3s homelab.
Those paths do not have the same purpose or evidence. Treating them as peers has made private cluster liveness look like product readiness, left developers with several conflicting Compose entry points, and obscured the custody boundary for institution-owned identity and durable state.
An exact integrated appliance witness at
67a6566e2335be108ca69bb5d60e0cfb761e63b5, which includes merged K3s-lane
retirement 75d157503f168fb534c34cd16edf9bf6b8721254, established a stronger
factual baseline:
- one Debian QCOW2 was built from repository code and a pinned base-image hash;
- its typed manifest re-hashed the image, base,
icnd, andicnctl; - a clean VM boot completed first-boot initialization, generated a per-instance
identity and secrets, started
icndunder systemd, and returned health; - a fixture organizer/member loop and its negative capability checks passed;
- the same retained overlay preserved node identity and a completion receipt
across
icndrestart and VM reboot; - the rehearsal workspace itself was process-local and did not survive restart;
- the artifact remained explicitly non-production, unsigned, mutable, and dependent on networked package installation during the build.
The decision must preserve those exact claim boundaries.
Decision
ICN has four deployment profiles with distinct purposes and no implied promotion between them.
Profile A: sovereign appliance node
The Debian appliance VM is the canonical ICN node artifact.
Its baseline is one role-neutral image running native systemd services. Each booted instance creates its own identity and secrets and owns its own durable state. Post-boot configuration may specialize that image as an institution node, member node, witness/archive node, domain host, or service host. Separate image forks are not created for each role unless verified technical evidence requires them.
The canonical appliance contract requires:
- a Debian-based QCOW2 or raw image;
- native systemd startup and restart behavior;
- per-instance identity and secret generation;
- institution-owned durable state;
- explicit genesis, activation, or enrollment;
- local backup and export;
- independent restoration, including the configuration secrets needed to open the restored keystore;
- manifest hashes and a release path that states signing and immutability honestly;
- no Kubernetes dependency.
Items 1–5 have partial runtime evidence. Item 6 exists as generic icnctl
backup tooling, but it writes a data-directory tar archive and is not yet an
encrypted appliance recovery contract. Item 7 is open for two independent
reasons, and closing either alone does not close the item. First, the current
data backup does not include /etc/icn/icnd.env, so restoring /var/lib/icn
alone is not an independently operable appliance recovery. Second, a restored
ledger cannot be shown to be complete: a db truncated to a partial length
reopens cleanly as a valid short prefix, and nothing commits to the extent it
should have had. Nothing available to a verifier distinguishes that from a
ledger that always held that many, so restoration cannot be shown to restore a
complete ledger (icn#2746). icn#2787 has landed and stops the verifier
overclaiming: verify-backup --verify-ledger now reports completeness as
unresolved and fails closed instead of certifying it. That removed a false
positive; it is not detection, and it did not make restoration provable.
icn#2786 owns the requirement for an independent extent/frontier commitment
that would make completeness checkable at all. It remains open, and the
mechanism is deliberately not yet selected — a durable count, a monotonic
frontier and a digest accumulator differ in what they can prove, and a count
alone can refute completeness but never establish it. Item 7 closes only when
BOTH causes are closed — the secret-bearing environment file must travel with
the backup, and icn#2786 must land. Closing either alone leaves an appliance
that cannot be independently restored, which is what item 7 asserts. Items
8–9 are only partially
met: manifests exist and Kubernetes is not required, but appliance artifacts
are not yet signed or reproducibly built.
Fixture/demo services are optional add-ons. Their state and claims are not the sovereign-node durability contract.
Profile B: disposable local development network
deploy/devnet/docker-compose.yml is the canonical Compose entry point
for fast multi-node development, protocol and gossip tests, integration work,
and disposable demos.
This profile carries no institutional-custody, restoration, production, adoption, or federation claim. Other Compose files are compatibility or historical material until a separate cleanup maps or retires them; this ADR does not delete them.
Profile C: optional hosted cluster
Kubernetes or K3s is optional operator infrastructure. It is appropriate for hosted gateways, relays, monitoring, logging, registries, and operators that already require orchestration.
It is not the canonical sovereign-node path and is not required to run ICN. Generic Helm/manifests and generic validation may remain public. A Kubernetes deployment does not, by itself, prove institutional custody, correct authority, state restoration, peer enrollment, or federation.
The current generic entry points are deploy/kubernetes/ and
deploy/helm/icn/. The separate deploy/k8s/ tree contains legacy
homelab-specific defaults and is not a generic operator entry point. This ADR
does not migrate or execute that private material; it requires a later bounded
archive, genericization, or private-repository move.
Profile D: advanced native Linux
Direct Linux installation remains available for experienced operators. It must preserve the same identity, secret, authority, durable-state, backup, and restoration invariants as Profile A. It is an advanced installation form, not a second canonical artifact.
Public/private repository boundary
The public ICN repository owns generic product artifacts:
- appliance build, verification, and release logic;
- generic OCI image build and validation;
- generic Kubernetes examples and Helm material;
- disposable development environments;
- documentation and non-private test evidence.
A private infrastructure repository owns deployment-specific operations:
- private addresses, registries, SSH targets, node names, credentials, and storage topology;
- actual private-cluster rollout and rollback automation;
- private monitoring endpoints and operational schedules;
- the current state of any private deployment.
A merge to public main must not automatically SSH into, push to, restart, or
otherwise mutate private infrastructure. Private cluster health must not be a
product build signal. A private repository may invoke a future generic reusable
workflow, but supplies and protects all deployment-specific values itself.
Evidence and claim matrix
| Claim | Current evidence | Disposition |
|---|---|---|
| Appliance builds and boots | Exact assembled QCOW2 witness at integrated PR #2456 head 67a6566e |
Partially proven for local non-production use |
| Identity survives restart/reboot | Stable retained-overlay identity/config/genesis hashes | Proven for the witnessed bytes |
| Durable receipt survives restart/reboot | Exact completion receipt re-fetched after both transitions | Proven for the witnessed fixture receipt |
| Full demo workspace is durable | Read-only status became uninitialized after process restart | Not proven; currently false |
| Independent appliance restoration | Two independent causes: the plain data-directory tar omits the secret-bearing environment file, and ledger completeness cannot be established at all — a truncated journal reopens as a valid short prefix and nothing commits to its expected extent (icn#2746; the verifier stopped overclaiming in icn#2787, which has landed, but the mechanism that would make completeness checkable is icn#2786 and remains open) | Open blocker |
| Signed immutable appliance release | Manifest states signed: false, immutable: false |
Not implemented |
| Generic OCI image builds | Local cold build plus merged hosted workflow from PR #2455 | Build evidence only |
| Kubernetes production readiness | Conflicting/stale generic and homelab material | Not claimed |
| Two independent institutions operate | No two-appliance authority/enrollment witness | Not proven |
| Federation | No qualifying two-institution witness | Not proven |
Consequences
- Product proof centers on an artifact an institution can own, restart, back up, and eventually restore without a cluster.
- Developers retain a fast disposable multi-node environment without confusing it with institutional custody.
- Hosted operators retain Kubernetes/Helm options without making K3s mandatory.
- Private homelab failures stop presenting as public product failures.
- The repository must reconcile duplicate Compose and Kubernetes paths over time.
- Appliance recovery and signed distribution become explicit product blockers rather than undocumented operator assumptions.
- This decision was adopted on 2026-09-15 after review, at the frozen revision named in § Status. Amending it now requires an amendment note under ADR-0018's lifecycle rather than an edit.
Alternatives considered
| Alternative | Disposition |
|---|---|
| K3s as the canonical node | Rejected: couples sovereign operation to cluster infrastructure and private liveness |
| OCI container as the only canonical artifact | Rejected for now: current image proves a build, not appliance-equivalent identity, systemd, backup, or restoration |
| Native Linux as the only canonical path | Rejected: increases operator variance and weakens artifact-level review evidence |
| Keep all deployment paths equal | Rejected: preserves contradictory purposes and unbounded readiness claims |
| Remove generic Kubernetes support | Rejected: hosted/operator use remains legitimate when kept optional and generic |
Non-goals
- No live cluster change and no private infrastructure migration.
- No production-readiness or pilot adoption follows from accepting this decision. Acceptance settles the classification and the frozen profile revision; it authorizes no deployment.
- No production-readiness, pilot, institutional-adoption, or federation claim.
- No
COMMUNITY_TOPIC, composition-root, ledger, or B1/B2 architecture change. - No assertion that a fixture rehearsal proves institution-owned durable workflow state.