The startup init (server booted with the card already in the reader) equips
the card and reads the ICCID itself, but never created server.net_state -
only /api/command equip and the auto-equip worker did. With a card present
at boot the monitor stayed empty, net-sim responses carried net_state: null
and the panel only started updating after pressing Refresh (which lazily
created the state). Fix:
- factor _netstate_read(app) / _netstate_install() / _netstate_init() in
server.py; _apply_equipped_card uses _netstate_init()
- __main__ startup: read the monitored EFs in the same CAT-free window as
the ICCID and install the state once the server object exists
- _netstate_ensure() lazily initializes the state in the net-sim/event hooks
so any equip path predating the monitor cannot leave it dead
- netSimRun falls back to netStateFetch() when a response has no net_state
- tests: tests/test_netstate_server.py (candidate order, record vs
transparent, absent files, install, ensure); SW cache simple-v204
Server (pysim_simple_server/netsim.py + POST /api/net-sim):
- pure builders for the observed phone write vocabulary (UICC_NAA.md §13):
EPSNSC (A0 TLV with KSI/KASME/counts/algo, padded to the card's FCP record
size; invalidate-wipe and invalidate-keep-key), LOCI/PSLOCI/EPSLOCI real
and dummy forms (PLMN kept, LAC FFFE, status 01/02), Kc/KcGPRS (9-byte
USIM and 33-byte GSM forms, 07 invalidates), EF.SMSstatus counter bump
(read-modify-write), CBMI/CBMIR, the Location status event (9B 01 <st>,
with the optional 13 07 location info for normal service) and the
AUTHENTICATE APDU (TS 31.102 7.1.2.1) with DB/DC response parsing
- scenario runner executes the recipes under _CARD_LOCK, picks the first
existing candidate path (ADF.USIM vs DF.GSM/DF.TELECOM), reads FCP/current
records where the format is card-specific, skips the event unless the card
subscribed to Location status, honours the scenario toggles and returns a
per-step log; only D6/DC, ENVELOPE and AUTHENTICATE are ever sent
- GET /api/mcc-mnc serves the optional worldwide operator list
(--mcc-mnc-list, default <workspace>/samples/mcc-mnc-list.json): ?q=
search and ?random=1&exclude= for roaming; the list stays out of the repo
PWA:
- Phone pill gains a 'Network simulation' fieldset: one button per scenario
(cold boot, EPS/2G attach, service lost, limited service, roaming denied,
churn, SMS received, CB reconfig, AUTHENTICATE), a collapsed Parameters
block (operator search + random roaming, LAC/Cell ID/TAC/RAC, optional
identities, toggles, churn count/delay) and a step log with SWs
- i18n EN/RU, help/README/api.md/AGENTS.md updated; version 2.5.0,
SW cache simple-v193
Tests: tests/test_netsim.py (19), frontend/tests/netsim.test.js (3) and
html guards - 423 frontend / 280 Python, all passing