Repository navigation
feat(dag-viewer): show the stage pipeline as three stacked lanes - #698
Merged
Merged
Conversation
zzylol
force-pushed
the
feat/viewer-lanes-g11a
branch
from
October 15, 2026 03:50
ba03be1 to
a3db2ff
Compare
The viewer drew one query at a time as a pre-ASAP and a post-ASAP DAG, read through stage-workload.js. It now shows the whole workload at each planning stage: Stage 0 (query-language frontends), the chosen Stage 1 logical ASAP candidate and its Stage 2 physical candidate, stacked top to bottom, with the Stage 3 candidate list beside them and node details below. - stages.js checks the document and builds each lane from the flat logical DAGs and the PhysicalASAPDAGs; a standalone scalar query is a Scalar node over the nodes it reads (scalar_roots in Stage 2). - The Stage 3 list keeps the candidate table: selected, costlier, rejected, pruned and composition-error rows, with a header that shows the Stage 1 error or selection.error. - The SQL and PromQL editor moves to editor.js and shows its result in the lanes. - server.py writes the examples.json documents into the git-ignored out/ on start (--regenerate rewrites them). Only Example 1 stays committed, for the stage_pipeline contract test; dag.example.json, generate-sample.sh and the scalar-queries fixture are removed, and the scalar test checks scalar_roots positions directly. - render.py, viewer.js, stage-workload.js and their tests go with the per-query view; test_viewer.py replaces test_render.py.
… in step - A logical BinaryOp names its operands `lhs` and `rhs`, which the lane builder did not read as inputs, so `a / b` had no input edges in the Stage 0 and Stage 1 lanes and its operand references went unchecked. The other operator fields of NonASAPOp and ASAPOp that hold an input were already read. - A Stage 2 DAG's `scalar_roots` must be in increasing query position, below the query count, and read existing nodes; a document that breaks this is reported instead of failing while drawing. - Choosing a Stage 1 candidate shows its physical plan; Stage 2 is cleared only for a pruned or uncomposed candidate. - When plan selection fails with an error, the physical candidates are "not judged" rather than invalid without a reason. - A node cost without a number no longer breaks the details panel, and the editor reports success only when the viewer showed the document.
zzylol
force-pushed
the
feat/viewer-lanes-g11a
branch
from
October 15, 2026 04:41
a3db2ff to
842e6e5
Compare
This was referenced Oct 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #574 (viewer redesign) and #638 (stacked lanes). Their
server.py,generate-sample.shanddag_exportparts conflicted with #686 and are not carried over. #618 was already superseded by #686.Why
Since #686 the live viewer plans through
stage_pipeline, but it still shows one query at a time as a "pre-ASAP" and a "post-ASAP" DAG. That split no longer exists in the planner: planning is Stage 0 → Stage 1 → Stage 2 → Stage 3 over the whole workload, and Pass 2 candidates share nodes across queries. A per-query view hides that sharing, as well as the candidates Stage 3 did not select.What
The viewer becomes the stage view approved for G11 (G11a):
× nfor a node that is not materialized and is computed once per reader). Lanes 1 and 2 have candidate pickers. Choosing a Stage 1 candidate shows its physical plan; Stage 2 is cleared only for a pruned or uncomposed candidate.error), then Stage 2 pruned and Stage 1 composition-error rows. The header shows the candidate count, the display cap, and the Stage 1 error orselection.error.time(),scalar(v),1 + 2) is a dashedScalarnode over the nodes it reads. Stage 0/1 read it from{"Scalar": expr}roots and Stage 2 fromscalar_roots.examples.jsonlists Examples 1, 3a and 3b (the onesstage_pipeline --examplesupports).server.pywrites the missing ones into the git-ignoredout/when it starts, and rewrites all of them with--regenerate. Onlyexamples/planner-layering-example1.jsonstays committed, for thestage_pipelinecontract test.planner-ui.jstoeditor.js, and shows its result in the lanes.viewer.js,stage-workload.js),render.py(the standalone HTML export) and itstest_render.py,dag.example.json,generate-sample.sh, thescalar-queries.jsonfixture and the old screenshots.stage_pipeline --deploymentin G11b, after G9.How
stages.js(no DOM) puts both DAG kinds into one shape. A flat logical DAG gets one edge per operator input (every input field ofNonASAPOpandASAPOp:child,children,left/right,lhs/rhs,summary_input,outer/inner) and one per operator a scalar expression reads. APhysicalASAPDAGuses its edge list, and its query roots are rebuilt fromrootsplusscalar_rootsby query position. From that shape it builds cytoscape elements with readable labels: summary family and parameters, grouping and instances, sort/limit partitions, timing, cost, and "root of q…". It also validates the document, including operand references andscalar_rootspositions, and computes the Stage 3 rows and header.app.jsis feat(dag-viewer): redesign the viewer around the stage pipeline #574's page logic adapted to the current document names (stage0_query_language_frontends,stage1_logical_asap_optimization,stage2_physical_asap_optimization,stage3_plan_selection). The layout is feat(dag-viewer): redesign the viewer around the stage pipeline #574's, with feat(dag-viewer): stack the stage lanes top to bottom #638's stacked lanes and sticky Stage 3 list.node-style.jskeepsKIND_CATEGORY_JSON, still checked byviewer_contract.rs, and gainsnodeGroup(source / relational / summary / scalar).crates/devtools/tests/stage_pipeline.rs: the scalar test now checks thescalar_rootspositions directly instead of comparing a committed fixture.Key code interfaces added / modified
No Rust interface changes. The viewer's own interfaces (
tools/dag-viewer):tools/dag-viewer/server.pytools/dag-viewer/examples.json[ { // Tab id; also the page's #<id> hash. "id": "example1", // Tab label. "name": "1 · dashboard panels", // The `stage_pipeline --example` name that produces the document. "example": "planner-layering-1", // Where the document is written, under the git-ignored out/. "file": "out/example1.json", // One-line description shown with the example. "story": "Two PromQL panels over the last minute, every 10 s: Q1 the exact per-job request rate, Q2 the top-10 series per job within ε = 0.01, δ = 0.001 and 100 ms." } ]New:
exampleis astage_pipeline --examplename;fileis its output under the git-ignoredout/. Replacesdag.example.jsonandexamples/scalar-queries.json.tools/dag-viewer/stages.js(new, no DOM; replacesstage-workload.js)tools/dag-viewer/app.js(new; replacesviewer.js),editor.js(new; replacesplanner-ui.js)tools/dag-viewer/node-style.jsUsage, end to end (the editor path; numbers from running
server.pyat90caee78, posting the request below, and callingstages.json the returned document in V8 astest_viewer.pydoes):Before this PR
The viewer had query tabs and one canvas with a pre-ASAP and a post-ASAP DAG per selected query. Only the selected plan's physical DAG was visible, as per-query slices. A 27k-line
dag.example.jsonand a scalar fixture were committed and regenerated by hand.After this PR
python3 tools/dag-viewer/server.pybuildsstage_pipeline, writesout/example{1,3a,3b}.json, and serves the stage view. Any Stage 1 candidate or Stage 2 plan can be opened from the pickers or the Stage 3 list. A Pass 2 candidate such as Example 1's L2 ("shared Scan #1") shows one Scan read by both queries.Loading the generated documents through
app.js(stub DOM) gives these counts lines:Screenshot: not applicable. No browser was available to render the page. The checks above run the page script against a stub DOM.
Verification
python3 -m unittest test_viewer test_server(fromtools/dag-viewer, with py_mini_racer and a builtstage_pipeline): 45 tests pass. They cover document validation, the Stage 3 rows and header (composition errors, Stage 1 error,selection.errorand not-judged rows), the lanes (edges, roots, timing, costs, Pass 2 shared scan), a binary PromQL query's two operand edges in Stage 0, 1 and 2 and scalar roots first/middle/last in Stage 0 and Stage 2 (both generated on demand), lane pickers, node details, the page and editor element ids, the example list,write_examples, and/api/plan.cargo nextest run -p asap-devtools: 25/25 pass, includingviewer_contractandstage_pipeline(the Example 1 fixture is current).server.py --skip-buildwrote the three examples intoout/(git-ignored) and served the page and documents./api/planplanned a mixed SQL + PromQL request.a3db2ff4(onmainat3a25450d):cargo fmt --all -- --checkandcargo clippy --workspace --all-targets --all-features --locked -- -D warningspass, andcargo nextest run --workspacepasses 1663 tests (46 skipped).Limitations and follow-ups
stage_pipeline --deployment <json>(after G9).docs/user_guide_docs/stage-viewer.mdstill describes six examples, a deployment panel and a PromQL-only editor.docs/develop_docs/physical-handoff-costs.mdstill namestest_render.py. Both are left for the docs pass (Update the docs after the G1–G11 consolidation groups land #677).