diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 1902cad..d4dea71 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -4,9 +4,9 @@ Specification for a Mechanical Compiler instance. | | | |---|---| -| Revision | 5.3 (2026-08-18) | +| Revision | 5.4 (2026-09-13) | | Supersedes | Revisions 1 through 4 | -| Basis | Revision 4, reconciled against the proven staging build, work orders 002 and 003, and container standardisation | +| Basis | Revision 5.3, reconciled against the running instance during the documentation audit of 2026-09-13. Divergences recorded; no requirement lowered. | | Scope | **Host-agnostic.** Applies to any instance. | | Instance state | `STAGING-STATE.md`, and later `PRODUCTION-STATE.md` | | Failure evidence | `FAILURES.md` | @@ -44,6 +44,18 @@ disagreed with it. Everything specific to `srv-b` has been removed. | **ASSUMED** | Decided without confirmation. Listed in §16. | | **DEFERRED** | Deliberately postponed. Not a defect, not a gap. | | **INSTANCE** | A value supplied per instance, not fixed here. | +| **DIVERGENCE** | The requirement stands and is **not currently met**. Cites its entry in `DIVERGENCES.md`. | + +**DIVERGENCE is never a reason to lower a requirement.** A REQ that stops being +met does not become a PREF, and it is not rewritten to describe what was built. +It stands, the gap is recorded, and the correction is owed by the thing rather +than by this document. A specification that agrees with whatever exists +specifies nothing. + +Added 2026-09-13. Its absence is why five unmet requirements in this document +went unrecorded for weeks — there was no notation to write them in, so nobody +wrote them. The six markers above could say how strong a requirement was and +where it came from, and none could say it was not being met. ### Provisioning method @@ -83,6 +95,11 @@ defence against YunoHost's "resource-hungry" criterion; that was overcalibrated. The criterion reads "compared to their features" and is aimed at marginal apps. The boundary stays; the apology is gone. +**Verified 2026-09-13** — `cadquery` and `OCP` both import in CT 100. This +document was correct; `HANDOFF.md` §5 had said the opposite for three weeks, and +DIV-005 was opened against this paragraph rather than against that one. Closed, +and recorded there as having been written backwards. + ### 1.2 YunoHost and Docker are parallel targets, not sequential YunoHost apps install natively — apt, venv, systemd, nginx — and the project @@ -98,6 +115,10 @@ directly would never exercise the `X-Forwarded-Proto` path. Staging is not publicly reachable and does not use the public FQDN. That forces the promotion path to be exercised rather than assumed. +**DIVERGENCE (DIV-003)** — the `srv-b` instance has been publicly reachable at +`dev.mechcomp.kane-il.us` since 2026-09-11. The requirement stands and the +instance does not meet it. §5.2 carries the same divergence with its reasoning. + ### 1.4 Directory layout mirrors YunoHost conventions `install_dir`, `data_dir`, a dedicated system user, a port treated as data. The @@ -307,6 +328,19 @@ hyphenated FQDN cannot serve as the token. publicly-trusted certificate: it consumes rate limit against a name production needs clean, and puts a development host on the internet. +**DIVERGENCE (DIV-003)** — all three are unmet on `srv-b` as of 2026-09-11. +Public `A` and `AAAA` records exist and a Let's Encrypt certificate terminates on +the hub. The reasoning above is a live claim nobody has rebutted, and half of it +is already visible: that certificate expires 2026-12-10 and **no renewal has +been observed to succeed for this name**. + +Whether this instance is still *non-production* is itself unsettled. +`WORK-ORDER-004` §3 records that `dev` abbreviates *Mechanical Compiler +Developers*, that the name is production, and that it appears on printed +material. If that reading holds, §5.2 never applied to it and §5.3 does — which +would make this a misfiled instance rather than a violated requirement. That is +a decision, not a correction. + **PROVEN** — A locally generated CA is sufficient and is the fallback whenever a site CA has no discoverable issuance path. The point of the TLS step is exercising termination and header forwarding, not the trust chain. Replacing the @@ -508,6 +542,12 @@ use `--break-system-packages`. | `requirements-base.txt` | shapely, fastapi, uvicorn, pydantic, sqlalchemy, jinja2, pytest, pytest-xdist | | `requirements-cad.txt` | cadquery / build123d | +**DIVERGENCE (DIV-002)** — `fastapi`, `uvicorn`, `pydantic`, `sqlalchemy` and +`jinja2` are installed on every instance and imported by nothing in the composer. +They describe the architecture §9 specifies and nobody built. The manifest is +not wrong about what it installs; it is a faithful description of an unbuilt +design. + CI runs the suite twice — with both, then with base alone — and the second run must pass. That is the mechanism keeping §1.1 honest. @@ -522,6 +562,17 @@ must pass. That is the mechanism keeping §1.1 honest. | `mechcomp.service` | FastAPI/uvicorn. Serves the catalogue, accepts jobs, returns cached artifacts. **Never runs geometry.** | | `mechcomp-worker.service` | Consumes the queue, runs generators, writes artifacts. | +**DIVERGENCE (DIV-002)** — neither unit exists as specified. `mechcomp.service` +runs a standard-library `http.server` and builds geometry synchronously in the +request thread, so the control plane *does* run geometry. +`mechcomp-worker.service` does not exist; `src/mechcomp/worker/` is a 36-byte +stub. + +The requirement stands. §1.1 reason 1 calls this separation a requirement +**regardless of distribution**, and reason 2 gives its purpose: a slow import +must never land in the request path for a page that only draws a cross-section. +Geometry itself now does, on a world-reachable service with no authentication. + **REQ** — Both: ```ini @@ -556,6 +607,9 @@ container. RabbitMQ. A table with a status column and a claim query is correct at this scale and adds no services to either packaging target. +**DIVERGENCE (DIV-002)** — no queue and no database exist. Nothing has ever +written to `MECHCOMP_DATA_DIR`. + **REQ (F-019)** — **Anything a proof depends on must be supervised.** This includes temporary scaffolding. A placeholder backend used to prove the proxy chain before the application exists is a systemd unit, obviously named and @@ -607,6 +661,7 @@ MECHCOMP_ENV= # staging | production MECHCOMP_BIND= # single address — see below MECHCOMP_PORT= MECHCOMP_BASE_URL= +MECHCOMP_MAX_EXPORT_MM= # bound on the exported sweep length MECHCOMP_DATA_DIR=/var/lib/mechcomp MECHCOMP_LOG_LEVEL=info MECHCOMP_DB_URL=sqlite:////var/lib/mechcomp/db/mechcomp.sqlite3 @@ -616,6 +671,21 @@ MECHCOMP_ARTIFACT_RETENTION_DAYS=30 MECHCOMP_SECRET_KEY= # generated on first provision, never committed ``` +**DIVERGENCE (DIV-004)** — the application reads four of these: `MECHCOMP_BIND`, +`MECHCOMP_PORT`, `MECHCOMP_MAX_EXPORT_MM` and `MECHCOMP_BASE_URL`. The other +eight are read by nothing. Most belong to the architecture DIV-002 records as +unbuilt, so this is largely the same divergence seen from the configuration +side. + +`MECHCOMP_MAX_EXPORT_MM` was added to this list on 2026-09-13. It had been read +by the code since `cdde394` and declared nowhere — the divergence running the +other way, and the harder one to notice, because a missing key looks like +nothing at all. + +`MECHCOMP_SECRET_KEY` deserves its own note: a secret that nothing reads is +protecting nothing, and its presence implies a session or signing mechanism that +does not exist. + **REQ** — `MECHCOMP_BIND` is a **single address**. Loopback is not additionally bound. @@ -742,6 +812,10 @@ committed; an example with empty values is. 10. The test suite passes with `requirements-cad.txt` uninstalled. 11. AGPL-3.0 §13 requires network users be offered the source. The web tier carries a visible source link to the repository. A licence obligation. + **DIVERGENCE (DIV-001) — not met.** The served page carries no such link, + and the deployment has been public since 2026-09-11. This is the only unmet + requirement in this document whose consequence falls outside the project, + and the smallest to correct. ### 14.1 Test validity @@ -846,6 +920,12 @@ the containers have no reason to originate mail. Not gated on gate 1. Dependencies installed from committed manifests. Real service and worker units active. Reference toolchain image reproduces `ddd0f154…`. Scaffolding removed. +**Status 2026-09-13 — the gate does not pass.** Dependencies: met. Toolchain +image: met, present in CT 100 and the oracle reproduced inside it on +2026-08-19. Scaffolding: met, `mechcomp-placeholder.service` retired 2026-09-11 +with the unit file left on disk disabled as the rollback path. +**Worker unit: not met (DIV-002).** + ### Gate 4 — Backup Undefined pending a strategy decision. @@ -913,6 +993,12 @@ The useful comparison for acceptable weight is `paperless-ngx_ynh` or ## 19. First application work item -Port `sb-geom` to Shapely; `pytest -n auto` green against the 123 frozen cases in -`strap-beam-fixtures-8.0.0.json`. The ten rejected cases are part of the -contract: a port that accepts them is wrong. +**Complete 2026-08-20.** `sb-geom` is ported to Shapely and the suite is green +against the 123 frozen cases in `strap-beam-fixtures-8.0.0.json`. The ten +rejected cases are part of the contract: a port that accepts them is wrong, and +this one does not. + +Retained rather than deleted because the framing outlived the task — the +rejected cases being part of the contract is the reason the oracle means +anything at all. What comes next is in `ROADMAP.md` §4, not here; an environment +specification should not carry a work queue. diff --git a/docs/STAGING-STATE.md b/docs/STAGING-STATE.md index 65d7e66..a44432c 100644 --- a/docs/STAGING-STATE.md +++ b/docs/STAGING-STATE.md @@ -6,7 +6,7 @@ Live state of the Mechanical Compiler staging instance on `srv-b`. |---|---| | Updated | 2026-09-13, after the documentation audit | | Instance | Staging / development | -| Specification | `ENVIRONMENT.md` revision 5 | +| Specification | `ENVIRONMENT.md` revision 5.4 | | Failure log | `FAILURES.md` | | Process | `PROCESS.md` — **read first** | | Method | Manual, one command group at a time |