FORENSIAWeb3 forensicsOpen workspace

What happens to a saved trace when a check is interrupted

A saved trace now records each check before it runs, keeps the attempt counted if the page closes, and never retries on its own. Broader browser lifecycle checks remain open.

· Forensia · 8 min read · Tracing, Saved work

Following funds is done one check at a time, and each check waits on an outside source. Pages get reloaded, laptops close, a second tab is opened by mistake. If a check was in flight when that happened, the old behavior was simple and unhelpful: the page forgot the attempt had ever started.

That matters because checks are rationed: a trace allows four attempts. Losing track of one means an attempt that silently did not count, or a result that arrived and was thrown away.

For traces you have explicitly saved, Forensia now writes down each attempt before it starts. After an interruption, the completed work is still there, the attempt is still counted, and the workspace waits for you to decide what to do. Nothing is retried automatically. This has been checked for specific reload and multi-tab situations. Broader lifecycle checks remain open, including crashes, power loss, a full disk and physical devices.

#Plain languageSigning the logbook before leaving the building

Mountain huts keep a logbook. You sign out before you leave, with your route. When you return, you sign back in. A sign-out with no return does not mean you arrived safely, and it does not mean the trip never happened. Someone has to look at the open entry and decide.

A saved trace now works like that logbook. Before a check is sent, an entry is written saying this attempt has started. When the answer comes back, a second entry records the outcome. A reload in between leaves an open entry. On reopening, the workspace shows it as one check that needs review. You can close it by marking it interrupted. That records that no result is claimed, keeps the attempt counted against the limit of four, and lets you move on to the next eligible check.

This applies to three kinds of saved trace: native-coin recipient checks on EVM networks, token recipient checks on EVM networks, and Bitcoin spent-output checks. It applies only after you save the trace. An unsaved trace remains temporary.

#How it worksReviewing a pending check after a reload

  1. Save the trace first: Save EVM trace or Save token trace under Follow captured transfers, or Save trace under Follow spent outputs. From then on, each later check shows Attempt saved while it waits for its result.
  2. If the page reloads or closes during a check, open Saved in the left rail and find the trace under Saved EVM traces, Token traces or Saved Bitcoin traces. The list shows the used count and that a pending check needs review.
  3. Reopen the trace. The original result loads with its original capture time and no new lookup. The panel shows One check needs review and the button to run another check is disabled.
  4. If you are confident no other tab is still running that check, choose Mark check interrupted. The attempt stays counted, the step is recorded with no result, and the next eligible recipient or output becomes available.
  5. If you see Result not saved yet, the check did finish but its result could not be written. Choose Save received result to store it without another network request, or prepare a backup and download it.

Marking a check interrupted does not cancel a request that another tab already sent. It records your decision, and it prevents a late response from replacing that decision in the saved record.

#Technical detailThe journal, the runner and the revision guard

An append-only journal around the original checkpoint

Each kind of trace has a recovery envelope with its own schema identifier: forensia.evm-native-recovery.v1, forensia.evm-token-recovery.v1 and forensia.bitcoin-recovery.v1. The envelope wraps the exact checkpoint that was saved and adds a list of events. Nothing in the checkpoint is edited.

Recovery envelope (shape from the code)
RecoverableNativeTrace {
  schema: "forensia.evm-native-recovery.v1"
  id                  // must equal the checkpoint id
  revision            // must equal events.length + 1
  startingCheckpoint  // the exact saved checkpoint
  events: [
    { type: "reserved", attemptId, rootTransactionHash, transactionHash, recordedAt }
    { type: "settled",  attemptId, recordedAt, outcome: { capture } | { failure } }
  ]
  stateDigest         // SHA-256 over canonical JSON of the fields above
}

A reserved event names a version 4 UUID and the exact next eligible occurrence: for a native trace, the starting transaction and the queued transaction hash, and for Bitcoin, the txid that the branch queue says comes next. Anything other than the exact next eligible item is rejected. Only one attempt can be pending at a time across all starting points, and a reservation is refused when used attempts have reached the limit (four checks for native and token traces, four steps for Bitcoin).

A settled event must carry the attempt ID of the pending reservation and exactly one of capture or failure. Recorded times must be canonical ISO strings and cannot go backwards from the checkpoint or the previous event. A capture dated later than its own settlement is rejected.

State is replayed, never imported

Opening or importing an envelope replays it. The completed steps in the checkpoint are restored, then each event is applied in order, and every successful observation passes through the same validator that live acquisition uses. Used attempts, the pending attempt and the queue are outputs of that replay. A file cannot declare them.

Order of operations in the runner

StepIf it fails
1. Build the reservation and commit it to IndexedDB against the revision the page holdsNo request is dispatched. A cancel during this write is treated as a used attempt, and still nothing is dispatched.
2. Acquire: challenge, then the bounded source request, honoring the abort signalA failure settlement is built. Transport error strings are not copied into the journal because they can contain provider URLs or credentials.
3. Validate the result, then check the abort signal againA cancel during validation settles as interrupted. A success is not committed after you have left.
4. Commit the settlement against the reservation revisionThe runner returns the reservation as still pending plus the unsaved settlement, which the panel shows as Result not saved yet.

There is no retry anywhere in this sequence. An interruption is stored as a failure outcome saying no result is claimed and the attempt still counts.

Cancelling while the browser verification in step 2 is still pending now ends the check straight away. The wait listens for the abort signal, and a check that was already cancelled does not ask for verification at all. If the verification answers late, the answer is consumed and cannot restart the cancelled check. The shared verification widget itself is not reset or bypassed, and no source request is sent for a cancelled check. This applies to the native, token and Bitcoin follow-up checks only.

Stopping two tabs from overwriting each other

Every write is a compare-and-swap. Inside one IndexedDB read-write transaction the store is read, the existing record must have the expected schema and revision, and the new record must have exactly one more event and one higher revision, with the starting checkpoint and all earlier events identical under canonical JSON. Otherwise the transaction aborts with a message that the trace changed in another tab.

The first reservation promotes an older completed-only checkpoint to an envelope. That is allowed only against the exact saved checkpoint, with one reserved event at revision 2. The reverse is refused: an envelope cannot be replaced by an older completed-only backup. The trace databases open at version 2, so an older copy of the application requesting version 1 fails instead of overwriting a journal.

A controlled test with three independent tabs exercised this on the native store. Tab A reserved an attempt and held its request open. Tab B, holding the older revision, was refused and sent no request. B then re-read the record and committed an interruption. When A released a valid response, the runner returned it as unsaved and it did not replace what B had committed. A fresh tab C read two charged attempts, nothing pending and an explicit interruption.

Real examples in the notes

  • Token trace, Ethereum transaction 0x22fc4a1bba0e2a711a5852f5c835eea4cb764f989895b1b48ec73d84dab8ed95: reload during a third check left 3 of 4 checks with one pending. A second tab holding the older revision had its write rejected.
  • Native trace, Ethereum transaction 0x351035eb60de36d50a6d491308a03971a0b8d68975610177de908e4eb96b555f: reload during the second check left 2 of 4 used and one check needing review. After Mark check interrupted, two attempts stayed charged.
  • Bitcoin trace, transaction f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16: reload left 3 of 4 with one check needing review. The pending backup imported into a separate origin with the same pending attempt.

#LimitsWhat recovery does not cover yet

  • Conflicting updates are reduced, not eliminated as a category. The tab tests are controlled interleavings, not proof of every simultaneous timing.
  • Marking a check interrupted does not cancel a request in another tab, and a request already sent may still count toward source limits.
  • The reservation time is a local clock reading. It is not blockchain time and it is not proof that a request reached a provider.
  • The attempt budget is local bookkeeping in your browser. It is not a server-side billing or abuse control.
  • The journal is unsigned metadata stored in the browser, not encrypted and not synced. Its digest shows consistency, not authenticity. Backups hold no raw source responses.
  • Recovery does not extend tracing. The four-attempt and two-hop bounds are unchanged, there is no background worker, and a recovered trace is not a complete history or proof that the same funds moved onward.
  • Bridge checks are saved as single completed observations and do not use this journal.