tests: close F-034; bound the derived trio at 8 ULP of the oracle record

The oracle records six significant figures, so the last digit of an area near 200 mm2 is worth 0.001 mm2. Every measured disagreement between port and reference is one, two or three units in that place. SECTION_AREA_MM2, VOLUME_MM3 and MASS_G are now bounded at 8 ULP of the expected value. Everything that positions material keeps the declared 1e-4 mm and remains exact in all 123 cases.

Option 1 scope kept, derivation rejected on measurement. Max |dA|/P over the accepted set is 1.434e-05 mm, one seven-hundredth of the 0.01 mm criterion, so a perimeter x 0.01 bound would have run 1800 to 4500 times the worst real discrepancy and caught nothing. Perimeter also anti-correlates with the error.

Suite 468 passed, 0 failed. The 30 expected failures are resolved, not suppressed. Mutation tested before landing: worst case uses 37.5 percent of its bound, 12 ULP offsets and 1e-4 relative scalings are caught in all 113 cases, 1e-6 and 1e-5 correctly are not.

Adds docs/ACCEPTANCE.md as the specification. Adds F-036, the venv interpreter error, same class as F-035. Corrects the F-034 per-profile distribution to Three-Fin 10, Y 7, A Frame 6, Rectangle 5, T 1, Four-Fin 1, which sums to the stated 30.
This commit is contained in:
2026-08-23 08:19:18 -05:00
parent 52d00b588b
commit 6836ece4ff
4 changed files with 447 additions and 34 deletions
+72 -2
View File
@@ -6,7 +6,7 @@ Compiler environment.
| | |
|---|---|
| Scope | All instances. Staging entries are marked `srv-b`. |
| Updated | 2026-08-18, after repository seeding and container standardisation |
| Updated | 2026-08-22, closing F-034 |
| Method | `PROCESS.md` section 7 |
| Rule | Append only. Never edit an entry except to add a `Resolution` line. |
| Numbering | Sequential, never reused. See §0 on the renumbering. |
@@ -904,6 +904,44 @@ Whichever is chosen, the checks that catch structural error — `SECTION_PARTS`,
genuine geometry fault runs 1e-2 relative or worse and would still be caught with
three orders of margin.
**Resolution (2026-08-22): closed.** Option 1's scope was kept and its
derivation was rejected on measurement.
A read-only pass over all 113 accepted cases re-expressed every area
discrepancy as `|dA| / P` — the uniform boundary displacement that would
produce it, directly comparable to the 0.01 mm criterion. Median 0, p95
9.075e-06 mm, **max 1.434e-05 mm**. A `perimeter x 0.01` bound would have run
1.86 mm^2 at the smallest section and 4.54 mm^2 at the largest — 1,800 to
4,500 times the worst real discrepancy — and would have caught nothing.
Perimeter is also the wrong normaliser: it anti-correlates with the error,
widening the spread from a factor of 3 to a factor of 6.5, because the error
is driven by how many corners tip from 12 segments to 13 rather than by
boundary length.
The real quantiser is the reference's own six-significant-figure `echo`.
**Every discrepancy in the set is 0.001, 0.002 or 0.003 mm^2** — one, two or
three units in the last digit the reference ever recorded. The bound adopted
is `8 * ulp(expected)` where `ulp(v) = 10 ** (floor(log10 |v|) - 5)`, applied
to `SECTION_AREA_MM2`, `VOLUME_MM3` and `MASS_G` only.
Propagation verified rather than assumed: `VOLUME/AREA` is exactly 100.0 in
all 113 cases with maximum deviation 2.8e-14, and `MASS/VOLUME` is uniform to
1e-8, so one bound governs all three keys honestly.
**Correction to the per-profile line above.** It records Three-Fin 9, Y 7, A
Frame 5, Rectangle 5, T 1, Four-Fin 1 — which sums to 28 against the stated
total of 30. Measured: **Three-Fin 10, Y 7, A Frame 6, Rectangle 5, T 1,
Four-Fin 1 = 30.** The entry above is left as written, per the append-only
rule; this is the correct distribution.
Result: **468 passed, 0 failed.** The 30 expected failures are resolved, not
suppressed. Mutation-tested before landing — worst case consumes 37.5% of its
bound, offsets of 12 or more last-place units are caught in all 113 cases on
all three keys, and a 1e-4 relative scaling is caught everywhere, while 1e-6
and 1e-5 correctly are not. `test_tolerance_policy_is_not_vacuous` asserts the
derived bound never exceeds 1e-4 relative, so a future widening fails a test
instead of passing quietly. Specification in `docs/ACCEPTANCE.md`.
---
### F-035 — `su` cannot run as a `nologin` service user
@@ -953,6 +991,37 @@ running every repository operation as `mechcomp`. All are now stated as facts in
---
### F-036 — a work order used the system interpreter instead of the virtualenv
CT 100. F-034 measurement pass.
**Observed:** a measurement script delivered by the architect was invoked as
`runuser -u mechcomp -- python3 /tmp/f034/f034-measure.py` and died at
`import pytest` with `ModuleNotFoundError`, three frames into loading
`tests/conftest.py`.
**Cause:** **Proven.** `Makefile` line 3 sets `PY ?= venv/bin/python`, and
`make deps` runs `pip install -r requirements-base.txt -r requirements-cad.txt`
followed by `pip install -e .` into that virtualenv. pytest, Shapely, numpy and
`mechcomp` itself all live in `/var/www/mechcomp/venv`. System `python3` has
none of them. Had the script got past the pytest import it would have failed
again on Shapely.
**Correction:** invoke `/var/www/mechcomp/venv/bin/python`. The script itself
needed no change; it ran first time on re-invocation.
**Consequence:** **This is F-035 exactly, one layer up, and it is the reason
F-035's own consequence was written.** `HANDOFF.md` §1 stated `runuser` as a
fact but left the interpreter to be inferred from the Makefile — learnable by
pattern-matching an existing command, not by reading. That fails precisely when
an assistant composes a command from scratch, which is what happened both
times. Now stated as a fact in §1.
The general form is worth keeping: **an operational fact that appears only
inside example commands has not been documented.** Grep the handoff for facts
that exist only as examples; each is a future F-035.
---
## Open, not closed
| # | Status |
@@ -973,7 +1042,8 @@ running every repository operation as `mechcomp`. All are now stated as facts in
| F-031 | **Corrected** 2026-08-18. Root cause of `ct-baseline.sh`. |
| F-032 | **Closed** 2026-08-18. No correction required; encoded in `ct-baseline.sh`. |
| F-033 | **Corrected** 2026-08-19. Restore path unreachable under `set -e`. |
| F-034 | **Open** 2026-08-20. Measured: the port is exact, the reference is noisy. 30 of 113 accepted cases, worst relative error 2.24e-05, confined to `SECTION_AREA_MM2` and its two derivatives. Nothing correctable in the port; awaiting a CIVICVS decision on the tolerance model. |
| F-034 | **Closed** 2026-08-22. Measured: the port is exact, the reference is noisy. 30 of 113 accepted cases, worst relative error 2.24e-05, confined to `SECTION_AREA_MM2` and its two derivatives. Nothing correctable in the port; resolved in `test_oracle.py` by bounding at eight units in the last place of the oracle's six-significant-figure record. Suite green at 468 passed. Specification in `docs/ACCEPTANCE.md`. |
| F-035 | **Corrected** 2026-08-19. Use `runuser`, never `su`; `mechcomp` is `nologin`. |
| F-036 | **Corrected** 2026-08-22. The interpreter is `venv/bin/python`, never system `python3`. Same class as F-035. |
Everything else is closed with a proven cause and a proven correction.