#include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include } namespace { constexpr uint64_t kAnalysisWorkingBytes = UINT64_C(20) * 1024u * 1024u; enum class Mode { kA6000, kS21 }; struct Options { Mode mode{}; bool has_mode{}; std::filesystem::path project_dir; std::vector roots; }; /* This validation-only mirror keeps the reported admission estimate aligned * with the v1 Task contract: retained request/context storage plus one bounded * 20 MiB group analysis allowance. It does not own or execute Task state. */ struct PhotoQualityContextLayout { char project_path[LARDON3D_APP_STATE_PATH_CAPACITY]; Lardon3DProjectDb *database; Lardon3DResourceGovernor *governor; uint64_t scanset_id; std::vector sources; std::vector confirmations; std::vector encoded; Lardon3DAcquisitionCampaignPlan plan; }; void usage(const char *program) { std::fprintf(stderr, "Usage: %s --mode a6000|s21 --project-dir ABSOLUTE_EMPTY_DIR " "--root ABSOLUTE_DIR [--root ABSOLUTE_DIR ...]\n", program); } bool parse_options(int argc, char **argv, Options &options) { for (int i = 1; i < argc; ++i) { const std::string argument(argv[i]); if ((argument == "--mode" || argument == "--project-dir" || argument == "--root") && i + 1 >= argc) return false; if (argument == "--mode") { const std::string value(argv[++i]); if (value == "a6000") options.mode = Mode::kA6000; else if (value == "s21") options.mode = Mode::kS21; else return false; options.has_mode = true; } else if (argument == "--project-dir") { options.project_dir = argv[++i]; } else if (argument == "--root") { options.roots.emplace_back(argv[++i]); } else if (argument == "--help") { usage(argv[0]); std::exit(0); } else { return false; } } return options.has_mode && !options.project_dir.empty() && !options.roots.empty() && options.roots.size() <= LARDON3D_ACQUISITION_CAMPAIGN_MAX_ROOTS; } bool canonical_directory(const std::filesystem::path &input, std::filesystem::path &output) { std::error_code error; if (!input.is_absolute()) return false; output = std::filesystem::canonical(input, error); return !error && std::filesystem::is_directory(output, error) && !error && output.string().size() < LARDON3D_ACQUISITION_CAMPAIGN_PATH_CAPACITY; } bool prepare_project_directory(const std::filesystem::path &input, std::filesystem::path &output) { if (!input.is_absolute()) return false; output = input.lexically_normal(); if (output != input || output.string().size() >= LARDON3D_APP_STATE_PATH_CAPACITY) return false; std::error_code error; if (std::filesystem::exists(output, error)) { if (error || !std::filesystem::is_directory(output, error) || error || !std::filesystem::is_empty(output, error) || error) return false; } else if (!std::filesystem::create_directories(output, error) || error) { return false; } return std::filesystem::create_directories(output / ".lardon3d" / "checkpoints", error) && !error; } const char *mode_name(Mode mode) { return mode == Mode::kA6000 ? "a6000" : "s21"; } std::string stem(const char *path) { const char *name = std::strrchr(path, '/'); name = name == nullptr ? path : name + 1; const char *dot = std::strrchr(name, '.'); return std::string(name, dot == nullptr ? std::strlen(name) : static_cast(dot - name)); } bool build_confirmations(Mode mode, const Lardon3DAcquisitionCampaignDiscovery &discovery, std::vector &confirmations) { if (mode == Mode::kS21) { confirmations.reserve(discovery.source_count); for (size_t i = 0; i < discovery.source_count; ++i) { if (discovery.sources[i].source_kind != LARDON3D_ACQUISITION_SOURCE_JPEG) return false; Lardon3DAcquisitionCampaignConfirmation confirmation{}; confirmation.source_count = 1; confirmation.source_indices[0] = i; confirmations.push_back(confirmation); } return true; } struct Pair { size_t raw = SIZE_MAX; size_t jpeg = SIZE_MAX; }; std::map pairs; for (size_t i = 0; i < discovery.source_count; ++i) { Pair &pair = pairs[stem(discovery.sources[i].path)]; if (discovery.sources[i].source_kind == LARDON3D_ACQUISITION_SOURCE_RAW) { if (pair.raw != SIZE_MAX) return false; pair.raw = i; } else if (discovery.sources[i].source_kind == LARDON3D_ACQUISITION_SOURCE_JPEG) { if (pair.jpeg != SIZE_MAX) return false; pair.jpeg = i; } else { return false; } } confirmations.reserve(pairs.size()); for (const auto &entry : pairs) { if (entry.second.raw == SIZE_MAX || entry.second.jpeg == SIZE_MAX) return false; Lardon3DAcquisitionCampaignConfirmation confirmation{}; confirmation.source_count = 2; confirmation.source_indices[0] = entry.second.raw; confirmation.source_indices[1] = entry.second.jpeg; confirmations.push_back(confirmation); } return confirmations.size() * 2u == discovery.source_count; } void json_string(const char *text) { std::putchar('"'); for (const unsigned char *p = reinterpret_cast(text); *p; ++p) { switch (*p) { case '"': std::fputs("\\\"", stdout); break; case '\\': std::fputs("\\\\", stdout); break; case '\b': std::fputs("\\b", stdout); break; case '\f': std::fputs("\\f", stdout); break; case '\n': std::fputs("\\n", stdout); break; case '\r': std::fputs("\\r", stdout); break; case '\t': std::fputs("\\t", stdout); break; default: if (*p < 0x20u) std::printf("\\u%04x", static_cast(*p)); else std::putchar(*p); } } std::putchar('"'); } const char *status_name(Lardon3DPhotoQualityMetricStatus status) { switch (status) { case LARDON3D_PHOTO_QUALITY_METRIC_OK: return "OK"; case LARDON3D_PHOTO_QUALITY_METRIC_UNAVAILABLE: return "UNAVAILABLE"; case LARDON3D_PHOTO_QUALITY_METRIC_INVALID_INPUT: return "INVALID_INPUT"; case LARDON3D_PHOTO_QUALITY_METRIC_DECODE_ERROR: return "DECODE_ERROR"; } return "UNKNOWN"; } const char *recommendation_name(Lardon3DPhotoQualityRecommendation recommendation) { switch (recommendation) { case LARDON3D_PHOTO_QUALITY_GOOD: return "GOOD"; case LARDON3D_PHOTO_QUALITY_SUSPECT: return "SUSPECT"; case LARDON3D_PHOTO_QUALITY_REJECT: return "REJECT"; } return "NONE"; } bool wait_terminal(Lardon3DTaskQueue *queue, Lardon3DProjectDb *database, uint64_t task_id, Lardon3DTaskSnapshot &snapshot, Lardon3DProjectDbTask &durable) { for (;;) { if (!lardon3d_task_queue_get(queue, task_id, &snapshot)) return false; if (snapshot.state == TASK_COMPLETED || snapshot.state == TASK_FAILED || snapshot.state == TASK_CANCELLED) { /* Queue terminal state precedes the finished callback. Report only after * that callback has durably published the matching generic Task state and * sequence count, so validation never samples an intermediate row. */ if (lardon3d_project_db_load_task(database, task_id, &durable) != LARDON3D_PROJECT_DB_OK) return false; if (durable.saved_state == snapshot.state) return true; } usleep(100000); } } void emit_group(const Lardon3DAcquisitionCampaignDiscovery &discovery, const Lardon3DAcquisitionCampaignGroup &group, const Lardon3DProjectDbPhotoQualityResult &result) { std::printf("{\"record\":\"group\",\"group_id\":%u,\"basis\":%u,\"source_indices\":[", result.group_id, static_cast(group.basis)); for (size_t i = 0; i < group.source_count; ++i) std::printf("%s%zu", i == 0 ? "" : ",", group.source_indices[i]); std::fputs("],\"source_paths\":[", stdout); for (size_t i = 0; i < group.source_count; ++i) { if (i != 0) std::putchar(','); json_string(discovery.sources[group.source_indices[i]].path); } std::fputs("],\"proxy_source_index\":", stdout); if (result.proxy_source_index == UINT32_MAX) std::fputs("null,\"proxy_path\":null", stdout); else { std::printf("%u,\"proxy_path\":", result.proxy_source_index); json_string(discovery.sources[result.proxy_source_index].path); } std::printf(",\"status\":\"%s\",\"recommendation\":\"%s\",\"reasons\":", status_name(result.metrics.status), recommendation_name(result.metrics.recommendation)); json_string(result.metrics.reasons); std::printf(",\"decoded_width\":%u,\"decoded_height\":%u,\"analysis_width\":%u," "\"analysis_height\":%u,\"sharpness_raw\":%.17g," "\"sharpness_normalized\":%.17g,\"clipped_black_fraction\":%.17g," "\"clipped_white_fraction\":%.17g,\"contrast_raw\":%.17g," "\"contrast_normalized\":%.17g,\"low_texture_fraction\":%.17g}\n", result.metrics.decoded_width, result.metrics.decoded_height, result.metrics.analysis_width, result.metrics.analysis_height, result.metrics.sharpness_raw, result.metrics.sharpness_normalized, result.metrics.clipped_black_fraction, result.metrics.clipped_white_fraction, result.metrics.contrast_raw, result.metrics.contrast_normalized, result.metrics.low_texture_fraction); } } // namespace extern "C" const Lardon3DTaskKindRegistry *lardon3d_task_kind_registry_production(void) { return nullptr; } int main(int argc, char **argv) { Options options; if (!parse_options(argc, argv, options)) { usage(argv[0]); return 2; } std::filesystem::path project_dir; if (!prepare_project_directory(options.project_dir, project_dir)) { std::fprintf(stderr, "project directory must be an absolute, normalized empty directory\n"); return 2; } std::vector roots(options.roots.size()); for (size_t i = 0; i < options.roots.size(); ++i) { std::filesystem::path canonical; if (!canonical_directory(options.roots[i], canonical)) { std::fprintf(stderr, "root must resolve to a bounded directory: %s\n", options.roots[i].c_str()); return 2; } const std::string path = canonical.string(); std::memcpy(roots[i].path, path.c_str(), path.size() + 1u); } auto discovery = std::make_unique(); const auto discovery_result = lardon3d_acquisition_campaign_discover(roots.data(), roots.size(), discovery.get()); if (discovery_result != LARDON3D_ACQUISITION_CAMPAIGN_OK || discovery->source_count == 0) { std::fprintf(stderr, "acquisition discovery failed: %u\n", static_cast(discovery_result)); return 1; } std::vector confirmations; if (!build_confirmations(options.mode, *discovery, confirmations)) { std::fprintf(stderr, "%s source set does not satisfy the required exact grouping shape\n", mode_name(options.mode)); return 1; } auto plan = std::make_unique(); if (lardon3d_acquisition_campaign_plan(discovery->sources, discovery->source_count, confirmations.data(), confirmations.size(), plan.get()) != LARDON3D_ACQUISITION_CAMPAIGN_OK || plan->group_count != confirmations.size() || plan->summary.explicit_group_count != confirmations.size()) { std::fprintf(stderr, "explicit campaign planning failed\n"); return 1; } const std::string database_path = (project_dir / "project.lardon3d").string(); char database_error[LARDON3D_PROJECT_DB_ERROR_CAPACITY]{}; Lardon3DProjectDb *database = nullptr; if (lardon3d_project_db_open(database_path.c_str(), &database, database_error) != LARDON3D_PROJECT_DB_OK) { std::fprintf(stderr, "project database open failed: %s\n", database_error); return 1; } Lardon3DProjectDbScanSet scanset{}; if (lardon3d_project_db_create_scanset(database, mode_name(options.mode), &scanset) != LARDON3D_PROJECT_DB_OK) { std::fprintf(stderr, "ScanSet creation failed\n"); lardon3d_project_db_close(database); return 1; } Lardon3DHardwareProfile profile{}; char hardware_error[256]{}; Lardon3DResourcePolicy policy{}; if (!lardon3d_hardware_profile_detect(&profile, hardware_error, sizeof(hardware_error)) || !lardon3d_resource_policy_default(&profile, &policy)) { std::fprintf(stderr, "hardware/resource policy detection failed: %s\n", hardware_error); lardon3d_project_db_close(database); return 1; } Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(&profile, &policy); Lardon3DTaskQueue *queue = governor ? lardon3d_task_queue_create(governor, 2) : nullptr; if (!queue) { std::fprintf(stderr, "Queue/Governor creation failed\n"); lardon3d_resource_governor_destroy(governor); lardon3d_project_db_close(database); return 1; } Lardon3DAppState state{}; lardon3d_app_state_init(&state); state.project_loaded = true; state.project_db = database; state.resource_governor = governor; state.task_queue = queue; state.hardware_profile = profile; const std::string project_path = project_dir.string(); std::memcpy(state.project_path, project_path.c_str(), project_path.size() + 1u); Lardon3DPhotoQualityTaskRequest request{discovery->sources, discovery->source_count, confirmations.data(), confirmations.size()}; size_t encoded_size = 0; if (!lardon3d_photo_quality_request_encode(&request, nullptr, 0, &encoded_size)) { std::fprintf(stderr, "request size calculation failed\n"); lardon3d_task_queue_destroy(queue); lardon3d_resource_governor_destroy(governor); lardon3d_project_db_close(database); return 1; } const uint64_t task_memory_estimate = kAnalysisWorkingBytes + sizeof(PhotoQualityContextLayout) + discovery->source_count * sizeof(Lardon3DAcquisitionCampaignSource) + confirmations.size() * sizeof(Lardon3DAcquisitionCampaignConfirmation) + encoded_size; const auto started = std::chrono::steady_clock::now(); uint64_t task_id = 0; if (!lardon3d_project_enqueue_photo_quality(&state, scanset.scanset_id, &request, &task_id)) { std::fprintf(stderr, "photo_quality.triage enqueue failed\n"); lardon3d_task_queue_destroy(queue); lardon3d_resource_governor_destroy(governor); lardon3d_project_db_close(database); return 1; } Lardon3DTaskSnapshot terminal{}; Lardon3DProjectDbTask durable_task{}; if (!wait_terminal(queue, database, task_id, terminal, durable_task) || terminal.state != TASK_COMPLETED) { std::fprintf(stderr, "photo_quality.triage ended in %s: %s\n", lardon3d_task_state_name(terminal.state), terminal.message); lardon3d_task_queue_destroy(queue); lardon3d_resource_governor_destroy(governor); lardon3d_project_db_close(database); return 1; } size_t good = 0, suspect = 0, reject = 0, unavailable = 0, metric_errors = 0; for (uint32_t group_index = 0; group_index < plan->group_count; ++group_index) { const uint32_t group_id = plan->groups[group_index].group_id; Lardon3DProjectDbPhotoQualityResult result{}; if (lardon3d_project_db_load_photo_quality_result(database, task_id, group_id, &result) != LARDON3D_PROJECT_DB_OK) { std::fprintf(stderr, "missing durable result for group %u\n", group_id); lardon3d_task_queue_destroy(queue); lardon3d_resource_governor_destroy(governor); lardon3d_project_db_close(database); return 1; } if (result.metrics.status == LARDON3D_PHOTO_QUALITY_METRIC_UNAVAILABLE) ++unavailable; else if (result.metrics.status != LARDON3D_PHOTO_QUALITY_METRIC_OK) ++metric_errors; if (result.metrics.recommendation == LARDON3D_PHOTO_QUALITY_GOOD) ++good; else if (result.metrics.recommendation == LARDON3D_PHOTO_QUALITY_SUSPECT) ++suspect; else if (result.metrics.recommendation == LARDON3D_PHOTO_QUALITY_REJECT) ++reject; emit_group(*discovery, plan->groups[group_index], result); } struct rusage usage{}; const bool loaded_usage = getrusage(RUSAGE_SELF, &usage) == 0; const double elapsed = std::chrono::duration(std::chrono::steady_clock::now() - started).count(); std::printf("{\"record\":\"summary\",\"mode\":\"%s\",\"task_id\":%llu," "\"sources\":%zu,\"groups\":%zu,\"good\":%zu,\"suspect\":%zu," "\"reject\":%zu,\"unavailable\":%zu,\"metric_errors\":%zu," "\"discovered_entries\":%zu,\"unsupported_entries\":%zu," "\"metadata_ok\":%zu,\"metadata_errors\":%zu," "\"request_encoded_bytes\":%zu,\"task_memory_estimate_bytes\":%llu," "\"sequence_count\":%u,\"elapsed_seconds\":%.6f,\"peak_rss_kib\":%ld}\n", mode_name(options.mode), static_cast(task_id), discovery->source_count, plan->group_count, good, suspect, reject, unavailable, metric_errors, discovery->summary.discovered_entry_count, discovery->summary.unsupported_entry_count, discovery->summary.metadata_ok_count, discovery->summary.metadata_error_count, encoded_size, static_cast(task_memory_estimate), durable_task.sequence_count, elapsed, loaded_usage ? usage.ru_maxrss : -1L); lardon3d_task_queue_destroy(queue); lardon3d_resource_governor_destroy(governor); lardon3d_project_db_close(database); return loaded_usage ? 0 : 1; }