Repository navigation
Tasklist O and P: the hardware build, and where programs come from - #3
Merged
Merged
Conversation
OQ-09 asked where programs are authored now that the web is read-only, and offered a display editor, a file import, or shipping only the examples. The answer is the third, as a decision rather than as a default: the profiles are compiled into the firmware and there is no authoring path anywhere. SWR-PRG-07 (create, update, rename, duplicate, delete over the web), SWR-PRG-08 (export and import as JSON) and SWR-PRG-10 (edit the remaining segments of a running program) are withdrawn with the reasoning kept. SWR-PRG-05 validates on start, since there is no save. SWR-PRG-09 now says what it has become: the examples are the device's whole repertoire. THE COST IS REAL AND IS WRITTEN DOWN RATHER THAN MINIMISED. A potter who wants a curve of their own needs a toolchain and a flash, which for most of them means somebody else does it. OQ-09 says so in those words, and names the cheapest reversal if it proves too expensive in use: the file import at service time, which needs physical access and so leaves the security argument intact. What it buys is that there is nothing to secure. No write route, no file format to validate, no parser taking operator data on the processor that commands a heater, and no editor to design for a rotary encoder. The web caught up with it. The Programs view called itself an Editor and was a set of permanently disabled inputs with a note offering to copy an example so you could make changes, which was untrue in three ways at once. It is a program view now: the name and description as text rather than as dead fields, the segments, the curve, and a notice that says where programs come from. The empty save-result line and the empty controls bar are gone with it. Verified by rendering it: three profiles listed, no editor, 25 host suites still green. What this decision leaves behind is recorded as P3 rather than done: kiln_program_store_save and kiln_program_store_delete are now called by nothing but their own tests, and SWR-PRG-04 asks for 20 persistent slots to hold three programs that arrive with the firmware. Removing the store for programs is the consistent finish and it deletes tested code, so it wants a decision rather than momentum.
…ilding it Checking tasklist O and P found something larger than any item in them. Every CI job builds sdkconfig.qemu, which sets CONFIG_KILN_PLANT_SIM and compiles the WiFi, the HTTP server and the whole hardware path out of main.cpp. The configuration that will actually ship was therefore guarded by no build at all, and O3 claimed "it compiles and passes analysis" on that basis. Built for the first time today. It did not compile: two -Wformat-truncation errors, one in the version string that has been there far longer than the WiFi work and one mine from the network scan. Both are bounded explicitly now, which is the same fix the SSID row in hmi.cpp needed last week and the same lesson: truncation written as "%s" into a shorter buffer reads as an accident, and GCC is right to say so. CI builds the hardware configuration on every push now, with a size report in the job summary. It is a build and not a test, because nothing in CI can run it; what it buys is that the half of the firmware aimed at real hardware cannot rot unnoticed between now and the first board. MEASUREMENTS, replacing numbers that predated several IDF releases: the hardware image is 888 kB, 57 % of the OTA slot free, against O2's claimed 831 kB. The simulated image CI publishes is 246 kB and has no WiFi and no HTTP server in it at all, which is worth keeping straight when reading a size report. the web assets are 18 kB gzipped against architecture 12.4's 44 kB budget: index.html 2.2, app.css 3.6, app.js 8.6, chart.js 4.2. That budget had never been measured against real assets, which P1 gave as a reason it was not done. It passes with room, and embedding them takes the hardware image to about 906 kB.
P1 said the UI is not served: no index.html in the firmware, a browser at the device gets a 404, and the API is usable with curl and nothing else. The four assets are gzipped at build time and linked in as binary data now, and httpd answers them before it consults the route table. VERIFIED WITHOUT HARDWARE, which is the part worth describing. The assets were extracted from the linked ELF by address, inflated, and compared byte for byte against the files in web/. All four round-trip. That is not the same as having served one over a socket, and P4 still says so, but it does establish that what is in the image is the interface rather than something shaped like it. index.html 2281 gz -> 7090 app.css 3656 gz -> 11772 app.js 8846 gz -> 24695 chart.js 4316 gz -> 12762 Architecture 12.4's budget was 44 kB gzipped and had never been measured against real assets, which P1 gave as a reason the work was not done. It is 18.6 kB. The hardware image goes from 888 kB to 908 kB, 56 % of the slot free. THE SIMULATED IMAGE IS UNCHANGED AT 246 kB, and that is the linker rather than a special case: CONFIG_KILN_PLANT_SIM compiles out the call that starts the server, nothing then references the asset table, and --gc-sections drops the blobs with it. The configuration that cannot serve the interface does not carry it, without anybody arranging that. Decisions in here worth the reader's time: Gzipped at BUILD time, not committed compressed, so the source of truth stays the readable file in web/ and nobody has to remember to recompress. `gzip -9 -n`, because without -n the header carries an mtime and the image stops being reproducible from the same sources, which the SBOM and the release both assume. Served still compressed. Every browser that can run this can inflate it, and doing it on the device would cost a window buffer per request on the processor running the kiln. Exact-match lookup against a table of four, no path walking. There is no filesystem behind this, so ".." is not dangerous, it simply matches nothing. Cache-Control: no-cache, which means revalidate rather than do not store. A firmware update changes all four assets at once, and a browser holding a stale app.js with a fresh index.html is the failure worth preventing; a 304 on a LAN costs nothing. Found on the way: GCC rejects "/api/*" inside a block comment (-Wcomment), so the comment says "the API routes" instead.
SWR-NET-04 has been open since mDNS left the ESP-IDF tree for the component
registry. The options were vendoring several thousand lines of somebody
else's protocol implementation, dropping the requirement, or taking the
dependency; UR-CON-04 forbade the third only insofar as it forbade an
unpinned fetch, so it is reworded to say what makes a fetched component
auditable rather than to forbid fetching:
1. pinned exactly, never to a range,
2. the resolved dependencies.lock committed, so what a release was built
from is recoverable from the repository alone,
3. present in the SBOM with its licence.
Web assets stay vendored at any version: they are reachable from the network
at run time and the component manager's integrity check does not cover them.
espressif/mdns 1.14.0 is Apache-2.0, which distributes under GPL-3.0.
tools/sbom.py gains managed_component(), because the generic path described
this as esp-idf-espressif__mdns at v6.0.1 -- the IDF version, for the one
entry in the inventory whose own version is the point. A CRA Article 13(1)
question about a known vulnerability is answered by matching a version, so it
is now listed as espressif/mdns 1.14.0 with pkg:idf/espressif/mdns@1.14.0 and
the registry content hash. Folded YAML values are unfolded rather than cut
mid-word. 12 new self-tests, 85/85.
ADV-6 no longer claims there is no package manager at build time, which had
become false. TH-13 pointed at the withdrawn SWR-NET-05 (the access point's
passphrase rule) for a threat about mDNS; it points at SWR-NET-04.
Hardware image 940 kB, 54 % of the slot free: mDNS costs 32 kB. The simulated
image is unchanged at 246 kB, since hal_net is compiled out of it.
…them
Q1 was recorded as an accepted trade and the trade was made against the
wrong failure mode. A NOR sector at the end of its life does not report an
error: it takes the write, returns success, and holds something else. The
store's answer was the CRC on the next read, which on this device is after a
firing rather than during the write it could still have redirected.
Every write is now read back and re-validated through read_copy, the same
path a mount uses, before the in-RAM index points at it. A copy that does
not verify retires its region and the write is re-attempted in a free region
at a higher seq, up to KILN_FILESLOT_WRITE_TRIES regions. The caller gets
KILN_OK, because the file is stored; what changed is where.
Retirement needs no bad-block table. After the new copy verifies, the old
region is erased best effort:
- it succeeds, so no stale copy remains to undo a later remove at the next
mount, and the region returns to the pool at the next boot, which is the
right answer for a sector that can still be erased rather than a life
sentence passed on one bad write;
- it fails, which is what a finished sector does, so the stale copy stays
at a LOWER seq. Two regions then claim one name, and mount resolves it
the only way it can be true: the lower seq is the write that failed, its
region is retired again, the higher seq is the file.
A power cut between the verify and the erase leaves the same state and is
resolved the same way. Still no wear levelling, deliberately: architecture
10.4 has four orders of magnitude of headroom.
Five tests, driven by two new knobs on the flash fake -- a sector that
accepts a write and keeps zeros, which is the failure no error code reports,
and a sector that will not erase, addressed by offset so the test says which
region is finished rather than how many erases have gone by.
Q2: mount cost measured rather than described, and the description was low
by a third. 768 reads and 47 808 bytes on the medium this firmware produces;
8 192 and 524 288 on a partition full of maximum-size files. Asserted against
a model derived in the test, so making mount lazy fails the suite instead of
happening quietly.
Q4 and Q5 were disclosures with nowhere to live: the name-length refusal is
now stated in port_filestore.h and architecture 10.6 beside the test that
proves it, and run_index's twenty-slot walk is explained in run_index.cpp
where somebody revisiting the file will see it.
The retired count is logged at boot and is the only warning anybody gets
that the part is going.
Verified: 25/25 host tests, the same under ASan/UBSan, kiln_core line
coverage 91.7 % against the 90 % floor, clang-tidy 20 clean on host and
target, both IDF configurations build, and the QEMU smoke test passes all
seven assertions on the emulated flash the store actually runs on.
…g to call Q3. Both were kept for the local program editor of P3, and the decision there was pre-compiled profiles with nothing editing them, so the caller they were waiting for is not coming. What was left was three implementations -- fileslots, the host HAL, the simulator -- and two tests for an interface the product never exercises: code that compiles, is covered, and is dead, which is worse than no code because it reads as supported. exists was read with the answer thrown away, and anything that needs to enumerate a fixed array of numbered slots can count to twenty. The two tests that drove them now drive what has callers: the removal is proved by a read rather than by exists, and the usage test additionally checks that usage survives a remount, since it is answered from the in-RAM index and the mount is the only thing that rebuilds it. 25/25 host tests, clang-tidy 20 clean, both IDF configurations build.
…entlessly
The firing-finished sound was fifteen repetitions of a chirp over thirty
seconds, and the fault sound was a 200/200 ms beat that is more polite than
the situation deserves. Both are rewritten:
completion three 90 ms chirps, then five seconds of quiet. A firing that
took nine hours has finished correctly: that is good news and
wants a notification, not an alarm. hmi.alarm_duration_s
defaults to 4 s rather than 30, so the operator hears the burst
once; the 0 to 600 s range is unchanged for anyone who wants
the kiln to keep saying so until somebody comes.
fault six 60 ms chirps at twice that rate, a 400 ms gap, and again
without end until acknowledged. Meant to be unpleasant and to
carry through a wall.
They differ in rhythm, rate and duty -- a third of the cycle sounding against
a twentieth, over a cycle five times shorter -- which is what SWR-SAF-20's
"audibly distinguishable" has to mean for a part with one tone and no volume
control.
The rhythms moved out of the adapter into kiln_core/alarmptn, a table and a
step function with no clock and no hardware, because in an esp_timer callback
the one thing SWR-SAF-20 requires was asserted by nobody and "continues until
acknowledged" was a comment. The adapter now sets a pin and arms a one-shot
timer for the interval it is handed. Eight host tests, including the
comparison between the two patterns as a comparison, that the fault pattern
never stops on its own, and that a buzzer which cannot be commanded -- null
sequence, or a pattern value that is not one of the three -- is silent rather
than stuck on, since an operator's only remedy for that is the mains switch.
SWR-SAF-20 now states the two patterns and its verification method changes
from Demonstration to Test. SWR-RUN-06 records the new default and why.
Architecture 10.7 carries the numbers.
26/26 host tests, clang-tidy 20 clean on host and target, hardware image
builds, StrictDoc exports clean.
Three things O4 was waiting on, none of which needs hardware. **The frame was English.** kiln_core/faults has carried faults and warnings in both languages from the start, so a device set to German announced its faults in German inside an English frame: every screen title, the whole menu, both answers to a confirmation and every footer were string literals at their draw sites. SWR-NFR-23's "no text embedded at its point of use" was half true, and is now true: 46 strings in kiln_hmi/strings, in two languages, and no operator-facing literal left in hmi.cpp. The German uses the transliteration kiln_core/faults has always used, because draw.cpp's 5x7 font is the 95 printable ASCII glyphs and nothing else -- which answers J1 from the code rather than from a hardware session. Two of the choices are worth knowing: HOLD is WARTET rather than the literal HALT, which a German reader would take as "stopped", the opposite of a kiln that is still firing; and ACK? is QUIT?, from quittieren, which is the verb German machinery uses for acknowledging an alarm. J4 still stands: no native speaker has read any of it. Six tests cover what a reviewer cannot see by reading: nothing missing in either language, nothing over the panel's 21 columns, no byte outside 0x20 to 0x7E, an unknown language falling back to English, an out-of-range identifier answering with nothing rather than a wrong label, and the menu and the confirmation actually changing when the language does. **A failed join now says so.** last_reason was recorded in the adapter and reported to nobody, so the display returned to the network screen saying "not connected" -- which is not an answer an operator can act on, and with the display the only route in (there is no access point), acting on it is the whole job. The screen now separates a join in flight from one the radio refused and prints the code: 15 is a failed four-way handshake, a wrong passphrase in almost every case, 201 is "no AP of that name answered". The number is there to be read out over a phone to somebody who can look it up, which beats a sentence that guesses between three different remedies. kiln_net_status_t carries the field and net_connect clears it, so a fresh attempt is not reported as an already-failed one. **The knob resumes where the last character left it**, which it always did; what was missing was a test saying so, since that property is the sort one "sensible" reset silently reverses. SWR-NET-12 gains the outcome-reporting and resume obligations. SWR-NFR-23 records that the single-resource rule was half kept, and the two constraints the panel puts on German. 26/26 host suites, 39 HMI tests, clang-tidy 20 clean on host and target, hardware image builds, StrictDoc exports clean.
… server SWR-WEB-05 asks for live values at least once a second by push. The payload has been written and tested since kiln_api_telemetry_event landed, and the browser has been asking all along -- app.js opens an EventSource on /api/events and listens for a `telemetry` event -- but nothing answered, so the dashboard went stale after four seconds exactly as SWR-WEB-25 says it should. The handler does not stream. esp_http_server runs one task and serialises handlers on it, so a handler looping once a second would hold that task for as long as a browser tab stayed open: the other sockets would never be served again and the kiln would appear to hang the moment somebody left a dashboard open and then tried to load the log. So the handler hands the socket to httpd_req_async_handler_begin, parks it in a two-slot table and returns. One task at priority 3 -- below the server's 4, far below control and safety -- pushes to every parked subscriber once a second, with an SSE comment frame every fifteen pushes to stop an idle proxy or a phone's radio dropping a stream that is working. Two subscribers of six sockets. A stream holds its socket indefinitely, so letting every socket become one would leave nothing for the page, the log or an update check; a third is refused with 503 and Retry-After, because a client told to come back does and one left hanging does not. Six rather than four because SWR-WEB-21 counts clients, and a client with the dashboard open holds one socket parked and needs another for everything else. The framing lives in kiln_web/api, not the transport: it is the part of SSE that can be got wrong and the transport cannot be host-tested. A frame that does not fit is not written at all, and a payload containing a newline is refused -- a newline in a data field is SSE's own multi-line syntax, so neither mistake fails visibly, both move the frame boundary into the middle of a JSON document and every frame after it is misread. Five tests, including the device's real telemetry payload framed and re-parsed. Driven against a real client over a socket as well: four frames in three and a half seconds, each event: telemetry with a parseable payload and a rising temperature. That found a bug no unit test would have -- the development harness announced Transfer-Encoding: chunked on the event stream and then sent unframed SSE, a response contradicting its own headers, which a browser may reject outright. The log stream stays chunked; the event stream now declares neither and ends with the connection. The harness also uses the shared framing function now, so the format the browser is tested against is the format the device sends. 26/26 host suites, 47 API tests, clang-tidy 20 clean on host and target (including one real null-deref it found in a new test, where CHECK records and carries on rather than aborting), hardware image builds at 54 % free.
P3, finished the way the pre-compiled-profiles decision implied. SWR-PRG-04
asked for 20 program slots in non-volatile storage, and with SWR-PRG-07,
SWR-PRG-08 and SWR-PRG-10 withdrawn there was nothing on the device that
could create or edit one: the store held a copy of the three examples that
arrive in the image and nothing else. Persistence of something already
persistent, in a medium that wears out, behind a seeding path that could fail
on a first boot and a store that could fail to mount.
It is withdrawn, program_store is deleted, and the API, the HMI and the
development harness all read kiln_profile_example.
What that fixed, which is why this is not only a deletion:
- **The local start path worked for the first time.** KILN_HMI_ACT_START
returned KILN_ERR_NOT_FOUND on hardware with a note that there was no
program store, and the view builder never filled the program list. So a
device carrying three firing profiles in its own flash showed "none
stored", and the first entry of its menu did nothing when pressed. Both
are now wired to the compiled-in profiles: SWR-HMI-10 delivered rather
than written.
- A device whose flash will not mount still has its programs. The list used
to answer 503 for programs the firmware was carrying.
- A factory reset no longer costs the operator their programs. The
partition holds run history, and losing history is what a reset is for.
- The first boot has nothing to get wrong.
About 200 lines and nine tests went. The properties worth keeping were
re-pointed rather than dropped: every compiled-in example is a valid program
with a distinct name and an index past the end is refused (it comes off a
URL); the atomic-replace-across-a-power-cut property is now driven through
run_index, which is what still writes to the store and does rewrite a slot
when it marks a run truncated; and the partition-sharing test became the
measurement that 20 of 64 regions are used. /api/storage reports the program
count outside "files", because programs are not files any more and saying
they were said the opposite of what is true.
Q2's mount cost halves with the medium: 488 reads and 31 888 bytes, from 768
and 47 808.
SWR-PRG-05 stays, and the reason is safety.max_temp_c: the programs are
trusted as data, but an operator can lower the ceiling below a program's peak,
and validation on start is what refuses that firing rather than running it
into a limit. A test now asserts every example validates against the default
ceiling, because an example that cannot start is one an operator discovers by
selecting it.
26/26 host suites, the same under ASan/UBSan, kiln_core line coverage 91.8 %
against the 90 % floor, clang-tidy 20 clean on host and target, both IDF
configurations build, StrictDoc exports clean, and the harness still serves
the three programs over HTTP with 404 past the end.
R9. SWR-ACQ-02 fixes the chamber couple at type K because the independent supervisor linearises for it, and a type register this side could change is a backstop that means something else: with the supervisor expecting K and an S couple fitted, the reading at 1300 degC is about a quarter of K's output and the backstop never fires. kiln_suplink's configure already refused, so sense.tc_type was a setting an operator could change and believe while nothing acted on it, which is worse than no setting at all. It is gone from the struct, from the item table and therefore from /api/config and the display. The enclosure channel's type stays configurable; that channel is not in the supervisor's remit. KILN_CFG_SCHEMA_VERSION is 2, and the migration is the part worth reviewing. Every earlier version change ADDED fields, which the prefix copy handles. This one removes a byte from the middle of the struct, so every field after the hole sits one lower: a prefix copy would have landed the whole sensing, control and network block one byte out of place, with the stored line filter frequency reading as half of itself plus half a calibration offset -- and the CRC would have passed on the way in, so nothing would have reported it. A device would have come back from an update quietly mis-calibrated. kiln_config_decode therefore splices version 1 explicitly, which meets SWR-CFG-05's "older: migrate" rather than answering it with defaults and costing an operator their configuration. The test forges a real version 1 blob and checks fields on both sides of the hole, the enclosure type that moved, and a re-encode round trip. SWR-CFG-02 now says there is no chamber TC type and why, and a test asserts the item does not come back. kiln_app_boot passes KILN_TC_TYPE_K to the chamber port from the code: refused on the product, which is the point, and correct on the simulated build where the port accepts it. 26/26 host suites, the same under ASan/UBSan, clang-tidy 20 clean on host and target, hardware image builds, StrictDoc exports clean.
R8's remaining item. Each stage of the chain was tested and the chain was
not: test_suplink proved that a quiet link and a stale sequence number both
become KILN_TC_FAULT_COMMS, test_safety_thermal proved that bit becomes
KILN_FAULT_TC_COMMS, and other tests proved a latched fault withholds heat.
An assembly of proven parts is not a proven assembly, and the chamber
temperature enters this firmware at exactly one place, over a wire: if
silence there does not stop the heater, nothing else in the safety argument
matters.
Two integration tests now run the real application with the real decoder
bound as the chamber port, the way main.cpp binds it on the board, against
the simulated plant:
- **Silence.** The board is pulled, the wire breaks, the other processor
hangs, and nothing announces it. After SWR-SAF-04's grace the fault
latches as TC_COMMS, authority is withdrawn and the contactor opens.
- **A supervisor repeating itself.** Frames keep arriving, the CRC is good,
the temperature is plausible, and the sequence number never advances --
a transmit buffer being replayed, or a processor stuck in a loop. This is
the failure that looks like health: a link check counting bytes would see
a working channel and let the kiln run on a reading from minutes ago. The
test asserts frames really were arriving throughout, so it cannot pass as
the silence case wearing a different hat.
Both assert the kiln was heating before the failure, because a test where the
heat never came on would pass the interesting half for the wrong reason.
31 integration tests, 26/26 suites, clean under ASan/UBSan and clang-tidy 20.
R5 and R7. The supervisor appeared nowhere in the system or safety
requirements, which meant the design document was the only place it existed: a
part holding one element of the contactor coil with no requirement to satisfy
and nothing to verify against.
Six new requirements in 02_system_req.sdoc:
SYS-HW-26 the separate microcontroller: own clock, own watchdog, own
front end on its own bus, own series element, own programming
interface, and the external pull-down the reset window needs,
since every GPIO is high impedance until the first instruction.
SYS-HW-27 the link: one direction, report only, and no message able to
raise the threshold, lower the sensitivity, clear the latch or
silence the reports. A link that only carries information out
cannot carry instruction in.
SYS-HW-28 the local clear button, edge triggered, deliberate hold, and a
line stuck low never arming it, so a short fails towards the
latch holding. Also that the panel must not imply there is one
acknowledgement, because there are two.
SYS-SAF-25 the compiled-in backstop and the persistent-fault trip, and why
a ceiling an operator can raise is not a backstop.
SYS-SAF-26 the latch, what clears it, and why it deliberately does not
survive a power cycle: the supervisor holds no non-volatile
state, and the controller's persisted fault meets the
system-level obligation.
SYS-SAF-27 4 Hz reporting, silence as a sensor fault rather than a comms
problem to retry, and the trip acting within one acquisition
period whether or not anything is listening.
Nine changed. SWR-ACQ-01 no longer says "the system shall measure" for a front
end the controller cannot reach. SYS-HW-02 required "a shared SPI bus with
individual chip selects", which is now exactly what must not happen: a
supervisor whose chip select can be driven by a controller that crashed with a
pin latched is not independent of it. SYS-HW-24 is superseded and rewritten
rather than deleted, keeping its test points. SYS-HW-25's freewheel reference
follows. SWA-04 says there are two supervisors and which one every sentence
means. SWA-05 explains why the supervisor's element is deliberately a static
level with a pull-down rather than a second charge pump. SG-01 is stronger on
MCU failure and explicitly weaker on the sensor. SG-03's "two" became "at least
two", and its "independent control" became true.
safety.md gains L2S -- lettered, not numbered, because the layer numbers are
cited from safety.sdoc, the firmware and the hardware design. Section 6's
independence table gains the three rows the design asked for: a genuine yes
for the supervisor against the controller sharing only the 3V3 rail; an
explicit no for the chamber couple, which both parts read from one junction;
and the thermal-versus-current row promoted from defence in depth to
load-bearing, because with one couple the CT is the only physically
independent detection channel left. The second part made the processor-failure
row writable and the couple row worse at the same time, and both are said.
The boundary diagram and the coil-path table follow: three elements break the
coil now, not four, and a dashed line that is not a signal keeps the diagram
from reading as two independent temperature channels.
Section K is superseded with the chain it described. K1 is answered rather
than mitigated, K2 dissolves, K5 drops from four hardware tests to three. K4
has grown rather than shrunk: the board carries the chain the design dropped
and does not carry the supervisor at all.
StrictDoc exports clean, 26/26 host suites unaffected.
…is left Housekeeping after the O/P/Q/R sweep. R7 appeared twice: the entry recording it done, and the original further down the section, which the replacement had skipped because the section is not in numeric order. O2's image size is re-measured at 945 kB after mDNS, the embedded assets, the event stream and the string table (of the growth from 888 kB, mDNS is 32 kB and the assets 18). O4 is checked off, its three code items being done and the hardware session belonging to O3. Section R's intro said nothing in it could start until R1 to R4 were answered. They are, and so are the firmware, the requirement deltas and the link tests: what is left there is the schematic and the panel button, both hardware.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checking tasklist sections O and P against the code.
Already true, so recorded rather than done
EMBED_FILESanywhere,httpd.cppregisters oneGET /*handler that routes everything to the API, and there is no/api/events.The thing that was not in either section
Every CI job builds
sdkconfig.qemu, which setsCONFIG_KILN_PLANT_SIMand compiles the WiFi, the HTTP server and the hardware path out ofmain.cpp. The configuration that ships was guarded by no build at all, and O3 claimed "it compiles and passes analysis" on that basis.It did not compile. Two
-Wformat-truncationerrors, one older than the WiFi work. Both fixed, and CI now builds the hardware configuration on every push with a size report.Measured, replacing stale numbers
Decided
OQ-09is resolved: the firing profiles are compiled into the firmware and nothing edits them.SWR-PRG-07,-08and-10are withdrawn. The web's "Editor", which was a set of permanently disabled inputs offering to copy an example so you could make changes, is a program view now.The cost is written down rather than minimised: a potter who wants their own curve needs a toolchain and a flash.