@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.
- package/dist/apps/chat/data/chat-data-mappers.js +18 -6
- package/dist/apps/chat/loop-api.js +22 -6
- package/dist/apps/chat-ui/assets/dist-B5PTVnox.js +1 -0
- package/dist/apps/chat-ui/assets/dist-B5ZAfwf5.js +1 -0
- package/dist/apps/{context-files-ui/assets/dist-ZsBbt0uY.js → chat-ui/assets/dist-BXjLdcn6.js} +1 -1
- package/dist/apps/{context-files-ui/assets/dist-DqYw0LH7.js → chat-ui/assets/dist-BeKdUsyg.js} +1 -1
- package/dist/apps/chat-ui/assets/dist-BkUONE3N.js +1 -0
- package/dist/apps/{context-files-ui/assets/dist-vnd7PMu3.js → chat-ui/assets/dist-BtQ20SMU.js} +1 -1
- package/dist/apps/{context-files-ui/assets/dist-DPG9jOQ-.js → chat-ui/assets/dist-CNv02m3N.js} +1 -1
- package/dist/apps/{context-files-ui/assets/dist-Dp5AH00p.js → chat-ui/assets/dist-CSBDio7C.js} +1 -1
- package/dist/apps/{context-files-ui/assets/dist-kmsvtHkH.js → chat-ui/assets/dist-CjXSEbsr.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-SVPsM5Oi.js → dist-D1KyNDg5.js} +2 -2
- package/dist/apps/{context-files-ui/assets/dist-DK01b7x4.js → chat-ui/assets/dist-D9B41N2f.js} +1 -1
- package/dist/apps/chat-ui/assets/dist-DKoyMSNr.js +1 -0
- package/dist/apps/chat-ui/assets/dist-DLMjd26T.js +1 -0
- package/dist/apps/chat-ui/assets/dist-DotDq_kD.js +1 -0
- package/dist/apps/chat-ui/assets/dist-QQuDy4KA.js +1 -0
- package/dist/apps/{context-files-ui/assets/dist-BOiGdrG-.js → chat-ui/assets/dist-TAhl1jC0.js} +1 -1
- package/dist/apps/{context-files-ui/assets/dist-TbjAhles.js → chat-ui/assets/dist-TS4EA6YQ.js} +1 -1
- package/dist/apps/{context-files-ui/assets/dist-TF5iO5ML.js → chat-ui/assets/dist-yjwDcRbw.js} +1 -1
- package/dist/apps/chat-ui/assets/{dockerfile-CUaqzcqp.js → dockerfile-CJb2sekW.js} +1 -1
- package/dist/apps/chat-ui/assets/{factor-C2tAxNob.js → factor-B2EMQZkP.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BoRl0OB_.js +473 -0
- package/dist/apps/chat-ui/assets/index-aTOOomMF.css +1 -0
- package/dist/apps/chat-ui/assets/{nsis-SMDwKltR.js → nsis-DOo3SJmd.js} +1 -1
- package/dist/apps/chat-ui/assets/{pug-Bo3wfL-f.js → pug-QU72BPAa.js} +1 -1
- package/dist/apps/chat-ui/index.html +3 -4
- package/dist/apps/chat-vscode-web/assets/index-DGcSd2ZH.js +275 -0
- package/dist/apps/chat-vscode-web/assets/{index-Bf2JvJ9z.css → index-Dupu1DzQ.css} +1 -1
- package/dist/apps/chat-vscode-web/index.html +2 -2
- package/dist/apps/context-files-ui/assets/dist-B07Whoa6.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-BACxmdQ2.js +9 -0
- package/dist/apps/context-files-ui/assets/dist-BFlEjppv.js +1 -0
- package/dist/apps/{chat-ui/assets/dist-CuGiEm5l.js → context-files-ui/assets/dist-BQK_wUMR.js} +2 -2
- package/dist/apps/context-files-ui/assets/dist-CigbyRK5.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-D68eIqmX.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-DT9QkgTN.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-De6eI3Cr.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-Dtv5S2qd.js +11 -0
- package/dist/apps/context-files-ui/assets/dist-TG9QLHKj.js +1 -0
- package/dist/apps/context-files-ui/assets/index-B5j33Q2B.js +438 -0
- package/dist/apps/context-files-ui/assets/{index-B92tL3Pp.css → index-CukPnd6A.css} +1 -1
- package/dist/apps/context-files-ui/index.html +2 -2
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.11.4.vsix +0 -0
- package/dist/core/routed-session.js +143 -24
- package/dist/core/runtime-telemetry.js +90 -0
- package/dist/core/runtime.js +1 -0
- package/dist/core/session-router.js +262 -50
- package/dist/debug/web-render-order-analysis.js +307 -0
- package/dist/debug/web-snapshot-browser-scripts.js +10 -1
- package/dist/debug/web-streaming-benchmark-analysis.js +12 -1
- package/dist/debug/web-streaming-browser-library.js +268 -58
- package/dist/debug/web-streaming-report.js +24 -0
- package/dist/debug/web.js +14 -3
- package/dist/gateway/server.js +2 -0
- package/dist/gateway/web.js +1 -0
- package/dist/loops/accounting.js +8 -1
- package/dist/loops/cli.js +1 -1
- package/dist/loops/service.js +167 -27
- package/dist/loops/store.js +229 -17
- package/dist/loops/tools.js +30 -9
- package/dist/plugins/context-files.js +3 -1
- package/dist/runs/registry.js +19 -0
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/dist--55mTWk3.js +0 -1
- package/dist/apps/chat-ui/assets/dist-BBVpFHAq.js +0 -11
- package/dist/apps/chat-ui/assets/dist-BXyVMdHv.js +0 -1
- package/dist/apps/chat-ui/assets/dist-BZ39rB1W.js +0 -1
- package/dist/apps/chat-ui/assets/dist-BiGfVaXN.js +0 -1
- package/dist/apps/chat-ui/assets/dist-BsedZGJo.js +0 -1
- package/dist/apps/chat-ui/assets/dist-C5YJOwhH.js +0 -1
- package/dist/apps/chat-ui/assets/dist-C5oXtFSP.js +0 -1
- package/dist/apps/chat-ui/assets/dist-CCGKu-Wj.js +0 -9
- package/dist/apps/chat-ui/assets/dist-CE0MvPLM.js +0 -1
- package/dist/apps/chat-ui/assets/dist-CKM5j-iy.js +0 -1
- package/dist/apps/chat-ui/assets/dist-CUp9us2q.js +0 -1
- package/dist/apps/chat-ui/assets/dist-CZ9T4Cly.js +0 -1
- package/dist/apps/chat-ui/assets/dist-DBnh8gXR.js +0 -1
- package/dist/apps/chat-ui/assets/dist-DSKQpPaz.js +0 -1
- package/dist/apps/chat-ui/assets/dist-DeOnZ-pw.js +0 -23
- package/dist/apps/chat-ui/assets/dist-DnQYnLQS.js +0 -1
- package/dist/apps/chat-ui/assets/dist-VT4x40uL.js +0 -6
- package/dist/apps/chat-ui/assets/dist-Zqt9kNG9.js +0 -1
- package/dist/apps/chat-ui/assets/dist-tGfufz3b.js +0 -1
- package/dist/apps/chat-ui/assets/dist-xtnVygdr.js +0 -1
- package/dist/apps/chat-ui/assets/index-DNeE4HrG.css +0 -1
- package/dist/apps/chat-ui/assets/index-vcg8JNj9.js +0 -173
- package/dist/apps/chat-ui/assets/rolldown-runtime-S-ySWqyJ.js +0 -1
- package/dist/apps/chat-vscode-web/assets/index-DVlCO7v_.js +0 -41
- package/dist/apps/context-files-ui/assets/index-BhAWD3dv.js +0 -202
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.11.2.vsix +0 -0
- /package/dist/apps/chat-ui/assets/{apl-BxEMbctQ.js → apl-14BqhLYK.js} +0 -0
- /package/dist/apps/chat-ui/assets/{asciiarmor-eFjeGRuZ.js → asciiarmor-WLvjqI7d.js} +0 -0
- /package/dist/apps/chat-ui/assets/{asn1-Cfx-0pt9.js → asn1-Bg4FbdCg.js} +0 -0
- /package/dist/apps/chat-ui/assets/{asterisk-B5BHTsBr.js → asterisk-B2MO-X4d.js} +0 -0
- /package/dist/apps/chat-ui/assets/{brainfuck-CAA2xofr.js → brainfuck-CV9kufud.js} +0 -0
- /package/dist/apps/chat-ui/assets/{clike-BoDCOLzN.js → clike-CjmcUpt6.js} +0 -0
- /package/dist/apps/chat-ui/assets/{clojure-kVFSWX0o.js → clojure-De3QGfx6.js} +0 -0
- /package/dist/apps/chat-ui/assets/{cmake-BUPAhezI.js → cmake-i2VDNaRq.js} +0 -0
- /package/dist/apps/chat-ui/assets/{cobol-BfgHZgup.js → cobol-BwO6DF08.js} +0 -0
- /package/dist/apps/chat-ui/assets/{coffeescript-G1Pe_1AZ.js → coffeescript-BtivDvRz.js} +0 -0
- /package/dist/apps/chat-ui/assets/{commonlisp-B3N0CjHn.js → commonlisp-DFkEQdLP.js} +0 -0
- /package/dist/apps/chat-ui/assets/{crystal-C15ndaGM.js → crystal-CU0NkcVL.js} +0 -0
- /package/dist/apps/chat-ui/assets/{css-BqOeyZOV.js → css-CbMZAQ1W.js} +0 -0
- /package/dist/apps/chat-ui/assets/{cypher-KjIKv-wW.js → cypher-Dke5QOzv.js} +0 -0
- /package/dist/apps/chat-ui/assets/{d-BlT5AEC-.js → d-TPqSVaHM.js} +0 -0
- /package/dist/apps/chat-ui/assets/{diff-oF98tbqj.js → diff-B365LSoZ.js} +0 -0
- /package/dist/apps/chat-ui/assets/{dtd-VCA9yr61.js → dtd-CBMymJ7O.js} +0 -0
- /package/dist/apps/chat-ui/assets/{dylan-O-V5Dw5W.js → dylan-08Azy1NK.js} +0 -0
- /package/dist/apps/chat-ui/assets/{ebnf-SPmdBkvT.js → ebnf-Dkum_1J8.js} +0 -0
- /package/dist/apps/chat-ui/assets/{ecl-ChfCttfI.js → ecl-dhxjHL8y.js} +0 -0
- /package/dist/apps/chat-ui/assets/{eiffel-cB9EbjeN.js → eiffel-C446m6dI.js} +0 -0
- /package/dist/apps/chat-ui/assets/{elm-BTiVflBU.js → elm-po1E9de0.js} +0 -0
- /package/dist/apps/chat-ui/assets/{erlang-egf0TXFm.js → erlang-BD5LkVkR.js} +0 -0
- /package/dist/apps/chat-ui/assets/{fcl-BiCjh1tj.js → fcl-DkEOamHd.js} +0 -0
- /package/dist/apps/chat-ui/assets/{forth-C4kDGW6u.js → forth-dCg2_HVB.js} +0 -0
- /package/dist/apps/chat-ui/assets/{fortran-DzkLaPnd.js → fortran-3ZpXLFh1.js} +0 -0
- /package/dist/apps/chat-ui/assets/{gas-DMOxskQF.js → gas-DMmxLZRI.js} +0 -0
- /package/dist/apps/chat-ui/assets/{gherkin-BPxBpp-k.js → gherkin-DUSFg2R6.js} +0 -0
- /package/dist/apps/chat-ui/assets/{groovy-CkEnc0ZY.js → groovy-Cmduloe1.js} +0 -0
- /package/dist/apps/chat-ui/assets/{haskell-Dadpo9-w.js → haskell-Cyr255R9.js} +0 -0
- /package/dist/apps/chat-ui/assets/{haxe-CDNZL9MW.js → haxe-BJVKtprM.js} +0 -0
- /package/dist/apps/chat-ui/assets/{http-jy9Zxxt3.js → http-DszHFpc-.js} +0 -0
- /package/dist/apps/chat-ui/assets/{idl-CGSB6iiy.js → idl-Cati9Nrv.js} +0 -0
- /package/dist/apps/chat-ui/assets/{javascript-DSlzRUd8.js → javascript-C5pDVaoP.js} +0 -0
- /package/dist/apps/chat-ui/assets/{julia-DTiF9v6R.js → julia-DlqY1cTU.js} +0 -0
- /package/dist/apps/chat-ui/assets/{livescript-Ci8Xxna6.js → livescript-C6p8-2W1.js} +0 -0
- /package/dist/apps/chat-ui/assets/{lua-eVxIrt9t.js → lua-BxuTHaF7.js} +0 -0
- /package/dist/apps/chat-ui/assets/{mathematica-Da3grj36.js → mathematica-nDHZUMJT.js} +0 -0
- /package/dist/apps/chat-ui/assets/{mbox-BWBMSafM.js → mbox-DAaR0Hcz.js} +0 -0
- /package/dist/apps/chat-ui/assets/{mirc-CtHu9S1B.js → mirc-CCA0FRfl.js} +0 -0
- /package/dist/apps/chat-ui/assets/{mllike-wTFlPWXS.js → mllike-Cw3Iccsb.js} +0 -0
- /package/dist/apps/chat-ui/assets/{modelica-cKbQ0UXu.js → modelica-Czx80fNR.js} +0 -0
- /package/dist/apps/chat-ui/assets/{mscgen-C5pXQCMK.js → mscgen-BmfuTbzG.js} +0 -0
- /package/dist/apps/chat-ui/assets/{mumps-CKBHkOQq.js → mumps-Ds_ZaumL.js} +0 -0
- /package/dist/apps/chat-ui/assets/{nginx-B00AiQel.js → nginx-D9M2PQ4U.js} +0 -0
- /package/dist/apps/chat-ui/assets/{ntriples-B_36EBV0.js → ntriples-DLHGTvHs.js} +0 -0
- /package/dist/apps/chat-ui/assets/{octave-BXPjzAif.js → octave-8jj96JiC.js} +0 -0
- /package/dist/apps/chat-ui/assets/{oz-Dedpat1M.js → oz-BmMq7iC4.js} +0 -0
- /package/dist/apps/chat-ui/assets/{pascal-CMcUg72K.js → pascal-BgMr6XpT.js} +0 -0
- /package/dist/apps/chat-ui/assets/{perl-DoVTbnzt.js → perl-D6YJObi_.js} +0 -0
- /package/dist/apps/chat-ui/assets/{pig-CULXT1YV.js → pig-nx7uchs8.js} +0 -0
- /package/dist/apps/chat-ui/assets/{powershell-Cv5Uhf6b.js → powershell-B4IPkVxR.js} +0 -0
- /package/dist/apps/chat-ui/assets/{properties-CQ1C2P-M.js → properties-CoavQdLC.js} +0 -0
- /package/dist/apps/chat-ui/assets/{protobuf-SRlvzrl6.js → protobuf-D5EWhcmc.js} +0 -0
- /package/dist/apps/chat-ui/assets/{puppet-ClSqCGj6.js → puppet-B_0GFuyD.js} +0 -0
- /package/dist/apps/chat-ui/assets/{python-C2_X1GpX.js → python-Cs7sNzy_.js} +0 -0
- /package/dist/apps/chat-ui/assets/{q-B_6Gdyzl.js → q-BIB9pPtI.js} +0 -0
- /package/dist/apps/chat-ui/assets/{r-BD07NGED.js → r-CN5s4f3o.js} +0 -0
- /package/dist/apps/chat-ui/assets/{rpm-CRu5Z2Jl.js → rpm-Ct_Ck8mQ.js} +0 -0
- /package/dist/apps/chat-ui/assets/{ruby-dZPnOz8h.js → ruby-BVPradRk.js} +0 -0
- /package/dist/apps/chat-ui/assets/{sas-S2t8_sDI.js → sas-DN4j74IF.js} +0 -0
- /package/dist/apps/chat-ui/assets/{scheme-WcyFWLW2.js → scheme-CvNgHAnh.js} +0 -0
- /package/dist/apps/chat-ui/assets/{shell-DUelnYSh.js → shell-BjiMLAaM.js} +0 -0
- /package/dist/apps/chat-ui/assets/{sieve-jDjlVhNh.js → sieve-C2U1O5Z4.js} +0 -0
- /package/dist/apps/chat-ui/assets/{simple-mode-CL04yRVp.js → simple-mode-DnMbQuKW.js} +0 -0
- /package/dist/apps/chat-ui/assets/{smalltalk-ddWDYy10.js → smalltalk-DkYwYufV.js} +0 -0
- /package/dist/apps/chat-ui/assets/{solr-C7rQhLuW.js → solr-BopnSD-v.js} +0 -0
- /package/dist/apps/chat-ui/assets/{sparql--fPCCgVd.js → sparql-Cpg3YQfd.js} +0 -0
- /package/dist/apps/chat-ui/assets/{spreadsheet-DjthqD5G.js → spreadsheet-kRxtVt9J.js} +0 -0
- /package/dist/apps/chat-ui/assets/{sql-D_dieYbr.js → sql-DYI2GwJR.js} +0 -0
- /package/dist/apps/chat-ui/assets/{stex-rHcFYcA0.js → stex-BCRT8IJ3.js} +0 -0
- /package/dist/apps/chat-ui/assets/{stylus-DxF70RNr.js → stylus-CARoeVE9.js} +0 -0
- /package/dist/apps/chat-ui/assets/{swift-T0hDoOb-.js → swift-DKNaLAK6.js} +0 -0
- /package/dist/apps/chat-ui/assets/{tcl-Dlzy1mPk.js → tcl-CQyXkgMH.js} +0 -0
- /package/dist/apps/chat-ui/assets/{textile-Dy5rFZe5.js → textile-Yg_UWn-t.js} +0 -0
- /package/dist/apps/chat-ui/assets/{tiddlywiki-DQP1OymS.js → tiddlywiki-dqVbkfX4.js} +0 -0
- /package/dist/apps/chat-ui/assets/{tiki-0vOj3DB2.js → tiki-CC_ic8g0.js} +0 -0
- /package/dist/apps/chat-ui/assets/{toml-DEltN0lI.js → toml-B7gGzVkJ.js} +0 -0
- /package/dist/apps/chat-ui/assets/{troff-CRbBpEqY.js → troff-Bq3z6oAu.js} +0 -0
- /package/dist/apps/chat-ui/assets/{ttcn-M5q1nLKg.js → ttcn-GvRgs2AT.js} +0 -0
- /package/dist/apps/chat-ui/assets/{ttcn-cfg-Rmw9NWq9.js → ttcn-cfg-CGCXz7Vo.js} +0 -0
- /package/dist/apps/chat-ui/assets/{turtle-BCDWhJK0.js → turtle-CwIpz2yy.js} +0 -0
- /package/dist/apps/chat-ui/assets/{vb-QQ7LGlOz.js → vb-BmcHUM2C.js} +0 -0
- /package/dist/apps/chat-ui/assets/{vbscript-BiSEdUzz.js → vbscript-Cs9dylre.js} +0 -0
- /package/dist/apps/chat-ui/assets/{velocity-CzMg5_6w.js → velocity-CBWU0VCy.js} +0 -0
- /package/dist/apps/chat-ui/assets/{verilog-BJOO83gk.js → verilog-DVCHmufx.js} +0 -0
- /package/dist/apps/chat-ui/assets/{vhdl-ed4zAZAA.js → vhdl-BGDk4f1d.js} +0 -0
- /package/dist/apps/chat-ui/assets/{webidl-Ddy6hbV6.js → webidl-egXQEWlC.js} +0 -0
- /package/dist/apps/chat-ui/assets/{xquery-Bw1zwhh6.js → xquery-5f0hn7cg.js} +0 -0
- /package/dist/apps/chat-ui/assets/{yacas-DZdTXy3s.js → yacas-DNs9XkmQ.js} +0 -0
- /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
|
|
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) };
|