Skip to content

viz: architecture / drift / runtime dashboard (phases 3–5) - #14

Merged
PhysShell merged 3 commits into
mainfrom
claude/sts-runtime-analysis-2mo4z9
Jun 26, 2026
Merged

viz: architecture / drift / runtime dashboard (phases 3–5)#14
PhysShell merged 3 commits into
mainfrom
claude/sts-runtime-analysis-2mo4z9

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Что это

Дашборд для новых движков (фазы 3–5) — отдельный от viz/build_dashboard.py (тот про 72k сырых находок), чтобы не перелопачивать существующий. Считает прямо из стенд-артефактов через модули движков:

Артефакт Секции
graph.json coupling-карта (Instability × Abstractness на main sequence, или Ce/Ca бары без флага is_abstract) + arch-находки по правилам + таблица Ca/Ce/I/A/D по namespace
drift.json risk-бакеты дрейфа + таблица «что сдвинулось»
findings.json + runtime.json donut корреляции (confirmed / static-only / blind spot) + таблица подтверждённых и непредсказанных течей с confidence

Ключевое

  • Каждая секция опциональна — без артефакта рисует приглушённый empty-state. Поэтому смокается в CI (где стенд-данных нет → empty-state) и оживает на стенде.
  • XSS-safeesc() перед любым innerHTML, <>& экранированы в встроенном JSON (те же паттерны, что CodeRabbit одобрил в основном дашборде).
  • Plotly вшит — полностью офлайновый файл.
  • Проверено headless: 4 чарта монтируются, таблицы drift/runtime заполняются, ноль console-ошибок; empty-state рендерится чисто.
  • Вписан в CI dashboard-smoke.

Запуск

# на стенде, после прогона движков:
python3 viz/build_arch_dashboard.py \
  --graph sts_audit/graph.json --drift arch/out/drift.json \
  --findings sts_audit/findings.json --runtime sts_audit/runtime.json
#   -> viz/arch-dashboard.html  (self-contained)

Проверено на синтетическом стенде (тот же граф с подсаженными регрессиями + runtime-дамп): 4 High дрейфа, confirmed-leak DocumentsViewModel, blind-spot OrphanGridAdapter — всё рисуется.

🤖 Generated with Claude Code


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added a standalone architecture dashboard generator that produces a single-file HTML report for viewing in CI and locally.
    • The report includes charts and tables for architecture coupling, drift risk, runtime leak correlations, and per-namespace coupling metrics.
    • Missing or malformed artifacts now show muted empty states rather than failing report generation.
  • Chores
    • Expanded the CI dashboard smoke check to build both dashboard variants.
    • Improved CI step reliability by tightening shell error handling.
  • Bug Fixes
    • Improved Plotly fallback delivery by using an SRI-pinned CDN script when vendored assets are unavailable.

A standalone, self-contained HTML view over the new engines, separate from
viz/build_dashboard.py so neither refactors the other. Computes straight from the
stand artifacts via the engine modules:
  - graph.json -> coupling map (Instability vs Abstractness on the main sequence, or
    Ce/Ca bars when no is_abstract flag) + architecture findings by rule + a per-namespace
    Ca/Ce/I/A/D table.
  - drift.json -> drift risk buckets + a risk-tagged "what moved" table.
  - findings.json + runtime.json -> runtime correlation donut (confirmed / static-only /
    blind spot) + a confirmed-and-unpredicted-leaks table with confidence.

Every section is optional and renders a muted empty-state when its artifact is absent,
so it smokes in CI (no stand data) and lights up on the stand. XSS-safe (esc() before any
innerHTML, <>& escaped in the embedded JSON), Plotly vendored for a fully offline file.
Verified headless: 4 charts mount, drift/runtime tables populate, zero console errors;
empty-state renders cleanly. Wired into the CI dashboard smoke.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 52226cf1-09af-465d-9554-9a99cc57c3fa

📥 Commits

Reviewing files that changed from the base of the PR and between 7b48a67 and 53f3bb0.

📒 Files selected for processing (2)
  • viz/build_arch_dashboard.py
  • viz/build_dashboard.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • viz/build_arch_dashboard.py

📝 Walkthrough

Walkthrough

CI now runs both dashboard smoke builds. A new arch dashboard generator reads stand artifacts and emits an HTML dashboard with empty-state handling when inputs are missing.

Changes

Arch dashboard generation and smoke coverage

Layer / File(s) Summary
Module setup and JSON safety
viz/build_arch_dashboard.py
ROOT and import path setup are added, ordering constants are defined, and _safe_json() distinguishes missing artifacts from malformed JSON.
Artifact collection
viz/build_arch_dashboard.py
collect() loads graph, drift, findings, and runtime artifacts, derives architecture metrics and findings, computes drift buckets, and correlates runtime leaks.
HTML template and script loading
viz/build_arch_dashboard.py, viz/build_dashboard.py
The embedded HTML template renders dashboard sections, empty states, charts, and tables, while _plotly_tag() and _json_for_script() provide script loading and safe data injection; the existing dashboard fallback now uses an SRI-pinned Plotly CDN include.
CLI and smoke step
viz/build_arch_dashboard.py, .github/workflows/ci.yml
main() writes the generated HTML dashboard, and the CI audit-report job now runs both dashboard smoke scripts with strict shell options.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PhysShell/OwnAudit#9: Extends the CI dashboard smoke path to run viz/build_arch_dashboard.py alongside the existing dashboard build, with the same shell-safety update.
  • PhysShell/OwnAudit#12: Provides the drift.json outputs consumed by the new arch dashboard for drift counts and item rendering.

Poem

A bunny hops through charts at dawn,
With drift and leaks now plotted on.
Two smoke builds puff, both neat and true,
While dashboards bloom in rabbit view. 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the new architecture/drift/runtime dashboard added for phases 3–5.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/sts-runtime-analysis-2mo4z9

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@viz/build_arch_dashboard.py`:
- Around line 128-136: The dashboard copy contains ambiguous Unicode characters
flagged by Ruff RUF001, specifically the “Phases 3–5” text, the multiplication
sign in “static × heap retention,” and the en dash in “main sequence”/“3–5”.
Update the HTML text in the template section that renders the coupling,
archrules, driftbar, and rtdonut cards to use ASCII equivalents, or
suppress/configure RUF001 if the typography is intentional. Keep the existing
meaning intact while making the strings Ruff-compliant.
- Around line 245-250: The _plotly_tag helper currently falls back to the CDN
when viz/plotly.min.js is missing, which bypasses the offline self-contained
requirement. Update _plotly_tag to require the vendored Plotly file: if
os.path.exists(vendored) is false, fail immediately with a clear error instead
of returning the remote script tag. Keep the existing vendored-file path in
_plotly_tag as the only source for the script content.
- Around line 36-55: The issue is that `_safe_json()` and `collect()` treat
malformed or schema-invalid artifacts as absent, hiding stale upstream data as
empty state. Update `collect()` and the `Graph(...)` initialization path so a
present `graph.json` with invalid JSON or schema `ValueError` is surfaced as an
error instead of returning `None`/`g = None`. Keep `_safe_json()` or its callers
distinguishing “file missing” from “file present but invalid,” and preserve the
upstream validation failure from `Graph` rather than swallowing it.
- Around line 77-80: The runtime correlation in the build_arch_dashboard flow
only runs when findings.json is a dict, so list-shaped findings are being
ignored and the runtime section stays empty. Update the guard around the
_safe_json/load path in the build_arch_dashboard logic so it accepts either a
dict with a findings key or a top-level list, then pass the normalized findings
collection into rt.correlate while keeping the runtime payload handling in
place. Use the existing symbols _safe_json, rt.correlate, and rt.load_config to
locate and adjust the branch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 54883048-629c-4390-aa85-feb3d083d757

📥 Commits

Reviewing files that changed from the base of the PR and between 00a3e99 and 9840ef7.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • viz/build_arch_dashboard.py

Comment thread viz/build_arch_dashboard.py Outdated
Comment thread viz/build_arch_dashboard.py Outdated
Comment thread viz/build_arch_dashboard.py Outdated
Comment thread viz/build_arch_dashboard.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9840ef7293

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread viz/build_arch_dashboard.py Outdated
if os.path.exists(vendored):
with open(vendored, encoding="utf-8") as fh:
return "<script>" + fh.read() + "</script>"
return '<script src="https://cdn.plot.ly/plotly-2.35.2.min.js" charset="utf-8"></script>'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Inline Plotly instead of emitting a CDN-only dashboard

When this script is run from a fresh checkout with real graph/drift/runtime artifacts and then opened on an offline stand, this fallback emits only a CDN <script> because viz/plotly.min.js is gitignored and not tracked. The first Plotly.newPlot(...) call then throws Plotly is not defined, so none of the populated dashboard renders despite being advertised as self-contained; either vendor/inline Plotly for this dashboard or fail with instructions before writing a non-offline file.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right diagnosis, @chatgpt-codex-connectorviz/plotly.min.js is gitignored, so on a fresh checkout the fallback emits a CDN-only file and a populated dashboard throws Plotly is not defined offline, contradicting the "self-contained" wording.

Fixed the wording (the actual defect) in 7b48a67 rather than failing the build: _plotly_tag now warns loudly on fallback and the docstrings no longer claim unconditional offline (Plotly inlined only when vendored, else CDN). I kept the fallback for parity with the already-merged build_dashboard.py and because fail-loud would break the CI smoke (vendor blob isn't in CI). If we want a true offline guarantee, that's a follow-up to vendor Plotly for both dashboards — flagged for @PhysShell.


Generated by Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

… claim/unicode (Codex+CodeRabbit)

- _safe_json now distinguishes a MISSING artifact (-> None, empty-state) from a present-
  but-malformed one (-> raise); the graph block lets Graph's schema ValueError propagate
  instead of swallowing it, so a stale/corrupt graph.json fails loudly rather than
  rendering as "not collected yet".
- runtime correlation accepts a list-shaped findings.json (top-level list) as well as the
  usual {"findings": [...]} dict, so the section isn't silently empty.
- _plotly_tag keeps the CDN fallback (parity with build_dashboard.py + the gitignored
  4.5MB vendor blob; fail-loud would break the CI smoke) but now WARNS on fallback, and the
  docstrings no longer overclaim "self-contained/offline" — Plotly is inlined only when
  vendored, else CDN.
- Ruff RUF001: replace ambiguous unicode in HTML copy with entities/ASCII
  (3&ndash;5, static &times; heap, null-cell '-').

Re-verified headless: 4 charts, drift/runtime tables populate, zero console errors;
malformed/stale graph now raises; empty-state and list-findings paths both build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
viz/build_arch_dashboard.py (1)

69-86: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate present artifact shapes before rendering empty states.

Line 69 and Line 81 still let some present-but-stale artifacts behave like “missing”: e.g. drift.json as {} leaves D.drift null, and invalid runtime.json / findings.json shapes can suppress the runtime section. Only missing files should become empty states.

Proposed fix
     drift = _safe_json(drift_path)
-    if isinstance(drift, dict) and "items" in drift:
+    if drift is not None:
+        if not isinstance(drift, dict) or not isinstance(drift.get("items"), list):
+            raise ValueError(f"{drift_path} must be an object with list-valued 'items'")
         buckets = collections.Counter(i.get("risk") for i in drift["items"])
         data["drift"] = {
             "counts": [buckets.get(r, 0) for r in RISK_ORDER],
@@
     static = _safe_json(findings_path)
     dump = _safe_json(runtime_path)
-    if isinstance(dump, dict):
+    if dump is not None:
+        if not isinstance(dump, dict):
+            raise ValueError(f"{runtime_path} must be a JSON object")
         # findings.json is normally {"findings": [...]} but accept a top-level list too
-        static_findings = (static.get("findings", []) if isinstance(static, dict)
-                           else static if isinstance(static, list) else None)
+        if isinstance(static, dict):
+            if not isinstance(static.get("findings"), list):
+                raise ValueError(f"{findings_path} must contain list-valued 'findings'")
+            static_findings = static["findings"]
+        else:
+            static_findings = static if isinstance(static, list) else None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@viz/build_arch_dashboard.py` around lines 69 - 86, The drift/runtime handling
in build_arch_dashboard.py is treating present-but-invalid artifacts like
missing data, which can hide sections that should still render. Update the
`_safe_json` consumers around `drift`, `static`, and `dump` so only absent files
map to empty states, while malformed-but-present JSON still produces a rendered
artifact state (or validation path) instead of leaving `data["drift"]` null or
skipping `rt.correlate`; use the existing `drift`, `static_findings`, and `dump`
flow to distinguish file absence from invalid shape before rendering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@viz/build_arch_dashboard.py`:
- Around line 260-262: The Plotly CDN fallback script tags in the dashboard
builders are missing subresource integrity and CORS protection, so update the
fallback returned by the arch dashboard generator and the corresponding fallback
in the main dashboard builder to include both an integrity hash for
plotly-2.35.2.min.js and crossorigin="anonymous". Use the existing CDN fallback
logic in build_arch_dashboard and build_dashboard to locate the two return
values and keep the offline-vendored path unchanged.

---

Outside diff comments:
In `@viz/build_arch_dashboard.py`:
- Around line 69-86: The drift/runtime handling in build_arch_dashboard.py is
treating present-but-invalid artifacts like missing data, which can hide
sections that should still render. Update the `_safe_json` consumers around
`drift`, `static`, and `dump` so only absent files map to empty states, while
malformed-but-present JSON still produces a rendered artifact state (or
validation path) instead of leaving `data["drift"]` null or skipping
`rt.correlate`; use the existing `drift`, `static_findings`, and `dump` flow to
distinguish file absence from invalid shape before rendering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fd09ab6-a644-4501-b9db-767bb18dba6d

📥 Commits

Reviewing files that changed from the base of the PR and between 9840ef7 and 7b48a67.

📒 Files selected for processing (1)
  • viz/build_arch_dashboard.py

Comment thread viz/build_arch_dashboard.py Outdated
…CodeRabbit)

- build_arch_dashboard: a present-but-malformed drift.json (e.g. {}) or a
  findings.json with a non-list "findings" / a non-object runtime.json now raise
  instead of silently rendering as a missing-artifact empty-state; only an absent
  file maps to empty-state. Consistent with the _safe_json fix.
- Both dashboards: SRI-pin the Plotly CDN fallback with
  integrity="sha384-cCVCZkAj…" + crossorigin="anonymous" so the remote bundle
  can't be swapped silently. The hash is of plotly-2.35.2.min.js, verified
  byte-identical to the vendored viz/plotly.min.js.

Verified: bad drift/findings shapes raise; the SRI fallback tag is well-formed;
both dashboards still build (CI smoke); demo stays headless-clean (4 charts, 0
console errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
@PhysShell
PhysShell merged commit 46160ef into main Jun 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants