v3.28.0 review: the batch failure classification

- A non-ValueError exception from the install run (a card removed
  mid-chain, a transport error) was recorded as a 'skipped' attempt with
  the error text - but the chain had started and died, which is a
  failure.  Only a ValueError (a request/eligibility error: the preset's
  ISD keyset, the plan) is a skip now; anything else is a 'failed' record
  carrying its error.  The PWA's failed row falls back to that error when
  there is no failing step / status word to show.
- The panel's Clear button is disabled while a batch is active (the
  server refuses the clear with 409 anyway) - no pointless error alert.
- api.md and the repo AGENTS document the two outcomes.  Tests: a
  transport error mid-chain is a failure (and the card stays seen), the
  plan's input validation (the block size, a missing cap_hex), the failed
  row without a step, the shared ram_format field, and the Clear state.
  915 frontend + 921 Python; sw cache simple-v438 (unchanged).
This commit is contained in:
2026-10-14 15:09:33 +03:00
parent ab373aff30
commit e8190c65f7
5 changed files with 73 additions and 5 deletions
+14 -3
View File
@@ -2640,12 +2640,18 @@ def _ram_batch_handle_card(state, server):
started = time.time()
result = None
error = None
request_error = False
try:
with _CARD_LOCK:
result = _ram_install_run(server, body, state['plan'], server.scc)
except ValueError as e:
# A request/eligibility error (the preset's ISD keyset, the plan): the
# install never started - the card is skipped.
error = str(e)
request_error = True
except Exception as e:
# A refused keyset, a lost card, a transport error: the card's outcome
# is a failure - the batch never retries it.
# The chain started and died (a lost card, a transport error): the
# attempt failed.
error = str(e)
finally:
with _RAM_BATCH_LOCK:
@@ -2667,11 +2673,16 @@ def _ram_batch_handle_card(state, server):
'cntr_low': bool(result.get('cntr_low')),
'error': result.get('error') or ''}
rec.update(_ram_batch_failure_fields(result))
else:
elif request_error:
outcome = 'skipped'
rec = {'iccid': iccid, 'preset': name, 'result': outcome,
'duration_ms': duration,
'reason': error or 'the install could not start'}
else:
outcome = 'failed'
rec = {'iccid': iccid, 'preset': name, 'result': outcome,
'duration_ms': duration,
'error': error or 'the install failed'}
with _RAM_BATCH_LOCK:
state['seen'][iccid] = outcome
_ram_batch_record(state, rec)