HANDOFF section 4 said WORK-ORDER-004 was pending and that CIVICVS could not see any of this work. It was rewritten thirty-two minutes after1fdb115closed the ingress, in the same session, against the work order's old state rather than its new one -- so HEAD described a world where the thing you were already looking at did not exist. Section 11 row 7 carried the same staleness. Both corrected, and the correction says how it happened, because section 0 was added to prevent exactly this and did not. Three things1fdb115recorded as unsettled were never promoted into section 11 and are now rows 8 through 10: TLS renewal has never been observed to succeed for this name and is first due before 2026-12-10; the composer has no acceptance criteria of its own, only the path to it does; and the service is world-reachable and unauthenticated, which section 4 item 5 called a conscious decision to be made before publishing and which publishing has now made due. Priority items 1 and 2 reversed. The original case for authorship first was that records made before the field exists can never be attributed. That was too strong, and too strong because the field is excluded from both hashes: a record regenerated later keeps its input_id. What it does not keep is build_id, which covers Shapely and GEOS, and boolean results on near-degenerate geometry shift between GEOS releases -- the F-034 mechanism. Attribution is recoverable, not free. The residual argument stands and the field landed first at48d5665. Recorded under item 2, because it is the first thing STL export runs into: length_view is not in COMMON_GROUPS, so the Full Length branch is unreachable from the composer and every export would silently be a 100 mm preview. The sweep must equal model_length_mm(p), already published as LENGTH_MM, or the record's VOLUME_MM3 and MASS_G describe a different object than the file beside them. Also split the roadmap's STL/STEP bullet: STEP needs the kernel, STL does not, and one line implying both was left behind by the section 5 correction. F-037: a tar stream rooted at "." re-owned the repository root. tar x ran as root and applied the "." entry's ownership to /var/www/mechcomp; the chown that followed named only src and tests. Everything below the root was correct, so 547 tests passed and only git noticed. Corrected by chown on one path, owner only, no -R. safe.directory was not added -- that is F-008 and would have masked this and every later instance. Two of F-037's three consequences are process defects of mine rather than facts about the environment. The verification step ran before the landing that destroyed it, so a git status ahead of the breaking step reads as a pass -- the F-027 pattern in a new place. And section 7 says record a failure before correcting it; I corrected first. Both recorded rather than quietly fixed. PROCESS section 3 gains two REQs, because the delivery path as documented produces F-037 every time: the chown must name the directory the files land in, and a tar transport must name its top-level directories rather than root at ".". pct push is simpler for a single file and cannot reproduce it at all. Section 8 gains the bytecode rule: PYTHONDONTWRITEBYTECODE=1 and clear __pycache__ between mutations. A stale .pyc masked a real defect once and every mutation result reported before that was optimistic by an unknown amount. A mutation surviving on stale bytecode is indistinguishable from one surviving on a weak test. Open question 11 is new and is CIVICVS's: ct-baseline.sh exits 0 with the F-037 condition present, so by section 9a the ownership of a service working tree is not part of the container standard. Whether it should be is a decision about host property covering three projects.
34 KiB
HANDOFF
This document is rewritten in place each session. It is state, not a log.
It is the only handoff you need to read. Dated handoffs in docs/archive/ are
historical and are not required reading — do not diff them against this to work
out what is true. If something here is wrong, correct it here.
Last updated 2026-09-12, after the authorship field landed.
This line used to carry the commit hash of its own rewrite. It cannot: the hash is not known until the commit is made, so the value was always the previous commit and section 3 drifted two commits behind without anyone noticing. Date only, from here.
0. Read these first, in this order
This document is not the first thing to read, despite being the handoff.
docs/PROCESS.md— how work is done here: who runs what, on which machine, with which tools. It constrains everything below. Reading it eleventh cost this session three sets of instructions the operator could not execute.docs/STAGING-STATE.md— what is true on the host right now.docs/FAILURES.md— what has already gone wrong and why.- This document — where the code stands.
docs/ACCEPTANCE.md,docs/STOCK.md,docs/PRECISION.md— the specifications the code is held to.
When documents disagree, STAGING-STATE.md wins on facts about the host and
FAILURES.md wins on what was actually observed. This one is corrected.
1. Invocation — read before typing anything
These are facts, not examples. Getting one wrong produces an error that looks like a problem with the repository or the containers.
mechcomp has nologin as its shell. Use runuser -u mechcomp -- <cmd>,
which executes directly. su - mechcomp cannot work and fails with
This account is currently not available — a message that looks like a broken
account and is not. See F-035.
The interpreter is /var/www/mechcomp/venv/bin/python, not python3.
Makefile line 3 sets PY ?= venv/bin/python, and make deps installs
pytest, Shapely, numpy and mechcomp itself into that virtualenv. System
python3 has none of them and fails at the first import (F-036).
All repository operations run as mechcomp, never root. The clone is at
/var/www/mechcomp in CT 100. Never add a git safe.directory exception to work
around an ownership complaint; fix the ownership (F-008).
mechcomp's home is the working tree. Anything writing to $HOME writes
into the repository. .cache/, .local/ and .ssh/ are in .gitignore for
that reason (F-029). Git identity is set --local for the same reason —
--global would write into the tree.
verify.sh is mode 100644. Invoke it as bash tools/reference-toolchain/verify.sh,
never ./tools/....
Gitea SSH is port 42022. Remotes need
ssh://git@host:42022/owner/repo.git; the git@host:path shorthand cannot carry
a port. CT 100 pushes with deploy key srv-b-ct100.
Deploy tokens in Gitea are account-level, under user Settings. Repository settings offer deploy keys only.
Files reach CT 100 by upload, then pct push, then chown. pct push
writes as root, so pct exec 100 -- chown mechcomp:mechcomp <path> immediately
after, every time.
Every network command needs an explicit timeout (F-030). One without hung the operator's shell.
Logs are in journalctl, not /var/log/. Proxmox ships without rsyslog
(F-024).
Long-running jobs go to systemd-run --unit=<name> --collect, not nohup or
setsid. pct exec tears those down when it exits; systemd owns the job and the
output lands in the journal.
Docker runs as root in CT 100 only. mechcomp cannot reach the daemon. CT 101
has no keyctl and cannot run it at all.
Assert the guest is running before interpreting any pct exec result (F-027).
A command that fails because the container is stopped otherwise reads as a pass.
Useful canonical form:
if [ "$(pct status 100 | awk '{print $2}')" != "running" ]; then
echo "CT 100 NOT RUNNING - stop here."
else
pct exec 100 -- runuser -u mechcomp -- git -C /var/www/mechcomp status --short
fi
2. The operator's constraint
CIVICVS has a shell on srv-b and a browser-based file manager. Nothing
else.
No workstation git. No SSH into a container. No IDE. No scp. Files arrive by
upload to /root/incoming on srv-b; every command runs in that one shell.
pct exec from that shell reaches all three containers — that is the container
path, and it is not a limitation.
An assistant that assumes otherwise produces instructions the operator cannot execute. This has happened repeatedly.
Deliver code by upload, not by paste. A sixty-line heredoc containing em-dashes and nested code fences was mangled by the browser terminal. Everything delivered since as a tarball — with a stated checksum, file list, and what it overwrites — has worked without exception. State what the archive contains, where it expands, and what it overwrites, every time.
When a delivery supersedes an earlier one, ship every file in the set, not just the changed one, so the resulting state is unambiguous.
3. Where things stand
Infrastructure — complete, do not revisit
srv-b, Proxmox VE 8.4.0, standalone.
| CT | Name | Address | Role |
|---|---|---|---|
| 100 | mechcomp |
10.20.0.10 |
application, worker, Docker |
| 101 | mcproxy |
10.20.0.11 |
reverse proxy, TLS |
| 102 | kane-fabric |
10.20.0.12 |
separate project |
All on vmbr1, a portless service bridge. srv-b is router and bastion:
internet → WireGuard → srv-b → containers. Containers cannot reach the home
LAN and cannot send mail.
ct-baseline.sh is read-only, runs any time, exits non-zero on divergence.
Installed at /usr/local/sbin/. Last run: 62 passed, 0 failed. A property it
does not check is not part of the standard — that is what makes conformance
terminate rather than recur.
Settled decisions. Do not reopen any of these:
- Webmin is the operator's only remote access. He works from Webmin on
wg-pk, the WireGuard hub, and from there into thesrv-bshell — not the other way round. Questioning this wasted a session once and was questioned again on 11 SEP, because the decision had been recorded without the fact it rests on. The fact is above. Do not ask again. dev.infradoes not exist on the internet. It is a hosts-file name onsrv-b, CT 100 and CT 101 only, and CT 101's leaf is signed by a local staging CA. Never tell the operator to open adev.infraURL or a10.20.0.xaddress in a browser:10.20.0.0/24is a portless bridge with LAN traffic dropped. The public name isdev.mechcomp.kane-il.usand it needsWORK-ORDER-004.- Backup is deliberately postponed. Entry condition:
ct-baseline.shexits 0. Do not raise it again. 4xis the end of the N-strap family.- The
--fulltoolchain gate's Docker root-ownership hazard is understood and handled by mounting read-only. See §6. - Accuracy criterion: 0.01 mm over the entire set. Set by CIVICVS on 20 AUG.
This is the standard the software is held to, and it is met with two orders of
margin on every dimensional quantity. See
docs/PRECISION.md.
The port — COMPLETE
Gitea main at 48d5665 before this commit. CT 100 clean and matching.
Suite: 547 passed, 0 failed. The 30 expected failures are gone, resolved
rather than suppressed, by the tolerance model in docs/ACCEPTANCE.md. A red
make test now means something is actually wrong.
The composer is live. mechcomp.service in CT 100 serves it on
10.20.0.10:8770, behind nginx on CT 101, proven HTTPS 200 end to end.
mechcomp-placeholder.service is disabled and retained as the rollback.
| Module | Ported from | Contents |
|---|---|---|
geom/primitives.py |
sb-geom.scad |
Pure geometry only. Vectors, degree trig, exact polyline distance, corner-radius derivation, monotone solver. Geo and Member are NOT here — an earlier version of this table said they were, and two modules were read on the strength of it |
geom/records.py |
sb-geom.scad |
Geo, Member, place, local_rect, sleeve and cavity paths, reach. The other half of sb-geom |
geom/rounding.py |
BOSL2 92d697c2 |
round_corners, _circlecorner, arc, segs, deduplicate, path_merge_collinear, is_collinear |
geom/region.py |
BOSL2 regions | Shapely booleans, nesting-parity decomposition, area, simplicity, hull, mitred offset, cleaning |
geom/join.py |
sb-join.scad |
Butt joints, hull caps, fillets, derived bore, ring fit, section assembly |
geom/report.py |
sb-report.scad |
Checks-as-values, metrics, five universal checks, ProfileRejected, report formatting |
geom/core.py |
sb-core.scad |
PROFILE record, failure representation, centred assembly |
geom/arrangements.py |
sb-profiles.scad |
Ring, spoke and fin arrangements, all N-generic |
profiles/_common.py |
both generators | Assembly pipeline and the eight shared base checks |
profiles/four_x.py |
strap-beam-4x.scad |
Five profiles, defaults, 4x base checks |
profiles/three_x.py |
strap-beam-3x.scad |
Six profiles, defaults, 3x base checks |
profiles/__init__.py |
— | build(), ProfileRejected, family registry |
stock.py |
— | COTS stock descriptor: RectStock, RoundStock, Fit, Provenance. A leaf module — imports nothing from mechcomp. See docs/STOCK.md |
design_record.py |
— | What a model was made from, at full precision, sufficient to regenerate it. input_id and build_id, and Author — recorded, rendered with its own limit, and in neither hash |
svg.py |
— | Cross-section as SVG, separately classed layers for material, cavities and stock |
web/app.py |
— | The composer. Standard library HTTP server; binding from /etc/mechcomp/mechcomp.env |
make deps is complete in CT 100 and must not be re-run.
4. What to do next
Nothing is blocked. The composer is live and the suite is green; everything below is new capability.
CIVICVS stated the goal on 22 AUG: he will not print anything that is not fully configurable. The compiler is a half-visual composer — the T encloses poly pallet straps in a T, the Y takes a metal electrical conduit core at its centre. That reorders what follows, because a fixed-profile STL is not a deliverable he wants. Two consequences:
- The bore is a declared interface, with a diameter and a fit class, specified by what goes through it. It is not a byproduct of the inside walls. Conduit for the Y, not only rebar.
- The catalogue front end is the product, not a convenience that comes
after export.
ROADMAP.md§4 orders it third; that ordering predates this and should be read against it.
Priority order, decided 11 SEP when CIVICVS delegated it. Items 1 and 2 were reversed on 12 SEP, for the reason given under item 1. The reasoning is given so a successor can disagree with the argument rather than only the sequence.
-
An authorship field in the design record. Landed at
48d5665. One field, and a door that narrows rather than closes. The original argument was that records created before it exists can never be attributed. That was too strong, and it was too strong because the field is excluded from both hashes: a record regenerated later with the author filled in keeps itsinput_id. Butbuild_idcovers the code revision and the Shapely and GEOS versions, and boolean results on near-degenerate geometry can shift between GEOS releases — the F-034 mechanism. Regenerate after a GEOS bump and you have attribution under a different build identity, beside a printed part nobody can now tie to either. Recoverable, not free. It still went first, because it is one field and one parser branch, and doing it first means the first coupon off the printer carries its author.The person is identified by an email address. A handle may be chosen later and does not replace it. Nothing verifies the address and the record says so on the line it appears on.
-
STL export. No new dependency, no kernel, and it is the only item that produces physical feedback. Everything so far is verified against a frozen oracle; a printed coupon is the first test against reality, and the first real measurement of whether
fit_clearance_mmsuits the operator's printer. The composer already makes stock, fit and walls configurable, which was his stated precondition for printing anything.length_viewis not inCOMMON_GROUPS. The Full Length branch is therefore unreachable from the composer, so every export would silently be a 100 mm preview — a file that looks right, slices right, and is the wrong object. The sweep must bemodel_length_mm(p), the value already published asLENGTH_MM, or the record'sVOLUME_MM3andMASS_Gdescribe something other than the file beside them. That control has to exist first. -
Per-member stock — the conduit core. What CIVICVS asked for on 22 AUG and still cannot be done:
Geois global to a build, so every member is the same rectangular strap by construction. Reaches intojoin.pyandarrangements.py; the first change that puts the oracle's own geometry at risk rather than merely near it. -
Persistence.
MECHCOMP_DATA_DIR=/var/lib/mechcomphas been declared since staging and nothing has ever written to it. Every design currently exists only for the duration of one HTTP request. This is the prerequisite for a library of saved designs and for access control. -
ACL. Deliberately last. There is nothing to control until 4 exists — access control over nothing is machinery without a subject. Note that the service is world-reachable and unauthenticated today, which is acceptable for a development name and should be a conscious decision before anything else is published this way.
Assemblies are not on this list and should not be added. See PRECISION.md
§7: positioning is field work, ruled out by design on 11 SEP.
Roadmap items — read ROADMAP.md before starting any:
- Dihedral parameterisation. If two panels meet at 137°, none of the eleven profiles gives you a member for it. This is the highest-value gap and it blocks a catalogue that could otherwise not serve the reference structure.
- Rebar- and conduit-core bore as a declared interface. See above.
- Per-member stock. This is what the conduit core actually needs.
Geois global to a build, so every member is the same rectangular strap by construction and the Y's centre cannot hold something of a different shape. Moving stock from the build to the placement reaches intojoin.pyandarrangements.py, and it is the first change where the oracle's own geometry is genuinely at risk rather than merely nearby. - The composer, deepened. It exists and serves; it does not export
anything, persist anything, or show a bill of materials.
payload["defaults"]is sent to the browser and nothing reads it — dead weight, and it is what made a verification grep lie on 11 SEP. - STEP export. Needs a CAD kernel and none is installed in CT 100 (§5). STL needs none — a member is prismatic by definition. See §5.
mechcomp-worker.service.src/mechcomp/worker/is still a 36-byte stub and nothing needs a worker yet.- Nodes (non-prismatic) and panels (sheet). No representation exists for either.
WORK-ORDER-004 is closed. The composer is public at
dev.mechcomp.kane-il.us. Executed 11 SEP at 1fdb115: browser, DNS, TLS on
wg-pk, the WireGuard tunnel, a DNAT on srv-b scoped to the hub as source,
CT 100. No WireGuard change and no route were made — the hub's peer entry for
srv-b is still a /32, as all twenty are — because every vhost there proxies
to a tunnel address directly and following that convention removed the only step
that could have locked the operator out of srv-b.
An earlier version of this paragraph said the work was pending and that CIVICVS could not see any of it. It was written thirty-two minutes after the ingress closed, in the same session, and was wrong the moment it was committed: the §4 rewrite was made against the work order's old state rather than its new one. Corrected 12 SEP. This is the staleness §0 exists to prevent, and it happened anyway, inside one session.
Note for anyone tempted to shortcut a test print: the OpenSCAD reference in
legacy/ does export printable STL today — sb_extrude_section does a
linear_sweep and legacy/openscad/README.md documents the invocation. That
is not what he asked for, and offering it again would be repeating a mistake
already made once.
5. Facts established by porting
The public entry point is mechcomp.profiles, not mechcomp.geom
conftest.py does importorskip("mechcomp.profiles") and requires a build
attribute. build(family, profile, params) -> Result and ProfileRejected are
exported from mechcomp.profiles. Params use the OpenSCAD parameter names
unchanged.
params carries only a case's overrides. Everything else comes from the
family's declared defaults, which is why those defaults live in the port rather
than the test harness.
Defaults are per-family, not shared
ring_corner_radius_mm is 2.00 in 3x and 1.25 in 4x. The two generators
declare their own parameter blocks and they are not identical. Do not assume a
value read from one file applies to the other. 4x also declares
rectangle_aspect, which 3x has no equivalent of, and its base-check list is
correspondingly one entry longer.
Check order is the reporting order
The reference reports the first failing check, not an aggregate. Base checks
run before profile checks, and both run before any geometry is measured — a
builder that failed returns an empty profile, and centred() on an empty profile
has no members to measure.
Report values are rounded to six significant figures
The oracle records what OpenSCAD's echo printed — C's %g at default
precision — not full-precision geometry. echo_num() does this; echo_vec()
handles vectors, which reach the oracle as strings like
'[20.5209, 20.5209, 20.5209]'.
Load-bearing, not cosmetic — and it is now the basis of the tolerance model.
Because the oracle holds six significant figures, the last recorded digit of
an area near 200 mm² is worth 0.001 mm², and the whole measured disagreement
between port and reference is one, two or three units in that place. See
docs/ACCEPTANCE.md.
Historical note, since it was the visible symptom for two sessions:
VOLUME_MM3 ends in _MM3, so the old comparison judged it at the lengths
tolerance of 1e-4 against a magnitude near 20,000 — 5e-9 relative, demanded
of discretised geometry, by accident of key naming.
Angles are degrees; the arbitrary constants are contract
OpenSCAD trigonometry is in degrees. The port keeps degrees throughout with
explicit cos_d/sin_d/tan_d so every expression matches its source line. The
44 solver iterations, the 0.999 and 0.98 scale factors, the 0.05/179.95 degree
cutoffs and the 1e9 sentinel are reproduced exactly. They produced the frozen
values.
Environment
Shapely 2.1.2 on GEOS 3.13.1 — keep these in step, boolean results on
near-degenerate geometry can shift between GEOS releases. numpy 2.4.6. Shapely is
in requirements-base.txt, the 2D path's own dependency set.
No CAD kernel is installed in CT 100. cadquery, OCP and build123d are
all absent, though requirements-cad.txt says it is installed by default. That
is the strictest environment for developing the 2D path.
STL export does not need one, and an earlier version of this section implied it did. A member here is prismatic by definition — a 2D section swept along a straight axis — so an STL is two triangulated caps plus a quad strip down the boundary. That is not a kernel problem.
Verified in CT 100 on 11 SEP: shapely.constrained_delaunay_triangles is
present in Shapely 2.1.2 and triangulates a polygon with a hole correctly —
summed triangle area equals the polygon area exactly, and no triangle falls
inside the hole. The second check is the one that matters: a triangulator that
fills bores would produce an STL that looks right in a slicer and prints solid
where the conduit goes.
STEP does need the kernel. requirements-cad.txt pins cadquery>=2.4 for it.
What is verified against the reference
Every dimensional quantity is exact to 1e-4 mm across all 123 cases, with no
exceptions. ENVELOPE_X_MM, ENVELOPE_Y_MM, MIN_WALL_ACTUAL_MM, and every
profile extra: AF_*, FIN_*, SPOKE_*, RING_*, T_*. Every count is exact.
All ten rejections fire correctly, including the bespoke A Frame and T paths, which were written from the join primitives rather than from a shared arrangement. That is strong evidence those two are structurally right.
Only SECTION_AREA_MM2 and its two derivatives ever disagree. See §7.
6. Probing the reference directly
The pinned toolchain image is in CT 100 and OpenSCAD will echo whatever you ask it. This settled F-034 in four exchanges and will settle any later disagreement the same way. Prefer it to reasoning.
Mount the tree read-only and keep the probe on a separate writable mount —
Docker runs as root, and a read-write mount against a mechcomp-owned tree is
the F-033 hazard. A nested single-file mount inside a read-only mount fails with
EXIT=125; give the probe its own directory.
pct exec 100 -- bash -c 'mkdir -p /tmp/probe && cat > /tmp/probe/p.scad << "EOF"
include </repo/legacy/openscad/lib/sb-core.scad>
$fn = 48;
g = sb_geo(15.875, 0.508, 1, 0.25, 1.20, 1.20, 1.20, 1.20);
echo(str("PROBE=", sb_area([sb_sleeve_path(sb_member(0,0,0), g)])));
EOF
docker run --rm -v /var/www/mechcomp:/repo:ro -v /tmp/probe:/probe -w /probe \
mechcomp/reference-toolchain:8.0.0 \
openscad -o /tmp/o.stl --export-format=asciistl p.scad 2>&1 | grep -E "PROBE|ERROR"'
EXIT=1 is normal — STL export fails on 2D geometry, the echoes still arrive.
The oracle itself is stable. The gate was run on 19 AUG: all 123 cases
regenerate byte-identically inside the pinned image, 113 accepted and 10
rejected, the only diff being frozen and the hash containing it.
verify.sh --full's restore path was broken, is now fixed, and is still
unexercised (F-033).
Instrumenting the port is equally cheap. Monkeypatching
mechcomp.geom.rounding._circlecorner to print its half-angle and segment count
turned the F-034 diagnosis from inference into measurement in one command. The
module calls it through the module global, so patching the attribute works.
7. F-034 — measured, decided, closed
The port is exact. The reference is noisy. That is the opposite of what the entry previously implied, and it changes what can be done about it.
_circlecorner computes raw = (90 - angle)/180 * segs(r, None, fn) and takes
ceil(raw). At $fn = 48 a 90° corner has half-angle 45, and (90-45)/180*48
is exactly 12. A ceiling on an exact integer is a knife edge.
Measured: the port prints half=45 raw=12 ceil=12 at %.17g — landing dead on
the integer, every call, both families. The reference's arithmetic lands a hair
under 45° at some corners, pushing raw fractionally above 12 and the ceiling to
13. On Rectangle: reference envelope 50 vertices, port 48 (13+13+12+12
against 12×4).
Do not try to fix this. Rounding before the ceiling was tried and reverted — it fixes Y exactly and breaks Three-Fin, because Three-Fin has the same asymmetry and the oracle records it. There is nothing to correct on the port's side.
Scale of the effect
30 of 113 accepted cases affected. 83 exact. Only three keys ever breach:
SECTION_AREA_MM2 (29), VOLUME_MM3 (30), MASS_G (22) — and volume is area
×100, mass is volume ×density/1000, so each case has one discrepancy reported
three times. Worst relative error 2.24e-05.
By profile: Three-Fin 9, Y 7, A Frame 5, Rectangle 5, T 1, Four-Fin 1. None on Equilateral, General Triangle, Square, Diamond or Cross.
Why the test fails when the geometry is fine
At $fn = 48 a chord deviates from its true arc by r(1 − cos 3.75°) =
r × 2.1413e-3: 2.68 µm at r=1.25, 4.28 µm at r=2.00. The port and the
reference differ from each other by at most ~0.4 µm. Against the 0.01 mm
criterion (§3) that is two orders of margin.
The tests fail because VOLUME_MM3 is compared at 1e-4 absolute against a
magnitude near 20,000 — demanding 5e-9 relative agreement from discretised
geometry. 3x/Y/steel0.79 breaches on VOLUME_MM3 alone while its area passes:
the same discrepancy, judged by two wildly different standards by accident of key
naming.
The options, and the constraint
Do not edit tolerance in the oracle JSON. It is inside the hashed document;
test_integrity_hash covers everything but fixtures_sha256. Editing it breaks
that test by design.
The change belongs in test_oracle.py, which is not hashed:
- Scale-aware bounds for the three discretisation-limited keys, derived from the 0.01 mm criterion and the section perimeter. Most faithful to where the error originates. Recommended.
- A relative floor — pass if within absolute tolerance or ~1e-4 relative.
Simplest; loosens
SECTION_AREA_MM2from 0.001 to ~0.02 mm². - Accept 30 known failures. Honest but
make testis never green and a real regression hides among them.
Closed 22 AUG. Option 1's scope was kept — the three keys, the change in
test_oracle.py, the oracle JSON untouched — but its derivation was
rejected on measurement and replaced.
Measuring |dA| / P, the boundary displacement that would produce each area
discrepancy, gives a maximum of 1.434e-05 mm: one seven-hundredth of the
0.01 mm criterion. A perimeter × 0.01 bound would have been 1.86 mm² at the
smallest section and 4.54 mm² at the largest, between 1,800 and 4,500 times
the worst real discrepancy, and would have caught nothing. Perimeter also
anti-correlates with the error — the largest discrepancy is at P = 209 mm and
the smallest at P = 454 mm — because the error is driven by how many corners
tip from 12 segments to 13, not by boundary length.
What replaced it: eight units in the last place of the oracle's
six-significant-figure record, for those three keys only. Worst case uses
37.5% of its bound, mutation-tested before landing. docs/ACCEPTANCE.md is
the specification — read it before touching any tolerance, and note E-4:
everything that positions material stays exact at 1e-4 mm and must never be
moved into that regime.
8. Method that has earned its keep
Read the pinned source; do not recall it. BOSL2 was fetched at
92d697c2856de2fed93a33e858068589cefc2898 and read directly. Every function
examined had a detail that mattered and that recollection would have got subtly
wrong. The same applied to the generators: reading sb-profiles.scad before
writing four_x.py confirmed the call signatures rather than inferring them from
call sites.
Check the invocation before concluding anything about state. A su that
failed identically on two commands read as a repository problem and was an
invocation problem. That is the F-027 pattern and it cost a session's opening
exchange.
Verify your own arithmetic before shipping it. A claim in PRECISION.md that
a 50 mm radius needs facets ≈ 460 was wrong — deviation falls with the square
of the segment angle, so the count grows with the square root of radius and the
answer is 158. A three-line script caught it.
Mutation-test every suite before landing it. Break the code deliberately and confirm the tests notice. This found real gaps in five of six slices. It also caught a malformed mutation of mine — cutting the cavities twice is idempotent. A surviving mutation is sometimes a bad mutation, not a test gap.
Set PYTHONDONTWRITEBYTECODE=1 and clear __pycache__ between mutations. A
stale .pyc once masked a real defect, and every mutation result reported
before that was caught was optimistic by an unknown amount. A mutation that
survives because the test ran old bytecode is indistinguishable from one that
survives because the test is weak — F-027 in different clothes, and the reason
that rule is general rather than about one harness.
Read-only before write. Every command group where the answer was not certain established the facts first.
One task, one command group, wait for output. Not a menu of next steps. If you find yourself writing "and also", delete it.
9. What the project is for
Build the capacity to construct real structures — the reference case is a faceted timber shell — from reclaimed and commodity materials, using whatever fabrication is to hand. The compiler makes the pieces computable, qualifiable, and reproducible by someone who was not present when they were designed.
Codes and permitting are out of scope, deliberately. The project records physical claims, never verdicts. Measure and attest; never adjudicate.
Three artifact classes: members (prismatic, exist — the eleven profiles), nodes (non-prismatic, no representation yet), panels (sheet, none yet).
A node is not an assembly. It is another artifact — non-prismatic, carrying
several declared interfaces — and it stays inside scope. What is out of scope is
positioning artifacts relative to one another, which is field work and belongs
to whoever is holding them. PRECISION.md §7 states the ruling and the reason.
The consequence is the project's actual obligation: make each artifact interchangeable. Fully specified, independently reproducible, carrying its own declared interfaces so the field can fit it to whatever it meets. The stock descriptor and the design record exist for exactly that, and it is the standard any new capability should be judged against.
The output must eventually be sealed manifolds and printable STL. The 2D
section is where manifold validity is decided, not downstream in the CAD kernel —
is_region_simple is already a build-blocking check, and a self-touching outline
extrudes into something untessellatable.
docs/PRECISION.md states what this compiler does not do: no assembly layer,
no structural analysis of any kind, prismatic shapes only, no toolpaths. That
document is scope-locked to additive and subtractive manufacturing. Requests to
widen it should be refused, not accommodated — see its §10.
10. Working with this operator
He is precise, keeps excellent records, and will tell you directly when you are wrong — including when you are being unhelpful. Take it at face value; it is accurate and it is not personal.
He decides. Bring evidence and a recommendation, then stop.
He has delegated all coding decisions — structure, algorithms, test design — and does not want to be consulted on them. Still bring him scope, provenance, and anything irreversible on the host. He runs every command, so nothing is autonomous regardless.
When he says he does not understand something, the writing was unclear. Rewrite it shorter; do not explain it again at greater length.
He watches for scope creep and treats it as the primary risk — "the greatest enemy of software is not bugs, it's feature-creep". Documents and code are both held to it. When in doubt, narrow.
11. Open questions, none blocking
| # | Question | Owner |
|---|---|---|
| 1 | Should wg-pk narrow mynetworks from 10.110.0.0/22 to explicit hosts? |
CIVICVS, estate decision (F-025) |
| 2 | Backup strategy — USB, IPFS, optical? | CIVICVS |
| 3 | Where is the 3+ TB USB disk attached? | CIVICVS |
| 4 | Kane Fabric participant mail, send and receive | Cross-project |
| 5 | Closed 22 AUG. See §7 and docs/ACCEPTANCE.md |
|
| 6 | Is the bore's fit class per-material, or one clearance for all inserts? | CIVICVS — raised by the conduit-core requirement, §4 |
| 7 | dev.mechcomp.kane-il.us |
Closed 11 SEP at 1fdb115. Executed without the WireGuard change the work order proposed |
| 8 | TLS renewal has never been observed to succeed for this name; first due before 2026-12-10 | CIVICVS |
| 9 | The composer has no acceptance criteria of its own — only the path to it does | Architect |
| 10 | The service is world-reachable and unauthenticated | CIVICVS; §4 item 5 makes this due rather than hypothetical now that it is published |
| 11 | Should ct-baseline.sh check the ownership of a service's working tree? |
CIVICVS — host property, raised by F-037 |
Question 4 is real and unaddressed. Containers do not send mail by standard and
nothing can reach vmbr1 from outside, so receiving has no path at all. It needs
a design conversation, not a configuration change.
12. Commit log
a8081e1 state: the composer replaced the placeholder; open public ingress
14514b0 web: the composer, served behind the existing proxy chain
e921cac design record: every build emits one
d2827c2 design record: what a model was made from, sufficient to regenerate it
70787ea stock: records delegates to the descriptor, and the descriptor stops gating
f5651d3 stock: name the COTS descriptor; the strap becomes the first entry
6836ece tests: close F-034; bound the derived trio at 8 ULP of the oracle record
52d00b5 docs: HANDOFF header commit line moved to b255ebb
b255ebb docs: F-034 rewritten from measurement; handoff updated
114189c docs: PRECISION.md -- scope, guarantees and limits, for lay readers
7b3182c port: the 3x and 4x profile catalogues; build() now exists
af196a2 docs: one canonical handoff, rewritten in place; F-035
009fcce docs: handoff for the 19 AUG session
86a47c3 rounding: record F-034, arc segment counts tip on the last bit
8d79431 geom: port sb-core and sb-profiles, the N-generic arrangements
b101fe6 geom: port sb-report, validation and report formatting
ebf02d6 geom: port sb-join, the junction and envelope strategies
38ea024 geom: Shapely-backed region layer
545eee7 geom: port BOSL2 round_corners and path cleanup
dfd02a4 geom: port the pure-geometry half of sb-geom
b67cc12 verify.sh: reach the restore on the diff branch
1d3eed0 Handover push
6967eef Conformance updates.
c7e32d8 Seed repository: rev-8.0.0 reference, frozen oracle, toolchain, test harness