What Revclust added beyond structured logs in a real Flutter regression
A controlled comparison using Lichess Mobile issue #2726.
A historical Lichess Mobile regression produced the same app-authored diagnostic evidence in a structured log and a Revclust incident. Both exposed stale analysis state. The difference was how that evidence was assembled and preserved.
In Lichess Mobile issue #2726, a legal move could silently stop working:
Open Analysis Board
→ play e4
→ return
→ open Opening Explorer
→ attempt d4
Opening Explorer displayed a fresh board, but the underlying analysis state still carried the e2e4 path from the previous session. That path did not exist in Explorer’s new analysis tree. The requested d4 move (d2d4 in UCI notation) was legal, but the path could not advance.
Buggy Lichess build after the rejected d4 move.
Opening Explorer directly accepted d4. The complete sequence also worked after the official fix.
There was no crash or exception. The relevant evidence was the journey into Explorer, the retained path, the legal move request, and the failed path advancement.
The matched structured log captured those app-authored facts. Revclust did not uncover information unavailable to logs. It assembled the expected-versus-observed failure, recent journey, and app-selected state into one durable incident, alongside SDK-collected runtime context and app-configured build information.
The comparison is therefore about evidence handling, not privileged diagnosis.
A controlled comparison
This was a known historical regression, not a blind investigation. The comparison used the buggy Lichess commit 05b713e and the fixed PR head acf0b44.
Three runs isolated the failure:
Buggy: Analysis e4 → Explorer → d4 failed
Buggy: Explorer directly → d4 succeeded
Fixed: Analysis e4 → Explorer → d4 succeeded
For each matched event, the instrumentation constructed the app-authored facts once, then sent the same map to the structured JSON log and Revclust. At the failure boundary, both recorded the same failure kind, subject, expected result, and observed facts.
The snapshot values also matched, but the capture mechanism differed. The JSONL path emitted the snapshot maps directly, while Revclust retrieved them through its state provider when the failure was captured.
Only the failing run emitted an invariant failure and produced a Revclust incident. Both controls recorded successful path advancement and produced no incident.
The comparison tests how Revclust captures and assembles evidence around matched app-authored facts, including SDK-collected runtime context and app-configured build information. It also verifies that the capture is accepted and available as a retrievable incident. It does not test blind root-cause discovery, diagnosis speed, or instrumentation effort.
Same evidence, different artifacts
The structured failure record contained enough evidence to explain the bug:
{
"failure_kind": "legal_analysis_move_not_applied",
"expected": {
"path_advanced": true
},
"observed": {
"requested_move_uci": "d2d4",
"move_legal": true,
"path_before_moves": ["e2e4"],
"path_exists_in_root": false,
"current_node_is_root": true,
"new_path_moves": null,
"path_advanced": false
}
}
The move was legal and the visible position had fallen back to the root, but the app still held the earlier e2e4 path. That path could not be resolved in the new tree, so d2d4 produced no new path.
The preceding JSONL records preserved the journey into Analysis Board, the successful e2e4 move, the transition to Explorer, and the failed d2d4 attempt. The JSONL also emitted the app-selected snapshot values at the failure boundary.
Revclust received the same app-authored timeline and failure facts.

At capture, it retrieved the matching snapshot through the app’s state provider and included it in the incident:
surface: opening_explorer
saved_path_moves: [e2e4]
saved_path_reused: true
saved_root_reused: false
path_exists_in_root: false
requested_move_uci: d2d4
path_advanced: false

It also included SDK-collected device, OS, network and update context, alongside the configured app version, build, Git revision and release stage. The capture was accepted and stored as one retrievable incident.

The structured log exposed the stale-path inconsistency. Revclust did not add a missing causal fact; it assembled the matched evidence and surrounding context into one incident artifact.
The controls
The failing and passing runs differed in their internal state:
| Run | State before d2d4 | Result |
|---|---|---|
| Buggy seeded sequence | Reused e2e4 path did not exist in the new root | Path did not advance |
| Buggy direct Explorer | No saved path; current path resolved at the root | Path advanced to d2d4 |
| Fixed seeded sequence | Saved analysis existed, but its path was not reused | Path advanced to d2d4 |
In the direct control, the same buggy build opened Explorer without first visiting Analysis Board. The d2d4 move was legal, resolved from the root, and produced a new path.
In the fixed build, the complete Analysis Board → Explorer sequence also succeeded. The earlier analysis session was present, but its e2e4 path was not carried into Explorer.
Neither control log contained an invariant_failure, capture_queued, or capture_accepted event.
Fixed seeded sequence after d2d4.
These controls tie the captured incident to the stale-path regression rather than the move itself or the instrumentation.
What the difference means
The difference was the unit of review. The JSONL contained a sequence of records. Revclust used the invariant failure as an incident boundary, then assembled the matched journey and state with runtime context and release identity.
The result was a different evidence model: one retrievable incident containing the relevant facts and context.
Keeping the evidence together
The harder test is a production failure whose cause is not already known.
Capture your next hard-to-reproduce Flutter incident with Revclust.