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 target is 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 target is a paired actuator (motion on sensor_3 β†’ turn on lamp_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
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support