@pasko70/pibo 1.11.2 → 1.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/dist/apps/chat/data/chat-data-mappers.js +18 -6
  2. package/dist/apps/chat/loop-api.js +22 -6
  3. package/dist/apps/chat-ui/assets/dist-B5PTVnox.js +1 -0
  4. package/dist/apps/chat-ui/assets/dist-B5ZAfwf5.js +1 -0
  5. package/dist/apps/{context-files-ui/assets/dist-ZsBbt0uY.js → chat-ui/assets/dist-BXjLdcn6.js} +1 -1
  6. package/dist/apps/{context-files-ui/assets/dist-DqYw0LH7.js → chat-ui/assets/dist-BeKdUsyg.js} +1 -1
  7. package/dist/apps/chat-ui/assets/dist-BkUONE3N.js +1 -0
  8. package/dist/apps/{context-files-ui/assets/dist-vnd7PMu3.js → chat-ui/assets/dist-BtQ20SMU.js} +1 -1
  9. package/dist/apps/{context-files-ui/assets/dist-DPG9jOQ-.js → chat-ui/assets/dist-CNv02m3N.js} +1 -1
  10. package/dist/apps/{context-files-ui/assets/dist-Dp5AH00p.js → chat-ui/assets/dist-CSBDio7C.js} +1 -1
  11. package/dist/apps/{context-files-ui/assets/dist-kmsvtHkH.js → chat-ui/assets/dist-CjXSEbsr.js} +1 -1
  12. package/dist/apps/chat-ui/assets/{dist-SVPsM5Oi.js → dist-D1KyNDg5.js} +2 -2
  13. package/dist/apps/{context-files-ui/assets/dist-DK01b7x4.js → chat-ui/assets/dist-D9B41N2f.js} +1 -1
  14. package/dist/apps/chat-ui/assets/dist-DKoyMSNr.js +1 -0
  15. package/dist/apps/chat-ui/assets/dist-DLMjd26T.js +1 -0
  16. package/dist/apps/chat-ui/assets/dist-DotDq_kD.js +1 -0
  17. package/dist/apps/chat-ui/assets/dist-QQuDy4KA.js +1 -0
  18. package/dist/apps/{context-files-ui/assets/dist-BOiGdrG-.js → chat-ui/assets/dist-TAhl1jC0.js} +1 -1
  19. package/dist/apps/{context-files-ui/assets/dist-TbjAhles.js → chat-ui/assets/dist-TS4EA6YQ.js} +1 -1
  20. package/dist/apps/{context-files-ui/assets/dist-TF5iO5ML.js → chat-ui/assets/dist-yjwDcRbw.js} +1 -1
  21. package/dist/apps/chat-ui/assets/{dockerfile-CUaqzcqp.js → dockerfile-CJb2sekW.js} +1 -1
  22. package/dist/apps/chat-ui/assets/{factor-C2tAxNob.js → factor-B2EMQZkP.js} +1 -1
  23. package/dist/apps/chat-ui/assets/index-BoRl0OB_.js +473 -0
  24. package/dist/apps/chat-ui/assets/index-aTOOomMF.css +1 -0
  25. package/dist/apps/chat-ui/assets/{nsis-SMDwKltR.js → nsis-DOo3SJmd.js} +1 -1
  26. package/dist/apps/chat-ui/assets/{pug-Bo3wfL-f.js → pug-QU72BPAa.js} +1 -1
  27. package/dist/apps/chat-ui/index.html +3 -4
  28. package/dist/apps/chat-vscode-web/assets/index-DGcSd2ZH.js +275 -0
  29. package/dist/apps/chat-vscode-web/assets/{index-Bf2JvJ9z.css → index-Dupu1DzQ.css} +1 -1
  30. package/dist/apps/chat-vscode-web/index.html +2 -2
  31. package/dist/apps/context-files-ui/assets/dist-B07Whoa6.js +1 -0
  32. package/dist/apps/context-files-ui/assets/dist-BACxmdQ2.js +9 -0
  33. package/dist/apps/context-files-ui/assets/dist-BFlEjppv.js +1 -0
  34. package/dist/apps/{chat-ui/assets/dist-CuGiEm5l.js → context-files-ui/assets/dist-BQK_wUMR.js} +2 -2
  35. package/dist/apps/context-files-ui/assets/dist-CigbyRK5.js +1 -0
  36. package/dist/apps/context-files-ui/assets/dist-D68eIqmX.js +1 -0
  37. package/dist/apps/context-files-ui/assets/dist-DT9QkgTN.js +1 -0
  38. package/dist/apps/context-files-ui/assets/dist-De6eI3Cr.js +1 -0
  39. package/dist/apps/context-files-ui/assets/dist-Dtv5S2qd.js +11 -0
  40. package/dist/apps/context-files-ui/assets/dist-TG9QLHKj.js +1 -0
  41. package/dist/apps/context-files-ui/assets/index-B5j33Q2B.js +438 -0
  42. package/dist/apps/context-files-ui/assets/{index-B92tL3Pp.css → index-CukPnd6A.css} +1 -1
  43. package/dist/apps/context-files-ui/index.html +2 -2
  44. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  45. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.11.4.vsix +0 -0
  46. package/dist/core/routed-session.js +143 -24
  47. package/dist/core/runtime-telemetry.js +90 -0
  48. package/dist/core/runtime.js +1 -0
  49. package/dist/core/session-router.js +262 -50
  50. package/dist/debug/web-render-order-analysis.js +307 -0
  51. package/dist/debug/web-snapshot-browser-scripts.js +10 -1
  52. package/dist/debug/web-streaming-benchmark-analysis.js +12 -1
  53. package/dist/debug/web-streaming-browser-library.js +268 -58
  54. package/dist/debug/web-streaming-report.js +24 -0
  55. package/dist/debug/web.js +14 -3
  56. package/dist/gateway/server.js +2 -0
  57. package/dist/gateway/web.js +1 -0
  58. package/dist/loops/accounting.js +8 -1
  59. package/dist/loops/cli.js +1 -1
  60. package/dist/loops/service.js +167 -27
  61. package/dist/loops/store.js +229 -17
  62. package/dist/loops/tools.js +30 -9
  63. package/dist/plugins/context-files.js +3 -1
  64. package/dist/runs/registry.js +19 -0
  65. package/package.json +1 -1
  66. package/dist/apps/chat-ui/assets/dist--55mTWk3.js +0 -1
  67. package/dist/apps/chat-ui/assets/dist-BBVpFHAq.js +0 -11
  68. package/dist/apps/chat-ui/assets/dist-BXyVMdHv.js +0 -1
  69. package/dist/apps/chat-ui/assets/dist-BZ39rB1W.js +0 -1
  70. package/dist/apps/chat-ui/assets/dist-BiGfVaXN.js +0 -1
  71. package/dist/apps/chat-ui/assets/dist-BsedZGJo.js +0 -1
  72. package/dist/apps/chat-ui/assets/dist-C5YJOwhH.js +0 -1
  73. package/dist/apps/chat-ui/assets/dist-C5oXtFSP.js +0 -1
  74. package/dist/apps/chat-ui/assets/dist-CCGKu-Wj.js +0 -9
  75. package/dist/apps/chat-ui/assets/dist-CE0MvPLM.js +0 -1
  76. package/dist/apps/chat-ui/assets/dist-CKM5j-iy.js +0 -1
  77. package/dist/apps/chat-ui/assets/dist-CUp9us2q.js +0 -1
  78. package/dist/apps/chat-ui/assets/dist-CZ9T4Cly.js +0 -1
  79. package/dist/apps/chat-ui/assets/dist-DBnh8gXR.js +0 -1
  80. package/dist/apps/chat-ui/assets/dist-DSKQpPaz.js +0 -1
  81. package/dist/apps/chat-ui/assets/dist-DeOnZ-pw.js +0 -23
  82. package/dist/apps/chat-ui/assets/dist-DnQYnLQS.js +0 -1
  83. package/dist/apps/chat-ui/assets/dist-VT4x40uL.js +0 -6
  84. package/dist/apps/chat-ui/assets/dist-Zqt9kNG9.js +0 -1
  85. package/dist/apps/chat-ui/assets/dist-tGfufz3b.js +0 -1
  86. package/dist/apps/chat-ui/assets/dist-xtnVygdr.js +0 -1
  87. package/dist/apps/chat-ui/assets/index-DNeE4HrG.css +0 -1
  88. package/dist/apps/chat-ui/assets/index-vcg8JNj9.js +0 -173
  89. package/dist/apps/chat-ui/assets/rolldown-runtime-S-ySWqyJ.js +0 -1
  90. package/dist/apps/chat-vscode-web/assets/index-DVlCO7v_.js +0 -41
  91. package/dist/apps/context-files-ui/assets/index-BhAWD3dv.js +0 -202
  92. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.11.2.vsix +0 -0
  93. /package/dist/apps/chat-ui/assets/{apl-BxEMbctQ.js → apl-14BqhLYK.js} +0 -0
  94. /package/dist/apps/chat-ui/assets/{asciiarmor-eFjeGRuZ.js → asciiarmor-WLvjqI7d.js} +0 -0
  95. /package/dist/apps/chat-ui/assets/{asn1-Cfx-0pt9.js → asn1-Bg4FbdCg.js} +0 -0
  96. /package/dist/apps/chat-ui/assets/{asterisk-B5BHTsBr.js → asterisk-B2MO-X4d.js} +0 -0
  97. /package/dist/apps/chat-ui/assets/{brainfuck-CAA2xofr.js → brainfuck-CV9kufud.js} +0 -0
  98. /package/dist/apps/chat-ui/assets/{clike-BoDCOLzN.js → clike-CjmcUpt6.js} +0 -0
  99. /package/dist/apps/chat-ui/assets/{clojure-kVFSWX0o.js → clojure-De3QGfx6.js} +0 -0
  100. /package/dist/apps/chat-ui/assets/{cmake-BUPAhezI.js → cmake-i2VDNaRq.js} +0 -0
  101. /package/dist/apps/chat-ui/assets/{cobol-BfgHZgup.js → cobol-BwO6DF08.js} +0 -0
  102. /package/dist/apps/chat-ui/assets/{coffeescript-G1Pe_1AZ.js → coffeescript-BtivDvRz.js} +0 -0
  103. /package/dist/apps/chat-ui/assets/{commonlisp-B3N0CjHn.js → commonlisp-DFkEQdLP.js} +0 -0
  104. /package/dist/apps/chat-ui/assets/{crystal-C15ndaGM.js → crystal-CU0NkcVL.js} +0 -0
  105. /package/dist/apps/chat-ui/assets/{css-BqOeyZOV.js → css-CbMZAQ1W.js} +0 -0
  106. /package/dist/apps/chat-ui/assets/{cypher-KjIKv-wW.js → cypher-Dke5QOzv.js} +0 -0
  107. /package/dist/apps/chat-ui/assets/{d-BlT5AEC-.js → d-TPqSVaHM.js} +0 -0
  108. /package/dist/apps/chat-ui/assets/{diff-oF98tbqj.js → diff-B365LSoZ.js} +0 -0
  109. /package/dist/apps/chat-ui/assets/{dtd-VCA9yr61.js → dtd-CBMymJ7O.js} +0 -0
  110. /package/dist/apps/chat-ui/assets/{dylan-O-V5Dw5W.js → dylan-08Azy1NK.js} +0 -0
  111. /package/dist/apps/chat-ui/assets/{ebnf-SPmdBkvT.js → ebnf-Dkum_1J8.js} +0 -0
  112. /package/dist/apps/chat-ui/assets/{ecl-ChfCttfI.js → ecl-dhxjHL8y.js} +0 -0
  113. /package/dist/apps/chat-ui/assets/{eiffel-cB9EbjeN.js → eiffel-C446m6dI.js} +0 -0
  114. /package/dist/apps/chat-ui/assets/{elm-BTiVflBU.js → elm-po1E9de0.js} +0 -0
  115. /package/dist/apps/chat-ui/assets/{erlang-egf0TXFm.js → erlang-BD5LkVkR.js} +0 -0
  116. /package/dist/apps/chat-ui/assets/{fcl-BiCjh1tj.js → fcl-DkEOamHd.js} +0 -0
  117. /package/dist/apps/chat-ui/assets/{forth-C4kDGW6u.js → forth-dCg2_HVB.js} +0 -0
  118. /package/dist/apps/chat-ui/assets/{fortran-DzkLaPnd.js → fortran-3ZpXLFh1.js} +0 -0
  119. /package/dist/apps/chat-ui/assets/{gas-DMOxskQF.js → gas-DMmxLZRI.js} +0 -0
  120. /package/dist/apps/chat-ui/assets/{gherkin-BPxBpp-k.js → gherkin-DUSFg2R6.js} +0 -0
  121. /package/dist/apps/chat-ui/assets/{groovy-CkEnc0ZY.js → groovy-Cmduloe1.js} +0 -0
  122. /package/dist/apps/chat-ui/assets/{haskell-Dadpo9-w.js → haskell-Cyr255R9.js} +0 -0
  123. /package/dist/apps/chat-ui/assets/{haxe-CDNZL9MW.js → haxe-BJVKtprM.js} +0 -0
  124. /package/dist/apps/chat-ui/assets/{http-jy9Zxxt3.js → http-DszHFpc-.js} +0 -0
  125. /package/dist/apps/chat-ui/assets/{idl-CGSB6iiy.js → idl-Cati9Nrv.js} +0 -0
  126. /package/dist/apps/chat-ui/assets/{javascript-DSlzRUd8.js → javascript-C5pDVaoP.js} +0 -0
  127. /package/dist/apps/chat-ui/assets/{julia-DTiF9v6R.js → julia-DlqY1cTU.js} +0 -0
  128. /package/dist/apps/chat-ui/assets/{livescript-Ci8Xxna6.js → livescript-C6p8-2W1.js} +0 -0
  129. /package/dist/apps/chat-ui/assets/{lua-eVxIrt9t.js → lua-BxuTHaF7.js} +0 -0
  130. /package/dist/apps/chat-ui/assets/{mathematica-Da3grj36.js → mathematica-nDHZUMJT.js} +0 -0
  131. /package/dist/apps/chat-ui/assets/{mbox-BWBMSafM.js → mbox-DAaR0Hcz.js} +0 -0
  132. /package/dist/apps/chat-ui/assets/{mirc-CtHu9S1B.js → mirc-CCA0FRfl.js} +0 -0
  133. /package/dist/apps/chat-ui/assets/{mllike-wTFlPWXS.js → mllike-Cw3Iccsb.js} +0 -0
  134. /package/dist/apps/chat-ui/assets/{modelica-cKbQ0UXu.js → modelica-Czx80fNR.js} +0 -0
  135. /package/dist/apps/chat-ui/assets/{mscgen-C5pXQCMK.js → mscgen-BmfuTbzG.js} +0 -0
  136. /package/dist/apps/chat-ui/assets/{mumps-CKBHkOQq.js → mumps-Ds_ZaumL.js} +0 -0
  137. /package/dist/apps/chat-ui/assets/{nginx-B00AiQel.js → nginx-D9M2PQ4U.js} +0 -0
  138. /package/dist/apps/chat-ui/assets/{ntriples-B_36EBV0.js → ntriples-DLHGTvHs.js} +0 -0
  139. /package/dist/apps/chat-ui/assets/{octave-BXPjzAif.js → octave-8jj96JiC.js} +0 -0
  140. /package/dist/apps/chat-ui/assets/{oz-Dedpat1M.js → oz-BmMq7iC4.js} +0 -0
  141. /package/dist/apps/chat-ui/assets/{pascal-CMcUg72K.js → pascal-BgMr6XpT.js} +0 -0
  142. /package/dist/apps/chat-ui/assets/{perl-DoVTbnzt.js → perl-D6YJObi_.js} +0 -0
  143. /package/dist/apps/chat-ui/assets/{pig-CULXT1YV.js → pig-nx7uchs8.js} +0 -0
  144. /package/dist/apps/chat-ui/assets/{powershell-Cv5Uhf6b.js → powershell-B4IPkVxR.js} +0 -0
  145. /package/dist/apps/chat-ui/assets/{properties-CQ1C2P-M.js → properties-CoavQdLC.js} +0 -0
  146. /package/dist/apps/chat-ui/assets/{protobuf-SRlvzrl6.js → protobuf-D5EWhcmc.js} +0 -0
  147. /package/dist/apps/chat-ui/assets/{puppet-ClSqCGj6.js → puppet-B_0GFuyD.js} +0 -0
  148. /package/dist/apps/chat-ui/assets/{python-C2_X1GpX.js → python-Cs7sNzy_.js} +0 -0
  149. /package/dist/apps/chat-ui/assets/{q-B_6Gdyzl.js → q-BIB9pPtI.js} +0 -0
  150. /package/dist/apps/chat-ui/assets/{r-BD07NGED.js → r-CN5s4f3o.js} +0 -0
  151. /package/dist/apps/chat-ui/assets/{rpm-CRu5Z2Jl.js → rpm-Ct_Ck8mQ.js} +0 -0
  152. /package/dist/apps/chat-ui/assets/{ruby-dZPnOz8h.js → ruby-BVPradRk.js} +0 -0
  153. /package/dist/apps/chat-ui/assets/{sas-S2t8_sDI.js → sas-DN4j74IF.js} +0 -0
  154. /package/dist/apps/chat-ui/assets/{scheme-WcyFWLW2.js → scheme-CvNgHAnh.js} +0 -0
  155. /package/dist/apps/chat-ui/assets/{shell-DUelnYSh.js → shell-BjiMLAaM.js} +0 -0
  156. /package/dist/apps/chat-ui/assets/{sieve-jDjlVhNh.js → sieve-C2U1O5Z4.js} +0 -0
  157. /package/dist/apps/chat-ui/assets/{simple-mode-CL04yRVp.js → simple-mode-DnMbQuKW.js} +0 -0
  158. /package/dist/apps/chat-ui/assets/{smalltalk-ddWDYy10.js → smalltalk-DkYwYufV.js} +0 -0
  159. /package/dist/apps/chat-ui/assets/{solr-C7rQhLuW.js → solr-BopnSD-v.js} +0 -0
  160. /package/dist/apps/chat-ui/assets/{sparql--fPCCgVd.js → sparql-Cpg3YQfd.js} +0 -0
  161. /package/dist/apps/chat-ui/assets/{spreadsheet-DjthqD5G.js → spreadsheet-kRxtVt9J.js} +0 -0
  162. /package/dist/apps/chat-ui/assets/{sql-D_dieYbr.js → sql-DYI2GwJR.js} +0 -0
  163. /package/dist/apps/chat-ui/assets/{stex-rHcFYcA0.js → stex-BCRT8IJ3.js} +0 -0
  164. /package/dist/apps/chat-ui/assets/{stylus-DxF70RNr.js → stylus-CARoeVE9.js} +0 -0
  165. /package/dist/apps/chat-ui/assets/{swift-T0hDoOb-.js → swift-DKNaLAK6.js} +0 -0
  166. /package/dist/apps/chat-ui/assets/{tcl-Dlzy1mPk.js → tcl-CQyXkgMH.js} +0 -0
  167. /package/dist/apps/chat-ui/assets/{textile-Dy5rFZe5.js → textile-Yg_UWn-t.js} +0 -0
  168. /package/dist/apps/chat-ui/assets/{tiddlywiki-DQP1OymS.js → tiddlywiki-dqVbkfX4.js} +0 -0
  169. /package/dist/apps/chat-ui/assets/{tiki-0vOj3DB2.js → tiki-CC_ic8g0.js} +0 -0
  170. /package/dist/apps/chat-ui/assets/{toml-DEltN0lI.js → toml-B7gGzVkJ.js} +0 -0
  171. /package/dist/apps/chat-ui/assets/{troff-CRbBpEqY.js → troff-Bq3z6oAu.js} +0 -0
  172. /package/dist/apps/chat-ui/assets/{ttcn-M5q1nLKg.js → ttcn-GvRgs2AT.js} +0 -0
  173. /package/dist/apps/chat-ui/assets/{ttcn-cfg-Rmw9NWq9.js → ttcn-cfg-CGCXz7Vo.js} +0 -0
  174. /package/dist/apps/chat-ui/assets/{turtle-BCDWhJK0.js → turtle-CwIpz2yy.js} +0 -0
  175. /package/dist/apps/chat-ui/assets/{vb-QQ7LGlOz.js → vb-BmcHUM2C.js} +0 -0
  176. /package/dist/apps/chat-ui/assets/{vbscript-BiSEdUzz.js → vbscript-Cs9dylre.js} +0 -0
  177. /package/dist/apps/chat-ui/assets/{velocity-CzMg5_6w.js → velocity-CBWU0VCy.js} +0 -0
  178. /package/dist/apps/chat-ui/assets/{verilog-BJOO83gk.js → verilog-DVCHmufx.js} +0 -0
  179. /package/dist/apps/chat-ui/assets/{vhdl-ed4zAZAA.js → vhdl-BGDk4f1d.js} +0 -0
  180. /package/dist/apps/chat-ui/assets/{webidl-Ddy6hbV6.js → webidl-egXQEWlC.js} +0 -0
  181. /package/dist/apps/chat-ui/assets/{xquery-Bw1zwhh6.js → xquery-5f0hn7cg.js} +0 -0
  182. /package/dist/apps/chat-ui/assets/{yacas-DZdTXy3s.js → yacas-DNs9XkmQ.js} +0 -0
  183. /package/dist/apps/chat-ui/assets/{z80-DMG02_YV.js → z80-B7Dfb4UO.js} +0 -0
@@ -0,0 +1,307 @@
1
+ const MAX_FINDINGS = 200;
2
+ const DOM_STATE_SETTLE_MS = 32;
3
+ export function analyzeStreamingRenderOrderCapture(capture) {
4
+ if (!capture)
5
+ return undefined;
6
+ const findings = [];
7
+ const pushFinding = (finding) => {
8
+ if (findings.length < MAX_FINDINGS)
9
+ findings.push(finding);
10
+ };
11
+ const internalStates = orderedInternalStates(capture.traceSnapshots);
12
+ for (const source of ["baseNodes", "currentNodes", "terminalRows", "visibleRows"]) {
13
+ analyzePartitionedStateSequences(internalStates.filter((state) => state.source === source), pushFinding);
14
+ }
15
+ const stableDomStates = capture.domStates.filter((state) => state.atBottom !== false);
16
+ analyzePartitionedStateSequences(stableDomStates.map(domState), pushFinding);
17
+ analyzeVisualOrder(stableDomStates, pushFinding);
18
+ analyzeStateDomAgreement(stableDomStates, internalStates, pushFinding);
19
+ const analysis = {
20
+ domStateCount: capture.domStates.length,
21
+ traceSnapshotCount: capture.traceSnapshots.length,
22
+ reorderCount: findings.filter((finding) => finding.kind === "reorder").length,
23
+ disappearReappearCount: findings.filter((finding) => finding.kind === "disappear-reappear").length,
24
+ identityReplacementCount: findings.filter((finding) => finding.kind === "identity-replacement").length,
25
+ stateDomMismatchCount: findings.filter((finding) => finding.kind === "state-dom-mismatch").length,
26
+ findings,
27
+ regressions: renderOrderRegressions(findings),
28
+ };
29
+ return { ...capture, analysis };
30
+ }
31
+ function orderedInternalStates(snapshots) {
32
+ const states = [];
33
+ for (const snapshot of snapshots) {
34
+ for (const layer of snapshot.layers ?? []) {
35
+ if (!isOrderedLayer(layer))
36
+ continue;
37
+ states.push({
38
+ source: layer.kind,
39
+ piboSessionId: snapshot.piboSessionId,
40
+ timestamp: snapshot.timestamp,
41
+ sequence: snapshot.sequence,
42
+ ids: uniqueStrings(layer.ids),
43
+ meta: Array.isArray(layer.meta) ? layer.meta : [],
44
+ });
45
+ }
46
+ }
47
+ return states.sort((left, right) => left.timestamp - right.timestamp || (left.sequence ?? 0) - (right.sequence ?? 0));
48
+ }
49
+ function isOrderedLayer(layer) {
50
+ return layer.kind === "baseNodes" || layer.kind === "currentNodes" || layer.kind === "terminalRows" || layer.kind === "visibleRows";
51
+ }
52
+ function domState(state) {
53
+ return {
54
+ source: "dom",
55
+ piboSessionId: state.piboSessionId,
56
+ timestamp: state.timestamp,
57
+ sequence: state.traceSequence,
58
+ ids: uniqueStrings(state.rowIds),
59
+ meta: state.rows,
60
+ };
61
+ }
62
+ function analyzePartitionedStateSequences(states, pushFinding) {
63
+ const bySession = new Map();
64
+ for (const state of states) {
65
+ const sessionStates = bySession.get(state.piboSessionId) ?? [];
66
+ sessionStates.push(state);
67
+ bySession.set(state.piboSessionId, sessionStates);
68
+ }
69
+ for (const sessionStates of bySession.values())
70
+ analyzeStateSequence(sessionStates, pushFinding);
71
+ }
72
+ function analyzeStateSequence(states, pushFinding) {
73
+ if (states.length < 2)
74
+ return;
75
+ for (let index = 1; index < states.length; index++) {
76
+ const before = states[index - 1];
77
+ const after = states[index];
78
+ const reordered = reorderedCommonIds(before.ids, after.ids);
79
+ if (reordered.length > 0) {
80
+ pushFinding({
81
+ source: after.source,
82
+ kind: "reorder",
83
+ timestamp: after.timestamp,
84
+ ids: reordered,
85
+ detail: `${after.source} changed relative order: ${compactOrder(before.ids)} -> ${compactOrder(after.ids)}`,
86
+ });
87
+ }
88
+ for (const replacement of identityReplacements(before, after)) {
89
+ pushFinding({
90
+ source: after.source,
91
+ kind: "identity-replacement",
92
+ timestamp: after.timestamp,
93
+ ids: [replacement.beforeId, replacement.afterId],
94
+ detail: `${after.source} changed id for ${replacement.logicalKey}: ${replacement.beforeId} -> ${replacement.afterId}`,
95
+ });
96
+ }
97
+ }
98
+ for (const reappearance of disappearReappearances(states)) {
99
+ pushFinding({
100
+ source: reappearance.source,
101
+ kind: "disappear-reappear",
102
+ timestamp: reappearance.timestamp,
103
+ ids: [reappearance.id],
104
+ detail: `${reappearance.source} removed ${reappearance.id} and later rendered it again`,
105
+ });
106
+ }
107
+ }
108
+ function analyzeVisualOrder(states, pushFinding) {
109
+ for (const state of states) {
110
+ const reordered = reorderedCommonIds(state.rowIds, state.visualRowIds);
111
+ if (reordered.length === 0)
112
+ continue;
113
+ pushFinding({
114
+ source: "visual",
115
+ kind: "reorder",
116
+ timestamp: state.timestamp,
117
+ ids: reordered,
118
+ detail: `visual order differs from DOM order: ${compactOrder(state.rowIds)} -> ${compactOrder(state.visualRowIds)}`,
119
+ });
120
+ }
121
+ }
122
+ function analyzeStateDomAgreement(domStates, internalStates, pushFinding) {
123
+ const terminalStates = internalStates.filter((state) => state.source === "terminalRows");
124
+ const visibleStates = internalStates.filter((state) => state.source === "visibleRows");
125
+ for (const dom of domStates) {
126
+ const sourceCandidates = dom.view === "compact-terminal" ? terminalStates : dom.view === "trace-timeline" ? visibleStates : [];
127
+ const candidates = sourceCandidates.filter((state) => state.piboSessionId === dom.piboSessionId);
128
+ const internal = nearestState(candidates, dom.timestamp, 500, dom.traceSequence);
129
+ if (!internal || dom.rowIds.length === 0)
130
+ continue;
131
+ if (isSubsequence(dom.rowIds, internal.ids))
132
+ continue;
133
+ if (nextSettledMatchingState(candidates, dom))
134
+ continue;
135
+ pushFinding({
136
+ source: "state-dom",
137
+ kind: "state-dom-mismatch",
138
+ timestamp: dom.timestamp,
139
+ ids: dom.rowIds.filter((id) => !internal.ids.includes(id)),
140
+ detail: `${dom.view} DOM is not an ordered subset of ${internal.source}: DOM ${compactOrder(dom.rowIds)}, state ${compactOrder(internal.ids)}`,
141
+ });
142
+ }
143
+ }
144
+ function reorderedCommonIds(before, after) {
145
+ const beforeSet = new Set(before);
146
+ const afterSet = new Set(after);
147
+ const beforeCommon = before.filter((id) => afterSet.has(id));
148
+ const afterCommon = after.filter((id) => beforeSet.has(id));
149
+ if (beforeCommon.length < 2 || arraysEqual(beforeCommon, afterCommon))
150
+ return [];
151
+ const beforeIndex = new Map(beforeCommon.map((id, index) => [id, index]));
152
+ return afterCommon.filter((id, index) => beforeIndex.get(id) !== index);
153
+ }
154
+ function identityReplacements(before, after) {
155
+ const beforeByLogicalKey = logicalIdentityMap(before);
156
+ const afterByLogicalKey = logicalIdentityMap(after);
157
+ const replacements = [];
158
+ const seenPairs = new Set();
159
+ for (const [logicalKey, beforeId] of beforeByLogicalKey) {
160
+ const afterId = afterByLogicalKey.get(logicalKey);
161
+ if (!afterId || afterId === beforeId)
162
+ continue;
163
+ const pair = `${beforeId}\u0000${afterId}`;
164
+ if (seenPairs.has(pair))
165
+ continue;
166
+ seenPairs.add(pair);
167
+ replacements.push({ logicalKey, beforeId, afterId });
168
+ }
169
+ return replacements;
170
+ }
171
+ function logicalIdentityMap(state) {
172
+ const idsByLogicalKey = new Map();
173
+ for (const raw of state.meta) {
174
+ const id = stringField(raw, "id");
175
+ if (!id)
176
+ continue;
177
+ const kind = stringField(raw, "kind") ?? stringField(raw, "type") ?? "node";
178
+ const aliases = [
179
+ ...identityFieldAliases(raw, kind, "stableKey"),
180
+ ...identityFieldAliases(raw, kind, "toolCallId"),
181
+ ...identityFieldAliases(raw, kind, "runId"),
182
+ ...identityFieldAliases(raw, kind, "entryId"),
183
+ ...identityFieldAliases(raw, kind, "eventId"),
184
+ ...stringArrayField(raw, "sourceNodeIds").flatMap((value) => identityAliases(kind, "sourceNodeId", value)),
185
+ ];
186
+ for (const logicalKey of aliases) {
187
+ const ids = idsByLogicalKey.get(logicalKey) ?? new Set();
188
+ ids.add(id);
189
+ idsByLogicalKey.set(logicalKey, ids);
190
+ }
191
+ }
192
+ const result = new Map();
193
+ for (const [logicalKey, ids] of idsByLogicalKey) {
194
+ if (ids.size === 1)
195
+ result.set(logicalKey, [...ids][0]);
196
+ }
197
+ return result;
198
+ }
199
+ function identityFieldAliases(raw, kind, field) {
200
+ const value = stringField(raw, field);
201
+ return value ? identityAliases(kind, field, value) : [];
202
+ }
203
+ function identityAliases(kind, field, value) {
204
+ return [`${kind}:${field}:${value}`, `${field}:${value}`];
205
+ }
206
+ function disappearReappearances(states) {
207
+ const seen = new Set();
208
+ const absentAfterSeen = new Set();
209
+ const reported = new Set();
210
+ const results = [];
211
+ let previous = new Set();
212
+ for (const state of states) {
213
+ const current = new Set(state.ids);
214
+ for (const id of previous) {
215
+ if (!current.has(id) && seen.has(id))
216
+ absentAfterSeen.add(id);
217
+ }
218
+ for (const id of current) {
219
+ if (absentAfterSeen.has(id) && !reported.has(id)) {
220
+ results.push({ source: state.source, id, timestamp: state.timestamp });
221
+ reported.add(id);
222
+ }
223
+ seen.add(id);
224
+ }
225
+ previous = current;
226
+ }
227
+ return results;
228
+ }
229
+ function nextSettledMatchingState(states, dom) {
230
+ return states
231
+ .filter((state) => {
232
+ if (state.timestamp < dom.timestamp || state.timestamp - dom.timestamp > DOM_STATE_SETTLE_MS)
233
+ return false;
234
+ if (dom.traceSequence !== undefined && state.sequence !== undefined && state.sequence <= dom.traceSequence)
235
+ return false;
236
+ return isSubsequence(dom.rowIds, state.ids);
237
+ })
238
+ .sort((left, right) => left.timestamp - right.timestamp || (left.sequence ?? 0) - (right.sequence ?? 0))[0];
239
+ }
240
+ function nearestState(states, timestamp, maxDistanceMs, traceSequence) {
241
+ let candidates = states;
242
+ if (traceSequence !== undefined) {
243
+ const causal = states.filter((state) => state.sequence !== undefined && state.sequence <= traceSequence);
244
+ const latestSequence = causal.reduce((latest, state) => Math.max(latest, state.sequence ?? -1), -1);
245
+ if (latestSequence >= 0)
246
+ candidates = causal.filter((state) => state.sequence === latestSequence);
247
+ }
248
+ let best;
249
+ let bestDistance = Number.POSITIVE_INFINITY;
250
+ for (const state of candidates) {
251
+ const distance = Math.abs(state.timestamp - timestamp);
252
+ const betterSequence = distance === bestDistance && (state.sequence ?? -1) > (best?.sequence ?? -1);
253
+ if (distance < bestDistance || betterSequence) {
254
+ best = state;
255
+ bestDistance = distance;
256
+ }
257
+ }
258
+ return bestDistance <= maxDistanceMs ? best : undefined;
259
+ }
260
+ function renderOrderRegressions(findings) {
261
+ const regressions = [];
262
+ const count = (kind, sources) => findings.filter((finding) => finding.kind === kind && (!sources || sources.includes(finding.source))).length;
263
+ const internalReorders = count("reorder", ["baseNodes", "currentNodes", "terminalRows", "visibleRows"]);
264
+ const renderedReorders = count("reorder", ["dom", "visual"]);
265
+ const reappearances = count("disappear-reappear");
266
+ const replacements = count("identity-replacement");
267
+ const mismatches = count("state-dom-mismatch");
268
+ if (internalReorders > 0)
269
+ regressions.push(`render order internal state reordered ${internalReorders} time${internalReorders === 1 ? "" : "s"}`);
270
+ if (renderedReorders > 0)
271
+ regressions.push(`render order DOM/visual rows reordered ${renderedReorders} time${renderedReorders === 1 ? "" : "s"}`);
272
+ if (reappearances > 0)
273
+ regressions.push(`render order rows disappeared and reappeared ${reappearances} time${reappearances === 1 ? "" : "s"}`);
274
+ if (replacements > 0)
275
+ regressions.push(`render order logical identities changed ids ${replacements} time${replacements === 1 ? "" : "s"}`);
276
+ if (mismatches > 0)
277
+ regressions.push(`render order DOM diverged from client state ${mismatches} time${mismatches === 1 ? "" : "s"}`);
278
+ return regressions;
279
+ }
280
+ function isSubsequence(candidate, full) {
281
+ let index = 0;
282
+ for (const id of full) {
283
+ if (id === candidate[index])
284
+ index += 1;
285
+ if (index === candidate.length)
286
+ return true;
287
+ }
288
+ return candidate.length === 0;
289
+ }
290
+ function uniqueStrings(values) {
291
+ return [...new Set(values.filter((value) => typeof value === "string" && value.length > 0))];
292
+ }
293
+ function stringField(value, key) {
294
+ const field = value[key];
295
+ return typeof field === "string" && field.length > 0 ? field : undefined;
296
+ }
297
+ function stringArrayField(value, key) {
298
+ const field = value[key];
299
+ return Array.isArray(field) ? field.filter((item) => typeof item === "string" && item.length > 0) : [];
300
+ }
301
+ function arraysEqual(left, right) {
302
+ return left.length === right.length && left.every((value, index) => value === right[index]);
303
+ }
304
+ function compactOrder(ids) {
305
+ const shown = ids.slice(0, 8);
306
+ return `[${shown.join(", ")}${ids.length > shown.length ? `, … +${ids.length - shown.length}` : ""}]`;
307
+ }
@@ -40,7 +40,7 @@ function classSummary(element) {
40
40
  }
41
41
  function attrMap(element) {
42
42
  const attrs = {};
43
- const allow = /^(id|role|aria-|data-pibo-|data-testid$|disabled$|checked$|selected$|hidden$|tabindex$|title$)/;
43
+ const allow = /^(id|role|aria-|data-pibo-|data-testid$|data-row-id$|data-row-kind$|data-row-status$|data-trace-node-id$|data-event-id$|data-run-id$|data-order-source$|data-order-stream-id$|data-order-frame-index$|data-span-type$|data-span-status$|data-stable-key$|disabled$|checked$|selected$|hidden$|tabindex$|title$)/;
44
44
  for (const attr of Array.from(element.attributes || [])) {
45
45
  if (!allow.test(attr.name)) continue;
46
46
  if (/token|cookie|authorization|secret|password/i.test(attr.name)) {
@@ -101,8 +101,17 @@ function identityOf(element) {
101
101
  const session = element.getAttribute('data-pibo-session-id');
102
102
  const room = element.getAttribute('data-pibo-room-id');
103
103
  const view = element.getAttribute('data-pibo-view-id');
104
+ const row = element.getAttribute('data-row-id');
105
+ const traceNode = element.getAttribute('data-trace-node-id');
106
+ const eventId = element.getAttribute('data-event-id');
107
+ const runId = element.getAttribute('data-run-id');
104
108
  const testId = element.getAttribute('data-testid');
105
109
  const id = element.id;
110
+ if (debug === 'terminal-row' && row) return { identity: 'terminal-row:' + row, kind: 'pibo-row' };
111
+ if (debug === 'trace-span' && traceNode) return { identity: 'trace-span:' + traceNode, kind: 'pibo-trace-node' };
112
+ if (debug && traceNode) return { identity: debug + ':' + traceNode, kind: 'pibo-trace-node' };
113
+ if (debug && eventId) return { identity: debug + ':event:' + eventId, kind: 'pibo-event' };
114
+ if (debug && runId) return { identity: debug + ':run:' + runId, kind: 'pibo-run' };
106
115
  if (debug && session) return { identity: debug + ':' + session, kind: 'pibo-session' };
107
116
  if (debug && room) return { identity: debug + ':' + room, kind: 'pibo-room' };
108
117
  if (debug && view) return { identity: debug + ':' + view, kind: 'pibo-view' };
@@ -1,5 +1,6 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { summarizeStreamingSelectedLiveEventSource } from "./web-streaming-report.js";
3
+ import { analyzeStreamingRenderOrderCapture } from "./web-render-order-analysis.js";
3
4
  const LIVE_PIPELINE_MIN_PRESERVATION_RATIO = 0.95;
4
5
  const LIVE_PIPELINE_MIN_FLUSH_RATIO = 0.75;
5
6
  const URL_COMPARISON_MAX_SMOOTHNESS_DROP = 15;
@@ -327,6 +328,12 @@ export function summarizeStreamingBenchmarks(runs) {
327
328
  firstVisibleMs: numericStats(runs.map((run) => run.dom.firstPositiveUpdateMs)),
328
329
  longTaskMaxMs: numericStats(runs.map((run) => run.longTasks.maxMs)),
329
330
  regressionCount: numericStats(runs.map((run) => run.regressions.length)),
331
+ renderOrderDomStateCount: numericStats(runs.map((run) => run.renderOrder?.analysis?.domStateCount)),
332
+ renderOrderTraceSnapshotCount: numericStats(runs.map((run) => run.renderOrder?.analysis?.traceSnapshotCount)),
333
+ renderOrderReorderCount: numericStats(runs.map((run) => run.renderOrder?.analysis?.reorderCount)),
334
+ renderOrderDisappearReappearCount: numericStats(runs.map((run) => run.renderOrder?.analysis?.disappearReappearCount)),
335
+ renderOrderIdentityReplacementCount: numericStats(runs.map((run) => run.renderOrder?.analysis?.identityReplacementCount)),
336
+ renderOrderStateDomMismatchCount: numericStats(runs.map((run) => run.renderOrder?.analysis?.stateDomMismatchCount)),
330
337
  debugEnqueueCount: numericStats(runs.map((run) => streamingDebugDeltaNumber(run, "enqueueCount"))),
331
338
  debugFlushCount: numericStats(runs.map((run) => streamingDebugDeltaNumber(run, "flushCount"))),
332
339
  debugFlushedEventCount: numericStats(runs.map((run) => streamingDebugDeltaNumber(run, "flushedEventCount"))),
@@ -529,7 +536,11 @@ function normalizeStreamingBenchmarkGroupArtifact(value, runs) {
529
536
  };
530
537
  }
531
538
  function normalizeStreamingBenchmarkRun(run) {
532
- const scored = { ...run, regressions: Array.isArray(run.regressions) ? run.regressions : [], warnings: Array.isArray(run.warnings) ? run.warnings : [], score: run.score ?? scoreStreamingBenchmark(run) };
539
+ const renderOrder = analyzeStreamingRenderOrderCapture(run.renderOrder);
540
+ const baseRegressions = Array.isArray(run.regressions) ? run.regressions.filter((regression) => !regression.startsWith("render order ")) : [];
541
+ const regressions = [...new Set([...baseRegressions, ...(renderOrder?.analysis?.regressions ?? [])])];
542
+ const withRenderOrder = { ...run, renderOrder, regressions, warnings: Array.isArray(run.warnings) ? run.warnings : [] };
543
+ const scored = { ...withRenderOrder, score: run.score ?? scoreStreamingBenchmark(withRenderOrder) };
533
544
  const withProviderPreservation = { ...scored, providerPreservation: run.providerPreservation ?? summarizeStreamingProviderPreservation(scored) };
534
545
  const withLivePipeline = { ...withProviderPreservation, livePipeline: run.livePipeline ?? summarizeStreamingLivePipeline(withProviderPreservation) };
535
546
  return { ...withLivePipeline, cadence: run.cadence ?? summarizeStreamingCadence(withLivePipeline) };