| 4273 | } |
| 4274 | |
| 4275 | static char *handle_check_index_coverage(cbm_mcp_server_t *srv, const char *args) { |
| 4276 | char *project = get_project_arg(args); |
| 4277 | cbm_store_t *store = resolve_store(srv, project); |
| 4278 | REQUIRE_STORE(store, project); |
| 4279 | |
| 4280 | yyjson_doc *adoc = yyjson_read(args, strlen(args), 0); |
| 4281 | yyjson_val *aroot = adoc ? yyjson_doc_get_root(adoc) : NULL; |
| 4282 | yyjson_val *paths = aroot ? yyjson_obj_get(aroot, "paths") : NULL; |
| 4283 | yyjson_val *scopes = aroot ? yyjson_obj_get(aroot, "scopes") : NULL; |
| 4284 | size_t path_count = paths && yyjson_is_arr(paths) ? yyjson_arr_size(paths) : 0U; |
| 4285 | size_t scope_count = scopes && yyjson_is_arr(scopes) ? yyjson_arr_size(scopes) : 0U; |
| 4286 | if (!aroot || (paths && !yyjson_is_arr(paths)) || (scopes && !yyjson_is_arr(scopes)) || |
| 4287 | (path_count == 0U && scope_count == 0U) || path_count > COVERAGE_PATH_MAX || |
| 4288 | scope_count > COVERAGE_SCOPE_MAX) { |
| 4289 | if (adoc) { |
| 4290 | yyjson_doc_free(adoc); |
| 4291 | } |
| 4292 | free(project); |
| 4293 | return cbm_mcp_text_result( |
| 4294 | "paths or scopes is required (arrays; max 128 paths and 32 scopes)", true); |
| 4295 | } |
| 4296 | |
| 4297 | cbm_project_t proj = {0}; |
| 4298 | bool have_project = cbm_store_get_project(store, project, &proj) == CBM_STORE_OK; |
| 4299 | cbm_coverage_meta_t meta = {0}; |
| 4300 | bool have_meta = cbm_store_coverage_meta_get(store, project, &meta) == CBM_STORE_OK; |
| 4301 | bool generation_matches = have_project && have_meta && proj.indexed_at && meta.generation && |
| 4302 | strcmp(proj.indexed_at, meta.generation) == 0; |
| 4303 | const char *recording_status = |
| 4304 | have_meta && meta.recording_status ? meta.recording_status : "unknown"; |
| 4305 | |
| 4306 | yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); |
| 4307 | yyjson_mut_val *root = yyjson_mut_obj(doc); |
| 4308 | yyjson_mut_doc_set_root(doc, root); |
| 4309 | yyjson_mut_obj_add_strcpy(doc, root, "project", project); |
| 4310 | yyjson_mut_obj_add_str(doc, root, "signal", "best_effort"); |
| 4311 | yyjson_mut_obj_add_strcpy(doc, root, "indexed_at", |
| 4312 | have_project && proj.indexed_at ? proj.indexed_at : ""); |
| 4313 | |
| 4314 | yyjson_mut_val *meta_obj = yyjson_mut_obj(doc); |
| 4315 | yyjson_mut_obj_add_strcpy(doc, meta_obj, "generation", |
| 4316 | have_meta && meta.generation ? meta.generation : ""); |
| 4317 | yyjson_mut_obj_add_strcpy(doc, meta_obj, "index_mode", |
| 4318 | have_meta && meta.index_mode ? meta.index_mode : "unknown"); |
| 4319 | yyjson_mut_obj_add_strcpy(doc, meta_obj, "recorded_at", |
| 4320 | have_meta && meta.recorded_at ? meta.recorded_at : ""); |
| 4321 | yyjson_mut_obj_add_strcpy(doc, meta_obj, "recording_status", recording_status); |
| 4322 | yyjson_mut_obj_add_int(doc, meta_obj, "ignored_files_stored", |
| 4323 | have_meta ? meta.ignored_files_stored : 0); |
| 4324 | yyjson_mut_obj_add_int(doc, meta_obj, "ignored_files_total", |
| 4325 | have_meta ? meta.ignored_files_total : 0); |
| 4326 | yyjson_mut_obj_add_bool(doc, meta_obj, "hash_records_complete", |
| 4327 | have_meta && meta.hash_records_complete); |
| 4328 | yyjson_mut_obj_add_int(doc, meta_obj, "coverage_version", |
| 4329 | have_meta ? meta.coverage_version : 0); |
| 4330 | yyjson_mut_obj_add_bool(doc, meta_obj, "generation_matches", generation_matches); |
| 4331 | yyjson_mut_obj_add_val(doc, root, "metadata", meta_obj); |
| 4332 |
no test coverage detected