feat(admin): the insights artifact, one page for topology and spend (issue #175) - #179
Merged
Conversation
… (issue #175) The fourth insights slice, the one the series exists for: /dispatch insights html [7d|30d|mtd] writes <graphDir>/insights.html, one self-contained file:// document -- the trigger/flow topology with spend badged onto its triggers, beside the cost fold drawn as hand-rolled inline SVG charts (KPI tiles, plan verdict cards, a daily spend column chart, the four breakdown bar lists). - graph-html.mjs gains exports, not loads: buildGraphScene is the normalize+layout+SVG-emission half of buildGraphHtml extracted whole (behavior-preserving; every existing pin green untouched), plus escapeHtml/embedJson/fmt/PAGE_JS/legendHtml/bannersHtml/PAGE_THEME. The purity pin is substring-level and directional on purpose: the module may be a source of truth for a sibling emitter, it may never load one itself. - insights-html.mjs: two loads only (graph-html, panel), so the money strings come from the REAL fmtCost -- a plan-covered bucket draws a plan:<id> chip and NO dollar bar, estimates are dashed and translucent beside their ~ est. text (hue never the sole encoding), floors carry >= on the chart, gap days render as baseline ticks, a null byTrigger renders 'not computed'. Byte-deterministic under permutation, total on junk, allowlist-normalized, one script element, no fetching, no innerHTML, textContent-only tips, row->node cross-highlight by replaying a guarded synthetic click so PAGE_JS keeps sole ownership of selection. The topology pane takes the scene's own aspect ratio (a fixed pane letterboxed a flat topology into a mostly-empty band; caught by a headless-Chrome screenshot). - index.ts: the insights subcommand (bare insights answers usage; the artifact IS the feature), USAGE/KNOWN_SUBCOMMANDS/description in step, completion for insights html <window>, assembleInsights composing the two existing assemblers, insightsHtmlCommand as graphHtmlCommand's structural twin (atomic stable path, URL first, headless skip-and-say, write-failure never opens). Default window 30d, deliberately not costs' mtd: the topology half is pinned at a 30d record window and one page's halves should agree. Specs in the same PR: NEW REQ-INSIGHTS-HTML-EXPORT; REQ-COST-ANALYTICS amended one sentence (the artifact joins the named surfaces; rules (a)-(g) unchanged); DES-ADMIN-VIA-PI-EXTENSION amended with the factoring facts and rejections (shared third emitter, duplication, in-place folding, a charting dependency); REQ-GRAPH-HTML-EXPORT UNCHANGED, checked (graph html stays the lighter topology-only export); REQ-TOPOLOGY-GRAPH UNCHANGED, checked; DES-GRAPH-EDGE-DERIVATION UNCHANGED, checked; DES-COST-FOLD-BY-SCAN UNCHANGED, checked. New docs/insights.md; cross-links in docs/graph.md and docs/costs.md. Suite green in the CI posture: 2224 tests, 0 skipped, live Valkey. Signed-off-by: Rob Boerman <robboerman@live.nl>
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.
Fourth slice of #175, the one the series exists for:
/dispatch insights html [7d|30d|mtd] [--no-open] [--full-paths]writes<graphDir>/insights.html, one self-containedfile://document that puts the trigger/flow topology (spend-badged) beside the cost fold drawn as real charts: KPI tiles, plan verdict cards, a daily spend column chart, and the four breakdown bar lists.Factoring
graph-html.mjsgains exports, not loads — its purity pin is substring-level and directional on purpose, so it may be a source of truth for a sibling emitter while never loading one itself.buildGraphSceneis the normalize+layout+SVG-emission half ofbuildGraphHtml, extracted whole and behavior-preserving: every existing graph-html pin is green untouched, zero test edits.insights-html.mjs(814 lines) loads exactly two modules —./graph-html.mjsfor the scene/escaping/theme and./panel.mjsfor the money — so every dollar string comes from the REALfmtCost, not a parity-pinned twin.The page keeps the class discipline in geometry
A plan-covered bucket draws a
plan:<id>chip and no dollar bar (a zero-length bar is the$0.00lie in geometry); estimates are dashed and translucent beside their~ est.text, hue never the sole encoding; floors carry≥on the chart; gap days render as baseline ticks, never compressed away; a nullbyTriggerrenders "not computed";limit: nullrenders "limit undisclosed by vendor" with no burn-down anywhere; NO_BASELINE renders its sentence and suppresses even a smuggled number; the page states both windows (spend window and the fixed 30d topology window) plus the retention sentence. Byte-deterministic under permutation of every input array; total on junk (an unreachable cost scan still writes the page with a banner); one script element; no fetching, no innerHTML, tips via textContent only; row→node cross-highlight replays a guarded synthetic click so PAGE_JS keeps sole ownership of selection (GRAPH.nodes[still appears exactly once).A headless-Chrome screenshot pass caught one visual defect no unit test saw (the #54 lesson holding): a fixed 75vh topology pane letterboxed a flat topology into a mostly-empty band — the svg now takes the scene's own aspect ratio, clamped.
Command surface
insightsjoins USAGE/KNOWN_SUBCOMMANDS/description in step (the pin holds member-for-member; the description string also gains thegraphmention it had silently dropped). Bareinsightsanswers usage — the artifact IS the feature.insightsHtmlCommandisgraphHtmlCommand's structural twin: atomic tmp+rename to the stable path, URL notified FIRST,--no-open, headless skip-and-say, write failure never opens. Default window 30d, deliberately not costs' mtd: the topology half is pinned at a 30d record window and one page's two halves should agree unless the operator asks otherwise. Completion coversinsights→html→ the windows. No new LLM tool (the topology assembly spawns git per folder;dispatch_costsunchanged)./dispatch graph htmlstays as-is — the lighter topology-only export, not an alias.Specs and docs
NEW
REQ-INSIGHTS-HTML-EXPORT(labeling rules inherited verbatim, the visual clauses, both windows, atomic/URL-first/headless/no-port/no-tool).REQ-COST-ANALYTICSAMENDED one sentence (the artifact joins the named surfaces; rules (a)-(g) unchanged).DES-ADMIN-VIA-PI-EXTENSIONAMENDED with the factoring facts and the rejections on the record (a shared third emitter module, duplication, folding costs into graph.html in place, a charting library).REQ-GRAPH-HTML-EXPORTUNCHANGED, checked.REQ-TOPOLOGY-GRAPHUNCHANGED, checked.DES-GRAPH-EDGE-DERIVATIONUNCHANGED, checked.DES-COST-FOLD-BY-SCANUNCHANGED, checked. Newdocs/insights.md; cross-links indocs/graph.mdanddocs/costs.md. READMEs are deliberately untouched here: the holistic pitch/screenshot pass is the next slice, so it describes the finished surface.Tests
Suite green in the CI posture (2224 tests, 0 skipped, live Valkey). New:
insights-html.test.mjs(17 tests mirroring the graph-html invariants: purity/import allowlist, class parity, XSS, byte-determinism under permutation, well-formedness, the seven file:// needles, the fmtCost honesty pins, chart geometry via the exported layout helpers, canary/path-leak with the fullPaths twin, honesty counters, script hardening incl.new Functionparse and the single guardedGRAPH.nodes[read, degrade pages) andinsights-command.test.mjs(9 tests cloning the graph-command harness plus the window argument and the both-halves smoke). Wiring gains the completion/routing pins.