@@ -52,16 +52,31 @@ export interface RunLedger {
5252/** Run tags are generated ids; anything else in the directory is not a record. */
5353const RUN_ID = / ^ [ A - Z a - z 0 - 9 _ - ] { 1 , 128 } $ /
5454
55+ /** A record as saved: the current shape, or the earlier one with `delivered` and `mustStop`. */
56+ type SavedRecord = Partial < RunRecord > & { delivered ?: unknown ; mustStop ?: unknown }
57+
58+ /**
59+ * The record's state. A record from before `state` existed (a released build wrote them) is read
60+ * as the state it meant: `mustStop` as `stop`, which wins, then `delivered` as `delivered`.
61+ */
62+ function stateOf ( saved : SavedRecord ) : RunState | null {
63+ if ( RUN_STATES . includes ( saved . state as RunState ) ) return saved . state as RunState
64+ if ( typeof saved . delivered !== 'boolean' ) return null
65+ if ( saved . mustStop === true ) return 'stop'
66+ return saved . delivered ? 'delivered' : 'started'
67+ }
68+
5569function parseRecord ( text : string ) : RunRecord | null {
5670 try {
57- const parsed = JSON . parse ( text ) as Partial < RunRecord >
71+ const parsed = JSON . parse ( text ) as SavedRecord
72+ const state = stateOf ( parsed )
5873 if (
5974 typeof parsed . runId === 'string' &&
6075 RUN_ID . test ( parsed . runId ) &&
6176 typeof parsed . pane === 'string' &&
6277 / ^ % \d + $ / . test ( parsed . pane ) &&
6378 typeof parsed . callId === 'string' &&
64- RUN_STATES . includes ( parsed . state as RunState ) &&
79+ state &&
6580 typeof parsed . socket === 'string' &&
6681 parsed . socket . startsWith ( '/' )
6782 ) {
@@ -70,7 +85,7 @@ function parseRecord(text: string): RunRecord | null {
7085 pane : parsed . pane ,
7186 socket : parsed . socket ,
7287 callId : parsed . callId ,
73- state : parsed . state as RunState ,
88+ state,
7489 }
7590 }
7691 } catch {
0 commit comments