v3.30.2: the batch RU wording sweep completed

The v3.30.1 review follow-up.  The sweep fixed the two batch-state
strings but two more shared (kind-independent) batch strings were still
install-specific, so a delete/reinstall batch started under an "install"
label:

- 'Start batch' was «Запустить пакетную установку» - the ram-batch-start
  button starts every kind - now «Запустить пакетную операцию» (aligning
  with the optgroup «Пакетные операции (по картам)»).
- the shared panel hint's «...перезапустите пакетную установку» is now
  «...перезапустите пакетную операцию» (the EN was already neutral).

The RU help quoted the old button label: its install row now says
«Запустить пакетную операцию не требует карты», and the row's other
generic "the batch" statements (never retries, the test-run exclusion)
are neutral too; the genuinely install-specific ones (the workflow, the
shared install form) stay.

The v3.30.1 notes were corrected: the counts labels do follow the last
run's kind after a clear (the values stay zero) - the AGENTS entry and
the _ramBatchLastKind/ramBatchRender comments say so now.  The
cleared-title test seeds the state before opening the modal (no reliance
on the previous test's sandbox leftovers).

930 frontend + 945 Python; sw cache simple-v452.
This commit is contained in:
catarrh committed 2026-10-15 09:41:29 +03:00
1 parent 19dc0c7d56
commit 3db6f59e69
6 files changed
+14 -12

No files matched your search

+1 -1
View File
@@ -323,7 +323,7 @@
<tbody>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Обзор карты (все данные GP)</td><td class="py-1 px-2">Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 (расширенные ресурсы карты: число установленных приложений и свободная энергонезависимая/энергозависимая память). Компактный листинг содержит только AID, состояние жизненного цикла и привилегии (версии в устаревшем формате нет); если карта отвергает его (<code class="font-mono text-sm">P2.b2=0</code>, устаревший по GP), запросы повторяются в расширенном формате <code class="font-mono text-sm">E3</code>, а флажок <strong>Запрашивать расширенные данные реестра (связи load-файла и SD)</strong> дополнительно запрашивает их и объединяет расширенные поля: версию исполняемого load-файла, AID load-файла, AID Security Domain, списки модулей, пункты меню STK апплета (SCP Registry Data, TS 102 226 8.2.1.6) и любые другие объекты реестра, которые вернула карта (показываются как есть, без потерь) &mdash; он стоит несколько дополнительных защищённых пакетов на каждый обзор и <strong>включён по умолчанию</strong> (запоминается в браузере; снимите флажок, чтобы пропустить). Карты различаются в том, что принимают, поэтому расширенный запрос пробуется в трёх формах &mdash; эталонный список тегов (с <code class="font-mono text-sm">EA</code> по TS 102 226), тот же список без <code class="font-mono text-sm">EA</code> и вовсе без списка тегов (форма GlobalPlatformPro) &mdash; а обзор сообщает, какая форма сработала и где выполнен откат к компактному списку (версии пакетов тогда недоступны). Если строки ELF всё ещё без версий, формы со списком тегов повторяются для обоих P1=10 и P1=20, пропуская уже отклонённые комбинации, и обход останавливается, как только версия найдена. Результаты отображаются в обзоре (строка успеха минимальна, счётчики — в заголовках разделов) с кнопками <strong>Удалить</strong> для каждого элемента и определённым форматом команд RAM (подсказка при наведении объясняет compact и expanded).</td></tr>
<tr><td class="py-1 px-2">Установка пакета (.cap файл)</td><td class="py-1 px-2">Отправка <code class="font-mono text-sm">.cap</code> файла на карту через сервер: INSTALL[for load] &rarr; LOAD &times;N &rarr; INSTALL[for install (+make selectable)]. Load-файл делится на LOAD APDU размера <strong>размер блока LOAD</strong> (1&ndash;240 байт полезной нагрузки, по умолчанию 240); каждый защищённый пакет доставляется одним SMS или, если он больше, конкатенированной SMS-PP загрузкой до 5 сегментов, так что большой <code>.cap</code> просто занимает несколько SMS. Сразу после выбора файл проверяется и в форме показывается <strong>оценка требований к памяти</strong>: <strong>требование NVRAM</strong> (образ кода + постоянные данные, сумма в стиле C6+C8 из GP Card Spec) и оценка RAM. Там же показаны <strong>библиотеки, с которыми слинкован CAP</strong> (его компонент Import: имя библиотеки, AID и минимальная версия <code class="font-mono text-sm">≥ x.y</code> — имена стандартных библиотек и семейства подставляются, а где известно, даётся подсказка о версии Java Card), идентификаторы пакета и апплетов и разбивка по компонентам (размеры и доли в порядке load-файла) — всё сгруппировано по разделам <strong>Package</strong>, <strong>Requires</strong>, <strong>Memory</strong> и <strong>Components</strong>. Строка <strong>Platform</strong> показывает минимальный уровень Java Card, который должна предоставить карта (выводится из импорта <code class="font-mono text-sm">javacard.framework</code>; флаг <code class="font-mono text-sm">int</code> в заголовке дополнительно требует поддержки int — Java Card 2.2+), и <strong>релиз ETSI</strong>, из которого пришли импорты UICC API (версия <code class="font-mono text-sm">uicc.toolkit</code> &rarr; REL-N по корпусу <code class="font-mono text-sm">sim-tools</code> в рабочем каталоге; основание показано в скобках): JCRE проверяет каждый импорт по своим пакетам при верификации load-файла (JC VM spec 4.5.2), поэтому карта со старой платформой отклоняет LOAD сразу после завершения компонента <strong>Import</strong> (в строке шага виден remote SW карты и компонент, который завершил блок, например <em>завершает Import</em>): подсказка при ошибке и попап предлагают <strong>тест совместимости CAP</strong> (в один клик — тот же <code class="font-mono text-sm">.cap</code> уже выбран), чтобы найти отсутствующий пакет и версию; меньший размер блока LOAD помогает только если блок превышает буфер карты. Повреждённый файл не проходит анализ, и <strong>Execute</strong> остаётся недоступной до успешного анализа. Оценка носит справочный характер и никогда не используется при установке: NVRAM — это образ кода плюс постоянные данные (сумма в стиле C6+C8 по GP Table 11-48; управление памятью карты, округление и запись в реестре не учитываются, а образ статических полей входит в обе части); рекомендуемый <strong>C6</strong> следует за load-файлом, а рекомендуемые квоты — это десятичные значения в байтах (шестнадцатеричное значение в скобках — это кодирование параметров установки C7/C8: C6 — энергонезависимый код, C7 — энергозависимая RAM, C8 — энергонезависимые данные). Флажок <strong>Удалить пакет перед установкой (с его приложениями)</strong> добавляет перед цепочкLine truncated
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Пакетная установка (.cap на множество карт)</td><td class="py-1 px-2">Массовый сценарий: один <code class="font-mono text-sm">.cap</code> и один набор параметров установки, применяемые карта за картой. <strong>Запустить пакетную установку</strong> не требует карты &mdash; цикл ведёт сервер: он ждёт карту, устанавливает сразу после завершения equip и затем ждёт следующую. Для каждой карты <strong>пресет находится по ICCID</strong> и задаёт keyset (по умолчанию из ролевой записи ISD TAR, v3.26.0), ключи и счётчик; карта без подходящего пресета или без пригодного keyset ISD TAR отмечается и пропускается. Каждая попытка попадает в список со временем, ICCID, пресетом, вердиктом и длительностью; при ошибке показаны шаг, на котором она произошла, и удалённый статусный байт &mdash; пакетная установка никогда не повторяет попытку и не останавливается при ошибке (ошибки остаются на ваше усмотрение). Карта обрабатывается <strong>один раз за запуск</strong>: повторная установка карты даёт «уже обработана» &mdash; для повтора перезапустите пакетную установку. <strong>Остановить</strong> завершает работу после окончания обработки текущей карты (прерванная цепочка LOAD может оставить полузагруженный пакет), а затем завершает запуск; <strong>Очистить</strong> удаляет отчёт завершённого запуска. Цикл работает на сервере, поэтому закрытие вкладки, переключение представлений или перезагрузка страницы его не прерывают; перезапуск сервера завершает запуск. Пакетная установка и тест-скрипт исключают друг друга. Пакетная установка использует ту же форму, поэтому параметр <strong>Удалить пакет перед установкой</strong> применяется к каждой карте.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Пакетная установка (.cap на множество карт)</td><td class="py-1 px-2">Массовый сценарий: один <code class="font-mono text-sm">.cap</code> и один набор параметров установки, применяемые карта за картой. <strong>Запустить пакетную операцию</strong> не требует карты &mdash; цикл ведёт сервер: он ждёт карту, устанавливает сразу после завершения equip и затем ждёт следующую. Для каждой карты <strong>пресет находится по ICCID</strong> и задаёт keyset (по умолчанию из ролевой записи ISD TAR, v3.26.0), ключи и счётчик; карта без подходящего пресета или без пригодного keyset ISD TAR отмечается и пропускается. Каждая попытка попадает в список со временем, ICCID, пресетом, вердиктом и длительностью; при ошибке показаны шаг, на котором она произошла, и удалённый статусный байт &mdash; пакетная операция никогда не повторяет попытку и не останавливается при ошибке (ошибки остаются на ваше усмотрение). Карта обрабатывается <strong>один раз за запуск</strong>: повторная установка карты даёт «уже обработана» &mdash; для повтора перезапустите пакетную операцию. <strong>Остановить</strong> завершает работу после окончания обработки текущей карты (прерванная цепочка LOAD может оставить полузагруженный пакет), а затем завершает запуск; <strong>Очистить</strong> удаляет отчёт завершённого запуска. Цикл работает на сервере, поэтому закрытие вкладки, переключение представлений или перезагрузка страницы его не прерывают; перезапуск сервера завершает запуск. Пакетная операция и тест-скрипт исключают друг друга. Пакетная установка использует ту же форму, поэтому параметр <strong>Удалить пакет перед установкой</strong> применяется к каждой карте.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Пакетная переустановка приложения (по картам)</td><td class="py-1 px-2">Сценарий исправления: для каждой карты удаляется экземпляр приложения (с допуском «не найдено») и заново выполняется INSTALL [for install] из уже загруженного пакета &mdash; без <code class="font-mono text-sm">.cap</code> и без LOAD. Поля — параметры одиночного INSTALL [for install] (Load File / Module / Instance AID, привилегии, параметры toolkit/STK, <em>make selectable</em>); пресет, keyset и счётчик берутся из пресета каждой карты, как в остальных пакетных операциях, а список попыток показывает оба вердикта (удаление и установка).</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Пакетное удаление (по картам)</td><td class="py-1 px-2">Удаляет один объект на каждой карте: приложение (только экземпляр, P2=<code class="font-mono text-sm">0x00</code>) или пакет с его приложениями (каскадно, P2=<code class="font-mono text-sm">0x80</code>). Поля: AID и цель. Результат «не найдено» (объект уже отсутствует) отмечается как таковой и считается успешным; любая другая ошибка показывается со статусным словом карты.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Проверка совместимости CAP</td><td class="py-1 px-2">Отвечает на один вопрос, ничего не устанавливая: <strong>может ли эта карта удовлетворить список импортов CAP?</strong> Сервер выполняет проверку формата, INSTALL[for load] и блоки LOAD только до блока, завершающего компонент <strong>Import</strong> &mdash; именно там JCRE проверяет список импортов &mdash; и останавливается: без флага последнего блока и без INSTALL[for install], поэтому ничего не фиксируется и удалять после этого ничего не нужно. Список <strong>«Версии импортов для проверки»</strong> предзаполняется из анализа CAP: <code class="font-mono text-sm">AID=version</code> переписывает запрошенную версию импорта, <code class="font-mono text-sm">+AID=version</code> добавляет синтетический импорт (запрос возможностей карты: LOAD проходит, только если карта экспортирует этот пакет версии &ge; указанной), а <strong>«Все 0.0»</strong> снимает все требования. Использование в два шага: нажмите «Все 0.0» &mdash; если проверка проходит, причиной был список импортов; затем возвращайте по одной строке, чтобы найти пакет и версию, которых не хватает карте. Вердикт явно указывает, что проверяется только <strong>этап LOAD/импортов</strong>: этап связывания (наличие реально вызываемых API) проверяет настоящая установка на INSTALL[for install]. Запуск и результат показываются в окне (как при установке): строки шагов, вердикт и блок деталей по каждому AID &mdash; при отказе он называет раздел CAP, который покрывает неудачный блок (диапазон байтов load-файла и компоненты, и завершает ли этот блок <strong>Import</strong>), SW команды с его значением, список импортов ровно в том виде, в каком он проверялся (версии CAP, правки пробы, добавленные синтетические записи, строки без совпадений) и что означает состояние пробы; при успехе — список импортов, который прошёл проверку.</td></tr>
+7 -6
View File
@@ -1932,7 +1932,7 @@
// ===== Version =====
// Single source of truth for the PWA version: shown in the header and used
// by the server version check in pysimConnect().
const SIMPLE_VERSION = '3.30.1';
const SIMPLE_VERSION = '3.30.2';
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
// ===== view history (the browser Back/Forward buttons) =====
@@ -10192,8 +10192,8 @@ let _ramBatchSummary = null; // /api/status.ram_batch
let _ramBatchProgress = null; // /api/status.ram_progress
let _ramBatchModalShown = false; // the batch status modal is open (v3.30.0)
let _ramBatchLastKind = null; // the last seen run kind: a cleared report
// (kind: null) keeps the modal's title right
// (v3.30.1)
// (kind: null) keeps the modal's title and the
// counts labels on that kind (v3.30.1)
// A fetch that never settled must not block the report forever (v3.28.7).
const RAM_BATCH_FETCH_STALE_MS = 10000;
@@ -10351,7 +10351,8 @@ function ramBatchRender() {
const phase = st.phase || (active ? 'waiting_card' : 'idle');
// The success labels follow the operation (v3.29.0): the counts bucket is
// 'installed' for every kind - "the operation succeeded". The last seen
// kind is remembered for the modal's title (v3.30.1).
// kind is remembered for the modal's title and these labels, so a cleared
// report keeps the run's kind (v3.30.1).
if (st.kind) _ramBatchLastKind = st.kind;
const kind = st.kind || _ramBatchLastKind || 'install-cap';
const okLabel = kind === 'delete' ? t('Deleted')
@@ -24681,7 +24682,7 @@ const LANG_RU = {
'Delete the package before installing (with its applications)': 'Удалить пакет перед установкой (с его приложениями)',
'AID must be 5-16 bytes of hex': 'AID должен быть 5-16 байт hex',
'not found': 'не найдено',
'Start batch': 'Запустить пакетную установку',
'Start batch': 'Запустить пакетную операцию',
'Stopping...': 'Остановка…',
'Batch stopped': 'Пакетная операция остановлена',
'Batch finished': 'Пакетная операция завершена',
@@ -24696,7 +24697,7 @@ const LANG_RU = {
'Skipped': 'Пропущено',
'attempts': 'попыток',
'No cards processed yet.': 'Карты ещё не обрабатывались.',
'The preset, keyset and counter come from each card\'s own preset (matched by ICCID). A card is attempted once per run: re-equipping it reports it as already processed - restart the batch to retry. Stop finishes the current card first.': 'Пресет, keyset и счётчик берутся из пресета каждой карты (совпадение по ICCID). Карта обрабатывается один раз за запуск: повторная установка карты отмечается как уже обработанная — для повтора перезапустите пакетную установку. «Остановить» завершает работу после окончания обработки карты.',
'The preset, keyset and counter come from each card\'s own preset (matched by ICCID). A card is attempted once per run: re-equipping it reports it as already processed - restart the batch to retry. Stop finishes the current card first.': 'Пресет, keyset и счётчик берутся из пресета каждой карты (совпадение по ICCID). Карта обрабатывается один раз за запуск: повторная установка карты отмечается как уже обработанная — для повтора перезапустите пакетную операцию. «Остановить» завершает работу после окончания обработки карты.',
'Do not close or reload this window while the operation is running.': 'Не закрывайте и не перезагружайте окно, пока операция выполняется.',
'Working...': 'Выполняется...',
'APDU hex': 'APDU (hex)',
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simple-v451';
const CACHE = 'simple-v452';
const URLS = [
'index.html',
'help.html',
+3 -2
View File
@@ -578,10 +578,11 @@ test('a cleared report keeps the run kind in the modal title (v3.30.1)', () => {
setModalEls();
setPanelEls();
app.setSummary(null);
app.ramBatchModalOpen();
// the state is seeded before the window opens: no reliance on the sandbox
// leftovers of the previous test (the modal opens into the run's kind)
app.setLast({ kind: 'delete', active: false, phase: 'finished', attempts: [],
counts: { installed: 2 }, attempts_total: 2 });
app.ramBatchRender();
app.ramBatchModalOpen();
assert.strictEqual(els['ram-op-title'].textContent, 'Batch delete (per card)');
// Clear empties the state (kind: null): the title must not flip to install
app.setLast({ kind: null, active: false, phase: 'idle', attempts: [],
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "pysim-simple-server"
version = "3.30.1"
version = "3.30.2"
description = "HTTP REST server wrapping pysim for the SIMple PWA"
requires-python = ">=3.8"
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
+1 -1
View File
@@ -37,7 +37,7 @@ from osmocom.tlv import BER_TLV_IE
from osmocom.utils import rpad
VERSION = '3.30.1'
VERSION = '3.30.2'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE