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:
@@ -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.
|
||||
Reference in New Issue
Block a user