Files
codebase-memory-mcp/internal/cbm/service_patterns.h
T
Martin Vogel 1a3425536b fix(graph): quality round after the v0.11.0 probe — deterministic resolution, findability, coverage, names
Nine findings from the 2026-09-16 graph-quality probe over the eleven bench corpora, each with a
test that fails without its fix and a before/after measurement on the real corpus.

Deterministic resolution (O9). Two indexes of one kernel tree differed in 5,821 IMPORTS and 632
CALLS edges. Three order/load dependencies carried it: the `#include` target was the first by-name
hit whose path ends with the include path — a bucket in worker merge order (include/linux/device.h
vs tools/virtio/linux/device.h); the registry broke suffix_match score ties by bucket position; the
LSP budget-share rule measured wall time. Include targets now prefer the File node, the least nested
path, then the lexicographic path; registry ties prefer the least nested QN, then the smaller QN; the
budget share is measured in thread CPU time like the budget itself. Two kernel indexes are now
identical (8,529,723 nodes, 1,974,940 CALLS, zero churn), as are two elasticsearch indexes.

Findability. search_graph's BM25 path honours the `label` filter and ranks an exact-name definition
above test methods that repeat the token (15/15 probe queries).

Coverage. The parse-coverage gap tree subtracts definitions the walker recovered inside an error
region (multi-line only); kernel/sched/core.c reports 476 flagged lines instead of 7,674.

Precision. Config-language callers (Makefile, CMake, YAML) no longer bind unique_name into code
(kernel Makefile -> C CALLS 195 -> 0). JS-family token names ({}, 1, (x: T) => U) are not
definitions; computed, quoted and escaped member keys stay (TypeScript 204 junk -> 0, 1,782 real
names kept). Names are cut at their first line (elasticsearch YAML 8,306 -> 0); a comment inside an
argument list is not an argument, so no Route node is named by a Java block comment; the wildcard
route `/*` is still a route. HTML/Vue/Svelte/Astro embedded member calls stay unbound.

Recall. A Python call through a self- or cls-rooted attribute keeps a specific unique_name member
target (Django +751, elasticsearch +3,288 CALLS, no new callee names).

Robustness. Edge properties never carry a split UTF-8 sequence (the 120-byte expression cut and the
JSON escaper both trim a partial code point). CLI array flags accept a JSON-array literal. Cypher
seeds a single-hop pattern from its selective end (kernel `MATCH (a)-[:CALLS]->(b) WHERE b.name =
'_printk'`: execution limit -> 7.9 s).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-21 20:29:27 +02:00

81 lines
3.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* service_patterns.h — Allowlists for HTTP clients, async dispatch, and config accessors.
*
* Used during call resolution to classify CALLS edges as:
* HTTP_CALLS — synchronous HTTP client calls
* ASYNC_CALLS — async message/task dispatch
* CONFIGURES — config/env access
*
* Lookup is O(1) via hash table initialized once at startup.
*/
#ifndef CBM_SERVICE_PATTERNS_H
#define CBM_SERVICE_PATTERNS_H
#include <stdbool.h>
/* Edge type returned by pattern match. */
typedef enum {
CBM_SVC_NONE = 0, /* Not a service pattern — use normal CALLS */
CBM_SVC_HTTP = 1, /* Synchronous HTTP client call */
CBM_SVC_ASYNC = 2, /* Async dispatch (message broker, task queue) */
CBM_SVC_CONFIG = 3, /* Config/env accessor */
CBM_SVC_ROUTE_REG = 4, /* Route registration (router.GET, app.get, Route::post) */
CBM_SVC_GRPC = 5, /* gRPC client call (protobuf stub invocation) */
CBM_SVC_GRAPHQL = 6, /* GraphQL client query/mutation */
CBM_SVC_TRPC = 7, /* tRPC client procedure call */
} cbm_svc_kind_t;
/* Initialize the pattern lookup tables. Call once at startup. Thread-safe after init. */
void cbm_service_patterns_init(void);
/* Check if a resolved QN contains a known service library identifier.
* Returns the pattern kind, or CBM_SVC_NONE if no match.
* Matches on library name substrings in the QN (e.g., "requests" in
* "project.venv.requests.api.get"). Import-alias transparent. */
cbm_svc_kind_t cbm_service_pattern_match(const char *resolved_qn);
/* True for a bare, unqualified call to the native `fetch()` API. Deliberately
* NOT part of the substring tables above: those are matched unconditionally
* against the raw callee name before/regardless of registry resolution
* (the #523 external-library bypass), and "fetch" — unlike "axios" or
* "requests" — collides with a plausible local identifier. Callers must
* only consult this after registry resolution has come back empty, so a
* locally resolvable `function fetch(){}` / `const fetch = () => {}` is
* classified via its real resolved QN instead and never reaches this check. */
bool cbm_service_pattern_is_global_fetch(const char *callee_name);
/* True when a string literal is a plausible HTTP route for the given callee.
* Rejects filesystem paths and non-HTTP string consumers. */
bool cbm_service_pattern_is_http_route_literal(const char *literal, const char *callee_name);
/* True when text that reached a path slot is a source comment rather than a
* path: a block comment (slash-star … star-slash), a line comment (slash-slash
* followed by a space), or any text with a line break. The wildcard route
* (slash-star alone) is a path. */
bool cbm_service_pattern_is_comment_text(const char *text);
/* Per-worker TLS cache for cbm_service_pattern_match results. The
* pattern matcher runs once per resolved CALL edge in emit_service_
* edge — that's 6 pattern lists × ~30 patterns × strstr per call ≈
* ~180 strstrs per call. The same resolved QN repeats across most of
* the call edges in a project (e.g. "fmt.Errorf"), so caching turns
* a linear pattern-list scan into one hash lookup. Call _begin once
* per worker thread before the resolve loop and _end at the end. */
void cbm_service_pattern_cache_begin(void);
void cbm_service_pattern_cache_end(void);
/* Get the HTTP method from the callee name suffix (e.g., ".get" → "GET").
* Returns NULL if method cannot be inferred. */
const char *cbm_service_pattern_http_method(const char *callee_name);
/* Get the HTTP method from a route registration callee name suffix
* (e.g., "router.GET" → "GET", "app.post" → "POST").
* Returns NULL if not a known route registration method. */
const char *cbm_service_pattern_route_method(const char *callee_name);
/* Get the broker name for an async QN (e.g., "pubsub" from a Pub/Sub QN).
* Returns NULL if not an async pattern. */
const char *cbm_service_pattern_broker(const char *resolved_qn);
#endif /* CBM_SERVICE_PATTERNS_H */