diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 27e5551..1902cad 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -4,9 +4,9 @@ Specification for a Mechanical Compiler instance. | | | |---|---| -| Revision | 5.2 (2026-08-17) | +| Revision | 5.3 (2026-08-18) | | Supersedes | Revisions 1 through 4 | -| Basis | Revision 4, reconciled against the proven staging build, then work orders 002 and 003 | +| Basis | Revision 4, reconciled against the proven staging build, work orders 002 and 003, and container standardisation | | Scope | **Host-agnostic.** Applies to any instance. | | Instance state | `STAGING-STATE.md`, and later `PRODUCTION-STATE.md` | | Failure evidence | `FAILURES.md` | @@ -769,6 +769,44 @@ wrong form reported a pass against containers that were not running. --- +## 14a. Conformance + +**REQ** — An instance carries an executable **baseline check**: read-only, +runnable at any time, exiting non-zero when any container diverges from the +standard. + +**REQ** — **A property not checked by it is not part of the standard.** This is +what makes conformance terminate. Without it, divergence is discovered one +property at a time whenever something behaves oddly, and the process never +finishes because nothing states what "the same" means. A property that must be +uniform belongs in the check, not in an operator's memory. + +**REQ (F-031)** — The check must examine **the thing being standardised**. An +assertion derived from a related observation is not a check. Postfix +configuration on the host says what the host does; it says nothing about the +containers, and a standard asserted that way was wrong on two of three. + +**REQ** — Each failure names the failure-log entry that established the +requirement, so the reason survives the person who found it. + +**REQ (F-032)** — Host-level requirements belong to the host, not to whichever +project discovered them first. Where several projects share a host, the check +is host-level and covers every container regardless of owner. Two projects on +this host independently rediscovered the same two defects before this was done. + +### Mail + +**REQ** — **Containers do not originate mail.** Only the host does, and only its +own operational alerts. A container with a mail agent installed but SMTP egress +blocked is worse than either alone: it queues indefinitely and delivers nothing, +while appearing configured. + +Application mail — participant notification and similar — is a separate design +problem with its own delivery and inbound requirements. It is not solved by +leaving a partially configured agent in a container. + +--- + ## 15. Acceptance gates **REQ** — Five independent gates. Revision 4 ran them as one list, which meant @@ -812,6 +850,15 @@ active. Reference toolchain image reproduces `ddd0f154…`. Scaffolding removed. Undefined pending a strategy decision. +**REQ** — **Conformance is a precondition, not a companion.** Backup work does +not begin until the baseline check (§14a) exits zero, and the check forms part +of restore verification. + +A backup of an unverified configuration does not preserve a system; it +preserves a state of confusion, and a restore returns that state faithfully. +This was not hypothetical: a backup taken before 2026-08-18 would have restored +two containers that queue mail forever (F-031). + ### Gate 5 — Production automation Idempotent scripts derived from a proven manual procedure. Firewall posture diff --git a/docs/FAILURES.md b/docs/FAILURES.md index f206e09..b01bdeb 100644 --- a/docs/FAILURES.md +++ b/docs/FAILURES.md @@ -6,7 +6,7 @@ Compiler environment. | | | |---|---| | Scope | All instances. Staging entries are marked `srv-b`. | -| Updated | 2026-08-17, after work order 003 | +| Updated | 2026-08-18, after repository seeding and container standardisation | | Method | `PROCESS.md` section 7 | | Rule | Append only. Never edit an entry except to add a `Resolution` line. | | Numbering | Sequential, never reused. See §0 on the renumbering. | @@ -634,6 +634,100 @@ device class. --- +### F-029 — pip cache written into the repository working tree +CT 100. Repository seeding. + +**Observed:** `git add -A` staged 465 files where 28 were expected. The extra +437 were `.cache/` — pip's download cache. +**Cause:** **Proven.** The service user's home is the install directory, so +`$HOME/.cache` **is** `/var/www/mechcomp/.cache`. `make deps` wrote there. +**Correction:** `.cache/`, `.local/`, `.ssh/`, `.gitconfig` and `.lesshst` +added to `.gitignore`; the cache unstaged before committing. +**Consequence:** Setting the service user's home to `install_dir` is correct +and matches YunoHost convention, but it means **any tool writing to `$HOME` +writes into the working tree**. `.gitignore` must anticipate that from the +first commit. + +Method note: reading the staged list by eye showed nothing wrong. Counting it +and grouping by top-level directory found the problem immediately. **Verify by +counting, not by scanning** — a long correct-looking list is exactly where an +extra 437 files hide. + +--- + +### F-030 — a network command in a work order could hang indefinitely +`srv-b`. Repository seeding. + +**Observed:** An SSH authentication test was issued with neither +`ConnectTimeout` nor `BatchMode`. Gitea's SSH is on port 42022, so the attempt +on 22 hung and the operator had to interrupt it. +**Cause:** **Proven.** Missing timeout options, and an incorrect assumption +about the port. +**Correction:** Re-issued with `-o ConnectTimeout=10 -o BatchMode=yes -p 42022`, +after a `timeout`-wrapped reachability probe that could not hang. +**Consequence:** **Every network command in a work order carries an explicit +timeout.** A command that can hang strands the session, and the operator cannot +tell a hang from slow progress. Reachability is probed with `timeout` before any +client is invoked. + +Also recorded, having been got wrong twice: Gitea **deploy tokens** are +account-level under user Settings, not repository settings. Repository-scoped +credentials are **deploy keys**. SSH here is on **42022**, so remotes need +`ssh://git@host:42022/owner/repo.git` — the `git@host:path` shorthand cannot +carry a port. + +--- + +### F-031 — a standard was asserted from a check that never examined the thing +CT 100, CT 101, CT 102. Container standardisation. + +**Observed:** The architect stated that CT 100 and CT 101 had no mail agent, and +standardised CT 102 by purging Postfix to match. The first run of +`ct-baseline.sh` reported a mail agent installed on **both** CT 100 and CT 101. +CT 102 — the container just "corrected" — was the only one conforming. + +**Cause:** **Proven.** The earlier assertion came from inspecting Postfix +configuration and `/etc/aliases` **on `srv-b`**, during work order 002. That +established what the host does. It said nothing about the containers, and the +containers were never examined. + +**Correction:** Postfix purged from CT 100 and CT 101. Queues were checked first +and both were empty, so nothing was lost. Re-run: 62 passed, 0 failed. + +**Consequence:** **A standard asserted from a proxy observation is not a +standard.** The check must examine the thing being standardised. This is the +same class as F-027 — a result that cannot distinguish the case it claims to +test — but reached through inference rather than through shell semantics. + +It is also the justification for `ct-baseline.sh` existing. Divergence had been +discovered by asking, one property at a time, whenever something behaved oddly. +That does not terminate: every check finds a new difference because nothing +states what "the same" means. The script is that statement, and it disagreed +with the architect on its first run. + +--- + +### F-032 — the same host defects were discovered independently by two projects +`srv-b`. Cross-project. + +**Observed:** Kane Fabric's `INFRASTRUCTURE_BASELINE.md`, written independently, +records `nesting=1,keyctl=1` against `226/NAMESPACE` systemd failures, and that +minimal Debian CTs lack a generated `en_US.UTF-8`. These are F-003 and F-004, +found again on the same host, in different words, at a different time. +**Cause:** **Proven.** Both are properties of the Proxmox/Debian 12 host, not of +either application. Neither project's documentation was visible to the other. +**Correction:** None required — both projects reached the correct conclusion. +**Consequence:** **Host-level requirements belong to the host, not to whichever +project discovered them first.** `ct-baseline.sh` encodes them once and checks +every container on `srv-b` regardless of owner, so the third project does not +have to discover them a third time. + +Note that `keyctl=1` is required **only where Docker runs**. CT 101 was proven +to work with `nesting=1` alone (F-003). Kane Fabric's baseline currently +specifies both; if CT 102 runs no containers, `keyctl` can be dropped. + +--- + ## Open, not closed | # | Status | @@ -649,5 +743,9 @@ device class. | F-026 | **Corrected** 2026-08-17. Reboot persistence proven. | | F-027 | **Corrected** 2026-08-17. Applies retroactively to F-018's proofs. | | F-028 | **Corrected** 2026-08-17. | +| F-029 | **Corrected** 2026-08-18. | +| F-030 | **Corrected** 2026-08-18. | +| F-031 | **Corrected** 2026-08-18. Root cause of `ct-baseline.sh`. | +| F-032 | **Closed** 2026-08-18. No correction required; encoded in `ct-baseline.sh`. | Everything else is closed with a proven cause and a proven correction. diff --git a/docs/PROCESS.md b/docs/PROCESS.md index 3153047..46e8026 100644 --- a/docs/PROCESS.md +++ b/docs/PROCESS.md @@ -356,6 +356,28 @@ needs a directory to exist, create it in the same group. --- +## 9a. The baseline check + +`ct-baseline.sh` is the executable definition of the container standard on this +host. Read-only, runnable at any time, exits non-zero on divergence. + +Run it: + +- before starting work on a container; +- after any change to a container or to host firewall rules; +- after any host reboot; +- before considering backup work (see `ENVIRONMENT.md` §15 gate 4). + +**A property not checked by it is not part of the standard.** If something +should be uniform across containers, add it to the script. If it should not, +leave it out and stop worrying about the difference. That is the whole point: +it converts an endless comparison into a pass or a fail. + +It covers containers belonging to more than one project, and encodes host +requirements neither project owns alone. Treat it as host property. + +--- + ## 10. Current mode **Infrastructure: complete and accepted.** Host, containers, network isolation, @@ -366,6 +388,12 @@ bastion access, TLS, reverse proxy, mail alerting, disk monitoring. See more than an afternoon; the documents are in Gitea. This changes when `artifacts/` stops being empty. +**Repository seeded** at `c7e32d8`: reference implementation, frozen oracle, +pinned toolchain, test harness. Dependencies installed in CT 100, oracle +verified in-container, `3 passed, 236 skipped`. + +**Container baseline established.** All three containers on `srv-b` conform. + **Development: starting.** First work item is the Shapely port — `pytest -n auto` green against the 123 frozen cases. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index e102bd4..5dd53b6 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -4,7 +4,7 @@ What the Mechanical Compiler is for, and the order in which it gets built. | | | |---|---| -| Updated | 2026-08-17 | +| Updated | 2026-08-18 | | Companions | `PROCESS.md`, `ENVIRONMENT.md`, `STAGING-STATE.md`, `FAILURES.md` | --- @@ -133,6 +133,11 @@ a new call into the same machinery, not a new machine. monitored, four test alerts received, serial numbers recorded, reboot-proven. - **Container SMTP egress blocked, 2026-08-17.** The project-local half of F-025 is corrected; the estate question about `wg-pk` client trust remains open. +- **Repository seeded, 2026-08-18.** Reference implementation, frozen oracle, + pinned toolchain and test harness at `c7e32d8`. Dependencies installed, oracle + verified in-container, `3 passed, 236 skipped`. +- **Container baseline established, 2026-08-18.** All three containers on + `srv-b` conform, asserted by an executable check rather than by inspection. ### Next — the port @@ -172,6 +177,24 @@ getting their own generators. --- +## 4a. Parallel project + +**Kane Fabric** — a separate project on the same host, and the platform on +which SASE, HOA Diagnostics, the Mechanical Compiler and other SASE-consuming +projects are implemented. + +It is recorded here so its existence is known, not because it creates work. +Kane Fabric owns geographic state; the Mechanical Compiler owns member +geometry, qualification and workflow state. Both sets of documents describe a +future interface between them; **neither defines it, and that is deliberate.** +Part I §6 holds that use cases precede interface proliferation, and no use case +crosses the boundary yet. + +The contract becomes real work when a compiled member first needs to be sited +somewhere. It will be cheaper to define then, against a concrete artifact. + +--- + ## 5. Staging to production `srv-b` is standalone and will remain so. Promotion is export/restore, not @@ -264,3 +287,14 @@ on whether it makes distributed manufacturing capacity legible. have observed the positive case. 12. **A component surviving its own restart is not proven to survive the host's.** Different machinery; assert against the one that matters (F-026). +13. **A standard must be executable.** If conformance cannot be asserted by + running something, it is not a standard but a recollection, and it will + drift. A property not checked is not part of the standard (F-031). +14. **Check the thing, not something related to it.** An assertion inferred + from an adjacent observation is not evidence, however reasonable the + inference (F-031). +15. **Verify by counting, not by scanning.** A long, correct-looking list is + exactly where an unexpected 437 files hide (F-029). +16. **Conformance precedes backup.** Backing up an unverified configuration + preserves the confusion along with the data, and a restore returns it + faithfully. diff --git a/docs/STAGING-STATE.md b/docs/STAGING-STATE.md index a962226..a2e365a 100644 --- a/docs/STAGING-STATE.md +++ b/docs/STAGING-STATE.md @@ -4,7 +4,7 @@ Live state of the Mechanical Compiler staging instance on `srv-b`. | | | |---|---| -| Updated | 2026-08-17, after work order 003 (monitoring, SMTP egress) | +| Updated | 2026-08-18, after repository seeding and container standardisation | | Instance | Staging / development | | Specification | `ENVIRONMENT.md` revision 5 | | Failure log | `FAILURES.md` | @@ -329,7 +329,10 @@ work. None is a defect. the four members, so drive age is a known quantity rather than an assumption. `smartctl -d cciss,N -A /dev/sda`. Read-only, one command. - [ ] **Backup infrastructure, entirely.** Postponed 2026-08-16 because the - strategy may change: `vzdump` job, archive sizing, retention, free-space + strategy may change, and reaffirmed 2026-08-18 on stronger grounds: a + backup of an unverified configuration restores the confusion along with + the data. **Entry condition: `ct-baseline.sh` exits 0.** Scope when + resumed: `vzdump` job, archive sizing, retention, free-space guard, host-side pull, `mechcomp-backup`, backup alerting, gold media, 3+ TB redundancy. @@ -348,6 +351,91 @@ hold the only instance with no monitoring, no alerting and no backup. --- +## 3b. Container baseline + +**`ct-baseline.sh` is the definition of "standard configuration" on this host.** +It changes nothing, runs any time, and exits 0 only when every container +conforms. + +``` +last run 2026-08-18 +result 62 passed, 0 failed, 3 informational +scope srv-b, CT 100, CT 101, CT 102 +``` + +**A property not checked by that script is not part of the standard.** That is +what makes it terminate. Divergence used to be discovered by asking, one +property at a time, whenever something behaved oddly — which never finishes, +because nothing stated what "the same" meant. If a property should be uniform, +it belongs in the script rather than in someone's memory. + +What it asserts, per container: `onboot`, unprivileged, `nesting=1`, a single +interface on the service bridge, systemd `running` with zero failed units, one +interface stanza, Debian 12, timezone, **generated** locale, `curl`, +`ca-certificates`, `openssh-server`, sshd active, admin account with +`authorized_keys` at `0600`, **no mail agent**, SMTP egress blocked, LAN +gateway unreachable. Host-level: systemd health, both firewall rules, `smartd` +device count, bastion key. + +Each failure cites the failure entry that established the requirement, so the +reason survives the person. + +### The mail standard + +**Containers do not send mail.** Only `srv-b` does, and only its own alerts, +through `[10.110.0.1]:25`. A container with a mail agent installed but SMTP +egress blocked is the worst case: it queues forever and delivers nothing. + +CT 100 and CT 101 were in exactly that state until 2026-08-18 (F-031). + +### Ownership + +The script checks containers belonging to two projects and encodes host +requirements neither owns alone (F-032). It is **host-level**, not Mechanical +Compiler property. Suggested home: `/usr/local/sbin/ct-baseline.sh` on `srv-b`, +with the canonical copy outside this repository. + +### Relationship to backup + +**Conformance is a precondition for backup, not a companion to it.** A backup +taken before 2026-08-18 would have preserved two containers that queue mail +forever, and a restore would have faithfully returned them to that state. + +Backing up an unverified configuration does not preserve a system; it preserves +a state of confusion. The entry condition for backup work is `ct-baseline.sh` +exiting 0 — and it becomes part of restore verification. + +--- + +## 3a. Parallel project on this host + +**Kane Fabric** is a separate project sharing `srv-b`. It is where SASE, HOA +Diagnostics, the Mechanical Compiler and other SASE-consuming projects are +implemented. + +| | | +|---|---| +| Repository | `github.com/git64bit/Kane-Fabric` | +| Container | CT 102 `kane-fabric` | +| Address | `10.20.0.12/24` on `vmbr1`, gateway `10.20.0.1` | +| Ownership | Separate project. Not Mechanical Compiler infrastructure. | +| Baseline | Conforms as of 2026-08-18, verified by `ct-baseline.sh` | + +Recorded here for two operational reasons only. + +**It shares the service network.** CT 102 sits on `vmbr1` alongside CT 100 and +CT 101, so host-level rules scoped to `10.20.0.0/24` apply to it. In particular +it **inherits the SMTP egress block** (F-025) — if Kane Fabric ever needs to +send mail, that will present as a Postfix failure with a non-obvious cause. + +**Host resources are shared, not pooled.** Neither project consumes or +repurposes the other's containers. Any integration is through an explicit +contract, not through co-location on `srv-b`. + +No interface between the two projects exists today, and none is assumed. + +--- + ## 4. Access model Confirmed: no workstation access from the home LAN is required. @@ -374,25 +462,31 @@ entire address space. Repository state: ``` -HEAD e85c4f4e5bab9a4f032230c99aa6784ace4c80e2 -top level .git LICENSE README.md venv -git status ?? venv/ -absent requirements-base.txt, requirements-cad.txt, service units +HEAD c7e32d8e0772d89d1117bab7ff08d61e5b2a497e +top level .gitignore LICENSE Makefile README.md docs/ fixtures/ legacy/ + pyproject.toml requirements-*.txt src/ tests/ tools/ venv/ +remote ssh://git@gitea.barternetwork.us:42022/TheRON/mechanical-compiler.git + deploy key srv-b-ct100, read/write +venv Python 3.11.2, shapely 2.1.2, cadquery 2.8.0, mechcomp editable +tests 3 passed, 236 skipped +oracle ddd0f154... verified in-container +absent the Shapely port itself ``` None of the following can be honestly completed, and none may be fabricated by provisioning: -- [ ] Dependency install from committed manifests +- [x] ~~Dependency install from committed manifests~~ — done 2026-08-18 - [ ] `mechcomp.service`, `mechcomp-worker.service` - [ ] Reference toolchain image `mechcomp/reference-toolchain:8.0.0` - [ ] Fixture reproduction against `ddd0f154...` - [ ] Application-runtime acceptance - [ ] Replacing the placeholder with the real service -**Architect decision:** `venv/` belongs in `.gitignore` — it is a legitimate -artifact inside `install_dir` per YunoHost convention, it simply should not be -tracked. Applied with the first application commit. +**Applied 2026-08-18:** `venv/` is in `.gitignore`, along with `.cache/`, +`.local/`, `.ssh/`, `.gitconfig` and `.lesshst` — the service user's home is +`install_dir`, so anything writing to `$HOME` writes into the working tree +(F-029). The Shapely port gates all of the above. @@ -425,4 +519,7 @@ All three need CIVICVS. | Why did delivery fail downstream? | `mx1` relay trust. Proven and corrected (F-023). | | Where does Postfix log on this host? | journald. No `rsyslog`, no `/var/log/mail.log` (F-024). | | Should container SMTP egress be blocked? | Yes. Implemented and reboot-proven (F-025 project-local half). | -| Do the containers autostart? | Yes, `onboot: 1` on both, proven by host reboot (F-026). | +| Do the containers autostart? | Yes, `onboot: 1` on all three, proven by host reboot (F-026). | +| How do files reach a container? | Upload to `/root/incoming` on `srv-b`, then `pct push` / `pct exec`. See `PROCESS.md`. | +| How does CT 100 push to Gitea? | Deploy key `srv-b-ct100`, SSH on port **42022**, read/write. | +| Do containers send mail? | **No.** Only `srv-b` does. See section 3b. |