Record six divergences between the documents and what is running

A register of requirements that stand and are not met. FAILURES.md records something that went wrong: an action was taken and it did not work. This records something that is wrong now: a requirement was written, it stands, and the thing it governs does not comply. Nothing failed and nobody was surprised, which is why none of it was written down.

That absence has a mechanical cause. ENVIRONMENT.md carries six markers for a requirement strength and provenance - REQ, PREF, PROVEN, ASSUMED, DEFERRED, INSTANCE - and none meaning this requirement is not currently met. Every entry below was visible in the documents for weeks and recorded in none of them.

DIV-001: the AGPL section 13 source link is absent from a public deployment, verified against web/app.py. DIV-002: the two-unit control-plane and worker architecture in ENVIRONMENT.md section 9 was never built. DIV-003: the instance is publicly reachable against three REQs. DIV-004: eight declared MECHCOMP keys are read by nothing, and MECHCOMP_MAX_EXPORT_MM is read and undeclared. DIV-005: requirements-cad.txt against CT 100, unverified, do not close. DIV-006: ct-baseline.sh has not run since two host changes.

DIV-001 first. Smallest remedy in the register, and the only entry whose consequence falls outside the project. It is also the only one where the document is right and the code does not comply.

Three of six are the same shape: a manifest or specification describing an architecture that was not built, with nothing recording the difference.

From a documentation audit reading all 18 documents against cdde394. No code, tests, fixtures or configuration changed. Suite 643 passed, oracle intact at 113 accepted and 10 rejected.
This commit is contained in:
2026-09-13 15:01:37 -05:00
parent cdde394bd8
commit 3ccec9ab40
+268
View File
@@ -0,0 +1,268 @@
# DIVERGENCES.md
**Requirements that stand and are not met.**
| | |
|---|---|
| Tier | record |
| Audience | whoever is deciding what to fix next |
| Tense | past — each entry describes a moment |
| Status | 6 entries; 5 verified, 1 unverified |
| Defers to | `FAILURES.md` on what was observed; `STAGING-STATE.md` on host facts |
| Opened | 2026-09-12, from the documentation audit against `cdde394` |
---
## 0. What this document is, and how it differs from `FAILURES.md`
`FAILURES.md` records **something that went wrong**: an action was taken, it did
not work, and the entry says why.
This document records **something that is wrong now**: a requirement was
written, it stands, and the thing it governs does not comply. Nothing failed.
Nobody was surprised. The divergence was simply never written down, because
there was no notation for it.
That absence is the reason this file exists. `ENVIRONMENT.md` carries six markers
for a requirement's strength and provenance — **REQ**, **PREF**, **PROVEN**,
**ASSUMED**, **DEFERRED**, **INSTANCE** — and none meaning *this requirement is
not currently met*. Every entry below was visible in the documents for weeks and
recorded in none of them.
### The rule these entries follow
A requirement is never made true by lowering it to match what was built. The
requirement stays where it is, the divergence is recorded against it, and the
correction is owed by the thing, not by the document.
### Form
Append-only. Never edit an entry except to add a `Resolution` line. Each entry
carries:
- **Requirement** — what is required, and the document and section stating it
- **Actual** — what is true at the stated commit
- **Evidence** — how that was established, and how far it was checked
- **Consequence** — what it costs. An entry with no consequence is either not
understood or not worth recording
- **Owed by** — code, configuration, host, or a decision
Ids are assigned when an entry is recorded, not by severity. The index in §7
carries priority.
---
## 1. DIV-001 — AGPL section 13 is not satisfied on a live public deployment
**Requirement.** Root `README.md`: section 13 obliges an offer of source to
users interacting with the software over a network, so any deployed web tier
carries a visible link back to this repository. The document calls this *a
licence obligation, not a courtesy*.
**Actual.** At `cdde394` the served page carries no such link.
**Evidence.** `src/mechcomp/web/app.py` read in full. The page is the single
`PAGE` constant. Its `<header>` holds the title and one line of description. The
document contains no anchor element except the one created in JavaScript at
download time to save the STL blob. `do_GET` serves `/`, `/api/build` and
`/m/stl`, and 404s everything else — there is no `/source` route. The composer
became publicly reachable at `https://dev.mechcomp.kane-il.us` on 2026-09-11
(`1fdb115`, `WORK-ORDER-004`).
**Consequence.** The obligation the front door states in its own words is unmet,
on a public name, and has been since 11 SEP. This is the only entry in this
register whose consequence falls outside the project.
It is also the only one where the **document is right and the code does not
comply**. Every other entry is a requirement the code declined to follow for
reasons that may be sound; this one has no such reading.
**Owed by.** Code. A visible link in `PAGE`'s header, and nothing else.
**Priority: first.** Smallest remedy in the register, largest exposure.
---
## 2. DIV-002 — the specified service architecture was never built
**Requirement.** `ENVIRONMENT.md` §9, marked **REQ**: two units split along a
control-plane / execution-plane boundary.
- `mechcomp.service` — FastAPI/uvicorn; serves the catalogue, accepts jobs,
returns cached artifacts, and **never runs geometry**
- `mechcomp-worker.service` — consumes the queue, runs generators, writes
artifacts
§9 further REQs a SQLite-backed in-process job queue. §15 gate 3 requires both
units active. §1.1 calls the control-plane / execution-plane separation a
requirement *regardless of distribution*.
**Actual.** `web/app.py` is a standard-library HTTP server that builds geometry
synchronously in the request thread. `src/mechcomp/worker/` is a 36-byte stub.
There is no queue and no database, and nothing has ever written to
`MECHCOMP_DATA_DIR`.
**Evidence.** `app.py` read in full at `cdde394`. Its imports are `json`, `os`,
`traceback`, `http.server`, `typing`, `urllib.parse` and `mechcomp.svg`. It runs
a `ThreadingHTTPServer`; `do_GET` calls `build_payload` -> `build(...)` inline.
Its own docstring states the constraint deliberately: *standard library only —
`http.server`. No framework, no build step, no new dependency.*
`requirements-base.txt` read: it does declare `fastapi`, `uvicorn`, `pydantic`,
`sqlalchemy` and `jinja2`, matching `ENVIRONMENT.md` §8.3 exactly. Those five are
not imported by the composer. **Not checked across the rest of `src/`** — only
`app.py` was read.
**Consequence.** Geometry runs in the request path on a world-reachable service
with no authentication. A long build occupies a request thread; the ceiling at
`MECHCOMP_MAX_EXPORT_MM` bounds the response size but not the computation, and
`/api/build` has the same exposure with no ceiling at all. The separation §1.1
requires is the mitigation, and it does not exist.
Five declared dependencies are installed on every instance and appear unused.
**Owed by.** A decision before any code. Either the architecture is built, or §9
is formally superseded by a written decision — not edited away.
---
## 3. DIV-003 — the instance is publicly reachable against three REQs
**Requirement.** `ENVIRONMENT.md` §1.3: staging is not publicly reachable and
does not use the public FQDN, *so the promotion path is exercised rather than
assumed*. §5.2, marked **REQ** for non-production instances: no public DNS
record, and no publicly-trusted certificate — because it consumes rate limit
against a name production needs clean, and puts a development host on the
internet.
**Actual.** `dev.mechcomp.kane-il.us` has public `A` and `AAAA` records and
terminates a Let's Encrypt certificate on `wg-pk`, expiring 2026-12-10.
**Evidence.** `WORK-ORDER-004`, closed 2026-09-11, §1 and §2. All eight
acceptance criteria met and recorded.
**Consequence.** Three **REQ**-marked statements are false of the running
instance, and §5.2's reasoning is a live claim nobody has rebutted: a rate limit
is being consumed against a name, and a non-production host is on the internet.
`WORK-ORDER-004` §3 records a related open item: the first renewal for this name
is due before 2026-12-10 and **no renewal has ever been observed to succeed**.
The other four certificates on `wg-pk` are managed identically, which is
reassuring but not evidence.
**Owed by.** A decision. Either §5.2 is superseded — the name may no longer be
"non-production", since `WORK-ORDER-004` §3 records that `dev` abbreviates
*Mechanical Compiler Developers*, the name is production, and it appears on
printed material — or the exposure is closed. The two documents currently
disagree about what kind of instance this is.
---
## 4. DIV-004 — the configuration contract declares eight keys nothing reads
**Requirement.** `ENVIRONMENT.md` §11 and `STAGING-STATE.md` §1 both carry the
`MECHCOMP_*` contract; `/etc/mechcomp/mechcomp.env` sets twelve keys.
**Actual.** The composer reads four: `MECHCOMP_BIND` and `MECHCOMP_PORT`
(`resolve_binding`), `MECHCOMP_MAX_EXPORT_MM` (`max_export_mm`), and
`MECHCOMP_BASE_URL` (`base_url`) — each checking the process environment before
the file.
Not read in `app.py`: `MECHCOMP_ENV`, `MECHCOMP_DATA_DIR`, `MECHCOMP_LOG_LEVEL`,
`MECHCOMP_DB_URL`, `MECHCOMP_WORKER_CONCURRENCY`, `MECHCOMP_CAD_BACKEND`,
`MECHCOMP_ARTIFACT_RETENTION_DAYS`, `MECHCOMP_SECRET_KEY`.
The omission also runs the other way: **`MECHCOMP_MAX_EXPORT_MM` is read by the
code and absent from `ENVIRONMENT.md` §11.** It was added at `cdde394`.
**Evidence.** `app.py` read in full. **Not checked across the rest of `src/`.**
**Consequence.** Most of the eight belong to the architecture DIV-002 records as
never built, so this is largely the same divergence seen from the configuration
side. It is recorded separately because it is the cheapest thing here to check
and the easiest to mistake for settled: a key present in an env file, a
specification and a state document looks live from all three.
`MECHCOMP_SECRET_KEY` deserves its own note. A secret that nothing reads is not
protecting anything, and its presence implies a session or signing mechanism
that does not exist.
**Owed by.** Documentation, once DIV-002 is decided. §11 should state which keys
are live and which are reserved for unbuilt components, and should add
`MECHCOMP_MAX_EXPORT_MM`.
---
## 5. DIV-005 — `requirements-cad.txt` declares a set that is not installed
**Requirement.** `requirements-cad.txt` declares a CAD dependency set and,
per `HANDOFF-2026-08-19.md` §3, says it is installed by default.
**Actual.** That same section records that `cadquery`, `OCP` and `build123d` are
**all absent from CT 100**, and notes the absence *will matter when STL and STEP
export starts*.
STL export started. It landed at `0545b79` on 2026-09-12.
**Evidence.** `HANDOFF-2026-08-19.md` §3, a session record, not a current
observation. **Unverified at `cdde394`.** `requirements-cad.txt` (347 b) and
`src/mechcomp/stl.py` (11,318 b) have not been read. **Do not close on this
evidence.**
**Consequence.** Unknown until verified. Note that the absence may be correct:
`ACCEPTANCE.md` E-8 requires the 2D path to import no CAD kernel, and asserts it
by test. If `stl.py` also needs none, the divergence is only that the manifest
describes an installation that does not happen — the same shape as DIV-002 and
DIV-004, and the third instance of a manifest describing an unbuilt architecture.
**Owed by.** Two cheap reads before anything else.
---
## 6. DIV-006 — conformance has not been re-run since the host changed
**Requirement.** `PROCESS.md` §9a, marked **REQ**: run `ct-baseline.sh` after any
change to a container or to host firewall rules.
**Actual.** `STAGING-STATE.md` §3b records the last run as **2026-08-18**,
62 passed, 0 failed.
Since then: a DNAT rule was added to `nat PREROUTING` and persisted
(`WORK-ORDER-004` §1, 2026-09-11), and `mechcomp-placeholder.service` was
replaced by `mechcomp.service` in CT 100. Both are changes the REQ names.
**Evidence.** Documents only. **It is not known whether the check was run and
not recorded, or not run.** Either way the record is wrong: a conformance result
with no date after the changes it is supposed to cover is not evidence.
**Consequence.** The conformance claim is the basis for *the three containers are
configured identically*. That claim currently rests on a run that predates two
host changes by three and a half weeks.
`WORK-ORDER-004` §2 is partial mitigation — it verified `POSTROUTING` order
unchanged and confirmed mail still delivers after `iptables-save` rewrote the
ruleset. That is careful work and it is not the same as the baseline.
`FAILURES.md` F-037 is also relevant: `ct-baseline.sh` exits 0 with the F-037
condition present, so a passing run does not cover everything the standard is
believed to cover.
**Owed by.** One run, and a dated line in `STAGING-STATE.md` §3b.
---
## 7. Index
| Id | Divergence | Verified | Owed by | Status |
|---|---|---|---|---|
| DIV-001 | AGPL §13 link absent from a public deployment | yes, `app.py` | code | **open — do first** |
| DIV-002 | Specified service architecture never built | yes, `app.py` | a decision | open |
| DIV-003 | Instance public against three REQs | yes, `WORK-ORDER-004` | a decision | open |
| DIV-004 | Eight declared config keys unread | yes, `app.py` | documentation | open, blocked on DIV-002 |
| DIV-005 | `requirements-cad.txt` vs CT 100 | **no** | verification first | open — **do not close** |
| DIV-006 | Conformance not re-run since host changed | documents only | one run | open |
**Three of six — DIV-002, DIV-004 and DIV-005 — are the same shape:** a manifest
or specification describing an architecture that was not built, with nothing
recording the difference. That pattern is the reason this file exists, and it is
worth watching for in anything written next.