Commit Graph
7 Commits
Author SHA1 Message Date
catarrh bd0c9a2c4a Files view: widen the change-details modal again and keep the legend on one row
- modal max-width 900px -> 1100px
- the legend's swatch and label were separate flex children, so a line break
  could split them and the three entries wrapped; each pair is now one
  `.hex-legend-item` (nowrap, no shrink) and the legend itself is
  `flex-wrap: nowrap` with `overflow-x: auto`, so it stays on a single row
- Node test: the modal test now checks the path header and that the legend
  follows the views as three grouped items
- SW cache simtrace-analyser-v70 (cosmetic, no version bump)
2026-10-17 21:40:50 +03:00
catarrh cbb73536f4 Files view: drop the ASCII column from the change-details hex views
- the modal's hex views carried a 16-byte ASCII column per row; file data is
  rarely text and the column halved the room for the two before/after views,
  so it is gone: `hexImageRows` no longer builds an `ascii` field,
  `hexImageHtml` no longer emits it and the `.hex-ascii` CSS rule is removed
- tests: the hex-row test asserts the field is gone (so it cannot come back
  silently); README/README_RUS wording updated
- SW cache simtrace-analyser-v67 (cosmetic, no version bump)
2026-10-17 21:29:31 +03:00
catarrh 407821ab3d Fix session loading: a no-op capture stop aborted the load (v2.4.1)
- `loadSession` begins by stopping a running capture; when there is nothing
  to stop the server answers 400 'No active capture' (or 403 with capture
  disabled) — and since the v2.3.1 `_fetch` status fix those answers throw, so
  the whole load was skipped and the UI alerted "Failed to load session":
  no session could be opened at all
- new `stopCaptureIfRunning()` swallows exactly that no-op answer; both
  `loadSession` and the capture button use it, and the button now resets its
  state outside the try so a tolerated stop still clears the UI
- the `_fetch` status check stays — real errors keep surfacing (an unknown
  session still throws 'Session not found')
- tests: the helper resolves on a 400 and still calls once; source pins that
  `loadSession` uses the tolerant helper (the regression guard) and that
  `stopCapture` resets the state
- v2.4.1; SW cache simtrace-analyser-v66
2026-10-17 21:25:48 +03:00
catarrh cad3999307 Files view: change details with before/after images (v2.4.0)
- the timeline's Δ glyph became a **Details** button, and it now appears on
  Update rows too (not just card-side changes); EN "Changed (card)" ->
  "Changed on card", RU "Изменено (картой)" -> "Изменено картой"
- the details modal shows the affected unit — the whole file, or the single
  record that changed — **before and after** the change as hex views (16 bytes
  per row, ASCII column, never-observed bytes as `--`), with the bytes that
  changed and the bytes the operation *first observed* highlighted in two
  different colours, plus the changed/new byte counts and the APDU reference;
  the old before/after byte table is gone
- `GET /api/sessions/<id>/files/image?key=…&change=…` returns those two views
  (segments with offsets) plus the change's metadata; the images are
  reconstructed from the current image by undoing the later changes
  (`FileTracker.change_images`), so nothing is duplicated per event — every
  value change is an event, hence the values are exact (a byte only first
  observed later can appear as known in both views)
- tracker: change events carry `observed_ranges` (bytes that were unknown
  before the operation) next to `ranges`; an update that only observes new
  bytes now records an event (so it can be inspected); record-file ranges are
  in-record byte offsets (the record number stays in its own field), which the
  previous "record number as position" could not express for a hex highlight
- tests: change-images reconstruction (before/after per event, later changes
  undone, records isolated, observation-only events, unknown gaps), the image
  endpoint (200/404/400), and Node tests for the hex-image helper (highlight
  classes, unknown gaps, ASCII, row limit) and the modal rendering
- v2.4.0; SW cache simtrace-analyser-v65
2026-10-17 21:19:14 +03:00
catarrh 87b6811adf Files view: surface fetch errors instead of "no operations" (v2.3.1)
- `API._fetch` never checked the HTTP status: an error body (e.g. the 404
  `{"error": "Session not found"}`) was returned as data, so the Files view
  rendered it as "No file operations recorded" — and, worse, that bad payload
  was cached per session id, which is why only re-opening the session (which
  resets the cache) appeared to fix it.  It now throws with the server's
  message for any non-OK response (all 13 `await API.*` call sites are inside
  try/catch) and marks the server unavailable only for a real network error
- `renderFileView` accepts a payload only when it carries a `timeline` array:
  a genuine `timeline_total === 0` keeps the empty state, anything else shows
  "Failed to load files: <reason>"; failures are not cached, so the next visit
  retries; a response that arrives after the user switched sessions is ignored
- tests: HTTP-error vs network-error behaviour of `_fetch` (network error is
  the only disconnected state), the valid/empty/error render paths and the
  retry-after-error, the stale-response guard
- v2.3.1; SW cache simtrace-analyser-v64
2026-10-17 21:04:03 +03:00
catarrh c494bf4111 Files view: per-file tracking (counters, image, device/card changes)
- new `simtrace_analyser/filetrack.py`: a single-pass tracker over a
  session's decoded messages, keyed by (DF, FID) and trace-wide (resets only
  wipe the per-channel selection): counters (`select`/`read`/`update`,
  successful operations only), a sparse image of the observed bytes
  (transparent files by offset, record files per record number) and the
  change log
- changes: **device** = an UPDATE seen in the trace (applied to the image,
  `no_change` flags a provable no-op); **card** = a READ whose bytes differ
  from the image on bytes already known (logged at the surfacing read with
  the changed ranges and the before/after hex; never-seen bytes just fill
  the image, they are an observation, not a change)
- SFI-addressed accesses join the same entry as path/FID ones: the SFI ↔ FID
  relations come from the normative tables and from every surfaced FCP `88`
  DO (including the spec's "SFI = 5 LSBs of the FID" rule when the DO is
  absent); an SFI used before its relation is learned stays provisional and
  merges into the resolved entry
- the DF identity follows TS 102 221 §8.4/Table 8.2: `selected_df_fid()` now
  resolves an EF path selection to its parent DF and returns `aid:<hex>` for
  applications selected by an unknown AID (named from EF.DIR when the trace
  surfaced it); `Database._decode_rows` gained an `on_message` hook and
  `track_files()`
- `GET /api/sessions/<id>/files`: the operation timeline, the per-file
  counters/coverage/change log, the SFI relations and the AID labels
- PWA: the side panel's Map/Stats tabs became a view selector (Map / Stats /
  Files); the Files view is a timeline of Read / Update / Changed (card) rows
  (colour-coded, the same file names as the Map view), a row click jumps to
  the APDU (loading the pages it needs) and a card-change row's Δ opens the
  changed ranges with the previous and the new bytes; EN/RU
- bounds: the image freezes past 64 KB of observed bytes per file, the change
  log keeps the last 1000 events per file (counters keep counting)
- tests: tests/test_filetrack.py (counters, resets, channels, image/diff
  semantics, record files, SFI resolution and the provisional merge, EF.DIR
  labels, caps, the endpoint) and Node tests for the Files-view helpers and
  wiring
- v2.3.0; MIN_SERVER_VERSION 2.3.0; SW cache simtrace-analyser-v63
2026-10-17 20:51:33 +03:00
catarrh 28bc8f1f24 Import COMPRION trace exports (Protocol Layer + Application Layer time base)
- new `simtrace_analyser/comprion.py`: parses the tab-separated ISO Protocol
  Layer export (metadata block, ATR/PPS exchanges, APDUs with continuation
  rows, delays in etu) and re-encodes every exchange into the wire-shaped
  TPDUs the analyser stores — a case-4 exchange becomes the command, a
  fabricated `61 <len>` status word and a GET RESPONSE (command's logical
  channel preserved), so command/response pairing, FCP/file decoding and the
  GET RESPONSE filters work unchanged; Cold reset / Power off become RST/VCC
  line events, deliberately without the sigrok CLK extension (the export
  carries no clock measurement)
- optional matching **ISO Application Layer** export as the exact time base:
  its one `Time:` row per exchange (ms precision) replaces the delay estimate
  (0-based elapsed, `started = Session Name + first Time`), guarded by a
  session-identity check (`Session Name`, falling back to `Working
  directory`; the two layers' export timestamps differ and are not compared)
  and an exchange-count check — mismatched files are refused, never mixed
- protocol-only imports keep the Delay-based timeline: card/line activity
  time (host pauses absent), the unit assuming 3.8 MHz (`CLK_HZ`); the
  estimate is not fed into the CLK/RST line-event annotation
- `POST /api/sessions/import?format=comprion` (raw text body, or a JSON
  `{text, times_text}` bundle) with stable error codes (app_layer /
  not_comprion / unsupported_layout / no_data / times_unparsable /
  session_mismatch / time_base_unverified / time_base_mismatch); a COMPRION
  file dropped on the PCAP path answers with a pointer (comprion_export);
  session mode `comprion`, window from the Session Name
- PWA: import dialog with two separate pickers (Protocol Layer required,
  Application Layer optional) whose hint switches between "activity time"
  and "exact timestamps"; errors stay in the dialog with both selections
  until fixed or cancelled (Cancel/Esc, also disabled while importing);
  EN/RU
- tests: tests/test_comprion.py (parser, wire encoding, time base + guards,
  import endpoint) and frontend/tests/comprion.test.js (file checks, slot
  validation, dialog state machine with a DOM stub, RU coverage)
- v2.2.0; MIN_SERVER_VERSION 2.2.0; SW cache simtrace-analyser-v61
2026-10-17 00:45:15 +03:00