Record the download guards and the feed watchdog

BRINGUP's cloud item said a print is capped by the ring and listed the two
gaps that closed when it stopped being. It now says what bounds a print
(memory, through pulse_reject_threshold_bytes) and what catches a feed that
wedges (progress against room, not ring depth), and it names the two new
cases that cannot be induced from the bench: a body past the memory guard,
because the service has no such job to send, and a wedged feed, because a
healthy machine will not stall on request.

forgectrl.settings-bounds gains a probe at the far end of the new byte
range, so the validator behind those keys is exercised rather than assumed.
This commit is contained in:
ScottW514
2026-08-20 09:23:10 -04:00
parent 0203887dc9
commit e3d23b8099
2 changed files with 24 additions and 9 deletions
+17 -9
View File
@@ -972,15 +972,23 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
for them under `/data` on a machine booted into the factory slot before for them under `/data` on a machine booted into the factory slot before
deciding whether to reimplement the mechanism. Finally the deferred emulator deciding whether to reimplement the mechanism. Finally the deferred emulator
homing-image smoke, now that the emulator can be pointed at live snapshots. homing-image smoke, now that the emulator can be pointed at live snapshots.
7. **Cloud mode.** The remaining gaps are tracked in 7. **Cloud mode.** A print is no longer capped by the ring: the client holds
`python3-gfhardware/forgefirm-app/docs/CLOUD.md` "Outstanding items": the compressed body, fills the ring before the button, and tops it up as it
streaming-during-run (would lift the ring-size cap on job length), plays, with the body bounded by `pulse_reject_threshold_bytes` because
oversize-job rejection against a real too-big job, packaged-path boot with memory is what that costs. A feed that wedges is caught by progress rather
`controller_mode = cloud`, the three unobserved actions, the lid-flash LED, than by ring depth (a healthy feeder keeps the ring brim-full, so depth
and taking the pause constants from the pulse header (`CCbp`/`CCbt`) once a only falls an hour after the feed died): thirty seconds of no progress with
capture confirms them. Not inducible from the bench: the room in the ring stops the job cleanly and retraces, and it resumes if the
cancel-with-a-rejected-`settings`-action case and a malformed frame (needs a feed moves again. The remaining gaps are tracked in
MITM). The pulse header's unenforced safety envelope is item 19: it is `python3-gfhardware/forgefirm-app/docs/CLOUD.md` "Outstanding items": a
live job longer than the ring (built and covered, never yet run from the
service), the memory guards against a real ceiling rather than a reasoned
one, packaged-path boot with `controller_mode = cloud`, the three unobserved
actions, the lid-flash LED, and taking the pause constants from the pulse
header (`CCbp`/`CCbt`) once a capture confirms them. Not inducible from the bench: the
cancel-with-a-rejected-`settings`-action case, a malformed frame (needs a
MITM), a body past the memory guard (the service has no such job to send),
and a wedged feed (a healthy machine will not stall on request). The pulse header's unenforced safety envelope is item 19: it is
listed separately because the enforcement lands in the cooling engine and listed separately because the enforcement lands in the cooling engine and
has to hold in GRBL mode too, not only under the cloud client. has to hold in GRBL mode too, not only under the cloud client.
8. **Shared machine services — remaining polish.** None of it blocking: 8. **Shared machine services — remaining polish.** None of it blocking:
+7
View File
@@ -129,6 +129,13 @@ def settings_bounds(ctx):
ctx.log("POST /settings laser_disarm_s=99999 -> %s", st) ctx.log("POST /settings laser_disarm_s=99999 -> %s", st)
ctx.check(st == 400, "out-of-range value -> %s, expected 400", st) ctx.check(st == 400, "out-of-range value -> %s, expected 400", st)
# The cloud download guard is bytes, so its range is far wider than the
# other numeric keys: check the far end is still a wall.
st, body = fc.post("/settings", data={"pulse_reject_threshold_bytes": "2000000000"})
ev["pulse_bytes_out_of_range"] = st
ctx.log("POST /settings pulse_reject_threshold_bytes=2000000000 -> %s", st)
ctx.check(st == 400, "out-of-range byte limit -> %s, expected 400", st)
st, body = fc.post("/settings", data={"no_such_key_forgetest": "1"}) st, body = fc.post("/settings", data={"no_such_key_forgetest": "1"})
ev["unknown_key"] = st ev["unknown_key"] = st
ctx.log("POST /settings no_such_key_forgetest=1 -> %s", st) ctx.log("POST /settings no_such_key_forgetest=1 -> %s", st)