v3.13.3: ELF version retry for both P1 values + query-based per-AID budget
elfTagListRetry walks the untried tag-list forms for P1=10 and P1=20 (skipping combinations the main pass already refused via the expandedTried map; only the tag-list forms are retried - the no-tag-list form never carries CE - and the walk stops as soon as a version appears). The form memory can skip the tag-list forms for P1=10 when the Apps listing served only the no-tag-list form (live 2026-10-02: EP BAP - its P1=10 tag lists were never queried while the P1=20 retry refused them). elfPerAidVersions filters to packages that actually have an applet candidate before the six-query cap: the budget counts queries, not list positions (EP BAP's first six packages are Oracle/JC-API entries with no app instances - they consumed the cap and the A113 packages were never queried). Docs: help EN/RU, repo AGENTS (v3.13.3 note). sw cache simple-v373. Tests: 667 Python + 796 frontend green.
This commit is contained in:
+50
-21
@@ -1877,7 +1877,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.13.2';
|
||||
const SIMPLE_VERSION = '3.13.3';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== Tab switching =====
|
||||
@@ -9937,10 +9937,15 @@ async function ramExplore(sp) {
|
||||
// occurrences (re-issued as a next-occurrence page, P2.b1=1). Returns
|
||||
// {form, parsed, sw, entries, fmt}; form is null when no form produced
|
||||
// data.
|
||||
async function expandedPass(p1, label, parser, spi2) {
|
||||
let forms = expandedForm
|
||||
? [expandedForm].concat(RAM_EXPANDED_FORMS.filter(f => f !== expandedForm))
|
||||
: RAM_EXPANDED_FORMS.slice();
|
||||
// The forms each P1 value actually attempted, so the version retry can
|
||||
// skip the combinations the main pass already refused (the form memory can
|
||||
// skip the tag-list forms for P1=10 - see elfTagListRetry).
|
||||
const expandedTried = {};
|
||||
async function expandedPass(p1, label, parser, spi2, onlyForms) {
|
||||
let forms = onlyForms ? onlyForms.slice()
|
||||
: expandedForm
|
||||
? [expandedForm].concat(RAM_EXPANDED_FORMS.filter(f => f !== expandedForm))
|
||||
: RAM_EXPANDED_FORMS.slice();
|
||||
if (p1 === '80') forms = [expandedForm || 'tags'];
|
||||
const runFmt = sp.ram_format || 'auto';
|
||||
let lastSw = '';
|
||||
@@ -9948,6 +9953,8 @@ async function ramExplore(sp) {
|
||||
let stopPass = false;
|
||||
for (const form of forms) {
|
||||
if (cntrLow || stopPass) break;
|
||||
if (!expandedTried[p1]) expandedTried[p1] = [];
|
||||
if (expandedTried[p1].indexOf(form) < 0) expandedTried[p1].push(form);
|
||||
const fmts = ramFmtLadder(runFmt, expandedFmt);
|
||||
for (const fmt of fmts) {
|
||||
if (cntrLow) break;
|
||||
@@ -10190,23 +10197,37 @@ async function ramExplore(sp) {
|
||||
if (!elfs.length) errors.push(...elfFailure);
|
||||
}
|
||||
// The ELF tag-list forms may be refused for P1=10 while P1=20 accepts
|
||||
// them (a card's P1=10 implementation can be stricter): when the ELF rows
|
||||
// have no version and the details pass never got a tag-list form, walk the
|
||||
// ladder once more with P1=20 and merge by AID (v3.7.0).
|
||||
// them (a card's P1=10 implementation can be stricter), and the form
|
||||
// memory can skip the tag-list forms for P1=10 altogether when the Apps
|
||||
// listing served only the no-tag-list form (live 2026-10-02: EP BAP - its
|
||||
// P1=10 tag lists were never queried while P1=20 refused them). When the
|
||||
// ELF rows have no version and the details pass never got a tag-list form,
|
||||
// walk the untried tag-list forms for both P1 values and merge by AID
|
||||
// (v3.7.0); only the tag-list forms are retried - the no-tag-list form
|
||||
// never carries CE - and the walk stops as soon as a version appears.
|
||||
async function elfTagListRetry() {
|
||||
if (cntrLow || !elfs.length || elfs.some(o => o.version)) return;
|
||||
const g = ramExpandedGroups(expandedReport).find(x => x.label === t('ELFs'));
|
||||
if (g && ['tags', 'noea', 'lean'].indexOf(g.form) >= 0) return;
|
||||
const saved = expandedForm;
|
||||
expandedForm = null; // start the ladder at the richest form
|
||||
try {
|
||||
const out = await expandedPass('20', t('ELFs'), ramParseElfStatus, ramListingSpi2('20'));
|
||||
expandedReport.push({ p1: '20', label: t('ELFs'), compact: true,
|
||||
form: out.form, sw: out.sw, entries: out.entries,
|
||||
transport: out.transport, more: out.more });
|
||||
if (out.parsed.length) ramMergeExpanded(elfs, out.parsed);
|
||||
} finally {
|
||||
if (expandedForm === null) expandedForm = saved;
|
||||
for (const p1 of ['10', '20']) {
|
||||
const tried = expandedTried[p1] || [];
|
||||
const forms = ['tags', 'noea', 'lean'].filter(f => tried.indexOf(f) < 0);
|
||||
if (!forms.length) continue;
|
||||
expandedForm = null; // start the ladder at the richest form
|
||||
try {
|
||||
const out = await expandedPass(p1, t('ELFs'), ramParseElfStatus,
|
||||
ramListingSpi2(p1), forms);
|
||||
if (out.form) {
|
||||
expandedReport.push({ p1: p1, label: t('ELFs'), compact: true,
|
||||
form: out.form, sw: out.sw, entries: out.entries,
|
||||
transport: out.transport, more: out.more, fmt: out.fmt });
|
||||
if (out.parsed.length) ramMergeExpanded(elfs, out.parsed);
|
||||
}
|
||||
} finally {
|
||||
if (expandedForm === null) expandedForm = saved;
|
||||
}
|
||||
if (elfs.some(o => o.version)) break;
|
||||
}
|
||||
}
|
||||
await elfTagListRetry();
|
||||
@@ -10260,11 +10281,19 @@ async function ramExplore(sp) {
|
||||
// holds the data), so it is retried with the GET RESPONSE chained into the
|
||||
// compact command string, like the ladder (v3.7.1).
|
||||
async function elfPerAidVersions() {
|
||||
const missing = elfs.filter(e => !e.version && e.aid);
|
||||
for (const e of missing.slice(0, 6)) {
|
||||
if (cntrLow) break;
|
||||
// Budget the queries, not the list positions: a package without an
|
||||
// applet instance has nothing to ask for, and counting it would starve
|
||||
// the packages that do (live 2026-10-02: EP BAP's first six packages
|
||||
// are Oracle/JC-API entries with no app instances - the A113 packages
|
||||
// were never queried).
|
||||
const missing = [];
|
||||
elfs.forEach(e => {
|
||||
if (e.version || !e.aid) return;
|
||||
const app = ramElfAppletCandidate(e, apps);
|
||||
if (!app) continue;
|
||||
if (app) missing.push({ elf: e, app: app });
|
||||
});
|
||||
for (const { elf: e, app } of missing.slice(0, 6)) {
|
||||
if (cntrLow) break;
|
||||
ramShowProgress(t('Version') + ' ' + e.aid + '...');
|
||||
const apdu = ramExpandedQueryApdu('40', 'tags', false, app.aid);
|
||||
const send = async a => {
|
||||
|
||||
Reference in New Issue
Block a user