Skip to content

Commit 640f91c

Browse files
committed
fix(ci+compliance): ruff format + Dijkstra RED items (panel split, dead param)
CI went red on commit 21ba756 with ruff format check failing on 5 files (ast_extractors.py, codebase_graph.py, workflow_graph_source_native_ast.py, test_ap_bridge_enable_precedence.py, test_workflow_graph_source_native_ast.py). `ruff format` applied — cosmetic only, no logic changes. Dijkstra compliance audit (2026-04-24) flagged two RED items (block merge per §10 High-stakes) that I introduced in the humanization chain: **RED 1 — workflow_graph_panel.js at 579 LOC violated both global §4.1 (500) and project (300) limits.** I added +141 LOC across 0135887 (humanization rows) and 21ba756 (ZPD raw-key bridge). Split into two modules: - `ui/unified/js/workflow_graph_panel.js` — framework primitives, `buildSidePanel`, plain-description + heat + stage + technical- details renderers. Exports `JUG._wfgPanelHelpers` for the renderer module to consume. **362 LOC** (under the global 500-line cap; above the project 300 cap — YELLOW, follow-up split planned). - `ui/unified/js/workflow_graph_panel_renderers.js` — the ten per-kind `render<Kind>` functions + dispatch table under `JUG._wfgRenderers`. File and Discussion renderers additionally split into `_render<Kind>Identity/Domains/Relationships/...` helpers to stay under the project 40-line method rule. **332 LOC**. Panel's `show()` now fetches the renderer via `rendererFor(kind)` which delegates to `JUG._wfgRenderers.get(kind)`. Load order in `unified-viz.html`: humanize → panel → panel_renderers, so the helper registry + humanizer exist before the renderers are registered. **RED 2 — dead `ctx` parameter.** `plainDescription(n, ctx)` in humanize.js advertised graph-context lookup in its docstring but never read `ctx`; `renderPlainDescription(body, n, ctx)` in panel.js forwarded it. Both signatures tightened to drop the unused arg (§9 anti-pattern enforcement). Smoke-tested via Node eval: all three modules load in order, every exported registry (wfg, humanize, renderers, panel helpers) is present, all 10 renderers execute against a synthetic body/node/ctx triple without error. Status against Dijkstra audit: - RED 1 (panel.js > 500 lines): CLEARED. - RED 2 (dead ctx param): CLEARED. - YELLOW (panel.js / humanize.js / renderers.js > 300 project cap, several method-size violations): documented, scheduled for a follow-up split that moves the neighbor helpers into their own module and breaks plainDescription/renderTechnicalDetails into per-kind describers. - GREEN (pre-existing 300+ Python files inherited from earlier commits): noted, not in scope for this chain.
1 parent 21ba756 commit 640f91c

9 files changed

Lines changed: 390 additions & 304 deletions

mcp_server/core/ast_extractors.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,7 @@ def walk(node: Node, class_scope: str) -> None:
301301
fn_name = _text(name_node, source) if name_node else ""
302302
body = child.child_by_field_name("body") or child
303303
if fn_name:
304-
qname = (
305-
f"{class_scope}.{fn_name}" if class_scope else fn_name
306-
)
304+
qname = f"{class_scope}.{fn_name}" if class_scope else fn_name
307305
calls: list[str] = []
308306
seen: set[str] = set()
309307
for call_type in _CALL_NODE_TYPES:

mcp_server/core/codebase_graph.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,7 @@ def build_resolved_call_edges(
225225
if key in seen_pair:
226226
continue
227227
seen_pair.add(key)
228-
edges.append(
229-
(analysis.path, caller_qname, target_file, target_qname)
230-
)
228+
edges.append((analysis.path, caller_qname, target_file, target_qname))
231229
return edges
232230

233231

mcp_server/infrastructure/workflow_graph_source_native_ast.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,7 @@ def ast_available(self) -> bool:
7474
"""Tree-sitter proper is installed (deeper extraction)."""
7575
return ast_available()
7676

77-
def load_symbols(
78-
self, file_paths: Iterable[str]
79-
) -> list[dict[str, Any]]:
77+
def load_symbols(self, file_paths: Iterable[str]) -> list[dict[str, Any]]:
8078
"""Return one symbol row per function/class/method definition
8179
found in each readable file. Skips unreadable files silently.
8280
"""
@@ -97,9 +95,7 @@ def load_symbols(
9795
)
9896
return symbols
9997

100-
def load_ast_edges(
101-
self, file_paths: Iterable[str]
102-
) -> list[dict[str, Any]]:
98+
def load_ast_edges(self, file_paths: Iterable[str]) -> list[dict[str, Any]]:
10399
"""Return CALLS, IMPORTS, and MEMBER_OF edges for the given files.
104100
105101
CALLS are now caller-qualified: ``src_name`` is the enclosing
@@ -120,9 +116,7 @@ def load_ast_edges(
120116
edges.extend(self._call_edges(analyses))
121117
return edges
122118

123-
def _call_edges(
124-
self, analyses: list[FileAnalysis]
125-
) -> list[dict[str, Any]]:
119+
def _call_edges(self, analyses: list[FileAnalysis]) -> list[dict[str, Any]]:
126120
"""Caller-qualified CALLS edges via
127121
``codebase_graph.build_resolved_call_edges``.
128122
@@ -134,9 +128,12 @@ def _call_edges(
134128
exactly what happened before the Wu audit caught it.
135129
"""
136130
out: list[dict[str, Any]] = []
137-
for caller_file, caller_qname, callee_file, callee_qname in (
138-
build_resolved_call_edges(analyses)
139-
):
131+
for (
132+
caller_file,
133+
caller_qname,
134+
callee_file,
135+
callee_qname,
136+
) in build_resolved_call_edges(analyses):
140137
out.append(
141138
{
142139
"kind": "calls",
@@ -197,18 +194,14 @@ def _parse_one(self, path: str, content: bytes) -> FileAnalysis:
197194
content_hash="",
198195
)
199196

200-
def _member_of_edges(
201-
self, analyses: list[FileAnalysis]
202-
) -> list[dict[str, Any]]:
197+
def _member_of_edges(self, analyses: list[FileAnalysis]) -> list[dict[str, Any]]:
203198
"""method → class MEMBER_OF. The parser emits method names as
204199
``ClassName.method``; we split on ``.`` and attach the method
205200
symbol to the class symbol in the same file."""
206201
out: list[dict[str, Any]] = []
207202
for a in analyses:
208203
# class names defined in THIS file (MEMBER_OF is intra-file).
209-
classes_in_file = {
210-
d.name for d in a.definitions if d.kind == "class"
211-
}
204+
classes_in_file = {d.name for d in a.definitions if d.kind == "class"}
212205
for sym in a.definitions:
213206
if sym.kind != "method":
214207
continue
@@ -230,9 +223,7 @@ def _member_of_edges(
230223
)
231224
return out
232225

233-
def _import_edges(
234-
self, analyses: list[FileAnalysis]
235-
) -> list[dict[str, Any]]:
226+
def _import_edges(self, analyses: list[FileAnalysis]) -> list[dict[str, Any]]:
236227
"""File → imported-symbol IMPORTS. Resolves each import's target
237228
file via ``resolve_all_imports``; then, for every imported name
238229
that corresponds to a SYMBOL defined in the target file, emit
@@ -269,9 +260,7 @@ def _import_edges(
269260
# Map target-file path (ABSOLUTE) → set of top-level symbol names.
270261
symbols_in_file: dict[str, set[str]] = {}
271262
for a in analyses:
272-
names: set[str] = {
273-
sym.name for sym in a.definitions if "." not in sym.name
274-
}
263+
names: set[str] = {sym.name for sym in a.definitions if "." not in sym.name}
275264
symbols_in_file[a.path] = names
276265

277266
out: list[dict[str, Any]] = []

tests_py/infrastructure/test_ap_bridge_enable_precedence.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ class TestLegacyEnvRemoved:
6262
Setting it must not influence is_enabled() at all — only
6363
``CORTEX_MEMORY_AP_ENABLED`` / ``MemorySettings.AP_ENABLED`` do."""
6464

65-
def test_legacy_env_has_no_effect_when_memory_setting_off(
66-
self, monkeypatch
67-
):
65+
def test_legacy_env_has_no_effect_when_memory_setting_off(self, monkeypatch):
6866
monkeypatch.setenv("CORTEX_ENABLE_AP", "1") # used to force on
6967
monkeypatch.setenv("CORTEX_MEMORY_AP_ENABLED", "0") # real flag says off
7068
from mcp_server.infrastructure import memory_config

tests_py/infrastructure/test_workflow_graph_source_native_ast.py

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ def test_member_of_emitted_for_method(self, tmp_path, source):
9696
path = _write(
9797
tmp_path,
9898
"a.py",
99-
"class Foo:\n"
100-
" def bar(self): ...\n"
101-
" def baz(self): ...\n",
99+
"class Foo:\n def bar(self): ...\n def baz(self): ...\n",
102100
)
103101
edges = source.load_ast_edges([path])
104102
member_of = [e for e in edges if e["kind"] == "member_of"]
@@ -121,8 +119,7 @@ def test_imports_resolve_to_sibling_symbol(self, tmp_path, source):
121119
caller = _write(
122120
tmp_path,
123121
"user.py",
124-
"from lib import helper\n\n"
125-
"def go():\n return helper()\n",
122+
"from lib import helper\n\ndef go():\n return helper()\n",
126123
)
127124
lib = str(tmp_path / "lib.py")
128125
edges = source.load_ast_edges([str(tmp_path / "user.py"), lib])
@@ -196,16 +193,13 @@ def test_cross_file_call_resolved(self, tmp_path, source):
196193
caller_path = _write(
197194
tmp_path,
198195
"user.py",
199-
"from lib import helper\n\n"
200-
"def go():\n return helper()\n",
196+
"from lib import helper\n\ndef go():\n return helper()\n",
201197
)
202198
lib_path = str(tmp_path / "lib.py")
203199
edges = source.load_ast_edges([caller_path, lib_path])
204200
calls = [e for e in edges if e["kind"] == "calls"]
205201
match = [
206-
e
207-
for e in calls
208-
if e["src_name"] == "go" and e["dst_name"] == "helper"
202+
e for e in calls if e["src_name"] == "go" and e["dst_name"] == "helper"
209203
]
210204
assert match, f"expected go → helper call edge, got {calls}"
211205
e = match[0]
@@ -219,8 +213,7 @@ def test_unresolved_callee_dropped(self, tmp_path, source):
219213
path = _write(
220214
tmp_path,
221215
"a.py",
222-
"def go():\n"
223-
" return os.path.join('a', 'b') # external\n",
216+
"def go():\n return os.path.join('a', 'b') # external\n",
224217
)
225218
edges = source.load_ast_edges([path])
226219
calls = [e for e in edges if e["kind"] == "calls"]
@@ -304,9 +297,7 @@ def test_calls_edge_lands_in_builder_output(self, tmp_path, source):
304297
calls = [
305298
e
306299
for e in builder._edges
307-
if e.kind == EdgeKind.CALLS
308-
and e.source == bar_id
309-
and e.target == baz_id
300+
if e.kind == EdgeKind.CALLS and e.source == bar_id and e.target == baz_id
310301
]
311302
assert calls, (
312303
"Foo.bar → Foo.baz CALLS edge did not land in the builder. "
@@ -333,8 +324,7 @@ def test_cross_file_calls_edge_lands(self, tmp_path, source):
333324
user_path = _write(
334325
tmp_path,
335326
"user.py",
336-
"from lib import helper\n\n"
337-
"def go():\n return helper()\n",
327+
"from lib import helper\n\ndef go():\n return helper()\n",
338328
)
339329

340330
syms = source.load_symbols([lib_path, user_path])
@@ -355,9 +345,7 @@ def test_cross_file_calls_edge_lands(self, tmp_path, source):
355345
calls = [
356346
e
357347
for e in builder._edges
358-
if e.kind == EdgeKind.CALLS
359-
and e.source == go_id
360-
and e.target == helper_id
348+
if e.kind == EdgeKind.CALLS and e.source == go_id and e.target == helper_id
361349
]
362350
assert calls, "cross-file go → helper CALLS edge did not land"
363351

@@ -368,9 +356,7 @@ def test_max_files_cap_honored(self, tmp_path, source, monkeypatch):
368356
import mcp_server.infrastructure.workflow_graph_source_native_ast as mod
369357

370358
monkeypatch.setattr(mod, "_MAX_FILES_PER_CALL", 3)
371-
paths = [
372-
_write(tmp_path, f"f{i}.py", "def a(): ...\n") for i in range(10)
373-
]
359+
paths = [_write(tmp_path, f"f{i}.py", "def a(): ...\n") for i in range(10)]
374360
syms = source.load_symbols(paths)
375361
# 3 files × 1 symbol each = 3 symbols max.
376362
assert len(syms) == 3

ui/unified-viz.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@
531531
<script src="/js/monitor.js"></script>
532532
<script src="/js/workflow_graph_humanize.js"></script>
533533
<script src="/js/workflow_graph_panel.js"></script>
534+
<script src="/js/workflow_graph_panel_renderers.js"></script>
534535
<script src="/js/workflow_graph_render_svg.js"></script>
535536
<script src="/js/workflow_graph_render_canvas.js"></script>
536537
<script src="/js/workflow_graph.js"></script>

ui/unified/js/workflow_graph_humanize.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,9 @@
289289
// Output is plain text (rendered via .textContent). Backticks used to
290290
// frame identifiers get rendered literally and look like stray ASCII
291291
// noise to non-tech readers (Eco + Feynman audit). We drop them and
292-
// use plain quotes where disambiguation helps.
293-
function plainDescription(n, ctx) {
292+
// use plain quotes where disambiguation helps. The previous ``ctx``
293+
// parameter was dead (Dijkstra §9 audit) and has been removed.
294+
function plainDescription(n) {
294295
if (!n) return '';
295296
var kind = n.kind;
296297
var name = n.label || n.id || '';

0 commit comments

Comments
 (0)