Skip to content

Commit 0ec2478

Browse files
committed
Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts: # tests/test_lang_contract.c
2 parents 0563cae + a688d85 commit 0ec2478

10 files changed

Lines changed: 713 additions & 92 deletions

File tree

‎src/cypher/cypher.c‎

Lines changed: 240 additions & 60 deletions
Large diffs are not rendered by default.

‎src/cypher/cypher.h‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ typedef struct {
181181
int rel_count;
182182
} cbm_pattern_t;
183183

184+
/* One argument to a multi-argument scalar function (coalesce, substring, ...). */
185+
typedef struct {
186+
const char *variable; /* variable reference (NULL if a literal) */
187+
const char *property; /* property of the variable (NULL if whole var / literal) */
188+
const char *literal; /* literal string/number text (NULL if a variable ref) */
189+
} cbm_func_arg_t;
190+
184191
/* WHERE condition */
185192
typedef struct {
186193
const char *variable;
@@ -198,6 +205,11 @@ typedef struct {
198205
* anchor, `value` the edge type (NULL = any), `exists_dir` the direction
199206
* (0 = outbound, 1 = inbound, 2 = any). */
200207
int exists_dir;
208+
/* Multi-arg scalar function on the LHS, e.g. coalesce(f.depth, 0) >= 2
209+
* (#874). NULL func = plain variable/property LHS. */
210+
const char *func;
211+
cbm_func_arg_t *args;
212+
int arg_count;
201213
} cbm_condition_t;
202214

203215
/* Expression tree for WHERE clause */
@@ -237,13 +249,6 @@ typedef struct {
237249
const char *else_val; /* NULL if no ELSE */
238250
} cbm_case_expr_t;
239251

240-
/* One argument to a multi-argument scalar function (coalesce, substring, ...). */
241-
typedef struct {
242-
const char *variable; /* variable reference (NULL if a literal) */
243-
const char *property; /* property of the variable (NULL if whole var / literal) */
244-
const char *literal; /* literal string/number text (NULL if a variable ref) */
245-
} cbm_func_arg_t;
246-
247252
/* RETURN item */
248253
typedef struct {
249254
const char *variable;
@@ -332,4 +337,9 @@ int cbm_cypher_parse(const char *query, cbm_query_t **out, char **error);
332337
/* Free a query AST. */
333338
void cbm_query_free(cbm_query_t *q);
334339

340+
/* Test-only (#601): force the wall-clock execution budget in milliseconds for
341+
* subsequent queries on the calling thread. 0 = trip on the first hot-loop
342+
* check; a negative value restores the default budget. */
343+
void cbm_cypher_test_set_deadline_ms(int64_t budget_ms);
344+
335345
#endif /* CBM_CYPHER_H */

‎src/foundation/system_info.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ static cbm_system_info_t detect_system_bsd(void) {
9595
info.total_cores = nprocs > 0 ? (int)nprocs : 1;
9696
info.perf_cores = info.total_cores;
9797

98-
#if defined(__OpenBSD__)
98+
#if defined(__OpenBSD__) || defined(__FreeBSD__)
9999
int mib[2] = {CTL_HW, HW_PHYSMEM};
100100
#else
101101
int mib[2] = {CTL_HW, HW_PHYSMEM64};

‎src/pipeline/fqn.c‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,19 @@ char *cbm_pipeline_fqn_compute(const char *project, const char *rel_path, const
117117

118118
char *path = strdup(rel_path ? rel_path : "");
119119
cbm_normalize_path_sep(path);
120-
strip_file_extension(path);
120+
/* #1077/#964: File-node QNs (name=="__file__") must preserve the full
121+
* filename so sibling files sharing a stem get DISTINCT nodes — e.g.
122+
* .env / .env.local / .env.production (which all strip to ".env" and
123+
* collide, so only one survives per directory), and a C/C++ header vs
124+
* its same-stem .cpp. Extension stripping stays for MODULE/symbol QNs
125+
* (name==NULL or a symbol): that stem unification is load-bearing for
126+
* C/C++ declaration↔definition cross-file resolution. All 26 __file__
127+
* QN sites route through here, so creation and every lookup stay
128+
* consistent. */
129+
bool is_file_qn = name && strcmp(name, "__file__") == 0;
130+
if (!is_file_qn) {
131+
strip_file_extension(path);
132+
}
121133

122134
const char *segments[CBM_SZ_256];
123135
int seg_count = 0;

‎src/pipeline/pipeline.c‎

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,47 @@ static bool is_infra_file(const char *fp) {
615615
strstr(fp, ".tf") != NULL || strstr(fp, ".hcl") != NULL || strstr(fp, ".toml") != NULL);
616616
}
617617

618+
/* CI/tooling configs describe the development TOOLCHAIN — their URLs are
619+
* repository/action/registry references, never endpoints this service
620+
* exposes. Minting infra Route nodes from them lets the route matcher's
621+
* root-service heuristic attach every handler of an ambiguous "/" route to
622+
* each tooling URL (junk HANDLES churn on plain pallets/flask, #999).
623+
* Deny by file identity, not URL shape: deployment configs (Cloud
624+
* Scheduler, compose) keep minting their genuine endpoints. */
625+
static bool is_ci_tooling_config(const char *fp) {
626+
if (!fp) {
627+
return false;
628+
}
629+
if (strstr(fp, ".github/") != NULL || strstr(fp, ".gitlab/") != NULL ||
630+
strstr(fp, ".circleci/") != NULL) {
631+
return true;
632+
}
633+
const char *slash = strrchr(fp, '/');
634+
const char *base = slash ? slash + 1 : fp;
635+
static const char *const tooling[] = {".pre-commit-config.yaml",
636+
".pre-commit-hooks.yaml",
637+
".gitlab-ci.yml",
638+
".travis.yml",
639+
"azure-pipelines.yml",
640+
"appveyor.yml",
641+
"bitbucket-pipelines.yml",
642+
".readthedocs.yaml",
643+
".readthedocs.yml",
644+
"codecov.yml",
645+
".codecov.yml",
646+
".goreleaser.yaml",
647+
".goreleaser.yml",
648+
".golangci.yml",
649+
".golangci.yaml",
650+
NULL};
651+
for (int i = 0; tooling[i]; i++) {
652+
if (strcmp(base, tooling[i]) == 0) {
653+
return true;
654+
}
655+
}
656+
return false;
657+
}
658+
618659
/* True when a YAML key path denotes an UPSTREAM dependency, CONFIG value, or
619660
* HEALTHCHECK target rather than an endpoint this service exposes. Such URLs
620661
* (auth JWKS, downstream service base URLs, package-registry URLs, healthcheck
@@ -683,7 +724,8 @@ static void cbm_pipeline_extract_infra_routes(cbm_gbuf_t *gbuf, const cbm_file_i
683724
CBMHashTable *denied = cbm_ht_create(16);
684725
for (int pass = 0; pass < 2; pass++) {
685726
for (int i = 0; i < file_count; i++) {
686-
if (!result_cache[i] || !is_infra_file(files[i].rel_path)) {
727+
if (!result_cache[i] || !is_infra_file(files[i].rel_path) ||
728+
is_ci_tooling_config(files[i].rel_path)) {
687729
continue;
688730
}
689731
for (int si = 0; si < result_cache[i]->string_refs.count; si++) {

‎tests/repro/repro_issue964.c‎

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,36 @@ static int r964_file_node_exists(cbm_store_t *store, const char *project, const
6060
return found;
6161
}
6262

63-
/* Count inbound IMPORTS edges whose TARGET node name is exactly `name`. */
64-
static int r964_inbound_imports(cbm_store_t *store, const char *project, const char *name) {
65-
cbm_edge_t *edges = NULL;
66-
int n = 0;
67-
if (cbm_store_find_edges_by_type(store, project, "IMPORTS", &edges, &n) != CBM_STORE_OK)
68-
return -1;
69-
int hits = 0;
70-
for (int i = 0; i < n; i++) {
71-
cbm_node_t tgt;
72-
if (cbm_store_find_node_by_id(store, edges[i].target_id, &tgt) != CBM_STORE_OK)
63+
/* Count INBOUND edges (any of the reporter's connection types) landing on the
64+
* File node named `name` — the exact disconnection metric from the issue's
65+
* query `NOT EXISTS { (f)<-[:IMPORTS|CALLS|CONTAINS_FILE|DEFINES|USAGE]-() }`.
66+
* A header that used to have no node at all (extension-stripped QN collision)
67+
* now has its own File node AND is connected (CONTAINS_FILE from its folder,
68+
* plus DEFINES of the class it declares); `#include` itself resolves to the
69+
* declared Class node via #983, not to the header File. */
70+
static int r964_file_inbound(cbm_store_t *store, const char *project, const char *name) {
71+
static const char *const types[] = {"IMPORTS", "CALLS", "CONTAINS_FILE",
72+
"DEFINES", "USAGE", NULL};
73+
int total = 0;
74+
for (int t = 0; types[t]; t++) {
75+
cbm_edge_t *edges = NULL;
76+
int n = 0;
77+
if (cbm_store_find_edges_by_type(store, project, types[t], &edges, &n) != CBM_STORE_OK)
7378
continue;
74-
if (tgt.name && strcmp(tgt.name, name) == 0)
75-
hits++;
76-
cbm_node_free_fields(&tgt);
79+
for (int i = 0; i < n; i++) {
80+
cbm_node_t tgt;
81+
if (cbm_store_find_node_by_id(store, edges[i].target_id, &tgt) != CBM_STORE_OK)
82+
continue;
83+
if (tgt.name && strcmp(tgt.name, name) == 0)
84+
total++;
85+
cbm_node_free_fields(&tgt);
86+
}
87+
cbm_store_free_edges(edges, n);
7788
}
78-
cbm_store_free_edges(edges, n);
79-
return hits;
89+
return total;
8090
}
8191

82-
TEST(repro_issue964_header_has_node_and_inbound_import) {
92+
TEST(repro_issue964_header_has_node_and_is_connected) {
8393
static const RFile files[] = {
8494
{"NodeController.h", "#pragma once\n"
8595
"class NodeController {\n"
@@ -102,20 +112,20 @@ TEST(repro_issue964_header_has_node_and_inbound_import) {
102112
ASSERT_NOT_NULL(store);
103113

104114
int header_node = r964_file_node_exists(store, lp.project, "NodeController.h");
105-
int header_inbound = r964_inbound_imports(store, lp.project, "NodeController.h");
115+
int header_inbound = r964_file_inbound(store, lp.project, "NodeController.h");
106116
if (!header_node || header_inbound < 1) {
107117
fprintf(stderr,
108-
" [964] FAIL header_file_node=%d inbound_imports=%d (header merged into "
109-
"same-stem .cpp by extension-stripped QN collision)\n",
118+
" [964] FAIL header_file_node=%d inbound_edges=%d (header merged into "
119+
"same-stem .cpp by extension-stripped QN collision, or left disconnected)\n",
110120
header_node, header_inbound);
111121
}
112-
ASSERT_TRUE(header_node); /* header must keep its own File node */
113-
ASSERT_TRUE(header_inbound >= 1); /* #include must land an edge on it */
122+
ASSERT_TRUE(header_node); /* header keeps its own File node (not merged) */
123+
ASSERT_TRUE(header_inbound >= 1); /* and is connected (not the reporter's zero-inbound) */
114124

115125
rh_cleanup(&lp, store);
116126
PASS();
117127
}
118128

119129
SUITE(repro_issue964) {
120-
RUN_TEST(repro_issue964_header_has_node_and_inbound_import);
130+
RUN_TEST(repro_issue964_header_has_node_and_is_connected);
121131
}

0 commit comments

Comments
 (0)