Skip to content

Commit 8373e3f

Browse files
author
Your Name
committed
feat(pipeline): auto-detect execution flows from entry points via BFS + Louvain
Add process detection as a post-indexing pass that discovers cross-community execution flows: 1. Find all entry point nodes (is_entry_point=true or Route label) 2. Load CALLS edges and run Louvain community detection 3. BFS from each entry point to depth 8, max 200 visited nodes 4. Identify the deepest node that crosses a Louvain community boundary 5. Name the flow 'EntryPoint → Terminal' with process_type=cross_community 6. Store to new processes + process_steps tables New schema: 'processes' table (id, project, label, process_type, step_count, entry_point_id, terminal_id) and 'process_steps' table (process_id, node_id, step). New store API: cbm_store_detect_processes(), cbm_store_list_processes(), cbm_store_get_process_steps() with corresponding free functions. New MCP tool: list_processes returns up to 300 processes ordered by step count. Tested: TS/Hapi monorepo detects 300 cross-community processes, matching the flow count from competing tools. Examples: 'ssoCallbackHandler → catchUnexpectedResponse', 'exportCourse → sendSQSMessage'.
1 parent 358de42 commit 8373e3f

4 files changed

Lines changed: 414 additions & 1 deletion

File tree

src/mcp/mcp.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ static const tool_def_t TOOLS[] = {
281281
"{\"type\":\"object\",\"properties\":{\"project\":{\"type\":\"string\"},\"aspects\":{\"type\":"
282282
"\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"project\"]}"},
283283

284+
{"list_processes",
285+
"List discovered execution flows (processes). Each process is a named path from an entry "
286+
"point through the call graph to a terminal node that crosses a community boundary. "
287+
"Processes are auto-detected during indexing using BFS from entry points + Louvain "
288+
"community detection. Returns up to 300 processes ordered by step count.",
289+
"{\"type\":\"object\",\"properties\":{\"project\":{\"type\":\"string\"}},\"required\":[\"project\"]}"},
290+
284291
{"search_code",
285292
"Graph-augmented code search. Finds text patterns via grep, then enriches results with "
286293
"the knowledge graph: deduplicates matches into containing functions, ranks by structural "
@@ -1158,6 +1165,45 @@ static char *handle_delete_project(cbm_mcp_server_t *srv, const char *args) {
11581165
return result;
11591166
}
11601167

1168+
static char *handle_list_processes(cbm_mcp_server_t *srv, const char *args) {
1169+
char *project = cbm_mcp_get_string_arg(args, "project");
1170+
cbm_store_t *store = resolve_store(srv, project);
1171+
REQUIRE_STORE(store, project);
1172+
1173+
cbm_process_info_t *procs = NULL;
1174+
int count = 0;
1175+
cbm_store_list_processes(store, project, &procs, &count);
1176+
1177+
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
1178+
yyjson_mut_val *root = yyjson_mut_obj(doc);
1179+
yyjson_mut_doc_set_root(doc, root);
1180+
1181+
yyjson_mut_obj_add_int(doc, root, "total", count);
1182+
1183+
yyjson_mut_val *arr = yyjson_mut_arr(doc);
1184+
for (int i = 0; i < count; i++) {
1185+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1186+
yyjson_mut_obj_add_int(doc, item, "id", procs[i].id);
1187+
yyjson_mut_obj_add_strcpy(doc, item, "label", procs[i].label ? procs[i].label : "");
1188+
yyjson_mut_obj_add_strcpy(doc, item, "process_type",
1189+
procs[i].process_type ? procs[i].process_type : "");
1190+
yyjson_mut_obj_add_int(doc, item, "step_count", procs[i].step_count);
1191+
yyjson_mut_obj_add_int(doc, item, "entry_point_id", procs[i].entry_point_id);
1192+
yyjson_mut_obj_add_int(doc, item, "terminal_id", procs[i].terminal_id);
1193+
yyjson_mut_arr_add_val(arr, item);
1194+
}
1195+
yyjson_mut_obj_add_val(doc, root, "processes", arr);
1196+
1197+
char *json = yy_doc_to_str(doc);
1198+
yyjson_mut_doc_free(doc);
1199+
cbm_store_free_processes(procs, count);
1200+
free(project);
1201+
1202+
char *result = cbm_mcp_text_result(json, false);
1203+
free(json);
1204+
return result;
1205+
}
1206+
11611207
static char *handle_get_architecture(cbm_mcp_server_t *srv, const char *args) {
11621208
char *project = cbm_mcp_get_string_arg(args, "project");
11631209
cbm_store_t *store = resolve_store(srv, project);
@@ -2919,6 +2965,9 @@ char *cbm_mcp_handle_tool(cbm_mcp_server_t *srv, const char *tool_name, const ch
29192965
if (strcmp(tool_name, "get_architecture") == 0) {
29202966
return handle_get_architecture(srv, args_json);
29212967
}
2968+
if (strcmp(tool_name, "list_processes") == 0) {
2969+
return handle_list_processes(srv, args_json);
2970+
}
29222971

29232972
/* Pipeline-dependent tools */
29242973
if (strcmp(tool_name, "index_repository") == 0) {

src/pipeline/pipeline.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,17 @@ int cbm_pipeline_run(cbm_pipeline_t *p) {
828828
"SELECT id, name, qualified_name, label, file_path FROM nodes;");
829829
cbm_store_close(fts_store);
830830
}
831+
832+
/* ── Process detection: discover execution flows from entry points ── */
833+
{
834+
cbm_store_t *proc_store = cbm_store_open_path(db_path);
835+
if (proc_store) {
836+
int nprocs = cbm_store_detect_processes(proc_store, p->project_name, 300);
837+
cbm_log_info("pass.done", "pass", "processes",
838+
"detected", itoa_buf(nprocs));
839+
cbm_store_close(proc_store);
840+
}
841+
}
831842
}
832843
}
833844

0 commit comments

Comments
 (0)