docs: bring the specification in line with the accepted implementation
The operator ruled the implementation repo's main (50c8719) the latest and accepted state. Sync the spec to it. Accepted changes are reflected: one bare-metal environment, TrueNAS bulk storage, R2 off-cluster backup, CloudNativePG, single-node VPN gateway with Cilium fail-closed, inbound WireGuard, per-app auth sidecars, Renovate, the CI gate as approver, and the pm-agent. New ADR-0017..0025; ADR-0016 corrected and accepted; R-* IDs unchanged, eight amended. Where the implementation has simply not met a requirement, the requirement stands and the shortfall is recorded in docs/16-known-gaps.md. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1ddc14b918
commit
250fb54154
43 files changed
+1672
-575
No files matched your search
+59
-31
@@ -4,18 +4,15 @@ How work is version-controlled for this repository. This complements the governa
|
||||
[`AGENTS.md`](AGENTS.md) (what agents may/may not change) — this file covers *how changes land in
|
||||
git*.
|
||||
|
||||
## Interim state (now): local git, feature branches → main
|
||||
## This repo (the spec)
|
||||
|
||||
There is **no remote git host on this network today**. (The previous `home-network` Gitea instance is
|
||||
gone from this network; the infrastructure it built still runs but is not reachable here.) So for now:
|
||||
The spec repo is hosted on the platform's own Gitea (`gitea.home.keithjackson.dev`).
|
||||
|
||||
- **Local git only.** The repository lives on the workstation; there is no push target yet.
|
||||
- **No work on `main`.** `main` holds only reviewed, completed work. Do **not** commit work-in-
|
||||
progress directly to `main`.
|
||||
- **Every change is a feature branch.** Create `feature/<short-description>` (or `fix/…`, `docs/…`)
|
||||
for any unit of work, commit there, then **merge into `main`** when the work is complete and — for
|
||||
implementation work — its conformance tests pass ([`agents/definition-of-done.md`](agents/definition-of-done.md)).
|
||||
- **Merge to `main` = "done".** Keep `main` always in a coherent, mergeable state.
|
||||
- **No work on `main`.** `main` holds only reviewed, completed work.
|
||||
- **Every change is a feature branch**, merged into `main` by pull request. Only the human operator
|
||||
merges a spec change (R-TEST-06).
|
||||
- **Merge a coherent batch.** Every spec commit on `main` must be adopted by the implementation (see
|
||||
below), so small drive-by commits each carry a real cost.
|
||||
|
||||
### Branch naming
|
||||
- `feature/<slug>` — new capability or spec area
|
||||
@@ -23,36 +20,67 @@ gone from this network; the infrastructure it built still runs but is not reacha
|
||||
- `docs/<slug>` — documentation-only changes
|
||||
- `chore/<slug>` — tooling/repo housekeeping
|
||||
|
||||
The implementation repo has its own convention (`feat/`, `fix/`, `docs/`, `chore/`).
|
||||
|
||||
### Commit hygiene
|
||||
- Small, single-responsibility commits; imperative subject lines.
|
||||
- Reference requirement IDs / ADR numbers / task-board IDs where relevant (they're stable across
|
||||
file moves).
|
||||
- Reference requirement IDs / ADR numbers where relevant (they're stable across file moves).
|
||||
- **Never commit plaintext secrets** — secrets are SOPS-encrypted only ([`docs/07-security-and-secrets.md`](docs/07-security-and-secrets.md));
|
||||
the [`.gitignore`](.gitignore) guards common leak paths but is not a substitute for care.
|
||||
|
||||
## Target state (soon): Gitea-hosted, CI/CD-driven GitOps
|
||||
## The implementation repo
|
||||
|
||||
The platform will **host its own git**. **Gitea is one of the first services brought online on the
|
||||
cluster** ([`docs/13-service-catalog.md`](docs/13-service-catalog.md), roadmap Phase 6 is pulled
|
||||
early — see [`roadmap/phases.md`](roadmap/phases.md)). Once Gitea is up and stable, the workflow
|
||||
shifts:
|
||||
The [implementation repo](https://gitea.home.keithjackson.dev/Home-Network/home-network-k3s-impl) is
|
||||
CI/CD-driven GitOps. Its `CLAUDE.md` is the delivery contract for how work lands there; intent is in
|
||||
[`docs/05-gitops-and-delivery.md`](docs/05-gitops-and-delivery.md) and
|
||||
[ADR-0024](decisions/adr-0024-delivery-authority-ci-gate.md).
|
||||
|
||||
1. **Repos move to Gitea** (`gitea.home.keithjackson.dev`). This local repo is pushed up as the
|
||||
origin of record.
|
||||
2. **GitOps source migrates** from local/bootstrap to Gitea: Flux reconciles the cluster from Gitea
|
||||
([`docs/05-gitops-and-delivery.md`](docs/05-gitops-and-delivery.md)).
|
||||
3. **CI/CD runs in Gitea** (Gitea Actions): the Kyverno L0 policy gate and the trigger for the
|
||||
in-cluster Chainsaw conformance Job run as pipelines on push/PR
|
||||
([`docs/14-testing-and-conformance.md`](docs/14-testing-and-conformance.md)); Renovate opens
|
||||
update PRs ([`docs/11-automated-updates.md`](docs/11-automated-updates.md)).
|
||||
4. **Pull requests become the merge gate** into `main`, with CI (policy + conformance) required
|
||||
green before merge — the same no-work-in-main rule, now enforced by the platform instead of by
|
||||
convention.
|
||||
- Every change is branch → PR → **merge gate green** → merge. Direct pushes to `main` are rejected.
|
||||
- The CI gate is the approver; sensitive paths also need a non-author review.
|
||||
- Flux reconciles the cluster from that repo's `main`.
|
||||
- Each unit of work records a dated handoff entry under that repo's `decisions/`. Those are
|
||||
implementation handoffs; this repo's `decisions/` holds ADRs.
|
||||
|
||||
### The bootstrapping caveat (self-hosted git is circular)
|
||||
### Where status lives
|
||||
|
||||
**`./conformance/run.sh --status` in the implementation repo is the live status surface**: per
|
||||
requirement, whether it is implemented, reconciled, has an executable test, and has recorded proof.
|
||||
[`docs/16-known-gaps.md`](docs/16-known-gaps.md) is a dated snapshot of the shortfalls at one point in
|
||||
time. [`agents/task-board.md`](agents/task-board.md) is a frozen historical seed.
|
||||
|
||||
## Adopting a spec change in the implementation
|
||||
|
||||
The implementation pins the exact spec commit it is built against, in `ci/SPEC_PIN`. Its
|
||||
spec-immutability check (R-TEST-06) fails when a spec checkout has uncommitted changes or its `HEAD`
|
||||
differs from the pin, so every movement of spec `main` is an explicit, reviewed act. On **every**
|
||||
spec change:
|
||||
|
||||
1. **Merge to spec `main`.** The human operator does this. Until step 2 lands, a local gate against
|
||||
a checkout of the new `main` reports blocked.
|
||||
2. **Bump the pin** in an implementation PR, to the new spec `main` commit. `ci/` is a sensitive path,
|
||||
so the PR needs the operator's review or the operator's own override; an agent never overrides
|
||||
for itself.
|
||||
3. **Reconcile requirement IDs in that same PR.** The registry
|
||||
(`conformance/requirements/registry.yaml`) mirrors the `R-*` IDs in
|
||||
[`docs/00-vision-and-scope.md`](docs/00-vision-and-scope.md):
|
||||
- A **new ID** must arrive with a requirement-tagged test, or be listed as a documented gap in the
|
||||
harness. Adding the registry entry attributes that ID to the change, so an uncovered ID blocks
|
||||
the merge; a safety-critical ID also needs an L3 test.
|
||||
- An **amended requirement** needs only its abridged registry summary updated, when the meaning
|
||||
changed.
|
||||
- A **retired ID** leaves the registry, every test label, and the gate's path-to-requirement map
|
||||
together. IDs are never renumbered or reused.
|
||||
4. **Write the handoff entry** for the adoption.
|
||||
|
||||
Some implementation checks read spec text when a spec checkout is present: the auditability section
|
||||
of [`docs/07`](docs/07-security-and-secrets.md), the Phase 7 entry in
|
||||
[`roadmap/phases.md`](roadmap/phases.md), and the requirement definitions in `docs/00`. Change those
|
||||
structures knowingly.
|
||||
|
||||
## The bootstrapping caveat (self-hosted git is circular)
|
||||
Gitea runs *on* the cluster that Flux reconciles *from* Gitea — a chicken-and-egg. Handling:
|
||||
- Bring the cluster up from a **bootstrap source** (this local repo / an out-of-band source), stand
|
||||
up Gitea, then **cut Flux's source over to Gitea**.
|
||||
- Bring the cluster up from a **bootstrap source** (an out-of-band copy of the repo), stand up Gitea,
|
||||
then **cut Flux's source over to Gitea** ([`docs/05-gitops-and-delivery.md`](docs/05-gitops-and-delivery.md)).
|
||||
- Because a cluster loss would take its own git host with it, **Gitea is DR-critical**: its repos are
|
||||
backed up **off-cluster** ([`docs/04-storage-and-state.md`](docs/04-storage-and-state.md)), and an
|
||||
off-cluster mirror of the platform repo is kept so the platform can always be rebuilt from a source
|
||||
|
||||
Reference in new issue
Block a user