v3.14.1: the counter probe demands its PoR

_counter_probe_params validates SPI2, forces b1 (PoR required; a caller's
00 becomes 01) and defaults to the RAM listing transport 21; the no-PoR
error names the effective SPI2, and ramSyncCounter posts
ramListingSpi2('40') for the RAM view (the failed operation's transport).

Live 2026-10-02 (NP BAP): the probe had sent the plain SCP80 form's 00
(no PoR) - the card answered the ENVELOPE 9000 and sent nothing, so the
probe stopped after one packet with "card verdict: no PoR".

Docs: docs/api.md, repo AGENTS.  sw cache simple-v376.
Tests: 670 Python + 798 frontend green.
This commit is contained in:
2026-10-02 14:40:07 +03:00
parent c18b6cd0d4
commit 475c13aeb8
7 changed files with 60 additions and 12 deletions
+23
View File
@@ -2433,6 +2433,29 @@ class CounterProbeTests(unittest.TestCase):
self.assertLessEqual(len(res['attempts']), 3)
self.assertIn('raise the preset counter manually', res['error'])
def test_spi2_always_requests_the_por(self):
# the probe cannot work without the PoR verdict: a caller's value
# without b1 is corrected (live 2026-10-02: the frontend posted the
# plain form's 00 and the probe stopped after one packet), an invalid
# one is refused, and the default is the RAM transport
self.assertEqual(_counter_probe_params(self._preset(), {})['spi2'], '21')
self.assertEqual(_counter_probe_params(self._preset(), {'spi2': '00'})['spi2'], '01')
self.assertEqual(_counter_probe_params(self._preset(), {'spi2': '20'})['spi2'], '21')
self.assertEqual(_counter_probe_params(self._preset(), {'spi2': '21'})['spi2'], '21')
with self.assertRaises(ValueError):
_counter_probe_params(self._preset(), {'spi2': 'ZZ'})
def test_probe_names_the_spi2_when_no_por_arrives(self):
def send_fn(p, cntr):
return ({'success': True, 'sw': '9000'}, None)
res = _counter_probe(None, None, self._preset(), {}, send_fn=send_fn)
self.assertFalse(res['success'])
self.assertEqual(res['stopped'], 'error')
self.assertEqual(res['packets'], 1)
self.assertIn('no PoR', res['error'])
self.assertIn('SPI2 21', res['error'])
def test_probe_params_validation(self):
# a keyset number the preset does not define
with self.assertRaises(ValueError) as cm: