HQ: the as-is base layer, the process, and the names #1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
@@ -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
|
||||
shipped behaviour gets lost.
|
||||
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.
|
||||
|
||||
## Non-negotiable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
## What to read
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
playbooks; agents must not act outside them.
|
||||
|
||||
@@ -8,7 +8,7 @@ playbooks; agents must not act outside them.
|
||||
|
||||
| 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. |
|
||||
| **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
|
||||
undocumented as-is is how a shipped behaviour gets lost.
|
||||
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.
|
||||
6. **On completion**, run the "when something ships" section of playbook
|
||||
[02](02-graduation.md).
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ status: canonical
|
||||
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
|
||||
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 |
|
||||
|---|---|
|
||||
| `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. |
|
||||
|
||||
## 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:
|
||||
|
||||
```
|
||||
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
|
||||
@@ -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 |
|
||||
|---|---|---|
|
||||
| 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 |
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
```
|
||||
hal-substrate/store/postgres/
|
||||
mesh-substrate/store/postgres/
|
||||
module.yml provides: database · profiles: [managed]
|
||||
parts/
|
||||
service/ the container, its volume, its network exposure
|
||||
@@ -215,7 +215,7 @@ hal-substrate/store/postgres/
|
||||
## The tree, at file level
|
||||
|
||||
```
|
||||
hal-host/ TIER 0
|
||||
mesh-host/ TIER 0
|
||||
cmd/host/
|
||||
internal/
|
||||
apply/ reconcile declared state
|
||||
@@ -230,14 +230,14 @@ hal-host/ TIER 0
|
||||
profile/ managed · user · edge
|
||||
substrate.lock pinned tier-1 descriptor
|
||||
|
||||
hal-substrate/ TIER 1
|
||||
mesh-substrate/ TIER 1
|
||||
bundle.yml the pinned set, by digest
|
||||
store/postgres/
|
||||
bus/<broker>/
|
||||
objects/<object-store>/
|
||||
images/<registry>/
|
||||
|
||||
hal-mesh/ TIER 2
|
||||
mesh-control/ TIER 2
|
||||
record/ the event log contexts integrate through
|
||||
inventory/ nodes · modules · assignments · versions
|
||||
config/ settings · secrets · derivation
|
||||
@@ -250,13 +250,13 @@ hal-mesh/ TIER 2
|
||||
knowledge/ memory · documents · retrieval
|
||||
api/ the one interface surfaces speak to
|
||||
|
||||
hal-surfaces/ TIER 3
|
||||
mesh-surfaces/ TIER 3
|
||||
tools/ web/ cli/
|
||||
|
||||
hal-catalog/ TIER 4
|
||||
mesh-catalog/ TIER 4
|
||||
<domain>/<module>/ layout as above
|
||||
|
||||
hal-lab/ hal-sdk/ hal-hq/
|
||||
mesh-lab/ mesh-sdk/ mesh-hq/
|
||||
```
|
||||
|
||||
## What this does not settle
|
||||
|
||||
@@ -20,8 +20,8 @@ bare machine
|
||||
│ one command lands ONE binary. Nothing else exists. TIER 0 host
|
||||
│
|
||||
│ it reads a pinned file it already carries and raises a
|
||||
│ database, a bus, an object store, a registry, an
|
||||
│ identity provider — locally, alone. TIER 1 substrate
|
||||
│ database, a bus, an object store and an image
|
||||
│ registry — locally, alone. TIER 1 substrate
|
||||
│
|
||||
│ on those, the mesh's brain starts: which nodes exist,
|
||||
│ 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
|
||||
|
||||
```
|
||||
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
|
||||
inventory/ what this node is, has, and is capable of
|
||||
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
|
||||
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
|
||||
bus/ commands and events
|
||||
objects/ blobs and build artifacts
|
||||
images/ container images
|
||||
identity/ the identity provider
|
||||
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
|
||||
inventory/ nodes · modules · assignments · versions
|
||||
config/ settings · secrets · derivation onto nodes
|
||||
@@ -75,17 +74,17 @@ hal-mesh/ TIER 2 — the control plane
|
||||
knowledge/ memory · documents · retrieval
|
||||
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
|
||||
web/ the operator-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
|
||||
|
||||
hal-lab/ the whole mesh, disposable, on one machine
|
||||
hal-sdk/ contracts shared across tiers — types, not behaviour
|
||||
hal-hq/ this repository
|
||||
mesh-lab/ the whole mesh, disposable, on one machine
|
||||
mesh-sdk/ contracts shared across tiers — types, not behaviour
|
||||
mesh-hq/ this repository
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
**The problem.** The mesh needs a database, a bus, an object store, a registry and an identity
|
||||
provider. Today those are modules, and modules are installed by the delivery pipeline, which
|
||||
**The problem.** The mesh needs a database, a bus, an object store and an image registry.
|
||||
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
|
||||
exists only because of the circularity, and every later change to the substrate has to pretend
|
||||
the circularity is not there.
|
||||
|
||||
**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
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
sits in the substrate and not the catalogue, despite being, in every other respect, an
|
||||
application like any other.
|
||||
managing nodes.** A media server does not. A relational store does — which is why it sits in the
|
||||
substrate and not the catalogue, despite being, in every other respect, an application like any
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
[`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
|
||||
@@ -273,8 +273,8 @@ pointing at infrastructure.
|
||||
|
||||
[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
|
||||
components: the control plane **brokers** (`hal-mesh`), the tier-0 binary **hosts**
|
||||
(`hal-host`), the participant **thinks** (`agents`, untouched).
|
||||
components: the control plane **brokers** (`mesh-control`), the tier-0 binary **hosts**
|
||||
(`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.
|
||||
|
||||
@@ -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
|
||||
opened: 2026-08-23
|
||||
located-in: [hal, hal-hq]
|
||||
located-in: [hal, hq]
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user