@@ -38,7 +71,12 @@ export function EditorShell({
-
+
@@ -59,7 +97,9 @@ export function EditorShell({
0
+ ? `SysML · breaks active: ${breaks.join(", ")}`
+ : "SysML · 6 blocks · 6 associations · 1 constraint"}
right={
Fit
@@ -75,6 +115,7 @@ export function EditorShell({
variant={diagramStyle}
focusBlockId={focusBlockId}
onSelect={setFocusBlockId}
+ issuesByElement={issuesByElement}
/>
@@ -82,6 +123,22 @@ export function EditorShell({
+
+
setFocusBlockId(id)} />
);
}
+
+/** Map an issue's anchor to a single string key matching either a block id or
+ * a synthetic key (`assoc:a1`, `req:req-001`, `constraint:ferpa`). The UI uses
+ * block ids most often, so block anchors return the bare id. */
+function anchorKey(anchor: ValidationIssue["anchor"]): string | null {
+ switch (anchor.kind) {
+ case "block": return anchor.id;
+ case "association": return `assoc:${anchor.id}`;
+ case "constraint": return `constraint:${anchor.id}`;
+ case "requirement": return `req:${anchor.id}`;
+ case "property": return anchor.blockId;
+ case "model": return null;
+ }
+}
diff --git a/apps/web/components/editor/IssuesPanel.tsx b/apps/web/components/editor/IssuesPanel.tsx
new file mode 100644
index 0000000..bc2fbec
--- /dev/null
+++ b/apps/web/components/editor/IssuesPanel.tsx
@@ -0,0 +1,73 @@
+// Floating panel listing current validation issues — shown next to the
+// status bar. Click an issue to focus its anchored element across the rail
+// + diagram (via setFocusBlockId). Lets the user verify the validator is
+// actually firing on the broken-fixture demos.
+
+"use client";
+
+import { useState } from "react";
+import type { ValidationIssue } from "../../lib/sysml/validate";
+
+interface IssuesPanelProps {
+ issues: ValidationIssue[];
+ onSelectAnchor?: (id: string) => void;
+}
+
+const SEV_GLYPH: Record