Reconcile: adopt initialization's consolidated HQ as canonical, re-home this session's new work #24
@@ -17,6 +17,15 @@ touches:
|
||||
Whether the catalogue's missing structure is a **graph** — modules declaring what they need,
|
||||
what they offer, and what they exclude — and what that replaces.
|
||||
|
||||
**[`features.md`](features.md) answers what happens to `feature`.** It is one word for four
|
||||
things spanning three tiers — artifacts built once per version, resources applied to a machine,
|
||||
actions run against something that is not this machine, and checks that are requirements in
|
||||
disguise. Measured: every one of the twenty-one handlers implements all six stages, so `configs`
|
||||
has a build stage with nothing to build and `npm` has a start stage with nothing to start. That
|
||||
emptiness is the conflation, and it is why a stage that did nothing and a stage that failed look
|
||||
alike. Nothing replaces it, because it was never one concept. **One property is worth keeping:
|
||||
content is detected, relationships are declared.**
|
||||
|
||||
**[`cases.md`](cases.md) enumerates what a module can be** — twenty kinds of thing the mesh has
|
||||
to install, run, own or know about — and extracts the axes a manifest must express. Two of those
|
||||
axes appear in no current thinking: **how many instances** a thing may have, and **whether two
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
# What a feature is, and what it splits into
|
||||
|
||||
Measured against `origin/main` of the code repository, 2026-08-26.
|
||||
|
||||
The operator wants the feature concept gone.
|
||||
[Research 006](../006-mesh-from-scratch/00-overview.md) left it open — *"does `feature`
|
||||
survive? The skeleton splits it in two and argues the conflation is what makes the delivery
|
||||
pipeline hard to reason about."*
|
||||
|
||||
This is what it actually is, and what it turns into.
|
||||
|
||||
## What it is today
|
||||
|
||||
A **feature** is a kind of content a module can carry, detected from what its directory
|
||||
contains rather than declared. Twenty-one of them, each with a handler that owns its whole
|
||||
lifecycle:
|
||||
|
||||
```
|
||||
configs dist-assets events hooks migrations migration-artifact npm npm-install
|
||||
prerequisite-env prerequisite-packages prerequisite-provision provision-migrations
|
||||
provision-seeds seeds service systemd tools verifiers verify vhost detect
|
||||
```
|
||||
|
||||
Each moves through **six stages**: build, publish, install, configure, start, verify.
|
||||
|
||||
## Finding — every handler implements every stage
|
||||
|
||||
The structural evidence, and it is not a style problem.
|
||||
|
||||
| handler | stages it implements |
|
||||
|---|---|
|
||||
| `configs` | build · configure · install · start · verify |
|
||||
| `service` | build · configure · install · start · verify |
|
||||
| `systemd` | build · configure · install · start · verify |
|
||||
| `tools` | build · configure · install · start · verify |
|
||||
| `vhost` | build · configure · install · start · verify |
|
||||
| `migrations` | build · configure · install · start · verify |
|
||||
| `npm` | build · publish · install · configure · start |
|
||||
|
||||
`configs` writes files onto a node. It has nothing to build, and it has a build stage.
|
||||
`npm` publishes a package to a registry. It has nothing to start, and it has a start stage.
|
||||
|
||||
**One interface spans build-time and apply-time, so every kind of content must implement both
|
||||
halves and most of them do nothing in one.** That is the conflation, and the emptiness is what
|
||||
makes the pipeline hard to reason about: a stage that does nothing and a stage that failed to
|
||||
do anything look identical from outside.
|
||||
|
||||
## What it splits into
|
||||
|
||||
The twenty-one are not one kind of thing. They are four, and they belong to different tiers.
|
||||
|
||||
**Artifacts — built once per version, then published.** `npm`, `dist-assets`,
|
||||
`migration-artifact`. Nothing about a node is involved; the output is a thing that exists in a
|
||||
registry. **Tier 2, delivery.**
|
||||
|
||||
**Resources — desired state on a machine.** `configs`, `service`, `systemd`, `vhost`, `tools`.
|
||||
Applied, converged, idempotent — which is exactly what
|
||||
[ADR 0043](../../02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md)
|
||||
already describes and what the host already does. **Tier 0.**
|
||||
|
||||
**Actions — run once, against something that is not this machine.** `migrations`, `seeds`,
|
||||
`provision-migrations`, `provision-seeds`, `hooks`. A migration runs against a database, and the
|
||||
database may be on another node entirely. Neither an artifact nor node state, which is why they
|
||||
sit awkwardly in a scheme built for both. **Tier 2, and the operator wants seeds gone.**
|
||||
|
||||
**Checks — assertions, not changes.** `prerequisite-env`, `prerequisite-packages`,
|
||||
`prerequisite-provision`, `verify`, `verifiers`, `detect`. The prerequisites are **requirements
|
||||
in disguise** — a module saying what must be true before it can be installed, which is precisely
|
||||
what an edge in the graph says. The verifiers are the read-back the host already performs.
|
||||
|
||||
## So the answer is: it splits, and the split is a tier boundary
|
||||
|
||||
**`feature` is one word for four things spanning three tiers.** That is why every handler
|
||||
implements every stage, why half of them are empty, and why the pipeline is hard to reason
|
||||
about.
|
||||
|
||||
Nothing replaces it, because it was never one concept:
|
||||
|
||||
| Was a feature | Becomes | Whose |
|
||||
|---|---|---|
|
||||
| npm, dist-assets, migration-artifact | an **artifact** | delivery |
|
||||
| configs, service, systemd, vhost, tools | a **resource** in a declaration | the host |
|
||||
| migrations, hooks | an **action** against something else | delivery |
|
||||
| seeds | *nothing* — the operator wants them gone | — |
|
||||
| prerequisite-* | an **edge** in the graph | the catalogue |
|
||||
| verify, verifiers | the host's **read-back** | the host |
|
||||
|
||||
## What is lost, and should not be
|
||||
|
||||
**Detection.** Features are detected from the directory rather than declared, and the reason is
|
||||
good: *a declared list and the directory it describes drift, and the directory is the one that
|
||||
is true.* That property is worth keeping whatever the concept is called — a module that says it
|
||||
has migrations and has none, or has them and does not say so, is a fault nobody sees until it
|
||||
matters.
|
||||
|
||||
Under the split, detection still applies: what a module **contains** is read from what is there.
|
||||
What it **requires**, **provides** and **excludes** is declared, because none of that is visible
|
||||
in a directory.
|
||||
|
||||
That line is worth stating precisely, because it is the one the current design got right:
|
||||
**content is detected, relationships are declared.**
|
||||
|
||||
## Open
|
||||
|
||||
- **Is an action a resource?** A migration is not node state and not an artifact. It could be a
|
||||
resource type the host applies with the target being a database rather than a machine — which
|
||||
would collapse the third category into the second, at the cost of the host reaching something
|
||||
that is not the machine it is on. That cost looks too high, but it has not been argued.
|
||||
- **Where do hooks go?** They are arbitrary code a module runs at a stage — the escape hatch. A
|
||||
design with no escape hatch is either very good or has not met reality yet, and this one has
|
||||
not.
|
||||
- **What does the pipeline schedule, once features are gone?** It currently schedules features.
|
||||
If the four categories have different lifecycles, the unit of work is different for each, and
|
||||
what the coordinator orchestrates needs naming.
|
||||
Reference in New Issue
Block a user