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.
12 KiB
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 geometrymechcomp-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.