fix: review fixes for the OTA slot

- The field is hasOtaSlot, like hasEthernet and the other "has" bools.
- The web UI shows the device's reason for any failed upload, not only
  for /restore, so it shows "no OTA slot" from a page that missed the
  header. The update routes' 500 replies give Update.errorString()
  instead of an empty reason.
- Native: the writer leaves hasOtaSlot out when true and writes "os":0.
- e2e: header() next to uptime(); the test skips on firmware without
  the field instead of failing, and matches the reason loosely. The
  README says what the test sends.
- PROTOCOL.md and the comments name only the builds that exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-28 22:19:27 +01:00
parent 5721d34a34
commit 657b345eaf
13 changed files with 41 additions and 38 deletions

View file

@ -37,17 +37,17 @@ test('a field the sync left out is its default', () => {
for (const g of m.groupList()) assert.ok(Array.isArray(g.linkedShades));
});
test('otaSlot is false only when the device says so', () => {
test('the device has an OTA slot unless it says it has none', () => {
// The recording is from firmware before the field.
assert.equal(synced().header.otaSlot, undefined);
assert.equal(synced().header.hasOtaSlot, undefined);
const schema = recordedSchema();
schema.add({ F: [['os', 'otaSlot', 'b', 1]] });
schema.add({ F: [['os', 'hasOtaSlot', 'b', 1]] });
const header = deviceSections(schema).find((d) => d.header).header;
const m = new ProtoModel(schema);
m.applySync({ header: header });
assert.equal(m.header.otaSlot, true);
assert.equal(m.header.hasOtaSlot, true);
m.applySync({ header: schema.expand(Object.assign({ os: 0 }, schema.pack(header))) });
assert.equal(m.header.otaSlot, false);
assert.equal(m.header.hasOtaSlot, false);
});
test('the lists come in their sort order', () => {