diff --git a/tools/dag-viewer/README.md b/tools/dag-viewer/README.md
index 8cd22c1a..1c3fd694 100644
--- a/tools/dag-viewer/README.md
+++ b/tools/dag-viewer/README.md
@@ -4,8 +4,8 @@ The viewer has one visualization mode: **Pre/Post-ASAP**.
- Select one query to see that query's complete pre-ASAP and post-ASAP DAGs.
- Select multiple queries to see two workload-union DAGs: one pre-ASAP union
- and one post-ASAP union. Structurally identical nodes and edges are
- collapsed while query roots and ownership are retained.
+ and one post-ASAP union. Nodes with the same exporter-assigned workload
+ identity are collapsed while query roots and ownership are retained.
- Pre-ASAP nodes show only their original IR content.
- Post-ASAP nodes show their translated IR content and the explicit planner
decision carried by that node.
diff --git a/tools/dag-viewer/index.html b/tools/dag-viewer/index.html
index 4379cc58..cb1a1d01 100644
--- a/tools/dag-viewer/index.html
+++ b/tools/dag-viewer/index.html
@@ -140,7 +140,7 @@
.schemaHint { color:var(--muted); font-size:.7rem; }
.plannerActions { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.55rem; }
#plannerStatus { color: var(--muted); font-size: 0.75rem; }
- #baPicker {
+ #scopePicker {
display: none;
flex-wrap: wrap;
gap: 0.6rem 1.2rem;
@@ -148,15 +148,15 @@
border-bottom: 1px solid var(--border);
background: var(--panel);
}
- #baPicker.visible { display: flex; }
- .baGroup { display: flex; flex-direction: column; gap: 0.3rem; min-width: 220px; }
- .baGroupLabel {
+ #scopePicker.visible { display: flex; }
+ .scopeGroup { display: flex; flex-direction: column; gap: 0.3rem; min-width: 220px; }
+ .scopeGroupLabel {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: .03em;
color: var(--muted);
}
- .baRow {
+ .scopeRow {
display: flex;
align-items: center;
gap: 0.5rem;
@@ -165,29 +165,16 @@
border-radius: 8px;
background: var(--panel2);
color: var(--fg);
- cursor: pointer;
font: inherit;
font-size: 0.78rem;
text-align: left;
}
- .baRow:hover { border-color: var(--accent); }
- .baRow:disabled { opacity: 0.55; cursor: not-allowed; }
- .baRow:disabled:hover { border-color: var(--border); }
- .baRow.active {
+ .scopeRow.active {
border-color: var(--accent);
background: var(--bg);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 15%, transparent);
}
- .baRow .baWinner {
- font-size: 0.66rem;
- font-weight: 700;
- color: var(--accent);
- border: 1px solid var(--accent);
- border-radius: 999px;
- padding: 0.05rem 0.4rem;
- flex-shrink: 0;
- }
- .baRow .baMeta { color: var(--muted); font-size: 0.72rem; margin-left: auto; white-space: nowrap; }
+ .scopeRow .scopeMeta { color: var(--muted); font-size: 0.72rem; margin-left: auto; white-space: nowrap; }
.proxyNote {
font-size: 0.72rem;
color: var(--muted);
@@ -424,7 +411,7 @@
Input table schemas
-
+
diff --git a/tools/dag-viewer/node-style.js b/tools/dag-viewer/node-style.js
index ca6c31d1..e688a80b 100644
--- a/tools/dag-viewer/node-style.js
+++ b/tools/dag-viewer/node-style.js
@@ -1,13 +1,12 @@
// Category table for QueryExpr node kinds — the single source of truth for
-// how the viewer colors/labels/icons each `DagNode.kind`. Edit this file to
+// how the viewer colors and labels each `DagNode.kind`. Edit this file to
// reclassify a kind or retune a palette; nothing else in index.html needs to
-// change. Icon SVGs are adapted from ProjectASAP/bgp-query-dag-explorer's
-// hand-drawn icon set (see tools/dag-viewer/README.md).
+// change.
//
// Also covers the 7 post-ASAP-only SummaryDagNode kinds (KeepPreAsap,
// SummaryAgg, SummaryJoin, SummarySubtract, SummaryDelete, SummaryEstimate,
-// SummaryMerge) that only ever appear in Before/After mode's After lane when
-// an entry's `after.kind === "Summary"` — see the `summary` category below.
+// SummaryMerge) that appear in the post-ASAP lane — see the `summary`
+// category below.
// kind (DagNode.kind from crates/ir/src/dag_export.rs) -> category name.
const KIND_CATEGORY = {
@@ -36,7 +35,7 @@ const KIND_CATEGORY = {
Sort: 'sort',
Limit: 'sort',
LetBinding: 'bind',
- // Post-ASAP SummaryDagNode kinds (Before/After mode's After lane only).
+ // Post-ASAP SummaryDagNode kinds (post-ASAP lane only).
KeepPreAsap: 'summary',
SummaryAgg: 'summary',
SummaryJoin: 'summary',
@@ -46,47 +45,6 @@ const KIND_CATEGORY = {
SummaryMerge: 'summary',
};
-const ICON_STROKE = '2.2';
-const ICON_FILL = 'rgba(255,255,255,.06)';
-
-// Each icon fn takes a stroke/fill color and returns a standalone SVG string
-// (viewBox 0 0 48 48, consistent stroke weight) for use as a node background
-// image. Cylinder/funnel/transform/grid/venn/dashed-circle/sort-arrow are
-// adapted directly from the reference repo's `iconFor()`; `bind` and the
-// root-node badge are new, drawn in the same style.
-const ICONS = {
- data: (c) => ``,
- filter: (c) => ``,
- derive: (c) => ``,
- aggregate: (c) => ``,
- window: (c) => ``,
- join: (c) => ``,
- set: (c) => ``,
- sort: (c) => ``,
- // New: a name tag, for LetBinding naming a sub-expression for reuse.
- bind: (c) => ``,
- // New: stacked layers, for the post-ASAP `summary` category — a materialized
- // structure (a sketch, a rollup, a merged/estimated join) rather than a
- // pre-ASAP relational operator.
- summary: (c) => ``,
-};
-
-// KeepPreAsap-only: a dashed box with a through-arrow, standing in for
-// "unchanged pre-ASAP content carried through as-is" — see the `summary`
-// CATEGORIES entry and buildCyStyle's `node[kind = "KeepPreAsap"]` override
-// in viewer.js for why this doesn't just reuse ICONS.summary's stroke color.
-const KEEP_PRE_ASAP_ICON = (c) => ``;
-
-function keepPreAsapIconDataUri() {
- const muted = getComputedStyle(document.documentElement).getPropertyValue('--muted').trim() || '#6b7280';
- return svgDataUri(KEEP_PRE_ASAP_ICON(muted));
-}
-
-// New: a small flag/marker badge layered onto whichever node is a query's
-// root, since QueryExpr has no dedicated terminal "output" node kind the way
-// the reference's BGP `out_*` steps do.
-const ROOT_BADGE_ICON = (c) => ``;
-
// name -> { label, description, light: {bg, border}, dark: {bg, border} }
const CATEGORIES = {
data: {
@@ -143,7 +101,7 @@ const CATEGORIES = {
light: { bg: '#fff5ea', border: '#b45309' },
dark: { bg: '#3a2408', border: '#fb923c' },
},
- // Post-ASAP only (Before/After mode's After lane): every other category
+ // Post-ASAP only (post-ASAP lane): every other category
// above is a saturated, hand-picked hue for a pre-ASAP QueryExpr operator.
// `summary` is deliberately plain neutral gray instead of another hue —
// partly because a 10th saturated color starts getting hard to
@@ -157,7 +115,7 @@ const CATEGORIES = {
// through) rather than a different concept.
summary: {
label: 'Summary',
- description: 'KeepPreAsap, SummaryAgg, SummaryJoin, SummarySubtract, SummaryDelete, SummaryEstimate, SummaryMerge — post-ASAP materialized structures (Before/After mode only)',
+ description: 'KeepPreAsap, SummaryAgg, SummaryJoin, SummarySubtract, SummaryDelete, SummaryEstimate, SummaryMerge — post-ASAP materialized structures',
light: { bg: '#f1f2f4', border: '#4b5563' },
dark: { bg: '#20242b', border: '#9ca3af' },
},
@@ -170,35 +128,10 @@ const ROOT_BADGE = {
dark: { border: '#f87171' },
};
-// `DagNote.kind` -> badge color, for a node whose `notes` array (issue #257 —
-// asap-aware-mapping's ReplacementExplanation, matched onto this node by
-// dag_export's own hash) is non-empty. Only the two kinds
-// asap_aware_mapping::ExplanationKind currently ships get their own entry;
-// NOTE_KIND_FALLBACK covers anything else (a future kind, or a node whose
-// notes mix more than one kind) without needing a new color per addition.
-const NOTE_KIND_COLOR = {
- SketchApproximation: { light: '#a16207', dark: '#facc15' }, // reuses the 'aggregate' category hue
- CommonSubexpressionReuse: { light: '#4f46e5', dark: '#a5b4fc' }, // reuses the 'set' category hue
-};
-const NOTE_KIND_FALLBACK = { light: '#334155', dark: '#cbd5e1' };
-const NOTE_BADGE_LABEL = {
- SketchApproximation: 'Sketch alternative available',
- CommonSubexpressionReuse: 'Shareable across consumers',
-};
-
-// Small "why" marker (a filled circle + exclamation mark) for a node whose
-// `notes` is non-empty — layered in the bottom-right corner, so it never
-// collides with the root badge (top-right) or the category icon (top-center).
-const NOTE_BADGE_ICON = (c) => ``;
-
function isDarkMode() {
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
-function svgDataUri(svg) {
- return `data:image/svg+xml,${encodeURIComponent(svg)}`;
-}
-
function categoryOf(kind) {
return KIND_CATEGORY[kind] || 'derive';
}
@@ -208,52 +141,12 @@ function categoryColors(name) {
return isDarkMode() ? cat.dark : cat.light;
}
-function categoryIconDataUri(name) {
- const { border } = categoryColors(name);
- const icon = ICONS[name] || ICONS.derive;
- return svgDataUri(icon(border));
-}
-
-function rootBadgeIconDataUri() {
- const { border } = isDarkMode() ? ROOT_BADGE.dark : ROOT_BADGE.light;
- return svgDataUri(ROOT_BADGE_ICON(border));
-}
-
-// The color a `notes` badge/chip should use for `kind` — one of
-// ExplanationKind's two known variants, or NOTE_KIND_FALLBACK for anything
-// else (future kind, or `noteBadgeColor`'s own "mixed kinds" case below).
-function noteKindColor(kind) {
- const c = NOTE_KIND_COLOR[kind] || NOTE_KIND_FALLBACK;
- return isDarkMode() ? c.dark : c.light;
-}
-
-// The color for a node's *badge* (as opposed to one note's own chip): the
-// shared color if every note on the node is the same kind, otherwise the
-// fallback — a node need not itself distinguish "two sketch findings" from
-// "a sketch finding and a reuse finding" the way the side-panel detail
-// (which lists each note individually) does.
-function noteBadgeColor(notes) {
- const kinds = new Set((notes || []).map((n) => n.kind));
- if (kinds.size === 1) return noteKindColor(notes[0].kind);
- const c = NOTE_KIND_FALLBACK;
- return isDarkMode() ? c.dark : c.light;
-}
-
-function noteBadgeIconDataUri(notes) {
- return svgDataUri(NOTE_BADGE_ICON(noteBadgeColor(notes)));
-}
-
-// Mirror the palette into CSS custom properties so plain-DOM chrome (legend,
-// side panel chips) can use var(--cat--bg/border) instead of
-// duplicating these hex values in index.html's