Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,36 @@ in `out/` is served by any static host (GitHub Pages, GitLab Pages, Bitbucket).
branch (`rf:branch-resolved` event) so the label matches the loaded report
(`main` 404 → `master` fallback)
- Reports rendered with Mustache.js (bundled template is authoritative)
- Graphs synthesized client-side from the nested hierarchy in
refactor-first.json (`lib/hierarchy-dot.js`, byte-identical to the report
module's Java `NestedDotBuilder`; packages nest as clusters, classes as
ellipses, break-up packages fill pink). The package map renders the flat
relationship graph — one ellipse per package with only the weighted
edges, break-up packages in red — through vizdom like the class and
cycle graphs; every graph's nodes are hyperlinked to their source
files/directories via `project.repoUrl` (http(s)-gated, new tab
restored post-render since vizdom drops the target); hovering a vizdom
edge highlights it plus both endpoints, hovering (or keyboard-focusing)
a node highlights its incoming edges + source nodes and outgoing edges +
sink nodes in two directional colors (`bindGraphHoverHighlights` in
`lib/report-view.js` derives the neighbor model from the vizdom
`<title>` texts and toggles `rf-hover-*` classes, styled per palette via
`--graph-hover-*`); highlighted nodes fill with their accent and their
label glyphs re-ink to `--graph-hover-on` (white on the dark light-mode
accents, black on the bright dark-mode accents) to keep AA contrast; the
2D/3D popups carry the same directional model (`bindSigmaHoverHighlight`
for the sigma 2D popup — node hover only, sigma 2.4 has no edge events —
and the hover block in `createForceGraph` for the 3D force graph, which
also highlights hovered links), resolving accents from the JS mirror
`GRAPH_HOVER_ACCENTS` in `lib/report-view.js`: the canvas-drawn 2D popup
follows the active palette like the SVGs, while the 3D popup's WebGL
canvas is always dark and therefore always uses the dark values. The 3D
popup's hover highlighting is always on (per-hover sprite recoloring
touches only nodes whose state changed, keeping it O(changed)), and
while nothing is highlighted the DOT graph's own colors show — each
link's DOT color (red removals, white fallback) and each node's DOT
color on its sprite label; the full
hierarchy stays in refactor-first.json for LLM consumption
- Enhanced report tables: sticky headers, pagination (>20 rows), sortable
columns, in-table search, CSV export, click/keyboard cell copy with toasts
- Repository submission via pre-filled platform issues — no login, apps or tokens
Expand Down Expand Up @@ -91,7 +121,10 @@ lib/ # shared logic (client + RSC): routes, fetcher,
# renderer, search, utils, host, rate-limiter,
# cache-manager, error-handler, repo-submission,
# report-view, static-params, widget-loader,
# breadcrumbs,
# breadcrumbs, hierarchy-dot (hierarchy-to-DOT
# synthesis mirroring the Java NestedDotBuilder in
# the report module; byte-identical goldens in
# tests/unit/hierarchy-dot.test.js),
# table-operations (filter/sort/paginate/CSV/copy +
# TABLE_CONFIG + REPORT_TABLES descriptors),
# table-enhancer (binds toolbar/sort/pagination/
Expand Down Expand Up @@ -158,12 +191,31 @@ coverage there when introducing new markup patterns.
SVGs' embedded black strokes/fills are likewise re-themed to
`--graph-line` (`#9fb0c0` dark = `CHART_LEGEND_TEXT.dark`) via
`path[stroke]`/`polygon` selectors on `.fullscreen-svg` — red cycle
edges stay red. Edge labels are glyph paths baked by vizdom, so CSS
can't reach them: `withEdgeFontColor` in `lib/report-view.js` rewrites
the DOT with `fontcolor = "#9fb0c0"` per edge when the dark palette
is active (vizdom uppercases the hex in the SVG), and theme switches
re-parse the graphs via `redrawGraphsForTheme` alongside the chart
legend redraw in `bindThemeChartRedraw`.
edges stay red — and the package clusters (`g.cluster rect[fill="white"]`,
the packages that do not need to be broken up) re-drive their fill to
`--bg-color` with their label glyph paths via a rect-sibling selector, so
the boxes match the page in dark mode. Break-up clusters
(`g.cluster rect[fill="pink"]`) re-drive through their own
`--graph-breakup-fill` (light: vizdom's baked `#ffc0cb`; dark: a deep rose
`#7f3350` that keeps the `--graph-line` edges crossing the box visible)
and `--graph-breakup-line` ink (light: baked black; dark: light pink
`#f2b8cd` for the boundary + label) — no fill can pass 3:1 against both
the near-black page and the light edges, so the fill prioritizes edge
visibility and the pink ink carries the perceivable boundary. Graph DOT
is synthesized
from the `.hierarchy` payloads
(`classMap`/`packageMap`/`largestCycle`, see `lib/hierarchy-dot.js`);
edge labels are fill-only glyph paths baked by vizdom, so CSS can't
reach them: the dark palette bakes `fontcolor = "#9fb0c0"` into every
edge at synthesis time via `graphDotOptions()` in `lib/report-view.js`
(vizdom uppercases the hex in the SVG), and theme switches
re-synthesize + re-render the graphs via `redrawGraphsForTheme` alongside
the chart legend redraw in `bindThemeChartRedraw`. Node labels sit on
vizdom's white shapes and keep the baked black ink in the non-hover
state (hovered or keyboard-focused node labels re-ink to
`--graph-hover-on`), while cluster labels are recolored by CSS along
with their rects (regular clusters' label glyphs follow `--graph-line`,
break-up clusters' labels take `--graph-breakup-line`).

## Report Tables (Enhanced)

Expand Down Expand Up @@ -220,7 +272,7 @@ coverage there when introducing new markup patterns.

## Current Test Count

~584 unit/integration + ~229 E2E (~202 across three browsers + 4 basePath leg + 27 dark mode).
~787 unit/integration + ~232 E2E (~202 across three browsers + 4 basePath leg + 30 dark mode).

WCAG 2.2 AA / HTML5 guards live in tests/unit/html5-attributes.test.js,
tests/unit/report-template-wcag.test.js, tests/unit/css-a11y.test.js and
Expand Down
167 changes: 167 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@
/* vizdom WASM graph edges bake black stroke/fill attributes into the SVG;
palette-driven so the dark theme can swap them to a readable tint. */
--graph-line: #000000;
/* Break-up package clusters: vizdom bakes fillcolor=pink onto the cluster
rect with the default black stroke/label glyphs. The light values equal
those baked colors, so the re-driving rules below never change the
light theme by a pixel; the dark block swaps them for a tuned surface. */
--graph-breakup-fill: #ffc0cb;
--graph-breakup-line: #000000;
/* DOT-graph hover highlights (vizdom SVGs): the hovered edge/node and its
partners take the amber attention accent; a hovered node colors its
incoming (source) and outgoing (sink) neighborhoods green/blue. All
three pass >= 3:1 on the white page and on the pink breakup clusters;
highlighted nodes fill with their accent, and the label ink flips to
--graph-hover-on to stay readable on it (white on these dark accents). */
--graph-hover-edge: #b45309;
--graph-hover-in: #1e8449;
--graph-hover-out: #2a6f97;
--graph-hover-on: #ffffff;
--error-color: #c0392b;
--success-color: #1e8449;
--error-bg: #fdf6f5;
Expand Down Expand Up @@ -101,6 +117,23 @@ html:root {
/* Hamburger glyph + 1px border on the dark menu surface (6.8:1). */
--menu-toggle-color: #6fb1d9;
--graph-line: #9fb0c0;
/* Break-up package clusters: the baked pink is a glaring pastel slab on
the dark page (11.8:1) and swallows the #9fb0c0 edges crossing it
(1.45:1), so the box drops to a deep rose — flagged against the
near-black regular clusters (2.2:1 plus a warm hue shift) while the
edges stay visible on it (3.8:1) — and a light pink ink carries the
boundary and label (5.0:1 on the fill, 10.8:1 on the page). */
--graph-breakup-fill: #7f3350;
--graph-breakup-line: #f2b8cd;
/* DOT-graph hover highlights: bright accents that stay distinct from the
slate #9fb0c0 edges (hue + width) and pass >= 3:1 on both cluster
fills (#10161d regular, #7f3350 rose). */
--graph-hover-edge: #f0b95a;
--graph-hover-in: #7ee2a8;
--graph-hover-out: #8ed0fa;
/* Label ink on the accent-filled highlighted nodes: the bright fills take
black glyphs (the labels bake a black fill in both palettes). */
--graph-hover-on: #000000;
--error-color: #f0928c;
--success-color: #5bbd8b;
--error-bg: #2b1d1f;
Expand Down Expand Up @@ -145,6 +178,23 @@ html:root {
/* Hamburger glyph + 1px border on the dark menu surface (6.8:1). */
--menu-toggle-color: #6fb1d9;
--graph-line: #9fb0c0;
/* Break-up package clusters: the baked pink is a glaring pastel slab on
the dark page (11.8:1) and swallows the #9fb0c0 edges crossing it
(1.45:1), so the box drops to a deep rose — flagged against the
near-black regular clusters (2.2:1 plus a warm hue shift) while the
edges stay visible on it (3.8:1) — and a light pink ink carries the
boundary and label (5.0:1 on the fill, 10.8:1 on the page). */
--graph-breakup-fill: #7f3350;
--graph-breakup-line: #f2b8cd;
/* DOT-graph hover highlights: bright accents that stay distinct from the
slate #9fb0c0 edges (hue + width) and pass >= 3:1 on both cluster
fills (#10161d regular, #7f3350 rose). */
--graph-hover-edge: #f0b95a;
--graph-hover-in: #7ee2a8;
--graph-hover-out: #8ed0fa;
/* Label ink on the accent-filled highlighted nodes: the bright fills take
black glyphs (the labels bake a black fill in both palettes). */
--graph-hover-on: #000000;
--error-color: #f0928c;
--success-color: #5bbd8b;
--error-bg: #2b1d1f;
Expand Down Expand Up @@ -953,3 +1003,120 @@ main#app .fullscreen-svg polygon:not([fill="red"]) {
stroke: var(--graph-line);
fill: var(--graph-line);
}

/* Package clusters: vizdom bakes the DOT's fillcolor onto each cluster rect
(probe against the vendored 0.1.19: g.cluster > a > rect fill="white"
stroke="black", with the cluster label as a black glyph path following the
rect as a sibling). appendPackage only ever emits fillcolor=white (regular
packages) or fillcolor=pink (break-up candidates), so the white boxes are
the packages that do not need to be broken up: their fill re-drives from
the palette so it matches the page — vizdom's default white on the light
page, the dark --bg-color in dark mode — and the baked black stroke follows
--graph-line like the rest of the graph. The cluster label glyphs ride on
the re-driven fill, so they follow --graph-line too; anchored to the white
rect sibling so the rule never touches the break-up clusters, which the
rules below theme through their own palette. Pure CSS: the DOT (and its
byte-identical lockstep with the Java NestedDotBuilder) keeps
fillcolor=white/fillcolor=pink. */
main#app .fullscreen-svg g.cluster rect[fill="white"] {
fill: var(--bg-color);
stroke: var(--graph-line);
}

main#app .fullscreen-svg g.cluster rect[fill="white"] ~ path[fill="black"] {
fill: var(--graph-line);
}

/* Break-up packages (the pink rects) invert that treatment: their problem
signal survives the dark page best as a deep rose box with a light pink
boundary and label, because no single fill can pass 3:1 against both the
near-black page and the light --graph-line edges crossing the box — the
rose fill keeps the edges visible (SC 1.4.11) and the pink ink keeps the
box boundary and its label readable (SC 1.4.3). The light palette values
equal vizdom's baked pink/black, so this never changes light mode. */
main#app .fullscreen-svg g.cluster rect[fill="pink"] {
fill: var(--graph-breakup-fill);
stroke: var(--graph-breakup-line);
}

main#app .fullscreen-svg g.cluster rect[fill="pink"] ~ path[fill="black"] {
fill: var(--graph-breakup-line);
}

/* Hover highlights on the DOT graphs: lib/report-view.js derives the
node/edge neighborhood from the vizdom titles and toggles rf-hover-*
state classes. Hovering an edge flags the edge plus both endpoint nodes
with the amber attention accent; hovering a node flags it with the same
accent while its incoming edges + source nodes go green and its outgoing
edges + sink nodes go blue, so dependency direction reads at a glance.
Highlighted nodes FILL with their accent (their baked white/red/pink fill
yields to the highlight like red removal edges do), and the node labels —
glyph paths with a baked black fill riding on the shape — re-ink to
--graph-hover-on to keep AA contrast on the fill. A node flagged both in
and out is a bidirectional partner of the hovered node and takes the
attention accent over either directional state. */
main#app .fullscreen-svg g.edge.rf-hover-edge path[stroke] {
stroke: var(--graph-hover-edge);
stroke-width: 2.5px;
}

main#app .fullscreen-svg g.edge.rf-hover-edge polygon {
stroke: var(--graph-hover-edge);
fill: var(--graph-hover-edge);
}

main#app .fullscreen-svg g.node.rf-hover-edge ellipse,
main#app .fullscreen-svg g.node.rf-hover-edge rect,
main#app .fullscreen-svg g.node.rf-hover-focus ellipse,
main#app .fullscreen-svg g.node.rf-hover-focus rect {
stroke: var(--graph-hover-edge);
fill: var(--graph-hover-edge);
stroke-width: 2px;
}

main#app .fullscreen-svg g.edge.rf-hover-in path[stroke] {
stroke: var(--graph-hover-in);
stroke-width: 2.5px;
}

main#app .fullscreen-svg g.edge.rf-hover-in polygon {
stroke: var(--graph-hover-in);
fill: var(--graph-hover-in);
}

main#app .fullscreen-svg g.node.rf-hover-in ellipse,
main#app .fullscreen-svg g.node.rf-hover-in rect {
stroke: var(--graph-hover-in);
fill: var(--graph-hover-in);
stroke-width: 2px;
}

main#app .fullscreen-svg g.edge.rf-hover-out path[stroke] {
stroke: var(--graph-hover-out);
stroke-width: 2.5px;
}

main#app .fullscreen-svg g.edge.rf-hover-out polygon {
stroke: var(--graph-hover-out);
fill: var(--graph-hover-out);
}

main#app .fullscreen-svg g.node.rf-hover-out ellipse,
main#app .fullscreen-svg g.node.rf-hover-out rect {
stroke: var(--graph-hover-out);
fill: var(--graph-hover-out);
stroke-width: 2px;
}

main#app .fullscreen-svg g.node.rf-hover-in.rf-hover-out ellipse,
main#app .fullscreen-svg g.node.rf-hover-in.rf-hover-out rect {
stroke: var(--graph-hover-edge);
fill: var(--graph-hover-edge);
}

main#app .fullscreen-svg g.node.rf-hover-edge path[fill="black"],
main#app .fullscreen-svg g.node.rf-hover-focus path[fill="black"],
main#app .fullscreen-svg g.node.rf-hover-in path[fill="black"],
main#app .fullscreen-svg g.node.rf-hover-out path[fill="black"] {
fill: var(--graph-hover-on);
}
Loading
Loading