<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tenant Model on Deevnet IoTaaS</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/</link><description>Recent content in Tenant Model on Deevnet IoTaaS</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/index.xml" rel="self" type="application/rss+xml"/><item><title>ADR-0034: Tenants Deliver Their Own Code</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0034-tenants-deliver-their-own-code/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0034-tenants-deliver-their-own-code/</guid><description>&lt;h1 id="adr-0034-tenants-deliver-their-own-code-and-deliver-it-again">
 ADR-0034: Tenants Deliver Their Own Code, and Deliver It Again
 &lt;a class="anchor" href="#adr-0034-tenants-deliver-their-own-code-and-deliver-it-again">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted (2026-10-05): already how the platform works. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0028-tenant-workload-login/">CHG-0028&lt;/a> gave tenants their own login on their workloads, and &lt;code>eds&lt;/code> runs its services this way (since 2026-09-28)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-10-05&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How a tenant&amp;rsquo;s application code and settings reach its workloads, and how they come back after a workload is lost. Not how the workload itself is built (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015&lt;/a>), and not how a tenant logs in (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0028-tenant-workload-login/">ADR-0028&lt;/a>).&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Supersedes&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0017-tenant-code-delivery/">ADR-0017: How Tenant Code Reaches a Tenant Workload&lt;/a>, whole&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0018-operator-access-to-tenants/">ADR-0018: Operator Access to Tenant Workloads&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0021-tenant-secrets/">ADR-0021: Tenant Secrets&lt;/a> (depended on ADR-0017; to be revisited), 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/">ADR-0033: Code Is the State&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>&lt;strong>ADR-0017 planned an unattended pull.&lt;/strong> A tenant would declare its workload&amp;rsquo;s configuration to the
API in a Deevnet schema, and an agent in the workload would fetch it at first boot through an SMBIOS
pointer. It forbade any push. None of it was built.&lt;/p></description></item><item><title>ADR-0033: Code Is the State</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/</guid><description>&lt;h1 id="adr-0033-code-is-the-state-for-the-substrate-and-for-every-tenant">
 ADR-0033: Code Is the State, for the Substrate and for Every Tenant
 &lt;a class="anchor" href="#adr-0033-code-is-the-state-for-the-substrate-and-for-every-tenant">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Proposed. Accepted when the change that moves device secrets into tenant code is built, and a tenant has been rebuilt from its repository with no restore&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-10-05&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Revised&lt;/strong>&lt;/td>
 &lt;td>2026-10-06: what it said about tenant indexes corrected to match the code (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/reviews/2026-10-rebuild-and-access/#t3-tenant-index">2026-10 review, T3&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Where the authoritative copy of everything the site runs lives, and how the site and its tenants recover with no backup on the path. Covers tenant state, device secrets, the Deevnet API&amp;rsquo;s database and audit log, and tenant buckets.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Supersedes&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a>, whole&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform API&lt;/a> §4 (the authoritative copy of a device secret), §5 (the restore source) and its audit-log paragraph; 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenant Onboarding Through the API&lt;/a> (the API&amp;rsquo;s database is a working copy of the registry); 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0026-object-storage/">ADR-0026: Object Storage&lt;/a> §3 and §4 (no replica)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>In conflict with&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a> (OpenBao&amp;rsquo;s data is kept data) and 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/">ADR-0025&lt;/a> §7 (Keycloak&amp;rsquo;s is); both to be revisited, see 
 &lt;a href="#consequences">Consequences&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/">ADR-0007: Terraform State Custody&lt;/a> §5, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §4, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0021-tenant-secrets/">ADR-0021: Tenant Secrets&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/">ADR-0025: Identity Directory&lt;/a> §7, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0031-deevnet-pki/">ADR-0031: Deevnet PKI&lt;/a> §6&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>&lt;strong>The site was designed so that code rebuilds everything.&lt;/strong> The substrate is rebuilt from inventory
and its vault. A tenant is rebuilt from its own repository. ADR-0007 §5 made it a rule for tenants:
&lt;em>&amp;ldquo;no tenant declares a resource whose value cannot be re-derived from code&amp;rdquo;&lt;/em>.&lt;/p></description></item><item><title>ADR-0028: Tenant Workload Login</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0028-tenant-workload-login/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0028-tenant-workload-login/</guid><description>&lt;h1 id="adr-0028-a-tenant-logs-in-to-its-own-workloads-with-its-own-key">
 ADR-0028: A Tenant Logs In to Its Own Workloads With Its Own Key
 &lt;a class="anchor" href="#adr-0028-a-tenant-logs-in-to-its-own-workloads-with-its-own-key">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted (2026-09-27): built and proven by 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0028-tenant-workload-login/">CHG-0028&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-27&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How a tenant gets a shell on a workload it owns: which account, which key, which template, and from where. Not how code arrives unattended (ADR-0017), and not people&amp;rsquo;s identities (ADR-0025).&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Answers&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0018-operator-access-to-tenants/">ADR-0018: Operator Access to Tenants&lt;/a>, open question 3&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a> §12, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0017-tenant-code-delivery/">ADR-0017: How Tenant Code Reaches a Tenant Workload&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0025-identity-directory/">ADR-0025: Identity Directory&lt;/a> §5, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0028-tenant-workload-login/">CHG-0028&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>A tenant can build a workload but cannot log in to it.&lt;/p></description></item><item><title>ADR-0021: Tenant Secrets</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0021-tenant-secrets/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0021-tenant-secrets/</guid><description>&lt;h1 id="adr-0021-tenants-keep-runtime-secrets-in-their-own-openbao-namespace">
 ADR-0021: Tenants Keep Runtime Secrets in Their Own OpenBao Namespace
 &lt;a class="anchor" href="#adr-0021-tenants-keep-runtime-secrets-in-their-own-openbao-namespace">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Proposed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Parked&lt;/strong>&lt;/td>
 &lt;td>2026-10-06: tenants keep their secrets as code for now: encrypted in their own repositories, merged into the settings they push (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0034-tenants-deliver-their-own-code/">ADR-0034&lt;/a>). This record stays Proposed as an optional service for a tenant that needs rotation without a redeploy, per-workload revocation or a read audit. Its delivery through ADR-0017&amp;rsquo;s channel becomes the tenant pushing each workload&amp;rsquo;s AppRole credential (
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/reviews/2026-10-rebuild-and-access/#s1-tenant-secrets">2026-10 review, S1&lt;/a>)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-21&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Where a tenant&amp;rsquo;s own runtime secrets live, such as a third-party API key its backend service calls with, how they reach the workload that needs them, and who holds the authoritative copy. Not device credentials, and not how the workload itself is filled with code.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>, whose §8 left &lt;em>&amp;ldquo;tenant namespaces&amp;rdquo;&lt;/em> out and said they need their own record. This is that record.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §4, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a> §4, §8, §9, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0017-tenant-code-delivery/">ADR-0017: How Tenant Code Reaches a Tenant Workload&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0020-direct-device-access-to-tenant-services/">ADR-0020: Direct Device Access to Tenant Services&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="a-tenant-has-secrets-of-its-own-and-nowhere-to-put-them">
 A tenant has secrets of its own, and nowhere to put them
 &lt;a class="anchor" href="#a-tenant-has-secrets-of-its-own-and-nowhere-to-put-them">#&lt;/a>
&lt;/h3>
&lt;p>A tenant&amp;rsquo;s backend service calls out: a weather API, a notification service, a payment provider. Each
call carries a key the tenant got from that provider. &lt;strong>The substrate did not issue it and cannot
re-derive it.&lt;/strong> The service needs it at runtime, on a workload the substrate built.&lt;/p></description></item><item><title>ADR-0017: How Tenant Code Reaches a Tenant Workload</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0017-tenant-code-delivery/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0017-tenant-code-delivery/</guid><description>&lt;h1 id="adr-0017-how-tenant-code-reaches-a-tenant-workload">
 ADR-0017: How Tenant Code Reaches a Tenant Workload
 &lt;a class="anchor" href="#adr-0017-how-tenant-code-reaches-a-tenant-workload">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Superseded by 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0034-tenants-deliver-their-own-code/">ADR-0034: Tenants Deliver Their Own Code&lt;/a>: the tenant pushes its own code over SSH, and pushes again after a workload is lost; unattended delivery is out of scope. Never accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-18&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Revised&lt;/strong>&lt;/td>
 &lt;td>2026-09-18, twice, before review. First written as a single choice between delivery mechanisms, with tenant-authored cloud-init user-data recommended; that draft argued the wrong layer. Rewritten to separate the &lt;strong>tenant-facing contract&lt;/strong> (§1, settled) from the &lt;strong>substrate-side mechanism&lt;/strong> (§2, open). Then revised again once both halves of the leading mechanism were tested rather than assumed, adding the measured SMBIOS limit and &lt;strong>§3, the fetch rule that keeps ADR-0012 provisioning-only&lt;/strong>.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How a tenant&amp;rsquo;s own application code and configuration arrive on a tenant workload, and how they are kept current — not what the code is, and not how the workload itself is built&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a>, which says tenants own their code but does not say how it is delivered; 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a>, which builds the empty workload this decision fills&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0001-tenant-network-fabric/">ADR-0001: Tenant Network Fabric&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0003-tenant-egress-single-member-fabric/">ADR-0003: Tenant Egress on a Single-Member Fabric&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0011-edge-devices-application-owned/">ADR-0011: Edge Devices Are Application-Owned&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0018-operator-access-to-tenants/">ADR-0018: Operator Access to Tenant Workloads&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="the-substrate-can-build-a-workload-but-cannot-fill-one">
 The substrate can build a workload but cannot fill one
 &lt;a class="anchor" href="#the-substrate-can-build-a-workload-but-cannot-fill-one">#&lt;/a>
&lt;/h3>
&lt;p>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015&lt;/a> made tenant building
complete: a tenant declares &lt;code>deevnet_workload&lt;/code> and gets a running Fedora VM with an address, a
name, DNS and egress. What arrives is an &lt;strong>empty machine&lt;/strong>. Nothing in the substrate puts an
application on it, and nothing says how a tenant should.&lt;/p></description></item><item><title>ADR-0015: Tenants Are Built Through the Deevnet API</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/</guid><description>&lt;h1 id="adr-0015-tenants-are-built-through-the-deevnet-api">
 ADR-0015: Tenants Are Built Through the Deevnet API
 &lt;a class="anchor" href="#adr-0015-tenants-are-built-through-the-deevnet-api">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/">ADR-0033: Code Is the State&lt;/a> &lt;em>(Proposed)&lt;/em>: the API&amp;rsquo;s database is a working copy of the registry; each tenant&amp;rsquo;s repository names the tenant and its index&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Accepted&lt;/strong>&lt;/td>
 &lt;td>2026-09-19, recording what 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0010-tenant-api-cutover/">CHG-0010&lt;/a> settled on 2026-09-17: the API was deployed and &lt;strong>both live tenants were rebuilt entirely through it&lt;/strong>. The record sat at &lt;code>Proposed&lt;/code> after it had already been built and proven, which the status was not saying.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-17&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Revised&lt;/strong>&lt;/td>
 &lt;td>2026-09-17, before review. First written as onboarding only; widened so that everything that builds a tenant (its network, workloads and DNS records) is behind the API and tenants hold no substrate credential (§11–§14). Admission by enrollment token (§10). Secrets handling moved to 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016&lt;/a>.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Who allocates a tenant&amp;rsquo;s index, who builds a tenant&amp;rsquo;s network, workloads and names, what a tenant holds, and where the record of tenants lives&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a>, whose API and provider become the way every tenant is created, not only the way it registers devices&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Supersedes, in part&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0002-tenant-fabric-numbering/">ADR-0002: Tenant Fabric Numbering&lt;/a>, where it says allocation is recorded in &lt;code>TENANTS.md&lt;/code> (the numbering itself stands); 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0006-tenant-code-boundary/">ADR-0006: Tenant Code Boundary&lt;/a> §1 (the module consumed by tag), §2 (the attachment rendered into the repository) and §3 (the reference implementation that cannot be applied). A tenant still lives in its own repository.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0003-tenant-egress-single-member-fabric/">ADR-0003: Tenant Egress on a Single-Member Fabric&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0004-tenant-dns-publication/">ADR-0004: Tenant DNS Publication&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0005-tenant-zone-apex-ownership/">ADR-0005: Tenant Zone Apex Ownership&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/">ADR-0007: Terraform State Custody&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0016-substrate-secrets-openbao/">ADR-0016: Substrate Secrets in OpenBao&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="onboarding-today-is-a-substrate-commit-and-five-automation-runs">
 Onboarding today is a substrate commit and five automation runs
 &lt;a class="anchor" href="#onboarding-today-is-a-substrate-commit-and-five-automation-runs">#&lt;/a>
&lt;/h3>
&lt;p>A tenant is created in two halves. The substrate half runs once:&lt;/p></description></item><item><title>ADR-0014: Tenant State Durability</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/</guid><description>&lt;h1 id="adr-0014-tenant-state-is-kept-data-copied-away-from-what-it-restores">
 ADR-0014: Tenant State Is Kept Data, Copied Away From What It Restores
 &lt;a class="anchor" href="#adr-0014-tenant-state-is-kept-data-copied-away-from-what-it-restores">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Superseded by 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/">ADR-0033: Code Is the State&lt;/a>: tenant state is re-derivable again, so no copy is kept and no restore is on the recovery path. Never accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-16&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How the tenant state store&amp;rsquo;s contents survive losing the host, disk or hypervisor they live on, and how that copy is kept apart from the platform API&amp;rsquo;s database, which the state restores&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/">ADR-0007: Terraform State Custody&lt;/a>, which offered the store and recorded its durability as &lt;em>&amp;ldquo;the weakest part of the decision&amp;rdquo;&lt;/em>; 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a>, whose §1 and §6 put the store and the API&amp;rsquo;s database in one VM&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0026-object-storage/">ADR-0026: Object Storage&lt;/a> — the store is defined by a contract, runs pgsty/silo, and also offers tenant buckets &lt;em>(Proposed)&lt;/em>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §4, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a> §4 and §5, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/substrate/storage/">Substrate Storage&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/policies/risk-management/resiliency/">Limits&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="adr-0007-sized-state-loss-as-a-rebuild">
 ADR-0007 sized state loss as a rebuild
 &lt;a class="anchor" href="#adr-0007-sized-state-loss-as-a-rebuild">#&lt;/a>
&lt;/h3>
&lt;p>When the store was offered, losing state was cheap, and ADR-0007 said exactly how cheap:&lt;/p></description></item><item><title>ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/</guid><description>&lt;h1 id="adr-0012-iot-platform-services-through-a-deevnet-api-and-terraform-provider">
 ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider
 &lt;a class="anchor" href="#adr-0012-iot-platform-services-through-a-deevnet-api-and-terraform-provider">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Amended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0033-code-is-the-state/">ADR-0033: Code Is the State&lt;/a> &lt;em>(Proposed)&lt;/em>: the authoritative copy of a device secret is the tenant&amp;rsquo;s code, not its state (§4); the restore path reads it from there (§5); the audit log is no longer the record of change, git is. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0035-fixed-address-for-a-tenant-device/">ADR-0035: A Fixed Address for a Tenant&amp;rsquo;s Device&lt;/a>: a device&amp;rsquo;s registered MAC is what a fixed address is reserved for, and the API reserves one when the tenant asks (§3, open question 3). 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0038-tenants-update-their-own-devices/">ADR-0038: Tenants Update Their Own Devices&lt;/a>: &lt;em>&amp;ldquo;firmware release hosting&amp;rdquo;&lt;/em> and &lt;em>&amp;ldquo;OTA&amp;rdquo;&lt;/em> are not later layers of the platform (§3); a tenant updates its own devices. &lt;em>&amp;ldquo;Jobs&amp;rdquo;&lt;/em> stays&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Accepted&lt;/strong>&lt;/td>
 &lt;td>2026-09-18, at the close of 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0013-tenant-wifi-ppsk-keys/">CHG-0013&lt;/a> — when the Wi-Fi half had been built, deployed and proven on the AP, not when it was written. The broker half (§8) and the device registry (§3) are decided but not built.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-14&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Reviewed&lt;/strong>&lt;/td>
 &lt;td>2026-09-14. Four of the original open questions were decided in review: the broker (§8), secrets after a rebuild (§4, §5), provider distribution (§7) and credential delivery (§9). The sources are quoted in each section. Revised the same day: the API is provisioning-only, and the broker authenticates from its own auth database (§8). Open questions 2, 5 and 6 were then answered: where the API, its database, the broker&amp;rsquo;s auth database and the Omada controller run (§7, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013&lt;/a>). Revised 2026-09-16: tenant workloads get broker accounts too (§3), and topic confinement is decided (§10, Open question 4). Revised 2026-09-18 by 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/changes/2026/0013-tenant-wifi-ppsk-keys/">CHG-0013&lt;/a>, which built the Wi-Fi half: a key is per tenant per trust class rather than per device (§3), v1 ships on &lt;code>DVNTM-IOT&lt;/code> only (§3), the drift report names profiles rather than counting keys (§6), and &lt;code>DVNTM-IOT&lt;/code> turned out to be a creation rather than a migration (Consequences).&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>How a tenant reaches an IoT platform service whose own interface can&amp;rsquo;t confine it to its scope, and what the substrate builds so it can&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/">ADR-0010: Tenants Consume Platform Services&lt;/a> §1 and §3, which require a scoped service but don&amp;rsquo;t say how one is built when the backing software can&amp;rsquo;t scope itself&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Answers, in part&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0011-edge-devices-application-owned/">ADR-0011: Edge Devices Are Application-Owned and Platform-Attached&lt;/a> open questions 1 (scoped registration) and 3 (Wi-Fi keys — answered per tenant per trust class, not per device; §3)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0004-tenant-dns-publication/">ADR-0004: Tenant DNS Publication&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0006-tenant-code-boundary/">ADR-0006: Tenant Code Boundary&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/">ADR-0007: Terraform State Custody&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0009-network-device-config-ownership/">ADR-0009: Network Device Configuration Is Inventory-Owned and Controller-Applied&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/substrate/0013-management-services-domain-vms/">ADR-0013: Management-Hypervisor Services Run as Containers on Domain VMs&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a> (§4 and §5 depend on it)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;h3 id="the-rule-has-no-mechanism-for-iot">
 The rule has no mechanism for IoT
 &lt;a class="anchor" href="#the-rule-has-no-mechanism-for-iot">#&lt;/a>
&lt;/h3>
&lt;p>ADR-0010 set the test for a platform service: &lt;em>does this recurring tenant action need a substrate
commit?&lt;/em> For IoT, two actions fail it today:&lt;/p></description></item><item><title>ADR-0010: Tenants Consume Platform Services</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0010-tenants-consume-platform-services/</guid><description>&lt;h1 id="adr-0010-tenants-consume-platform-services-they-are-not-woven-into-the-substrate">
 ADR-0010: Tenants Consume Platform Services; They Are Not Woven Into the Substrate
 &lt;a class="anchor" href="#adr-0010-tenants-consume-platform-services-they-are-not-woven-into-the-substrate">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Accepted&lt;/strong>&lt;/td>
 &lt;td>2026-09-19. The principle is the test every later record applies, and two of the three services that failed it have since been remedied. It sat at &lt;code>Proposed&lt;/code> while 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012&lt;/a>, which extends it, was already &lt;code>Accepted&lt;/code> — an inversion both records had noticed and neither had fixed.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-13&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>What makes a substrate-run service safe for a tenant to depend on, and where issuing a tenant something ends and becoming part of it begins&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0004-tenant-dns-publication/">ADR-0004: Tenant DNS Publication&lt;/a> §5, which drew the onboarding-versus-recurring line for DNS only&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0012-iot-platform-api/">ADR-0012: IoT Platform Services Through a Deevnet API and Terraform Provider&lt;/a> — how §3 is met when the backing service can&amp;rsquo;t confine a tenant itself. 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0015-tenant-onboarding-through-api/">ADR-0015: Tenants Are Built Through the Deevnet API&lt;/a> — the same principle applied to building a tenant at all, not only to the services it consumes&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Related&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0006-tenant-code-boundary/">ADR-0006: Tenant Code Boundary&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/">ADR-0007: Terraform State Custody&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/edge-devices/0011-edge-devices-application-owned/">ADR-0011: Edge Devices Are Application-Owned and Platform-Attached&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>Three records have drawn the same line, each for one thing, and none of them says it is a rule:&lt;/p></description></item><item><title>ADR-0007: Terraform State Custody</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0007-terraform-state-custody/</guid><description>&lt;h1 id="adr-0007-terraform-state-custody">
 ADR-0007: Terraform State Custody
 &lt;a class="anchor" href="#adr-0007-terraform-state-custody">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-03&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Where Terraform state lives, who may read it, and what protects it&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Depends on&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0006-tenant-code-boundary/">ADR-0006: Tenant Code Boundary&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extended by&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-model/0014-tenant-state-durability/">ADR-0014: Tenant State Durability&lt;/a> — how the store&amp;rsquo;s contents survive losing their host, once state holds device secrets &lt;em>(Proposed)&lt;/em>; 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/platform-services/0026-object-storage/">ADR-0026: Object Storage&lt;/a> — the store is defined by a contract, runs pgsty/silo, and also offers tenant buckets &lt;em>(Proposed)&lt;/em>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>State custody was never decided. &lt;code>architecture/tenant/building.md&lt;/code> offered three bullets —&lt;/p></description></item><item><title>ADR-0006: Tenant Code Boundary</title><link>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0006-tenant-code-boundary/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/tenant-model/0006-tenant-code-boundary/</guid><description>&lt;h1 id="adr-0006-tenant-code-boundary">
 ADR-0006: Tenant Code Boundary
 &lt;a class="anchor" href="#adr-0006-tenant-code-boundary">#&lt;/a>
&lt;/h1>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;/th>
 &lt;th>&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Status&lt;/strong>&lt;/td>
 &lt;td>Accepted&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Date&lt;/strong>&lt;/td>
 &lt;td>2026-09-03&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Scope&lt;/strong>&lt;/td>
 &lt;td>Where a tenant&amp;rsquo;s code lives, and what it needs from the substrate to stand alone&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Depends on&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0001-tenant-network-fabric/">ADR-0001: Tenant Network Fabric&lt;/a>, 
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/tenant-networking/0002-tenant-fabric-numbering/">ADR-0002: Tenant Fabric Numbering&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Extends&lt;/strong>&lt;/td>
 &lt;td>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0004-tenant-dns-publication/">ADR-0004: Tenant DNS Publication&lt;/a> §5&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="context">
 Context
 &lt;a class="anchor" href="#context">#&lt;/a>
&lt;/h2>
&lt;p>
 &lt;a href="https://deevnet.github.io/deevnet-docs/deevnet-docs/docs/architecture/decisions/naming-and-dns/0004-tenant-dns-publication/">ADR-0004&lt;/a> §5 drew a line that has held
up well: &lt;strong>onboarding may touch substrate; the recurring lifecycle may not.&lt;/strong> Adding a record,
rebuilding, destroying — those are &lt;code>terraform apply&lt;/code> and nothing else.&lt;/p></description></item></channel></rss>