@@ -22,6 +22,23 @@ function asNumber(value, fallback = 0) {
2222 return Number . isFinite ( numeric ) ? numeric : fallback ;
2323}
2424
25+ function formatEntityLine ( entity , options = { } ) {
26+ const source = asObject ( entity ) ;
27+ const limit = Number . isFinite ( Number ( options . labelLimit ) )
28+ ? Math . max ( 6 , Math . floor ( Number ( options . labelLimit ) ) )
29+ : 14 ;
30+ const label = sanitizeText ( source . label ) || sanitizeText ( source . entityId ) || "entity" ;
31+ const compactLabel = label . length > limit
32+ ? `${ label . slice ( 0 , limit - 1 ) } .`
33+ : label ;
34+ const marker = source . selected === true ? "*" : "-" ;
35+ const frameDelta = asNumber ( source . frameDelta , 0 ) ;
36+ const status = sanitizeText ( source . divergenceStatus || source . status ) || "unknown" ;
37+ const severity = sanitizeText ( source . severity ) || "low" ;
38+ const alignment = sanitizeText ( source . alignment ) || "unavailable" ;
39+ return `${ marker } ${ compactLabel } delta=${ frameDelta } status=${ status } severity=${ severity } align=${ alignment } ` ;
40+ }
41+
2542function toNetworkSnapshot ( snapshot ) {
2643 return asObject ( snapshot ?. assets ?. networkSampleC ) ;
2744}
@@ -35,32 +52,60 @@ function toDivergenceLines(snapshot) {
3552 const scenario = asObject ( network . scenario ) ;
3653 const divergence = asObject ( network . divergence ) ;
3754 const transport = asObject ( network . network ) ;
55+ const entities = asArray ( divergence . entities ) ;
56+ const selectedEntityId = sanitizeText ( divergence . selectedEntityId ) ;
57+ const selectedEntity = entities . find ( ( entity ) => sanitizeText ( asObject ( entity ) . entityId ) === selectedEntityId ) ;
3858
39- return [
40- `status=${ sanitizeText ( divergence . status ) || "unknown" } ` ,
59+ const lines = [
60+ `selectedStatus= ${ sanitizeText ( divergence . status ) || "unknown" } overallStatus =${ sanitizeText ( divergence . overallStatus ) || sanitizeText ( divergence . status ) || "unknown" } ` ,
4161 `severity=${ sanitizeText ( divergence . severity ) || "low" } correction=${ sanitizeText ( divergence . correctionMode ) || "hold-annotate" } ` ,
4262 `phase=${ sanitizeText ( scenario . phaseLabel ) || "n/a" } (${ sanitizeText ( scenario . phaseId ) || "n/a" } )` ,
43- `frameDelta=${ asNumber ( divergence . frameDelta , 0 ) } ` ,
63+ `selectedEntity=${ sanitizeText ( divergence . selectedEntityLabel ) || selectedEntityId || "n/a" } selectedFrameDelta=${ asNumber ( divergence . selectedFrameDelta ?? divergence . frameDelta , 0 ) } ` ,
64+ `overallFrameDelta=${ asNumber ( divergence . overallFrameDelta , asNumber ( divergence . frameDelta , 0 ) ) } ` ,
4465 `authoritativeFrame=${ asNumber ( divergence . authoritativeFrame , 0 ) } ` ,
4566 `predictedFrame=${ asNumber ( divergence . predictedFrame , 0 ) } ` ,
4667 `alignment=${ sanitizeText ( divergence . alignment ) || "unavailable" } ` ,
4768 `targetOffsetFrames=${ asNumber ( divergence . targetOffsetFrames , 0 ) . toFixed ( 2 ) } ` ,
4869 `rttMs=${ asNumber ( transport . rttMs , 0 ) } jitterMs=${ asNumber ( transport . jitterMs , 0 ) } lossPct=${ asNumber ( transport . packetLossPct , 0 ) } ` ,
4970 `hint=${ sanitizeText ( divergence . reconciliationHint ) || "n/a" } `
5071 ] ;
72+
73+ if ( selectedEntity ) {
74+ lines . push ( `selectedEntityDetail ${ formatEntityLine ( selectedEntity ) } ` ) ;
75+ }
76+ if ( entities . length > 0 ) {
77+ lines . push ( `entityCount=${ entities . length } ` ) ;
78+ entities . slice ( 0 , 5 ) . forEach ( ( entity ) => {
79+ lines . push ( formatEntityLine ( entity ) ) ;
80+ } ) ;
81+ }
82+ return lines ;
5183}
5284
5385function toTimelineLines ( snapshot ) {
5486 const network = toNetworkSnapshot ( snapshot ) ;
5587 const timeline = asObject ( network . timeline ) ;
5688 const history = asObject ( timeline . history ) ;
89+ const entityHistory = asArray ( history . entities ) ;
5790 const events = asArray ( timeline . events ) ;
5891 const lines = [
5992 `history=${ asNumber ( history . size , 0 ) } /${ asNumber ( history . limit , 0 ) } ` ,
6093 `oldestFrame=${ history . oldestFrameId ?? "n/a" } latestFrame=${ history . latestFrameId ?? "n/a" } ` ,
61- `alignment=${ sanitizeText ( history . alignment ) || "unavailable" } frameGap=${ history . frameGap ?? "n/a" } `
94+ `alignment=${ sanitizeText ( history . alignment ) || "unavailable" } frameGap=${ history . frameGap ?? "n/a" } ` ,
95+ `entityHistoryCount=${ asNumber ( history . entityCount , entityHistory . length ) } `
6296 ] ;
6397
98+ if ( entityHistory . length > 0 ) {
99+ entityHistory . slice ( 0 , 5 ) . forEach ( ( entityStatus ) => {
100+ const source = asObject ( entityStatus ) ;
101+ const marker = source . selected === true ? "*" : "-" ;
102+ lines . push (
103+ `${ marker } ${ sanitizeText ( source . entityId ) || "entity" } history=${ asNumber ( source . historySize , 0 ) } /${ asNumber ( source . historyLimit , 0 ) } `
104+ + `aligned=${ source . alignedFrameId ?? "n/a" } gap=${ source . frameGap ?? "n/a" } align=${ sanitizeText ( source . alignment ) || "unavailable" } `
105+ ) ;
106+ } ) ;
107+ }
108+
64109 if ( events . length === 0 ) {
65110 lines . push ( "No timeline events recorded yet." ) ;
66111 return lines ;
@@ -97,19 +142,37 @@ function toValidationLines(snapshot) {
97142function toRewindLines ( snapshot ) {
98143 const network = toNetworkSnapshot ( snapshot ) ;
99144 const rewind = asObject ( network . rewindPreparation ) ;
145+ const rewindEntities = asArray ( rewind . entities ) ;
146+ const rewindSelected = asArray ( rewind . selectedEntityIds ) ;
100147 const correction = asObject ( network . correction ) ;
101148 const replay = asObject ( network . rewindReplay ) ;
149+ const replaySelected = asArray ( replay . selectedEntityIds ) ;
102150
103- return [
151+ const lines = [
104152 `status=${ sanitizeText ( rewind . status ) || "n/a" } ` ,
105153 `canPrepare=${ Boolean ( rewind . canPrepare ) } ` ,
106154 `anchorFrame=${ rewind . rewindAnchorFrameId ?? "n/a" } targetFrame=${ rewind . rewindTargetFrameId ?? "n/a" } ` ,
107155 `resimulateFrameCount=${ asNumber ( rewind . resimulateFrameCount , 0 ) } ` ,
108156 `alignment=${ sanitizeText ( rewind . alignment ) || "unavailable" } frameGap=${ rewind . frameGap ?? "n/a" } ` ,
157+ `selectedEntityIds=${ rewindSelected . join ( "," ) || "n/a" } ` ,
109158 `correctionMode=${ sanitizeText ( correction . mode ) || "hold-annotate" } severity=${ sanitizeText ( correction . severity ) || "low" } ` ,
110- `lastReplayId=${ replay . replayId ?? "none" } replayedFrames=${ asNumber ( replay . replayedFrameCount , 0 ) } postReplaySeverity=${ sanitizeText ( replay . postReplaySeverity ) || "n/a" } ` ,
159+ `lastReplayId=${ replay . replayId ?? "none" } replayedFrames=${ asNumber ( replay . replayedFrameCount , 0 ) } replayEntityIds=${ replaySelected . join ( "," ) || "n/a" } ` ,
160+ `postReplaySeverity=${ sanitizeText ( replay . postReplaySeverity ) || "n/a" } ` ,
111161 sanitizeText ( rewind . note ) || "No rewind preparation note."
112162 ] ;
163+
164+ if ( rewindEntities . length > 0 ) {
165+ lines . push ( `rewindEntityCount=${ rewindEntities . length } ` ) ;
166+ rewindEntities . slice ( 0 , 6 ) . forEach ( ( entityPrep ) => {
167+ const source = asObject ( entityPrep ) ;
168+ lines . push (
169+ `${ sanitizeText ( source . entityId ) || "entity" } status=${ sanitizeText ( source . status ) || "n/a" } `
170+ + `canPrepare=${ Boolean ( source . canPrepare ) } anchor=${ source . rewindAnchorFrameId ?? "n/a" } `
171+ + `resim=${ asNumber ( source . resimulateFrameCount , 0 ) } severity=${ sanitizeText ( source . severity ) || "low" } `
172+ ) ;
173+ } ) ;
174+ }
175+ return lines ;
113176}
114177
115178function toTraceLines ( snapshot , maxLines = 10 ) {
@@ -139,20 +202,30 @@ function commandLinesForDivergence(context) {
139202 const scenario = asObject ( snapshot . scenario ) ;
140203 const divergence = asObject ( snapshot . divergence ) ;
141204 const network = asObject ( snapshot . network ) ;
205+ const entities = asArray ( divergence . entities ) ;
142206
143- return [
144- `status=${ sanitizeText ( divergence . status ) || "unknown" } ` ,
207+ const lines = [
208+ `selectedStatus=${ sanitizeText ( divergence . status ) || "unknown" } ` ,
209+ `overallStatus=${ sanitizeText ( divergence . overallStatus ) || sanitizeText ( divergence . status ) || "unknown" } ` ,
145210 `severity=${ sanitizeText ( divergence . severity ) || "low" } ` ,
146211 `correctionMode=${ sanitizeText ( divergence . correctionMode ) || "hold-annotate" } ` ,
147212 `alignment=${ sanitizeText ( divergence . alignment ) || "unavailable" } ` ,
213+ `selectedEntityId=${ sanitizeText ( divergence . selectedEntityId ) || "n/a" } ` ,
148214 `phase=${ sanitizeText ( scenario . phaseId ) || "unknown" } ` ,
149215 `phaseElapsed=${ asNumber ( scenario . phaseElapsedSeconds , 0 ) . toFixed ( 2 ) } s/${ asNumber ( scenario . phaseDurationSeconds , 0 ) . toFixed ( 2 ) } s` ,
150216 `cycleCount=${ asNumber ( scenario . cycleCount , 0 ) } ` ,
151- `frameDelta=${ asNumber ( divergence . frameDelta , 0 ) } ` ,
217+ `selectedFrameDelta=${ asNumber ( divergence . selectedFrameDelta ?? divergence . frameDelta , 0 ) } ` ,
218+ `overallFrameDelta=${ asNumber ( divergence . overallFrameDelta , asNumber ( divergence . frameDelta , 0 ) ) } ` ,
152219 `authoritativeFrame=${ asNumber ( divergence . authoritativeFrame , 0 ) } ` ,
153220 `predictedFrame=${ asNumber ( divergence . predictedFrame , 0 ) } ` ,
154221 `rttMs=${ asNumber ( network . rttMs , 0 ) } jitterMs=${ asNumber ( network . jitterMs , 0 ) } lossPct=${ asNumber ( network . packetLossPct , 0 ) } `
155222 ] ;
223+
224+ if ( entities . length > 0 ) {
225+ lines . push ( `entityCount=${ entities . length } ` ) ;
226+ entities . slice ( 0 , 6 ) . forEach ( ( entity ) => lines . push ( formatEntityLine ( entity ) ) ) ;
227+ }
228+ return lines ;
156229}
157230
158231function commandLinesForTrace ( context , args = [ ] ) {
@@ -222,22 +295,39 @@ function commandLinesForReproduction(context) {
222295function commandLinesForRewind ( context ) {
223296 const snapshot = getCommandSnapshot ( context ) ;
224297 const rewind = asObject ( snapshot . rewindPreparation ) ;
298+ const rewindEntities = asArray ( rewind . entities ) ;
299+ const rewindSelected = asArray ( rewind . selectedEntityIds ) ;
225300 const timeline = asObject ( snapshot . timeline ) ;
226301 const history = asObject ( timeline . history ) ;
227302 const correction = asObject ( snapshot . correction ) ;
228303 const replay = asObject ( snapshot . rewindReplay ) ;
304+ const replaySelected = asArray ( replay . selectedEntityIds ) ;
229305
230- return [
306+ const lines = [
231307 `rewindStatus=${ sanitizeText ( rewind . status ) || "n/a" } ` ,
232308 `canPrepare=${ Boolean ( rewind . canPrepare ) } ` ,
233309 `rewindAnchorFrame=${ rewind . rewindAnchorFrameId ?? "n/a" } ` ,
234310 `rewindTargetFrame=${ rewind . rewindTargetFrameId ?? "n/a" } ` ,
235311 `resimulateFrameCount=${ asNumber ( rewind . resimulateFrameCount , 0 ) } ` ,
312+ `selectedEntityIds=${ rewindSelected . join ( "," ) || "n/a" } ` ,
236313 `history=${ asNumber ( history . size , 0 ) } /${ asNumber ( history . limit , 0 ) } alignment=${ sanitizeText ( history . alignment ) || "unavailable" } frameGap=${ history . frameGap ?? "n/a" } ` ,
237314 `correctionMode=${ sanitizeText ( correction . mode ) || "hold-annotate" } severity=${ sanitizeText ( correction . severity ) || "low" } ` ,
238- `lastReplayId=${ replay . replayId ?? "none" } replayedFrames=${ asNumber ( replay . replayedFrameCount , 0 ) } postReplaySeverity=${ sanitizeText ( replay . postReplaySeverity ) || "n/a" } ` ,
315+ `lastReplayId=${ replay . replayId ?? "none" } replayedFrames=${ asNumber ( replay . replayedFrameCount , 0 ) } replayEntityIds=${ replaySelected . join ( "," ) || "n/a" } ` ,
316+ `postReplaySeverity=${ sanitizeText ( replay . postReplaySeverity ) || "n/a" } ` ,
239317 sanitizeText ( rewind . note ) || "Rewind preparation status unavailable."
240318 ] ;
319+
320+ if ( rewindEntities . length > 0 ) {
321+ lines . push ( `rewindEntityCount=${ rewindEntities . length } ` ) ;
322+ rewindEntities . slice ( 0 , 8 ) . forEach ( ( entityPrep ) => {
323+ const source = asObject ( entityPrep ) ;
324+ lines . push (
325+ `${ sanitizeText ( source . entityId ) || "entity" } status=${ sanitizeText ( source . status ) || "n/a" } `
326+ + `canPrepare=${ Boolean ( source . canPrepare ) } anchor=${ source . rewindAnchorFrameId ?? "n/a" } resim=${ asNumber ( source . resimulateFrameCount , 0 ) } `
327+ ) ;
328+ } ) ;
329+ }
330+ return lines ;
241331}
242332
243333export function createNetworkSampleCDebugPlugin ( ) {
0 commit comments