HQ: the as-is base layer, the process, and the names #1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: hal-amend-design
|
name: hal-amend-design
|
||||||
description: Use when a hal-hq design document must change, or when an as-is document is found to be wrong about what the mesh actually does. Triggers on "the design changed", "that's not how it works any more", "update the as-is", "this shipped differently".
|
description: Use when an HQ design document must change, or when an as-is document is found to be wrong about what the mesh actually does. Triggers on "the design changed", "that's not how it works any more", "update the as-is", "this shipped differently".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-amend-design
|
# hal-amend-design
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: hal-diagnose
|
name: hal-diagnose
|
||||||
description: Use when investigating an open hal-hq issue — finding which component owns a symptom, and why. Triggers on "diagnose issue N", "where does this live", "who owns this bug", "why does this happen".
|
description: Use when investigating an open HQ issue — finding which component owns a symptom, and why. Triggers on "diagnose issue N", "where does this live", "who owns this bug", "why does this happen".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-diagnose
|
# hal-diagnose
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: hal-graduate
|
name: hal-graduate
|
||||||
description: Use when a hal-hq research effort concludes and becomes design, or when a design must change. Triggers on "graduate this research", "this is decided", "write the ADR", "close the effort", "the design changed".
|
description: Use when a research effort in HQ concludes and becomes design, or when a design must change. Triggers on "graduate this research", "this is decided", "write the ADR", "close the effort", "the design changed".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-graduate
|
# hal-graduate
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: hal-handoff
|
name: hal-handoff
|
||||||
description: Use when a hal-hq design is settled and implementation is about to start in a code repository. Triggers on "start building this", "hand this off", "ready to implement", "who owns this now".
|
description: Use when an HQ design is settled and implementation is about to start in a code repository. Triggers on "start building this", "hand this off", "ready to implement", "who owns this now".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-handoff
|
# hal-handoff
|
||||||
@@ -20,7 +20,7 @@ Hands a settled design to a code repository. **Authoritative playbook:**
|
|||||||
`03-DESIGN/00-as-is/` before it is changed. Building against an undocumented as-is is how
|
`03-DESIGN/00-as-is/` before it is changed. Building against an undocumented as-is is how
|
||||||
shipped behaviour gets lost.
|
shipped behaviour gets lost.
|
||||||
4. **Flip the status** to `in-progress`, `updated:` today.
|
4. **Flip the status** to `in-progress`, `updated:` today.
|
||||||
5. Build in the code repository. hal-hq never carries implementation.
|
5. Build in the code repository. HQ never carries implementation.
|
||||||
6. On completion, run `hal-graduate`'s "when something ships" section.
|
6. On completion, run `hal-graduate`'s "when something ships" section.
|
||||||
|
|
||||||
## Non-negotiable
|
## Non-negotiable
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: hal-new-research
|
name: hal-new-research
|
||||||
description: Use when starting a new research effort in hal-hq — an idea, technology or approach worth investigating before it is committed to design. Triggers on "research X", "investigate X", "spike X", "should we use X", "is X worth doing".
|
description: Use when starting a new research effort in HQ — an idea, technology or approach worth investigating before it is committed to design. Triggers on "research X", "investigate X", "spike X", "should we use X", "is X worth doing".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-new-research
|
# hal-new-research
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: hal-status
|
name: hal-status
|
||||||
description: Use when you need a cross-cutting view of where hal-hq stands — research state, design implementation state, open issues, or the decision-record index. Triggers on "what's the status", "show the ADR index", "where do things stand", "what's in progress", "what's open".
|
description: Use when you need a cross-cutting view of where HQ stands — research state, design implementation state, open issues, or the decision-record index. Triggers on "what's the status", "show the ADR index", "where do things stand", "what's in progress", "what's open".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-status
|
# hal-status
|
||||||
|
|
||||||
Generates a cross-cutting view **from frontmatter**. This is a read-and-render skill, not a
|
Generates a cross-cutting view **from frontmatter**. This is a read-and-render skill, not a
|
||||||
workflow — hal-hq has **no central status file by design** (decision 35). Every view is
|
workflow — HQ has **no central status file by design** (decision 35). Every view is
|
||||||
generated on demand and never written back to disk.
|
generated on demand and never written back to disk.
|
||||||
|
|
||||||
## What to read
|
## What to read
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: hal-sync-constitution
|
name: hal-sync-constitution
|
||||||
description: Use after changing a rule in hal-hq's 00-META/how-we-build.md, to publish the derived constitution page the mesh injects into design sessions. Triggers on "sync the constitution", "publish the rules", "I changed how-we-build", "update the governed page".
|
description: Use after changing a rule in HQ's 00-META/how-we-build.md, to publish the derived constitution page the mesh injects into design sessions. Triggers on "sync the constitution", "publish the rules", "I changed how-we-build", "update the governed page".
|
||||||
---
|
---
|
||||||
|
|
||||||
# hal-sync-constitution
|
# hal-sync-constitution
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Process — overview
|
# Process — overview
|
||||||
|
|
||||||
How work moves through hal-hq, and who may do what. Every other document in this folder is a
|
How work moves through HQ, and who may do what. Every other document in this folder is a
|
||||||
playbook: trigger, who runs it, steps, outputs. Engineers and agents follow the same
|
playbook: trigger, who runs it, steps, outputs. Engineers and agents follow the same
|
||||||
playbooks; agents must not act outside them.
|
playbooks; agents must not act outside them.
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ playbooks; agents must not act outside them.
|
|||||||
|
|
||||||
| Audience | Contract |
|
| Audience | Contract |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Engineers** | Read and write everything. hal-hq is the single source of truth for mission, research, design, decisions and issue diagnosis. |
|
| **Engineers** | Read and write everything. HQ is the single source of truth for mission, research, design, decisions and issue diagnosis. |
|
||||||
| **Agents** | The same rights as engineers, exercised through these playbooks. |
|
| **Agents** | The same rights as engineers, exercised through these playbooks. |
|
||||||
| **Anyone else** | This repository is public and written for them, but it is not a support channel. Nothing here identifies the mesh it describes. |
|
| **Anyone else** | This repository is public and written for them, but it is not a support channel. Nothing here identifies the mesh it describes. |
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
replaced is stated there; if it is not, write it before changing it. Building against an
|
replaced is stated there; if it is not, write it before changing it. Building against an
|
||||||
undocumented as-is is how a shipped behaviour gets lost.
|
undocumented as-is is how a shipped behaviour gets lost.
|
||||||
4. **Flip the status.** `status: in-progress`, `updated:` today.
|
4. **Flip the status.** `status: in-progress`, `updated:` today.
|
||||||
5. **Build in the code repository.** hal-hq is not a code repository and never carries
|
5. **Build in the code repository.** HQ is not a code repository and never carries
|
||||||
implementation.
|
implementation.
|
||||||
6. **On completion**, run the "when something ships" section of playbook
|
6. **On completion**, run the "when something ships" section of playbook
|
||||||
[02](02-graduation.md).
|
[02](02-graduation.md).
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@ status: canonical
|
|||||||
updated: 2026-08-23
|
updated: 2026-08-23
|
||||||
---
|
---
|
||||||
|
|
||||||
# The HAL repositories
|
# The Novox repositories
|
||||||
|
|
||||||
The map of where implementation lives. Humans use it for orientation; agents use it for issue
|
The map of where implementation lives. Humans use it for orientation; agents use it for issue
|
||||||
triage (playbook [`process/03-issues.md`](process/03-issues.md)). The `code:` frontmatter
|
triage (playbook [`process/03-issues.md`](process/03-issues.md)). The `code:` frontmatter
|
||||||
@@ -15,7 +15,7 @@ and a forge address is an operational detail (see [`README`](../README.md)).
|
|||||||
| Repository | Owns |
|
| Repository | Owns |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `hal` | The monorepo — the node runtime, the module catalogue, the delivery machinery, and the bootstrap scripts. Every core module lives here. |
|
| `hal` | The monorepo — the node runtime, the module catalogue, the delivery machinery, and the bootstrap scripts. Every core module lives here. |
|
||||||
| `hal-hq` | This repository — mission, research, design, decisions, issue diagnosis. The source of truth for *why*. Carries no implementation. |
|
| `hq` | This repository, under the company organisation — mission, research, design, decisions, issue diagnosis. Company-scoped ([ADR 0028](../02-DECISIONS/0028-hq-is-company-scoped.md)); the mesh is its first product. The source of truth for *why*. Carries no implementation. |
|
||||||
| *(one per application)* | Every standalone application, site or side-project gets its own repository, with `module.yml` at the root. Registered with the mesh as a build source; built and deployed by the same pipeline as anything in the monorepo. |
|
| *(one per application)* | Every standalone application, site or side-project gets its own repository, with `module.yml` at the root. Registered with the mesh as a build source; built and deployed by the same pipeline as anything in the monorepo. |
|
||||||
|
|
||||||
## What lives where inside the monorepo
|
## What lives where inside the monorepo
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Run the test. *Can the control plane exist without a relational store?* No. **Po
|
|||||||
tier 1.** It lives once:
|
tier 1.** It lives once:
|
||||||
|
|
||||||
```
|
```
|
||||||
hal-substrate/store/postgres/
|
mesh-substrate/store/postgres/
|
||||||
```
|
```
|
||||||
|
|
||||||
There is no second copy in the catalogue, because the thing that differs between the mesh's own
|
There is no second copy in the catalogue, because the thing that differs between the mesh's own
|
||||||
@@ -40,7 +40,7 @@ database and a project's database is **not the module**. It is how that instance
|
|||||||
| | The mesh's own instance | A project's database |
|
| | The mesh's own instance | A project's database |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Brought up by | the host, from the pinned bundle, with no control plane present | the ordinary delivery and provisioning path |
|
| Brought up by | the host, from the pinned bundle, with no control plane present | the ordinary delivery and provisioning path |
|
||||||
| Declared in | `hal-substrate/bundle.yml` | the consuming module's `requires:` |
|
| Declared in | `mesh-substrate/bundle.yml` | the consuming module's `requires:` |
|
||||||
| Exists because | the control plane cannot start without it | something asked for it |
|
| Exists because | the control plane cannot start without it | something asked for it |
|
||||||
|
|
||||||
Same module, two roles. **Tier is a property of the module** — what must exist before what — and
|
Same module, two roles. **Tier is a property of the module** — what must exist before what — and
|
||||||
@@ -66,7 +66,7 @@ feels.
|
|||||||
## Becoming self-hosting — the forge and the registries
|
## Becoming self-hosting — the forge and the registries
|
||||||
|
|
||||||
Self-improvement means the mesh hosts the things it improves itself with: a forge, an image
|
Self-improvement means the mesh hosts the things it improves itself with: a forge, an image
|
||||||
registry, a package registry. The obvious worry is that these duplicate — a `hal-mesh-gitea`
|
registry, a package registry. The obvious worry is that these duplicate — a `mesh-gitea`
|
||||||
for the mesh and a `gitea` for everyone else. **They do not, and the reason is worth stating
|
for the mesh and a `gitea` for everyone else. **They do not, and the reason is worth stating
|
||||||
carefully, because it is the same reason the bootstrap keeps failing today.**
|
carefully, because it is the same reason the bootstrap keeps failing today.**
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ parts is not a module.
|
|||||||
Worked through for the substrate's relational store:
|
Worked through for the substrate's relational store:
|
||||||
|
|
||||||
```
|
```
|
||||||
hal-substrate/store/postgres/
|
mesh-substrate/store/postgres/
|
||||||
module.yml provides: database · profiles: [managed]
|
module.yml provides: database · profiles: [managed]
|
||||||
parts/
|
parts/
|
||||||
service/ the container, its volume, its network exposure
|
service/ the container, its volume, its network exposure
|
||||||
@@ -215,7 +215,7 @@ hal-substrate/store/postgres/
|
|||||||
## The tree, at file level
|
## The tree, at file level
|
||||||
|
|
||||||
```
|
```
|
||||||
hal-host/ TIER 0
|
mesh-host/ TIER 0
|
||||||
cmd/host/
|
cmd/host/
|
||||||
internal/
|
internal/
|
||||||
apply/ reconcile declared state
|
apply/ reconcile declared state
|
||||||
@@ -230,14 +230,14 @@ hal-host/ TIER 0
|
|||||||
profile/ managed · user · edge
|
profile/ managed · user · edge
|
||||||
substrate.lock pinned tier-1 descriptor
|
substrate.lock pinned tier-1 descriptor
|
||||||
|
|
||||||
hal-substrate/ TIER 1
|
mesh-substrate/ TIER 1
|
||||||
bundle.yml the pinned set, by digest
|
bundle.yml the pinned set, by digest
|
||||||
store/postgres/
|
store/postgres/
|
||||||
bus/<broker>/
|
bus/<broker>/
|
||||||
objects/<object-store>/
|
objects/<object-store>/
|
||||||
images/<registry>/
|
images/<registry>/
|
||||||
|
|
||||||
hal-mesh/ TIER 2
|
mesh-control/ TIER 2
|
||||||
record/ the event log contexts integrate through
|
record/ the event log contexts integrate through
|
||||||
inventory/ nodes · modules · assignments · versions
|
inventory/ nodes · modules · assignments · versions
|
||||||
config/ settings · secrets · derivation
|
config/ settings · secrets · derivation
|
||||||
@@ -250,13 +250,13 @@ hal-mesh/ TIER 2
|
|||||||
knowledge/ memory · documents · retrieval
|
knowledge/ memory · documents · retrieval
|
||||||
api/ the one interface surfaces speak to
|
api/ the one interface surfaces speak to
|
||||||
|
|
||||||
hal-surfaces/ TIER 3
|
mesh-surfaces/ TIER 3
|
||||||
tools/ web/ cli/
|
tools/ web/ cli/
|
||||||
|
|
||||||
hal-catalog/ TIER 4
|
mesh-catalog/ TIER 4
|
||||||
<domain>/<module>/ layout as above
|
<domain>/<module>/ layout as above
|
||||||
|
|
||||||
hal-lab/ hal-sdk/ hal-hq/
|
mesh-lab/ mesh-sdk/ mesh-hq/
|
||||||
```
|
```
|
||||||
|
|
||||||
## What this does not settle
|
## What this does not settle
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ bare machine
|
|||||||
│ one command lands ONE binary. Nothing else exists. TIER 0 host
|
│ one command lands ONE binary. Nothing else exists. TIER 0 host
|
||||||
│
|
│
|
||||||
│ it reads a pinned file it already carries and raises a
|
│ it reads a pinned file it already carries and raises a
|
||||||
│ database, a bus, an object store, a registry, an
|
│ database, a bus, an object store and an image
|
||||||
│ identity provider — locally, alone. TIER 1 substrate
|
│ registry — locally, alone. TIER 1 substrate
|
||||||
│
|
│
|
||||||
│ on those, the mesh's brain starts: which nodes exist,
|
│ on those, the mesh's brain starts: which nodes exist,
|
||||||
│ what runs where, what is reachable. TIER 2 control plane
|
│ what runs where, what is reachable. TIER 2 control plane
|
||||||
@@ -46,7 +46,7 @@ A tier is not a repository and not a bounded context. Those are different cuts:
|
|||||||
## The tree
|
## The tree
|
||||||
|
|
||||||
```
|
```
|
||||||
hal-host/ TIER 0 — the only thing ever installed by hand
|
mesh-host/ TIER 0 — the only thing ever installed by hand
|
||||||
apply/ reconcile declared state on this machine
|
apply/ reconcile declared state on this machine
|
||||||
inventory/ what this node is, has, and is capable of
|
inventory/ what this node is, has, and is capable of
|
||||||
link/ the single outbound connection to the control plane
|
link/ the single outbound connection to the control plane
|
||||||
@@ -54,15 +54,14 @@ hal-host/ TIER 0 — the only thing ever installed by hand
|
|||||||
profile/ capability detection: managed · user · edge
|
profile/ capability detection: managed · user · edge
|
||||||
substrate.lock pinned tier-1 descriptor, appliable with no mesh present
|
substrate.lock pinned tier-1 descriptor, appliable with no mesh present
|
||||||
|
|
||||||
hal-substrate/ TIER 1 — declarations only, no logic of its own
|
mesh-substrate/ TIER 1 — declarations only, no logic of its own
|
||||||
store/ relational state
|
store/ relational state
|
||||||
bus/ commands and events
|
bus/ commands and events
|
||||||
objects/ blobs and build artifacts
|
objects/ blobs and build artifacts
|
||||||
images/ container images
|
images/ container images
|
||||||
identity/ the identity provider
|
|
||||||
bundle.yml the pinned set tier 0 can raise alone
|
bundle.yml the pinned set tier 0 can raise alone
|
||||||
|
|
||||||
hal-mesh/ TIER 2 — the control plane
|
mesh-control/ TIER 2 — the control plane
|
||||||
record/ the event log every context integrates through
|
record/ the event log every context integrates through
|
||||||
inventory/ nodes · modules · assignments · versions
|
inventory/ nodes · modules · assignments · versions
|
||||||
config/ settings · secrets · derivation onto nodes
|
config/ settings · secrets · derivation onto nodes
|
||||||
@@ -75,17 +74,17 @@ hal-mesh/ TIER 2 — the control plane
|
|||||||
knowledge/ memory · documents · retrieval
|
knowledge/ memory · documents · retrieval
|
||||||
api/ the one interface every surface speaks to
|
api/ the one interface every surface speaks to
|
||||||
|
|
||||||
hal-surfaces/ TIER 3 — thin; no logic lives here
|
mesh-surfaces/ TIER 3 — thin; no logic lives here
|
||||||
tools/ the agent-facing tool surface
|
tools/ the agent-facing tool surface
|
||||||
web/ the operator-facing interface
|
web/ the operator-facing interface
|
||||||
cli/ the shell-facing interface
|
cli/ the shell-facing interface
|
||||||
|
|
||||||
hal-catalog/ TIER 4 — what the mesh hosts
|
mesh-catalog/ TIER 4 — what the mesh hosts
|
||||||
<domain>/ grouped per ADR 0017, list per research 005
|
<domain>/ grouped per ADR 0017, list per research 005
|
||||||
|
|
||||||
hal-lab/ the whole mesh, disposable, on one machine
|
mesh-lab/ the whole mesh, disposable, on one machine
|
||||||
hal-sdk/ contracts shared across tiers — types, not behaviour
|
mesh-sdk/ contracts shared across tiers — types, not behaviour
|
||||||
hal-hq/ this repository
|
mesh-hq/ this repository
|
||||||
```
|
```
|
||||||
|
|
||||||
## The dependency rule
|
## The dependency rule
|
||||||
@@ -101,15 +100,15 @@ rule enforced by intention is the same as no tier rule — that is
|
|||||||
|
|
||||||
## Move 1 — the substrate is applied, not delivered
|
## Move 1 — the substrate is applied, not delivered
|
||||||
|
|
||||||
**The problem.** The mesh needs a database, a bus, an object store, a registry and an identity
|
**The problem.** The mesh needs a database, a bus, an object store and an image registry.
|
||||||
provider. Today those are modules, and modules are installed by the delivery pipeline, which
|
Today those are modules, and modules are installed by the delivery pipeline, which
|
||||||
needs the database and the bus. The first node is therefore raised by a special script that
|
needs the database and the bus. The first node is therefore raised by a special script that
|
||||||
exists only because of the circularity, and every later change to the substrate has to pretend
|
exists only because of the circularity, and every later change to the substrate has to pretend
|
||||||
the circularity is not there.
|
the circularity is not there.
|
||||||
|
|
||||||
**The move.** The host can apply a declaration without anyone telling it to. The substrate is
|
**The move.** The host can apply a declaration without anyone telling it to. The substrate is
|
||||||
a **pinned bundle** the host carries: a fixed, versioned, self-contained descriptor of the
|
a **pinned bundle** the host carries: a fixed, versioned, self-contained descriptor of the
|
||||||
five services and nothing else. Raising a first node is `host apply substrate.lock` — not a
|
four services and nothing else. Raising a first node is `host apply substrate.lock` — not a
|
||||||
special path, just the ordinary one with no control plane on the other end.
|
special path, just the ordinary one with no control plane on the other end.
|
||||||
|
|
||||||
The circularity disappears rather than being worked around: **the substrate is applied by tier
|
The circularity disappears rather than being worked around: **the substrate is applied by tier
|
||||||
@@ -217,9 +216,10 @@ confusing.
|
|||||||
|
|
||||||
Tiers 0–3 are the mesh. Tier 4 is everything it carries, and the boundary is stated by
|
Tiers 0–3 are the mesh. Tier 4 is everything it carries, and the boundary is stated by
|
||||||
requirement rather than by taste: **a module is part of the mesh if removing it stops the mesh
|
requirement rather than by taste: **a module is part of the mesh if removing it stops the mesh
|
||||||
managing nodes.** A media server does not. An identity provider does — which is why identity
|
managing nodes.** A media server does not. A relational store does — which is why it sits in the
|
||||||
sits in the substrate and not the catalogue, despite being, in every other respect, an
|
substrate and not the catalogue, despite being, in every other respect, an application like any
|
||||||
application like any other.
|
other. An identity provider, notably, does **not**: the control plane authenticates its own
|
||||||
|
callers, so identity is a hosted service like the media server.
|
||||||
|
|
||||||
That test also settles the IT-company goal without a special category. Development, design and
|
That test also settles the IT-company goal without a special category. Development, design and
|
||||||
deployment tooling are **workloads** — tier 4, hosted, provisioned, delivered like anything
|
deployment tooling are **workloads** — tier 4, hosted, provisioned, delivered like anything
|
||||||
@@ -261,7 +261,7 @@ being the one thing nobody exercises until it breaks.
|
|||||||
|
|
||||||
## A naming near-miss, recorded
|
## A naming near-miss, recorded
|
||||||
|
|
||||||
The tier-0 binary was first called `hal-agent`, because "node agent" is the reflex everywhere
|
The tier-0 binary was first called `mesh-agent`, because "node agent" is the reflex everywhere
|
||||||
else in the industry. That is wrong here, and wrong in the specific way
|
else in the industry. That is wrong here, and wrong in the specific way
|
||||||
[`how-we-build.md`](../../00-META/how-we-build.md) §4 exists to catch: **Agent** is a
|
[`how-we-build.md`](../../00-META/how-we-build.md) §4 exists to catch: **Agent** is a
|
||||||
first-class concept in this mesh — a participant, some of whom are human, holding identity and
|
first-class concept in this mesh — a participant, some of whom are human, holding identity and
|
||||||
@@ -273,8 +273,8 @@ pointing at infrastructure.
|
|||||||
|
|
||||||
[ADR 0015](../../02-DECISIONS/0015-mesh-brokers-nodes-host-agents-think.md) supplies the fix in
|
[ADR 0015](../../02-DECISIONS/0015-mesh-brokers-nodes-host-agents-think.md) supplies the fix in
|
||||||
its own title — *the mesh brokers capabilities; nodes host; agents think.* Three verbs, three
|
its own title — *the mesh brokers capabilities; nodes host; agents think.* Three verbs, three
|
||||||
components: the control plane **brokers** (`hal-mesh`), the tier-0 binary **hosts**
|
components: the control plane **brokers** (`mesh-control`), the tier-0 binary **hosts**
|
||||||
(`hal-host`), the participant **thinks** (`agents`, untouched).
|
(`mesh-host`), the participant **thinks** (`agents`, untouched).
|
||||||
|
|
||||||
`hal-node` was the alternative and was rejected: *Node* is the aggregate in the inventory — the
|
`mesh-node` was the alternative and was rejected: *Node* is the aggregate in the inventory — the
|
||||||
record of a machine — while the binary is what runs on it and does the hosting.
|
record of a machine — while the binary is what runs on it and does the hosting.
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
---
|
||||||
|
status: active
|
||||||
|
initiated: 2026-08-23
|
||||||
|
touches:
|
||||||
|
- 01-RESEARCH/006-mesh-from-scratch/code-skeleton.md
|
||||||
|
- 03-DESIGN/01-to-be/01-end-to-end-testing.md
|
||||||
|
- 02-DECISIONS/0016-a-lab-node-is-a-virtual-machine.md
|
||||||
|
- 03-DESIGN/00-as-is/00-overview.md
|
||||||
|
became: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# 009 — Getting from the mesh that exists to the mesh that is designed
|
||||||
|
|
||||||
|
## What is being investigated
|
||||||
|
|
||||||
|
How a running mesh becomes the one in
|
||||||
|
[research 006](../006-mesh-from-scratch/code-skeleton.md), without losing what it currently
|
||||||
|
carries.
|
||||||
|
|
||||||
|
The proposed shape: **build tiers 0, 1 and 2, then replace the current setup in one move.**
|
||||||
|
|
||||||
|
## Why big-bang is the right instinct here
|
||||||
|
|
||||||
|
Recorded because incremental is the reflex answer and it is wrong in this case.
|
||||||
|
|
||||||
|
- **The two models are structurally incompatible.** The tier rule, the host absorbing what are
|
||||||
|
now modules, the artifact/part split, provisioning generalised to the control plane's own
|
||||||
|
requirements — none of these can half-apply. Running both models at once means the old one's
|
||||||
|
assumptions keep constraining the new one, which is how a migration becomes permanent.
|
||||||
|
- **Nothing external depends on it.** No users outside the operator, no service level to hold.
|
||||||
|
- **The lab exists precisely for this** ([ADR 0016](../../02-DECISIONS/0016-a-lab-node-is-a-virtual-machine.md)).
|
||||||
|
A big-bang that has been rehearsed end to end, repeatedly, on identical machines is not the
|
||||||
|
same risk as one performed for the first time on the real mesh.
|
||||||
|
- **Incremental would carry the rot forward.** The as-is layer documents silent failure paths,
|
||||||
|
a dead test harness and unenforced rules. A gradual migration preserves them by definition.
|
||||||
|
|
||||||
|
## The distinction that lowers the risk
|
||||||
|
|
||||||
|
**Replace the control plane; do not move the workloads.**
|
||||||
|
|
||||||
|
The things that would hurt to lose — mail, media, source, databases, their data directories —
|
||||||
|
are not the mesh. They are what the mesh manages. They sit in container volumes on nodes, and
|
||||||
|
they do not need to move for the control plane above them to be replaced.
|
||||||
|
|
||||||
|
So the big-bang is: the old control plane stops managing these nodes, and the new one starts —
|
||||||
|
with the workload data untouched, in place, and re-declared rather than migrated.
|
||||||
|
|
||||||
|
That reframing turns "replace the mesh" into "replace the part with no persistent state of its
|
||||||
|
own", which is a materially smaller act than it first sounds.
|
||||||
|
|
||||||
|
## The tension this exposes
|
||||||
|
|
||||||
|
Taking over already-running workloads is **adoption**, and adoption was ruled out of scope —
|
||||||
|
recorded as a legacy path in
|
||||||
|
[`03-DESIGN/01-to-be/01-end-to-end-testing.md`](../../03-DESIGN/01-to-be/01-end-to-end-testing.md).
|
||||||
|
The migration appears to need exactly the capability the design declared it would not have.
|
||||||
|
|
||||||
|
The way out, to be tested: the new mesh does not adopt anything. It **declares** the workloads
|
||||||
|
from scratch and points them at data directories that already exist. Nothing inspects a running
|
||||||
|
machine to learn what is there; the declarations are written from the as-is layer, which is what
|
||||||
|
that layer is for. Data survives because it was never touched, not because it was adopted.
|
||||||
|
|
||||||
|
If that holds, adoption stays out of scope and the migration is ordinary declaration. If it does
|
||||||
|
not, adoption needs a one-time, explicitly unsupported tool, and that should be a decision rather
|
||||||
|
than a discovery.
|
||||||
|
|
||||||
|
## Sequencing
|
||||||
|
|
||||||
|
| Phase | What | Done when |
|
||||||
|
|---|---|---|
|
||||||
|
| A | Build tier 0. The host's interface first — it carries the skeleton's biggest unproven claim. | A bare machine becomes a managed node with no mesh present. |
|
||||||
|
| B | Build tier 1 and 2. | The lab raises a full mesh from nothing, repeatedly, from pinned external artifacts. |
|
||||||
|
| C | Enough of tier 3 to operate it. | The mesh can be driven without direct database access. |
|
||||||
|
| D | Declare the existing workloads against the new model. | The lab runs them, with copies of real data shapes. |
|
||||||
|
| E | **Rehearse the cutover in the lab** against a mesh built to resemble the real one. | Repeatable, and repeatably reversible. |
|
||||||
|
| F | Cut over. | The real nodes are managed by the new control plane. |
|
||||||
|
| G | Reach self-hosting — re-bind delivery from external providers to the mesh's own forge and registries. | The mesh builds and deploys itself. |
|
||||||
|
|
||||||
|
Phase G is deliberately last. Per research 006, self-hosting is a state the mesh **reaches**;
|
||||||
|
attempting the cutover and the self-hosting transition in the same move recreates exactly the
|
||||||
|
circularity the skeleton removes — and would mean a failed cutover could take away the means to
|
||||||
|
fix it.
|
||||||
|
|
||||||
|
## The questions
|
||||||
|
|
||||||
|
| Question | Why it matters |
|
||||||
|
|---|---|
|
||||||
|
| What state must **survive** the cutover, versus be re-created? | Workload data must. Provisioned credentials could be re-issued. The mesh's own inventory could be re-declared. Each answer changes the risk. |
|
||||||
|
| What is the **way back**? | A cutover with no rollback is not a plan. If workload data is untouched, reverting may be as small as re-pointing the old control plane at it — to be verified, not assumed. |
|
||||||
|
| How is the cutover **rehearsed** against something resembling the real mesh, without copying the real mesh into a repository? | The lab must be able to model the real topology's shape without carrying its identity. |
|
||||||
|
| Does anything have to keep running **during** the cutover? | Mail and source are the obvious candidates. If yes, "big-bang" is really "big-bang with exceptions", and the exceptions should be named now. |
|
||||||
|
| Is the forge inside or outside the cutover? | If the mesh's own forge goes down with the old control plane, the means of deploying a fix goes with it. This is the self-hosting circularity appearing as a migration risk. |
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
status: accepted
|
||||||
|
date: 2026-08-23
|
||||||
|
deciders: jochen
|
||||||
|
reconstructed: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# 27. The product is Novox Mesh; Nox is an identity, not a second system
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The name `HAL` was never chosen. This began as a dotfiles repository, the first commits in
|
||||||
|
February 2026 adopt dotfiles and per-node overrides, and the name arrived with the code — as
|
||||||
|
recorded in
|
||||||
|
[`03-DESIGN/00-as-is/10-module-catalogue.md`](../03-DESIGN/00-as-is/10-module-catalogue.md),
|
||||||
|
most of the current shape is inherited from that origin rather than designed for a mesh. The
|
||||||
|
name is part of the inheritance.
|
||||||
|
|
||||||
|
Three things make it worth changing rather than living with.
|
||||||
|
|
||||||
|
**It is borrowed, and borrowed badly.** HAL is the canonical *untrustworthy* machine
|
||||||
|
intelligence. For infrastructure whose entire proposition is that it manages your machines,
|
||||||
|
heals itself, and is trusted with credentials, that is an unhelpful flag to fly, and it is not
|
||||||
|
a name anyone owns.
|
||||||
|
|
||||||
|
**There is a name available that is owned.** The company is Novox. A product of Novox should
|
||||||
|
carry that lineage rather than a film reference.
|
||||||
|
|
||||||
|
**A platform and a persona are different things, and one name was doing both.** `HAL` named the
|
||||||
|
mesh *and*, implicitly, the thing an operator talks to. Those are separate concerns — the
|
||||||
|
platform is what runs; the persona is who answers.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Keep `HAL`.** Rejected. Every reason to keep it is sunk cost, and the sunk cost is at its
|
||||||
|
smallest today.
|
||||||
|
2. **Rename everything to a single new name covering platform and persona.** Rejected: it
|
||||||
|
repeats the conflation that made `HAL` ambiguous.
|
||||||
|
3. **Separate the two: a product name and an identity.** Chosen.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**The product is `Novox Mesh`**, shortened to `mesh` in internal use — repository names, the
|
||||||
|
module namespace, environment variables, paths.
|
||||||
|
|
||||||
|
**`Nox` is an identity of Novox**, and specifically an **agent identity within the mesh's own
|
||||||
|
model** — a named participant, exactly as
|
||||||
|
[ADR 0012](0012-agents-are-persistent-employees.md) defines one. Not a separate product, not a
|
||||||
|
separate runtime, not a privileged path.
|
||||||
|
|
||||||
|
**Nox is the agent of the mesh, not of a node.** This is the part that carries weight:
|
||||||
|
|
||||||
|
- **Every node keeps its own identity.** That already exists and stays — a node is a named
|
||||||
|
participant with its own character, and addressing one directly remains possible and normal.
|
||||||
|
- **Nox is scoped to the whole mesh.** It is what the mesh is called when the mesh itself
|
||||||
|
speaks, rather than one machine within it.
|
||||||
|
- **Nox addresses node identities.** Asking Nox for something that lives on one node is Nox
|
||||||
|
talking to that node, not a human choosing a machine.
|
||||||
|
- **A human mostly talks to Nox.** It is the front door.
|
||||||
|
|
||||||
|
That last point makes Nox the concrete form of the vision in
|
||||||
|
[`00-META/mission.md`](../00-META/mission.md): *an agent states an intent and the mesh carries
|
||||||
|
it out — no console to open, no runbook to follow, no remembering which node holds which
|
||||||
|
thing.* Nox is who that intent is stated to. The mission described the behaviour; this names
|
||||||
|
the thing that has it.
|
||||||
|
|
||||||
|
Nox holds no private channel. Whatever it can do, it does through the same surfaces every other
|
||||||
|
agent uses — which is not a naming detail: a persona with its own path would be the one part of
|
||||||
|
the mesh with no human checkpoint, and the skeleton already rules that out.
|
||||||
|
|
||||||
|
`HAL` is retired.
|
||||||
|
|
||||||
|
**Timing is the substance of this decision, not an aside.** The skeleton in
|
||||||
|
[research 006](../01-RESEARCH/006-mesh-from-scratch/code-skeleton.md) is not built. Renaming
|
||||||
|
before it exists costs a search and replace across research documents. Renaming after costs the
|
||||||
|
same class of migration as everything else this repository is trying to avoid, and would
|
||||||
|
therefore not happen.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- **The as-is layer keeps `HAL`.** It describes what runs, and what runs is called HAL. The
|
||||||
|
to-be layer uses `mesh`. The rename is part of the migration, and the two-layer split
|
||||||
|
([ADR 0020](0020-design-is-written-in-two-layers.md)) is what makes holding both names
|
||||||
|
coherent rather than confusing.
|
||||||
|
- **Records 0001–0026 keep `HAL`.** They are immutable and they say what was decided when it
|
||||||
|
was decided. No record is edited for a name.
|
||||||
|
- Tier 2 cannot be `mesh-mesh`. The control plane is **`mesh-control`**; `mesh-broker` was
|
||||||
|
rejected because the substrate already contains a message broker.
|
||||||
|
- The namespace, environment variable prefix, service names and on-disk paths all change. In
|
||||||
|
the existing system that is a migration and is not attempted here.
|
||||||
|
- **`mesh` is a generic word**, and it already means something specific in infrastructure — a
|
||||||
|
service mesh is a different thing. Recorded as a known trade rather than an oversight: the
|
||||||
|
full name `Novox Mesh` is distinctive, and the short form is internal.
|
||||||
|
- The persona has a name before it has behaviour. That is the right order — it is an identity in
|
||||||
|
a system that already has a model of identities, so it needs no new machinery to exist.
|
||||||
|
- **Except in one respect, and it is a real gap.**
|
||||||
|
[ADR 0012](0012-agents-are-persistent-employees.md) binds every agent to a home node, one to
|
||||||
|
one, with a workspace on that machine. A mesh-scoped agent has no home node by definition, so
|
||||||
|
the model does not currently have a shape for Nox. Extending it — an agent whose scope is the
|
||||||
|
mesh rather than a machine — is a decision of its own and is not taken here.
|
||||||
|
- Two levels of identity now exist where there was one: the node, and the mesh. The distinction
|
||||||
|
has to stay visible in every surface, or "ask Nox" and "ask a node" collapse into each other
|
||||||
|
and it stops being clear who is answering.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [ADR 0012](0012-agents-are-persistent-employees.md) — what an identity is in this system, and
|
||||||
|
why `Nox` needs no separate mechanism.
|
||||||
|
- [ADR 0020](0020-design-is-written-in-two-layers.md) — why the as-is and to-be layers can
|
||||||
|
legitimately use different names for the same system.
|
||||||
|
- The dotfiles origin, and the naming inheritance it explains:
|
||||||
|
[`03-DESIGN/00-as-is/10-module-catalogue.md`](../03-DESIGN/00-as-is/10-module-catalogue.md).
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
status: accepted
|
||||||
|
date: 2026-08-23
|
||||||
|
deciders: jochen
|
||||||
|
reconstructed: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# 28. HQ is company-scoped; the mesh is its first product
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
This repository was `hal-hq` — one product's headquarters, named for the product. Then the
|
||||||
|
product was renamed ([ADR 0027](0027-the-product-is-novox-mesh.md)), which forced the question
|
||||||
|
of what the repository is actually the headquarters *of*.
|
||||||
|
|
||||||
|
Two facts settled it, and both were checked rather than assumed.
|
||||||
|
|
||||||
|
**Novox already delivers other things.** The company's forge organisation holds live projects
|
||||||
|
beside the mesh, and they are registered as build sources — meaning the mesh already builds and
|
||||||
|
deploys them. They are not hypothetical future products; they exist and ship today.
|
||||||
|
|
||||||
|
**They are tenants, not peers.** They run *on* the mesh. Every one of them is developed,
|
||||||
|
delivered and hosted by it. So the mesh is not one product among several — it is the ground the
|
||||||
|
others stand on.
|
||||||
|
|
||||||
|
That distinction decides the scope. If the mesh were a product beside others, a per-product HQ
|
||||||
|
would be right. Because it is the substrate the company operates on, a decision about the mesh
|
||||||
|
is a decision about how the company works.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **`mesh-hq` — one HQ per product.** The safe choice, and the reversible one: a second
|
||||||
|
product creates its own HQ and shared practice graduates upward later. Rejected, knowingly,
|
||||||
|
because it models the mesh as a peer of things that are actually its tenants.
|
||||||
|
2. **A company HQ *and* a product HQ, from the start.** Rejected as ceremony — two repositories
|
||||||
|
for one operator, and the constitution's own YAGNI rule says not to.
|
||||||
|
3. **One company-scoped HQ, `novox/hq`, with the mesh as its first product.** Chosen.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
The repository is **`novox/hq`** — Novox's headquarters, not the mesh's.
|
||||||
|
|
||||||
|
It holds the reasoning behind what Novox builds. Today almost all of that is the mesh, because
|
||||||
|
the mesh is what Novox is building. That is a fact about the present, not a definition of the
|
||||||
|
repository.
|
||||||
|
|
||||||
|
**The scope of each document is fixed now, so the eventual split is mechanical rather than
|
||||||
|
archaeological:**
|
||||||
|
|
||||||
|
| Scope | Documents | Moves if products separate? |
|
||||||
|
|---|---|---|
|
||||||
|
| **Company** | [`how-we-build.md`](../00-META/how-we-build.md), [`process/`](../00-META/process/), [`repos.md`](../00-META/repos.md), this record and [0019](0019-hq-is-its-own-repository.md)–[0027](0027-the-product-is-novox-mesh.md) | No — they stay at the top |
|
||||||
|
| **Product (mesh)** | [`mission.md`](../00-META/mission.md), [`context.md`](../00-META/context.md), [`effect.md`](../00-META/effect.md), `01-RESEARCH`, `03-DESIGN`, `04-ISSUES`, records 0001–0018 | Yes — into a product section |
|
||||||
|
|
||||||
|
The folders are **not** restructured now. One product's content under a company name is
|
||||||
|
correct while there is one product's worth of it, and nesting before there is anything to nest
|
||||||
|
is the ceremony option 2 was rejected for.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- Engineering practice has a home that does not belong to the mesh. `how-we-build.md` — never
|
||||||
|
write to production directly, migrations for schema changes, runtime evidence for behavioural
|
||||||
|
criteria — is true of any Novox project, and its being in a mesh repository was always a
|
||||||
|
slight mislabelling.
|
||||||
|
- The constitution derived from it ([ADR 0025](0025-hq-is-the-source-of-the-constitution.md))
|
||||||
|
can legitimately govern work outside the mesh. Under a product HQ it could not have, without
|
||||||
|
either duplicating or reaching across repositories.
|
||||||
|
- **The bet is not entirely forward-looking, and that is worth being honest about.** Novox
|
||||||
|
already has work that is *not* a mesh tenant — client engagements and at least one product
|
||||||
|
that is developed outside it. So the company genuinely has a scope wider than the mesh
|
||||||
|
**today**, which strengthens the case for a company HQ and simultaneously means the split in
|
||||||
|
the table above is closer than "some day". The table is not a precaution; it is a plan whose
|
||||||
|
trigger already half-exists.
|
||||||
|
- What has *not* happened yet is any of that work needing the constitution. That is the actual
|
||||||
|
trigger ([ADR 0025](0025-hq-is-the-source-of-the-constitution.md)): the moment something
|
||||||
|
outside the mesh must be governed by the same rules, product-level content moves down a level
|
||||||
|
and this repository becomes what its name already claims.
|
||||||
|
- A new repository was created rather than the old one transferred — the forge predates the
|
||||||
|
transfer API. `jschoubben/hq` is left in place untouched; it is not the source of truth and
|
||||||
|
nothing points at it.
|
||||||
|
- The mesh's own documents now live one conceptual level below the repository they are in. A
|
||||||
|
reader arriving at `01-RESEARCH` should understand it as the mesh's research, not Novox's.
|
||||||
|
Nothing in the folder names says so, and that is the cost of not restructuring.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [ADR 0027](0027-the-product-is-novox-mesh.md) — the product name that forced the question.
|
||||||
|
- [ADR 0019](0019-hq-is-its-own-repository.md) — why HQ is a repository at all. Unchanged; only
|
||||||
|
its scope moves.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
status: open
|
status: open
|
||||||
opened: 2026-08-23
|
opened: 2026-08-23
|
||||||
located-in: [hal, hal-hq]
|
located-in: [hal, hq]
|
||||||
fixed-by:
|
fixed-by:
|
||||||
amended-design:
|
amended-design:
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Agent instructions — hal-hq
|
# Agent instructions — Novox HQ
|
||||||
|
|
||||||
This repository is the source of truth for the HAL mesh's mission, research, design and
|
This repository is the source of truth for the HAL mesh's mission, research, design and
|
||||||
decisions. Implementation lives in the code repositories (see
|
decisions. Implementation lives in the code repositories (see
|
||||||
|
|||||||
Reference in New Issue
Block a user