Files
mechanical-compiler/docs/WORK-ORDER-004-public-ingress.md
T
TheRON c72036cbbb docs: the ACL leaves the roadmap, and the development-name excuse is withdrawn
Four documents brought into line with what landed at 54f0296 and ee3fedf.

HANDOFF section 4 item 5 said the ACL was deliberately last. It is deleted, not
deferred. Authorisation lives upstream at the last proxy hop, decided against a
membership system this repository knows nothing about, so the compiler will
never have a user table, a login form, a session, or a group name in any form --
including as a configuration value, which is how that leak arrives by the side
door. An item left the roadmap rather than moving down it.

Item 4 claimed persistence was the prerequisite for a library of saved designs
and for access control. The second half has been false since the identity
contract landed and was found by reading the anchor rather than recalling it.
Corrected, and item 4 now states the position that follows: the filesystem is
the first store, not a database. Design records are already plain text, already
content-addressed by input_id, and already readable by someone with none of this
software. A directory of them is a store with perfect provenance and no schema
to migrate. SQL earns its way in when there is a query walking files cannot
answer -- "every design by this author since March" is that query, and it
arrives with membership, not before.

"Acceptable for a development name" is withdrawn from HANDOFF section 4 and
WORK-ORDER-004 section 3. The name is production, dev abbreviates Mechanical
Compiler Developers, and it appears on printed material. The posture is
unchanged -- world-reachable, unauthenticated, /m/ not yet gated, STL export
will ship open -- but it is carried openly as open question 10 instead of
excused. The phrase survived three documents and two earlier corrections
because it was plausible and nobody challenged it, which is the same mechanism
that produced the stale ingress paragraph.

Section 0 gains the two new documents, with CONSUMER_INTERFACE_GATES.md marked
read-before-proposing-an-integration: several tempting cross-project moves are
recorded there specifically as things not to build yet, and a successor who
finds them independently will be tempted to solve them. Also a note that
deploy/ now holds the unit and the vhost as they actually run, and that the
repository is the single source of truth -- read a container when you suspect
drift, then fix the drift here rather than on the host.

HANDOFF section 1 and PROCESS section 9 gain the same rule: pct exec runs no
shell. A glob, redirect, pipe or && is expanded by the host shell against the
host's filesystem and the container receives whatever literal survives, so an
unwrapped glob reports "No such file or directory" and reads as a broken
container. Third instance of this class after F-035 and F-036 -- each time the
tool was invoked wrongly and the error named the wrong subject. Not filed as a
new failure: it is the same finding as those two, and a third entry would
record the instance rather than the pattern.

STAGING-STATE records the deployment configuration as committed. The unit had
been marked delivered at deploy/mechcomp.service on 11 SEP while existing only
on the host.
2026-09-12 09:48:22 -05:00

6.0 KiB

WORK-ORDER-004 — public ingress for the composer

CLOSED 2026-09-11. The composer is live at https://dev.mechcomp.kane-il.us.

Mode Infrastructure (PROCESS.md §2)
Created 2026-09-11
Closed 2026-09-11
Executed on wg-pk and srv-b, by CIVICVS

0. This document was rewritten mid-execution

The original proposed widening AllowedIPs on the hub's peer entry for srv-b to carry 10.20.0.0/24, adding a route, and warned at length about the lockout risk of changing a live WireGuard peer.

None of that was done, and none of it was necessary. It was written before reading the hub, from an assumption about how the estate must be wired.

Reading it showed the convention: every vhost on wg-pk — witness.diagnostics.kane-il.us, otium.civicus.us, shell.infra.civicus.us, corpusdb.infra.civicus.us — proxies to a 10.110.0.x tunnel address directly. Not one routes into a subnet behind a peer. All twenty peers carry a /32.

Following that convention removed the WireGuard change entirely, and with it the only step that could have locked the operator out of srv-b.

The original text is in git history at a8081e1. It is kept there rather than here, because a work order describing a plan nobody executed is exactly the stale record this project does not tolerate.


1. What was actually built

browser
  -> dev.mechcomp.kane-il.us   A     198.58.111.109
                              AAAA  2600:3c00::f03c:92ff:fe42:43d7
  -> nginx on wg-pk, Let's Encrypt TLS, expires 2026-12-10
  -> proxy_pass http://10.110.0.12:8770      srv-b's own tunnel address
  -> DNAT on srv-b                        -> 10.20.0.10:8770
  -> mechcomp.service in CT 100

Four changes, in the order made:

1. DNAT on srv-b, added live, persisted only after being proven from the hub. Rollback copy at /etc/iptables/rules.v4.before-mechcomp-dnat.

-A PREROUTING -s 10.110.0.1/32 -d 10.110.0.12/32 -i wg0 \
   -p tcp -m tcp --dport 8770 -j DNAT --to-destination 10.20.0.10:8770

Scoped to the hub as source. The other nineteen tunnel peers cannot reach the service network through it.

curl http://10.110.0.12:8770 from srv-b itself fails, correctly: locally-originated traffic traverses OUTPUT, not PREROUTING. Test from the hub.

2. DNS. A and AAAA for dev.mechcomp.kane-il.us, TTL 300. Not a CNAME — the hub's other names are all A/AAAA, and matching the zone's own convention beat the marginal tidiness of an alias. The AAAA was safe to publish immediately because witness and otium already carry listen [::]:443 ssl.

Nothing was created at mechcomp.kane-il.us: CIVICVS never serves at the root of a subdomain.

3. Port-80 vhost on wg-pk, no TLS. HTTP-01 needs a live vhost to validate against, and a listen 443 block naming certificate paths that do not exist yet fails nginx -t and takes the reload down with every other site.

4. certbot --nginx -d dev.mechcomp.kane-il.us, run once. HTTP-01 through the nginx plugin, matching all four existing certificates — verified by reading /etc/letsencrypt/renewal/*.conf rather than assuming. No DNS plugin is installed and BIND was not involved. Certbot wrote the 443 block, the redirect and the certificate lines into the same file.


2. Acceptance — all met 2026-09-11

Criterion Result
1 https://dev.mechcomp.kane-il.us/ from outside 200
2 Let's Encrypt chain, no -k issued, expires 2026-12-10
3 /api/build returns real JSON confirmed
4 Reachable over IPv6 200
5 HTTP redirects rather than serving plaintext 301
6 Negative: mechanical-compiler.dev.infra still answers 200
7 Negative: CT 100 direct still answers 200
8 Negative: mail from srv-b still delivers delivered to theron@ via wg-pk and mx1

The three negatives matter as much as the positives. iptables-save rewrote the whole ruleset on srv-b, and mail traverses the same wg0 interface the DNAT was added to. POSTROUTING order was verified unchanged — the RETURN still precedes both masquerades.


3. What this did not settle

  • Renewal has never been observed to succeed for this name. The certbot timer is scheduled and the other four certificates are managed identically, but the first renewal for dev.mechcomp is due before 2026-12-10 and nobody has watched one complete. certbot renew --dry-run counts against a rate limit and was not repeated after one attempt timed out.
  • No acceptance criteria exist for the composer itself, only for the path to it. A 200 says the chain works, not that the page is right.
  • The service has no authentication. It is world-reachable and computes geometry for anyone who asks. An earlier version of this bullet called that acceptable for a development name. It is not: dev abbreviates Mechanical Compiler Developers, the name is production, and it appears on printed material. Corrected 12 SEP — the posture is unchanged and the justification is withdrawn. docs/IDENTITY-CONTRACT.md specifies how it will be gated and by whom.

4. Found while working, not this project's to fix

shell.infra.civicus.us and corpusdb.infra.civicus.us publish AAAA 2600:3c00:e000:365::. wg-pk holds 2600:4c00:e000:365:: — one hex digit apart, 3c against 4c. Both names are unreachable for v6-preferring clients right now, while v4 clients see working sites: the intermittent fault that looks like anything except DNS.

Recorded in STAGING-STATE.md §6 so it does not evaporate with the scrollback.


5. Method note

The one thing that made this go quickly, after several turns of it not going quickly at all: read the estate's own conventions before designing against it. Every wrong turn in this work order's history — a route that was not needed, a lockout risk that did not exist, a CNAME where the zone uses A/AAAA, a DNS-01 challenge where HTTP-01 was already standard — came from proposing a design before reading what four working services already did.