cooling.gate-off: a gate setting trips in range and is off at its far end

The acceptance catalog gains the test behind forgectrl 9e44fdc: the
coolant ceiling set just over its legal minimum must trip OVERTEMP with
a hold and fire blocked at the next run start; set to its top the engine
must skip the gate (verdict OK), report it in gates_off on /status and
/cool/status, and log the run-start line; the original values are
restored, on failure too, and proven restored. Five host cases against a
scripted engine. The cooling covers map now names the files that carry
gate state (gates, settings, status, the panel) and corrects a glob that
matched nothing: the GRBL cooling client is src/glowforge_cooling.c, not
src/gfcool*. The fake forgectrl serves /logs/tail and keeps blank form
values as "clear", which is what the daemon does with them.

Docs: COOLING.md section 8 carries each setting's legal range and
recommended band and a new 8a on turning a gate off; SAFETY.md names
what no setting can reach; ACCEPTANCE.md records that gates are
exercised through the settings API, never GFCOOL_* env overrides;
BRINGUP item 19 records the pattern as landed and the catalog is 43.

forgectrl pin moves to 9e44fdc; fetch-verified.
This commit is contained in:
ScottW514
2026-08-21 17:06:49 -04:00
parent f4b70a0826
commit bf3483e994
8 changed files with 344 additions and 26 deletions
+5
View File
@@ -235,6 +235,11 @@ tests:
2. does that test's `covers` map name the files touched - if not, widen it
in the same change.
A gate or a limit is exercised through the settings API (a value a healthy
machine cannot meet, re-read by the engine at the next run start, restored
by the test's own teardown), never through `GFCOOL_*` environment overrides,
which need a daemon restart and stay bench-only.
A behavior change with no catalog consequence needs a sentence of
justification in the commit message. Coverage gaps are defects: under the
domain model an uncovered path lets an inherited PASS stay valid across a
+16 -3
View File
@@ -48,7 +48,7 @@ hardware-validated.**
modes (cancel-and-return on a lid or interlock open, button pause/resume),
bench-validated 2026-08-17.
- **Releases are gated by the acceptance tool** (`forgetest`, dev image only):
a 42-test catalog, domain-scoped inheritance, an always-required safety core,
a 43-test catalog, domain-scoped inheritance, an always-required safety core,
and a release gate that reads the exported artifact. The full campaign on
dev image `20260821181036` (the first built on the `<recipe>-pin.inc`
layout) satisfied 42 of 42 and its export authorizes a release;
@@ -579,12 +579,13 @@ under the domain model from the day's earlier dev images) and the export reads "
YES" for that image's manifest. That authorizes a release; it is not one
until `releases/v<version>/acceptance.json` is committed.
- **Catalog: 42 tests** in `forgetest/forgetest/suite/`, every one a port of a
- **Catalog: 43 tests** in `forgetest/forgetest/suite/`, every one a port of a
proven bench drill or a bench-verified check — the always-required core
(`image.health`, `kernel.latch-locked-idle`, `kernel.k1-k2`,
`kernel.fire-line`), `forgectrl.*`, `logs.*`, `update.*`, `motion.*`
(pacing, jog round-trip, liveness probe, cancel/abort, dead-man, the lid,
interlock and button parity tests), `cooling.*`, `camera.snapshot`,
interlock and button parity tests), `cooling.*` (flow verification, fans
quiet after motion, a gate setting tripping and off by value), `camera.snapshot`,
`laser.*` (emission witness, arm-wait lid, disarm-in-hold, armed kill,
pause/resume/lid-cancel) and `cloud.*`. Tests that share a setup are merged;
the `auto` tests stay separate for failure isolation.
@@ -1314,6 +1315,18 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
data format, both checked before a byte reaches the ring) and drops the
rest. Seventeen of the mandatory ones are among the dropped.
**Landed first, the pattern every gate ships on:** a gate is a plain
setting with a wide legal range, a recommended band, and an off end (a
ceiling at its maximum, a window of zero) that turns the gate off by
value, with no separate switch; the panel warns outside the band and
while any gate is off, the engine logs each gate setting at every run
start, `/status` and `/cool/status` carry `gates_off`, and an off gate
keeps measuring. Applied to the coolant ceiling, its resume gate, the
flow window and the flow rise (`forgectrl/src/gates.c`, `SERVICES.md`
"Gate settings", `COOLING.md` §8a, `cooling.gate-off` in the catalog).
The fan gates, the pass-through of header limits, the coolant critical
tier and the watch-only board temperatures follow on it.
Nothing here can put energy where it was not commanded: the hardware chain
is the emission boundary and no header field touches it, and forgectrl runs
its own coolant ceiling, flow verification, emission witness, liveness gate
+37 -12
View File
@@ -300,25 +300,49 @@ All of these live in the panel's Machine tab, are validated on entry, and can
only be changed while the machine is idle. The engine re-reads them at the
start of every run, so a change takes effect on your next job.
| Setting | Default | What it controls |
|---|---|---|
| `cool_flow_rise` | 14.4 °C | Downstream rise that counts as no-flow. Set this from **flow calibrate**. |
| `cool_flow_heater_pct` | 40 % | Heater duty during a check. Raising it separates the bands further at the cost of warming the loop more. |
| `cool_flow_check_s` | 50 s | Length of a check window. `0` disables flow verification entirely. |
| `cool_recheck_s` | 150 s | How often checks repeat during a job. |
| `cool_confirm_max_s` | 480 s | How long a suspicion may stay unresolved before it escalates to a fault. |
| `cool_temp_max` | 33 °C | Run ceiling — above it, hold. |
| `cool_temp_resume` | 31 °C | Resume gate — below it, continue. |
| `cool_cooldown_s` | 15 s | Smoke-clear phase at run duty after a job. |
| `cool_cooldown_max_s` | 300 s | Cap on the thermal cooldown phase. |
| Setting | Default | Legal range | Recommended | What it controls |
|---|---|---|---|---|
| `cool_flow_rise` | 14.4 °C | 1 to 40 °C | 8 to 16 °C | Downstream rise that counts as no-flow. Set this from **flow calibrate**; above the band the check can never fault. |
| `cool_flow_heater_pct` | 40 % | 0 to 100 % | | Heater duty during a check. Raising it separates the bands further at the cost of warming the loop more. |
| `cool_flow_check_s` | 50 s | 0 to 300 s | 30 to 120 s | Length of a check window. `0` turns flow verification off (§8a). |
| `cool_recheck_s` | 150 s | 0 to 3600 s | | How often checks repeat during a job. |
| `cool_confirm_max_s` | 480 s | 60 to 3600 s | | How long a suspicion may stay unresolved before it escalates to a fault. |
| `cool_temp_max` | 33 °C | 5 to 60 °C | 25 to 38 °C | Run ceiling: above it, hold. `60` turns the gate off (§8a). |
| `cool_temp_resume` | 31 °C | 5 to 59 °C | 20 to 36 °C | Resume gate: below it, continue. Always kept below the ceiling. |
| `cool_cooldown_s` | 15 s | 0 to 1800 s | | Smoke-clear phase at run duty after a job. |
| `cool_cooldown_max_s` | 300 s | 0 to 1800 s | | Cap on the thermal cooldown phase. |
Two settings are deliberately not on the panel:
- `cool_fire_ir_delta` — the lid-IR fire gate (§7). It is `0`, watch-only, and
- `cool_fire_ir_delta`, the lid-IR fire gate (§7). It is `0`, watch-only, and
changing it by hand is not recommended until the watch is lamp-aware.
- `GFCOOL_*` environment overrides exist for bench work; they win for the
lifetime of the process and are not a normal operating path.
### 8a. Turning a gate off
The gates are settings, and the far end of a gate setting's range is the off
switch: a coolant ceiling of 60 °C never trips, and a check window of 0 s runs
no flow verification at all. There is no other switch, and no list of names to
get wrong. The ranges are wide on purpose: the shipped defaults and the
recommended bands come from one bench machine, and a machine whose loop or
sensors read differently changes the number rather than waiting for new
firmware.
A gate that is off is not a gate that is forgotten. The panel flags any value
outside its recommended band beside the field and says "this gate is OFF" at
the far end; the Status tab shows a standing banner while any gate is off; the
engine logs one line per gate setting at every run start, and with the ceiling
off it still logs the first reading in a job that would have tripped the
default. `/status` and `/cool/status` carry the off gates as `gates_off`.
Nothing about it reaches the cloud service.
What no setting can reach: the hardware safety chain, the laser latch, the
emission witness, the lid-IR fire watch, the controller-silence dead-man, and
the motion-liveness gate. A machine with every thermal gate off still stops
firing the moment its controller goes quiet; what it no longer does is hold a
job for a stopped pump or an overheating loop. The banner says so.
---
## 9. Not implemented yet
@@ -348,6 +372,7 @@ Stated plainly so nobody counts on them:
| Suspicion unresolved past the budget | Escalates to `FAULT`. |
| Three cleared suspicions in one job | Aggregated "check your coolant" warning. |
| Upstream coolant above 33 °C | `OVERTEMP`: hold + forced cooling; auto-resume under 31 °C. |
| A gate setting at its off end (ceiling 60 °C, check window 0 s) | No verdict from that gate; a run-start log line, `gates_off` in `/status`, and a standing panel banner. |
| Job ends | 15 s smoke clear at run duty, then reduced airflow until the loop is under the resume gate. |
| Controller stops reporting | Fire blocked at once, stand-down through cooldown. |
| Silence while armed, or a program still playing | Motion stopped and the latch locked by the engine itself. |
+5 -1
View File
@@ -205,7 +205,11 @@ would not allow.
finish the queue tail so a controlled stop can never leave FIRE driven.
- **Coolant fire gates.** The armed window requires a fresh `fire_ok` verdict
from the cooling engine (flow verification, over-temperature, lid-IR
emission witness); a stale or failed verdict relocks in-process.
emission witness); a stale or failed verdict relocks in-process. The
thermal gates are settings with a wide range whose far end turns the gate
off by value (`COOLING.md` §8a), loudly; the fresh-report rule, the
emission witness, the dead-man and the latch are not settings and stay in
force whatever the gates are set to.
- **Safety door.** `doors` (lid) and `interlock` (loop open) are the core's
safety-door signal, shown to the core only while it is in a job-time state
(cycle, hold, tool change, door): a running job parks with a planned