Files
TheRON 61b8f1eb4c HANDOFF: reconcile against the code, and delete what git already reports
Section 3 said main was at ee3fedf with 547 passing. Section 12 transcribed a commit log ending at a8081e1, ten commits behind. Neither is corrected; both are removed. git rev-parse, git describe and git log report them, and the header already explained why the hash line could never be right - it is not known until the commit is made, so the value was always the previous commit. The same reasoning applies to the rest and nobody had applied it.

Section 4 item 2 listed STL export as forthcoming work. It landed at 0545b79 and the bounded route at cdde394. The length_view gap that would have made every export a silent 100 mm preview was fixed before the route shipped. The roadmap entry still said the composer does not export anything.

Section 3 module table was missing stl.py entirely. The baseline run is now dated 2026-08-18 and marked overdue against DIV-006, since it predates both the DNAT rule and the placeholder service replacement, which PROCESS section 9a names as requiring a run.

Section 7 recorded the F-034 per-profile breakdown as Three-Fin 9, Y 7, A Frame 5, Rectangle 5, T 1, Four-Fin 1 - which sums to 28 against its own stated total of 30. The measured distribution had been recorded correctly in ACCEPTANCE section 7 and in F-034 resolution for three weeks, while the wrong numbers stayed in the document a successor reads first.

Section 0 reading order gains DIVERGENCES.md and ENVIRONMENT.md. ENVIRONMENT.md was missing from it for three weeks while PROCESS section 8 carried ENVIRONMENT and omitted HANDOFF instead. Two lists, neither complete, each looking authoritative. Both now carry both.

PROCESS correction: the amendment rule added at 15e90fd claimed a document replaced rather than amended loses content, citing HANDOFF.md. Checked today against both archived handoffs - it had lost nothing. The dihedral gap, the three artifact classes, the cross-project mail question and the toolchain probe recipe are all still present. The hazard is structural, a rewrite has no diff, but the loss I asserted did not happen. Corrected rather than left standing.

Applied by anchored patcher, all-or-nothing across both files. Suite 643 passed, oracle intact. Documentation only.

Known cosmetic defect: the baseline paragraph in section 3 now has two adjacent bold spans and a line over 80 columns, because the anchor stopped mid-paragraph. Renders correctly. To be rewrapped with the next patch that touches the file.
2026-09-13 15:39:01 -05:00

546 lines
22 KiB
Markdown

# PROCESS.md
How work gets done on the Mechanical Compiler.
| | |
|---|---|
| Created | 2026-08-17 |
| Scope | All work on a Mechanical Compiler instance |
| Companions | `ENVIRONMENT.md`, `STAGING-STATE.md`, `FAILURES.md`, `ROADMAP.md` |
---
## 0. Why this document exists
The four companion documents describe what the environment **is**. None of them
describes how work gets **done** in it — where files land, who runs what, how a
change travels from a conversation into a running container.
Until now that gap was filled by restating the mechanics inside each work
order. That worked while the orders were written consecutively by one author.
It does not survive a handoff: an assistant reading `ENVIRONMENT.md` learns how
the host is built and nothing about how to operate on it.
**Read this before your first command.**
---
## 1. Who does what
Three parties, and confusing them is the most common way to waste a session.
| Party | Has | Does |
|---|---|---|
| **Operator** (CIVICVS) | A shell on `srv-b` and a file manager | Runs every command. Uploads files. Decides. |
| **Assistant** | This conversation | Writes commands, reads output, writes code and documents |
| **Architect** | This conversation, in a different mode | Sets specification, accepts work, maintains the documents |
### The constraint that shapes everything
**The operator has a shell on `srv-b` and a browser-based file manager.
Nothing else.**
No workstation git client. No direct container shell. No IDE. No ability to
`scp`. Every file arrives by upload to a folder on `srv-b`; every command runs
in that one shell.
An assistant that assumes otherwise produces instructions the operator cannot
execute. This has already happened once.
### What follows from it
- Files reach a container as: **upload to `srv-b`** → `pct push` or expand and
copy → `pct exec` to act on them.
- `srv-b` is the only place a human types. Containers are reached through
`pct exec`, never by SSH from elsewhere.
- **This is a legitimate deployment path, not a workaround.** Do not design
around a git client that does not exist.
---
## 2. Two modes of work, and they are not the same
Applying the wrong one is slow in one direction and dangerous in the other.
### Infrastructure mode
For anything that changes the host, the containers, the network, or a service
that other work depends on.
- One command group at a time
- Read-only before write
- Record a failure **before** correcting it, in `FAILURES.md` format
- Smallest corrective experiment — not the one that also fixes three adjacent
worries
- Preserve a rollback copy before editing any configuration file
- Prove the negative: assert the forbidden path fails, not that the interface
is gone
- Assert health **after a host reboot**, never before
This is deliberate ceremony. Each step is irreversible or expensive to undo,
and the failure log is a deliverable in its own right — it is the primary input
to the eventual production automation.
Work orders 001 through 004 were all infrastructure mode.
### Development mode
For anything inside the repository: code, tests, documents, fixtures.
- Iterate freely. Edit, run the tests, edit again.
- No command-group ceremony. A test-fix-rerun loop is not a provisioning step.
- Failures during a normal red-green loop are **not** `FAILURES.md` entries.
- Commit when something works, not when something is finished.
**The distinction is reversibility.** A wrong `iptables` rule can strand the
operator. A wrong line of Python fails a test and gets deleted. Ceremony
appropriate to the first is obstruction applied to the second.
### Which mode am I in?
Ask: *if this is wrong, what does it cost?*
| Cost | Mode |
|---|---|
| A rebooted host, a lost shell, a broken service | Infrastructure |
| A red test | Development |
If genuinely unsure, use infrastructure mode. Being slow is recoverable.
---
## 3. Getting files into the environment
### The path
```
assistant produces a tarball
-> operator downloads it
-> operator uploads it to /root/incoming on srv-b (file manager)
-> operator expands it on srv-b
-> pct push, or expand-then-copy, into CT 100
-> pct exec to act on it
```
**REQ** — `/root/incoming` on `srv-b` is the landing area. One directory,
always the same, so nothing has to be remembered between sessions.
**REQ** — Files landing in a container must end up owned by `mechcomp`.
`pct push` writes as root; fix ownership immediately afterwards. See F-008 —
repository operations run as the service user, and a root-owned file inside the
tree causes exactly that failure later.
**REQ (F-037)** — The `chown` must name the directory the files landed *in*, not
only the files. A tar stream rooted at `.` carries an entry for the destination
directory itself, and `tar x` as root rewrites that directory's ownership.
Naming only the payload subdirectories leaves the repository root `root:root`,
and git then refuses the worktree with the F-008 message — which invites the
F-008 mistake as its own remedy. Fix the owner. Never add `safe.directory`.
**REQ (F-037)** — Verification that depends on the repository being intact must
run *after* the landing, and a landing step must not be able to destroy the
check that would have caught it. A `git diff` placed before the step that broke
git reports nothing wrong and looks like a pass.
**REQ** — An assistant delivering files states, in this order: what the archive
contains, where it expands, what it overwrites, and how to verify it landed
correctly. "Overwrites nothing" is a claim that must be checked, not assumed.
### Delivering a whole tree
Prefer one tarball that expands over the existing tree. Individual file paths
are error-prone to transcribe through a file manager.
Name the payload's top-level directories explicitly, when creating the archive
and when extracting it: `tar cf - -C <dir> src tests`, never `-C <dir> .`. The
second form is what produced F-037. For a single file, `pct push` is simpler and
cannot reproduce it at all.
### Delivering a single small file
For anything that fits comfortably on screen, a heredoc in the `srv-b` shell is
faster than an upload, and leaves the content visible in the session transcript
where it can be checked.
---
## 3a. The delivery chain, end to end
The whole path from an assistant producing something to it existing in Gitea.
It has been explained conversationally to every new assistant for months and was
written in no document until now, which is the reason this section exists.
**Nothing but the operator writes.** The assistant reads Gitea over MCP, which
is read-only, and builds files in its own sandbox. The operator is the only party
with write access anywhere in the chain. That is deliberate, and it is section 1
restated: the operator executes, and the assistant never assumes a command
succeeded.
### The steps
```
assistant builds the artifact in its sandbox
-> states sha256, size, contents, where it lands, what it overwrites
-> operator downloads it and uploads to /root/incoming on srv-b
-> assistant gives ONE command group
-> operator pastes it into the srv-b shell, pastes output back
-> repeat until landed, verified, pushed
```
### Three groups, not one
**REQ** — landing, verification and commit are separate command groups, because
section 4 requires a suite result the assistant *has actually seen* before a
commit exists. A single group that lands and commits cannot satisfy that.
| Group | Does | Ends when |
|---|---|---|
| 1 | `pct push` or expand-and-copy, fix ownership, confirm checksum, `git status` | the file is in place and owned by `mechcomp` |
| 2 | `make verify-oracle`, `make test` | the assistant has read a real result |
| 3 | `git add`, `git commit`, `git push`, verify | `git status -sb` shows no ahead marker |
### Idioms that need no shell
`pct exec` runs no shell (section 9). These forms avoid needing one:
- `make -C /var/www/mechcomp test` — never `cd ... && make test`
- `git -C /var/www/mechcomp status` — never `cd ... && git status`
- `runuser -u mechcomp -- <cmd>` — never `su`
**REQ** — a commit message is parsed by the **host** shell before `pct` sees it.
Use repeated `-m` flags, and no dollar sign, backtick or exclamation mark
anywhere in the text. A heredoc does not survive `pct exec`.
### State which failures are passes
**REQ** — an instruction set says what the expected output is, including where
an **error is the correct result**. The group-1 check that a target does not yet
exist fails with `No such file or directory` when the delivery is correct; an
operator who reads that as a fault stops a working delivery. An operator who
cannot tell success from failure cannot report usefully (section 9).
### Amending a large document
**REQ** — do not ship a rewritten file to change a few passages of a large one.
Ship an anchored replacement script that validates every anchor matches exactly
once and writes nothing if any does not.
A rewrite regenerates the whole document from the assistant's reading of it, and
a transcription error is silent. `FAILURES.md` is 52 kB of correct prose whose
value depends on never being rewritten, and the same hazard applies to any
document large enough that nobody will diff it carefully.
The hazard is structural rather than observed: a document **replaced** rather
than **amended** has no diff, so nothing reports what left.
`HANDOFF.md` is rewritten in place every session, and on 13 SEP it was checked
against both archived handoffs to see what that had cost. It had cost nothing —
the dihedral gap, the three artifact classes, the cross-project mail question
and the toolchain probe recipe were all still there. The practice survived
because a careful author carried the content forward by hand, every time. That
is a property of the authors, not of the method, and it is not one to rely on.
---
## 4. The repository
**Gitea is the source of truth.** `https://gitea.barternetwork.us/TheRON/mechanical-compiler`
CT 100 holds a clone at `/var/www/mechcomp`, owned by `mechcomp`.
### Two directions, both valid
**Gitea → container.** `git pull` inside CT 100, as `mechcomp`. Use this
whenever the change already exists in Gitea.
**Upload → container → Gitea.** Land the files, verify they work, then commit
and push from inside CT 100. Use this when the assistant produced something new.
The second direction is the normal one for assistant-produced work, because the
operator has no git client outside the environment.
**REQ (F-008)** — Every `git` command runs as `mechcomp`. Never as root, and
never add a root `safe.directory` exception — it would mask every future
instance of the same mistake.
### What must be true before a push
- The oracle verifies: `python3 fixtures/strap-beam-8.0.0/make_fixtures.py --verify`
- The test suite runs, with a result the assistant has actually seen
- `git status` shows nothing unexpected — particularly not `venv/`
**The first and third are one check, not two (F-033).** `--verify` recomputes the
hash from the document it reads and compares it against the value stored inside
that same document, so a wholly regenerated oracle is self-consistent and passes.
It proves internal integrity, never identity with the committed bytes. Only
`git status` can tell you *which* oracle is present. Dropping either as redundant
removes the only check that catches a substituted oracle.
**The two interpreters are deliberate, and the Makefile is right.**
`make verify-oracle` runs `python3` because `make_fixtures.py` imports nothing
outside the standard library — that is what makes the oracle check trustworthy on
any machine at any time, and it must not be made to depend on a deployment.
`make test` runs `venv/bin/python` because the suite imports `mechcomp`, Shapely
and pytest, none of which system `python3` has (F-036). Neither is a mistake to
be tidied into consistency.
### Recording provenance
Artifacts are attributed to the **commit that produced them**, not to a
timestamp or a file copy. When an artifact is generated, the commit SHA of the
tree that produced it is part of its record. This is why the transport does not
matter but the SHA does.
---
## 5. The development loop
Inside CT 100, as `mechcomp`, from `/var/www/mechcomp`:
```
make deps once, and after any requirements change
make test the loop
make verify-oracle before any commit that touches fixtures
```
### The oracle is the gate
`fixtures/strap-beam-8.0.0/` holds 123 frozen cases. It is the acceptance
criterion for the port, and it is not negotiable.
**The ten rejected cases are part of the contract.** A port that accepts them is
wrong however good its numbers are elsewhere. Reproducing geometry is
straightforward; keeping the constraint that made the geometry trustworthy is
the actual work.
**The oracle is never edited to make a test pass.** If the port disagrees with
it, the port is wrong until proven otherwise. If the oracle is genuinely wrong,
that is a finding, it is recorded, and it is regenerated inside the pinned
toolchain — never hand-edited.
### Test discipline
**A test must distinguish failure of the tool from failure of the thing under
test** (F-027). Every negative assertion first establishes that it could have
observed the positive case. A test whose failure mode is indistinguishable from
success manufactures confidence.
Prove a new harness by making it fail deliberately before trusting it green.
---
## 6. Work orders
A work order is an infrastructure-mode instruction set. Development work does
not need one.
### When to write one
- The work changes the host, containers, network, or a shared service
- The work has an acceptance criterion that can be stated in advance
- The work will be executed by someone other than the author
### Required sections
| Section | Purpose |
|---|---|
| Scope | In and out. Explicit "do not touch" list. |
| Success criteria | Strict, testable, stated before the work |
| Known state | So the operator does not re-derive what is already recorded |
| Command groups | One at a time, read-only first |
| Acceptance | What must be true to close |
| Reporting | What comes back to the architect |
### Executing one
- One group at a time. Paste output back before the next.
- Record a failure before correcting it.
- **A defect in the work order is a finding**, not something to work around
silently. F-024 and F-028 are work-order defects, logged as such.
- "The problem is elsewhere and here is the evidence" is a complete outcome.
Do not manufacture a local workaround for a remote problem.
---
## 7. When something goes wrong
### Is it a `FAILURES.md` entry?
**Yes** if it is a surprise about the environment: something behaved
differently from what the specification or a work order said, and a future
automation writer would get it wrong the same way.
**No** if it is an ordinary development failure: a red test, a syntax error, a
wrong algorithm. Those are the loop working.
### Entry format
```
### F-nnn — one-line summary
Host or container. Phase.
**Observed:** verbatim where possible
**Cause:** proven, or explicitly "unproven"
**Correction:** the smallest change that fixed it
**Consequence:** what the specification or automation must do differently
```
An entry with no `Consequence` is either not understood or not worth recording.
**"Unproven" is a respectable result.** F-006, F-012 and F-022 are carried open
and the log is better for it. Never invent a cause to close an entry, and never
close one on a change that merely coincided with the symptom disappearing.
### Escalating
Stop and ask the operator when:
- A decision is needed that is not the assistant's to make
- The work requires changing infrastructure outside this project
- A **REQ** in the specification cannot be satisfied
- The specification and observed reality disagree
The last one is not a blocker — reality wins, and the specification is
corrected. But it is always worth saying out loud.
---
## 8. Session handoff
Sessions end abruptly. Assume the next assistant has these documents and
nothing else.
### Before a session ends
- Anything working is committed and pushed
- Anything learned is in `FAILURES.md`
- Anything changed on a host is in `STAGING-STATE.md`
- Any open decision is in `STAGING-STATE.md` section 6
### Starting a session
Read in this order:
1. **`PROCESS.md`** — this document
2. **`STAGING-STATE.md`** — what is true right now
3. **`FAILURES.md`** — what has already gone wrong
4. **`HANDOFF.md`** — where the last session left off
5. **`DIVERGENCES.md`** — what is required and not met
6. **`ENVIRONMENT.md`** — the specification
7. `ROADMAP.md` — where it is going
`HANDOFF.md` was created after this list was written and was missing from it for
three weeks, while its own section 0 carried a different list missing
`ENVIRONMENT.md`. Two reading orders, neither complete, each looking
authoritative. **If you add a document, add it here.**
If writing provisioning automation, read `FAILURES.md` **before** the
specification. Every entry is something a script written from the specification
alone would have got wrong.
### Authority when documents disagree
1. `STAGING-STATE.md` — factual, wins on what is true
2. `FAILURES.md` — evidence from contact with real hosts
3. `DIVERGENCES.md` — where a requirement stands and is not met
4. `ENVIRONMENT.md` — the specification, corrected when proven wrong
5. `ROADMAP.md` — sequence
**The rule underneath the list:** a document that *describes* something yields to
the thing it describes; a document that *prescribes* something does not.
`STAGING-STATE.md` describes a host, so the host wins. `deploy/README.md`
prescribes a host configuration, so it does not — and it says so itself. Both are
correct, and the apparent contradiction dissolves once the two kinds are named.
**A permanent deviation is not a deviation. It is the specification.** Promote
it and delete the exception.
**That applies to facts about a host, not to requirements the code has not met.**
A REQ is never lowered to match what was built. It stands, the gap is recorded in
`DIVERGENCES.md`, and the correction is owed by the code. Promoting a divergence
would make every document true by construction and worthless — a specification
that agrees with whatever exists specifies nothing.
---
## 9. Instructions the operator can actually run
**REQ** — `pct exec` runs no shell. A glob, redirect, pipe or `&&` in a `pct
exec` command is expanded by the host shell against the host's filesystem, and
the container receives whatever literal survives. Wrap them: `pct exec 101 --
sh -c '...'`. An unwrapped glob produces an error that describes the container
rather than the invocation, which is the same misdirection as F-035 and F-036 —
three instances now, all of them the tool being invoked wrongly and the message
naming the wrong subject.
This section exists because it has already gone wrong.
**REQ** — One command group per message. Wait for output.
**REQ** — Commands run in the `srv-b` shell, or via `pct exec` from it. Nothing
assumes a tool the operator does not have.
**REQ** — A group is copy-pasteable as a block, with `echo` markers separating
sections so the output can be read back.
**REQ** — State what the expected output is. An operator who cannot tell
success from failure cannot report usefully.
**Do not** deliver a numbered multi-stage procedure spanning several systems and
expect it to be executed. It will not be, and the parts that are will not be
separable in the output.
**Do not** assume the operator will improvise the missing step. If a command
needs a directory to exist, create it in the same group.
---
## 9a. The baseline check
`ct-baseline.sh` is the executable definition of the container standard on this
host. Read-only, runnable at any time, exits non-zero on divergence.
Run it:
- before starting work on a container;
- after any change to a container or to host firewall rules;
- after any host reboot;
- before considering backup work (see `ENVIRONMENT.md` §15 gate 4).
**A property not checked by it is not part of the standard.** If something
should be uniform across containers, add it to the script. If it should not,
leave it out and stop worrying about the difference. That is the whole point:
it converts an endless comparison into a pass or a fail.
It covers containers belonging to more than one project, and encodes host
requirements neither project owns alone. Treat it as host property.
---
## 10. Current mode
**Infrastructure: complete and accepted**, and now includes public ingress —
`WORK-ORDER-004-public-ingress.md`, closed 2026-09-11. See `STAGING-STATE.md`
for what is true on the host, and `DIVERGENCES.md` for where the running instance
and the specification disagree.
**Backup: deliberately postponed.** Nothing exists yet whose loss would cost
more than an afternoon; the documents are in Gitea. This changes when
`artifacts/` stops being empty.
**Container baseline: established, and not re-run since the host last changed.**
See DIV-006.
**Development: the Shapely port is complete.** The compiler builds cross
sections, reports them, renders SVG, exports STL, and serves a composer over
HTTP. `ROADMAP.md` section 4 carries what comes next.
**This section no longer records a commit, a version or a test count.** Those are
reported by `git rev-parse HEAD`, `git describe --tags` and `make test`, and
every previous attempt to hold them current in prose went stale — the last one
claimed the repository was still at its seed commit while the work it described
had been finished for three weeks. A document states what no command can report:
a decision, a constraint, a reason, a hazard.
From here the mode is **development** unless the work touches the host, the
containers, or a shared service.