mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-09 09:11:00 +08:00
fix(pipeline): align parallel env access graphing
Reuse the existing sequential EnvVar/CONFIGURES materialization helper from the parallel full-index registry phase so full rebuilds remain a valid oracle for incremental slices. Add a sequential-vs-parallel pipeline canary for C getenv access that verifies the CONFIGURES edge and canonical graph equality. This fixes the route_handler self-dogfood mismatch where incremental containment had EnvVar data that parallel full rebuild omitted. Validation: make -f Makefile.cbm -j8 build/c/test-runner; CBM_ONLY_SUITE=pipeline build/c/test-runner; bash scripts/check-source-safety.sh src/pipeline/pass_definitions.c src/pipeline/pass_parallel.c src/pipeline/pipeline_internal.h tests/test_pipeline.c; git diff --check; make -f Makefile.cbm -j8 cbm; route_handler self-dogfood rerun passed. Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
This commit is contained in:
@@ -371,8 +371,8 @@ static void create_channel_edges_for_file(cbm_pipeline_ctx_t *ctx, const CBMFile
|
||||
* env key and link the enclosing function (or the file node) CONFIGURES-> it,
|
||||
* so environment-driven configuration is visible even when the accessor is a
|
||||
* stdlib symbol that never resolves to an in-graph callee. */
|
||||
static int create_env_configures_for_file(cbm_pipeline_ctx_t *ctx, const CBMFileResult *result,
|
||||
const char *rel) {
|
||||
int cbm_pipeline_create_env_configures_for_file(cbm_pipeline_ctx_t *ctx,
|
||||
const CBMFileResult *result, const char *rel) {
|
||||
int count = 0;
|
||||
char *file_qn = NULL;
|
||||
const cbm_gbuf_node_t *file_node = NULL;
|
||||
@@ -491,7 +491,7 @@ int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
|
||||
* map is available without the cache (single-file scope). */
|
||||
total_imports += cbm_pipeline_create_import_edges_for_file(ctx, result, rel, NULL);
|
||||
create_channel_edges_for_file(ctx, result, rel);
|
||||
create_env_configures_for_file(ctx, result, rel);
|
||||
cbm_pipeline_create_env_configures_for_file(ctx, result, rel);
|
||||
cbm_free_result(result);
|
||||
}
|
||||
}
|
||||
@@ -524,7 +524,7 @@ int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
|
||||
total_imports += cbm_pipeline_create_import_edges_for_file(
|
||||
ctx, result, files[i].rel_path, namespace_map);
|
||||
create_channel_edges_for_file(ctx, result, files[i].rel_path);
|
||||
create_env_configures_for_file(ctx, result, files[i].rel_path);
|
||||
cbm_pipeline_create_env_configures_for_file(ctx, result, files[i].rel_path);
|
||||
}
|
||||
cbm_pipeline_namespace_map_free(namespace_map);
|
||||
if (owns_local_cache) {
|
||||
|
||||
@@ -889,6 +889,7 @@ int cbm_build_registry_from_cache(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
|
||||
|
||||
imports_edges += cbm_pipeline_create_import_edges_for_file(ctx, result, rel, namespace_map);
|
||||
create_channel_edges(ctx, result, rel);
|
||||
cbm_pipeline_create_env_configures_for_file(ctx, result, rel);
|
||||
}
|
||||
|
||||
cbm_pipeline_namespace_map_free(namespace_map);
|
||||
|
||||
@@ -395,6 +395,9 @@ int cbm_pipeline_create_import_edges_for_file(cbm_pipeline_ctx_t *ctx,
|
||||
const CBMFileResult *result,
|
||||
const char *rel_path,
|
||||
CBMHashTable *namespace_map);
|
||||
int cbm_pipeline_create_env_configures_for_file(cbm_pipeline_ctx_t *ctx,
|
||||
const CBMFileResult *result,
|
||||
const char *rel_path);
|
||||
|
||||
/* Extract IMPORTS edge local_name from the canonical edge JSON. Caller frees. */
|
||||
char *cbm_pipeline_import_edge_local_name_dup(const cbm_gbuf_edge_t *edge);
|
||||
|
||||
@@ -2485,6 +2485,85 @@ TEST(pipeline_parallel_duplicate_import_inherits_matches_sequential) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(pipeline_parallel_env_access_matches_sequential) {
|
||||
enum {
|
||||
FILLER_FILE_COUNT = 52,
|
||||
FILE_COUNT = FILLER_FILE_COUNT + 1,
|
||||
SEQUENTIAL_WORKERS = 1,
|
||||
PARALLEL_WORKERS = 4
|
||||
};
|
||||
const char *files[FILE_COUNT];
|
||||
const char *contents[FILE_COUNT];
|
||||
char filler_files[FILLER_FILE_COUNT][CBM_SZ_64];
|
||||
char filler_bodies[FILLER_FILE_COUNT][CBM_SZ_128];
|
||||
|
||||
files[0] = "src/env.c";
|
||||
contents[0] = "#include <stdlib.h>\n\n"
|
||||
"const char *load_temp(void) {\n"
|
||||
" return getenv(\"CBM_TEST_PARALLEL_ENV\");\n"
|
||||
"}\n";
|
||||
for (int i = 0; i < FILLER_FILE_COUNT; i++) {
|
||||
int rn = snprintf(filler_files[i], sizeof(filler_files[i]), "fillers/filler_%02d.c", i);
|
||||
int bn = snprintf(filler_bodies[i], sizeof(filler_bodies[i]),
|
||||
"int filler_%02d(void) {\n return %d;\n}\n", i, i);
|
||||
ASSERT_GT(rn, 0);
|
||||
ASSERT_LT((size_t)rn, sizeof(filler_files[i]));
|
||||
ASSERT_GT(bn, 0);
|
||||
ASSERT_LT((size_t)bn, sizeof(filler_bodies[i]));
|
||||
files[i + 1] = filler_files[i];
|
||||
contents[i + 1] = filler_bodies[i];
|
||||
}
|
||||
|
||||
if (setup_lang_repo(files, contents, FILE_COUNT) != 0) {
|
||||
FAIL("tmpdir");
|
||||
}
|
||||
|
||||
char seq_db[CBM_SZ_512];
|
||||
char par_db[CBM_SZ_512];
|
||||
int n = snprintf(seq_db, sizeof(seq_db), "%s/env-seq.db", g_lang_tmpdir);
|
||||
ASSERT_GT(n, 0);
|
||||
ASSERT_LT((size_t)n, sizeof(seq_db));
|
||||
n = snprintf(par_db, sizeof(par_db), "%s/env-par.db", g_lang_tmpdir);
|
||||
ASSERT_GT(n, 0);
|
||||
ASSERT_LT((size_t)n, sizeof(par_db));
|
||||
|
||||
char saved_workers[CBM_SZ_32] = {0};
|
||||
bool had_workers = cbm_safe_getenv("CBM_WORKERS", saved_workers, sizeof(saved_workers),
|
||||
NULL) != NULL;
|
||||
|
||||
char *project = NULL;
|
||||
int seq_rc =
|
||||
pipeline_run_with_worker_count(g_lang_tmpdir, seq_db, SEQUENTIAL_WORKERS, &project);
|
||||
int par_rc = pipeline_run_with_worker_count(g_lang_tmpdir, par_db, PARALLEL_WORKERS, NULL);
|
||||
pipeline_restore_workers_env(had_workers, saved_workers);
|
||||
ASSERT_EQ(seq_rc, 0);
|
||||
ASSERT_EQ(par_rc, 0);
|
||||
ASSERT_NOT_NULL(project);
|
||||
|
||||
char source_qn[CBM_SZ_512];
|
||||
n = snprintf(source_qn, sizeof(source_qn), "%s.src.env", project);
|
||||
ASSERT_GT(n, 0);
|
||||
ASSERT_LT((size_t)n, sizeof(source_qn));
|
||||
const char *env_qn = "__env__CBM_TEST_PARALLEL_ENV";
|
||||
|
||||
ASSERT_TRUE(pipeline_store_has_edge_between_qns(seq_db, project, source_qn, "CONFIGURES",
|
||||
env_qn));
|
||||
ASSERT_TRUE(pipeline_store_has_edge_between_qns(par_db, project, source_qn, "CONFIGURES",
|
||||
env_qn));
|
||||
|
||||
char diff_err[CBM_SZ_8K] = {0};
|
||||
int diff_rc = cbm_test_compare_canonical_graphs(seq_db, par_db, project, diff_err,
|
||||
sizeof(diff_err));
|
||||
if (diff_rc != 0) {
|
||||
printf(" [parallel:env-access-diff] %s\n", diff_err);
|
||||
}
|
||||
ASSERT_EQ(diff_rc, 0);
|
||||
|
||||
free(project);
|
||||
teardown_lang_repo();
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(pipeline_parallel_channel_edges_target_channels) {
|
||||
enum { FILLER_FILE_COUNT = 52, PARALLEL_WORKERS = 4 };
|
||||
const char *files[] = {"app/main.py"};
|
||||
@@ -13022,6 +13101,7 @@ SUITE(pipeline) {
|
||||
RUN_TEST(pipeline_python_reexport_call_uses_resolved_import_edge);
|
||||
RUN_TEST(pipeline_incremental_reexport_target_matches_full);
|
||||
RUN_TEST(pipeline_parallel_duplicate_import_inherits_matches_sequential);
|
||||
RUN_TEST(pipeline_parallel_env_access_matches_sequential);
|
||||
RUN_TEST(pipeline_parallel_channel_edges_target_channels);
|
||||
RUN_TEST(pipeline_go_type_classification);
|
||||
RUN_TEST(pipeline_go_grouped_types);
|
||||
|
||||
Reference in New Issue
Block a user