ThoxMesh-Head-C6 β v3.0.0 (4-head slot predictor)
int8 LiteRT-Micro head for the Seeed XIAO ESP32-C6. 9,848 bytes β 26Γ under the 256 KB budget.
No
base_model: trained from scratch. There is no upstream checkpoint.
β οΈ Status: three of six model gates FAIL. Read before integrating.
| gate | threshold | v3.0.0 | |
|---|---|---|---|
| event accuracy (int8) | β₯ 0.98 | 0.9979 | β |
motion F1 |
β₯ 0.97 | 0.9903 | β (v2: 0.9565) |
sensor_alert F1 |
β₯ 0.97 | 0.9862 | β (v2: 0.9470) |
| cmd-slot accuracy | β₯ 0.97 | 0.9608 | β |
| target-slot accuracy | β₯ 0.95 | 0.7843 | β |
| arg-bucket accuracy | β₯ 0.90 | 0.4519 | β |
assembled line parses act.gbnf |
1.00 | 1.00 | β (structural) |
The event head is production-quality and improves on v2. The three action slots are not. If you need triage only β the v2 job β v3's event head is strictly better. Do not ship the ACT path on these weights.
What v3 changes
v2 classified events but could not act: it emitted an argmax over 8 classes
with no way to produce ACT <target> <cmd> [arg]. v3 widens the trunk into four
heads and assembles the action from enumerated slots:
features(16) β trunk(32,32) β event(8) | target(17) | cmd(9) | arg(17)
A language model was deliberately NOT used: the C6 has ~512 KB SRAM with no working PSRAM path, and the smallest Microprocessor tier is 1.11 MB at INT4.
Grammar adherence is structural β and that number is not a capability claim
Because the line is assembled from enumerated slots rather than decoded, it
cannot be malformed. Proven exhaustively offline over 124,848 slot
combinations β 0 grammar failures, 0 property failures β validated against
grammars/act.gbnf using the microprocessor repo's own validator, so both ends
of the RV1103βC6 link check against one artifact.
grammar_failures: 0 therefore carries no information about correctness. It
confirms the assembler and nothing else. A well-formed ACT lamp_1 on naming the
wrong lamp is still wrong. The lane's parallel finding on the 8M was the same:
constrained decoding gave "valid but not correct".
attr_id_norm earned its place
v3's feature 12 (ZCL attribute id) was added specifically to separate motion
from sensor_alert, where v2's error concentrated. It worked:
| v2 | v3 | |
|---|---|---|
motion F1 |
0.9565 | 0.9903 |
sensor_alert F1 |
0.9470 | 0.9862 |
Why the three action gates fail β a design question, not a tuning gap
Two generator bugs were found and fixed during this build; a third issue is architectural and is not resolved.
Fixed: the first v3 run scored target 0.2323 (chance) because the label
was drawn at random β not a function of any input, so unlearnable by
construction. arg was nan because no event produced set/dim, leaving the
metric with empty support. Both are corrected; the numbers above are from the
corrected run.
Unresolved β what does target mean? The remaining error is not capacity. It
is that the task is ambiguous:
- If
targetis the device that reported the event, the C6 already knows it from the radio frame header. Predicting it from features is solving a problem that does not exist, and any accuracy below 1.0 is pure loss. - If
targetis a paired actuator (motion onsensor_3β turn onlamp_1), it is a pairing/policy lookup that the 16-feature vector does not carry. No amount of training fixes a label the inputs cannot determine.
arg at 0.4519 has the same shape: 16 buckets decoded from a single normalised
scalar, under int8 input quantisation. It is far above chance (0.0625) but exact
bucket match is the wrong metric if adjacent buckets are operationally
equivalent β an off-by-one dim level is not a failure the way a wrong device is.
These are questions for the architecture owner, and tuning the numbers to clear a gate without answering them would be measuring the wrong thing.
β οΈ Training data is SYNTHETIC
Grounded in published ZCL cluster ids (0x0006 OnOff, 0x0500 IAS Zone,
0x0406 Occupancy) and attribute ids, plus real dBm ranges β but not captured
from hardware.
missed_wakeups: 0 / false_wakeups: 0 again. As in v2, zero in both
directions is evidence that the generator makes ignore linearly separable, not
that the head is perfect. Per the design doc: if v3 repeats the perfect
separation, the generator is the finding, not the model. It did. It is.
What would make this real: a labelled capture from a C6 on a populated mesh.
Contract
16 features (v2's 10 unchanged, in order, plus 6 appended), 8 event classes,
17 target slots (0 = TARGET_NONE), 9 commands (0 = CMD_NONE β NOACT),
17 arg buckets (0 = none). meta.json is the single machine-readable source of
truth β generate the firmware header from it, never hand-code the orders.
model_data.cc is generated from the exact .tflite described by meta.json,
and meta.json carries its model_sha256. Verify that at build time: it is the
mechanical check that makes v1's two-model defect impossible to reintroduce.
Firmware must still clamp arguments regardless of prediction (dim 0β100,
set 5β35), and the C6 never executes an action β it emits a line the RV1103
validates against policy and the live roster.
- Downloads last month
- -