From 8c3f8c5e01d23018ca7cb07d58051b642cdf1d05 Mon Sep 17 00:00:00 2001 From: udo Date: Tue, 14 Jul 2026 21:44:31 +0000 Subject: [PATCH] fix persisted unit failure identity --- docs/wasm-runtime-architecture.md | 4 +++- site/tests/units.uce | 4 +++- src/lib/compiler.cpp | 10 ++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/wasm-runtime-architecture.md b/docs/wasm-runtime-architecture.md index 8bd1722..6f0a723 100644 --- a/docs/wasm-runtime-architecture.md +++ b/docs/wasm-runtime-architecture.md @@ -398,7 +398,9 @@ header free-functions are `inline`. The wasm backend exposes only declarations and the resolved unit path; otherwise nested relative targets resolve from the caller after a repeated parent invocation. Resolved component paths are canonical absolute paths: equivalent spellings containing `.` or `..` must - share one source, compile, artifact, and module-cache identity. + share one source, compile, artifact, and module-cache identity. The compiler + independently enforces the same canonical identity, and persisted failures + are reused only when their recorded source path matches the current request. - **WebSocket end-to-end**: a headless client performs a raw WS handshake to `:HTTP_PORT` with path `/site/tests/websockets.ws.uce` (self-resolving diff --git a/site/tests/units.uce b/site/tests/units.uce index 6aac875..9fd7f50 100644 --- a/site/tests/units.uce +++ b/site/tests/units.uce @@ -17,6 +17,7 @@ RENDER(Request& context) auto unit_paths = units_list(); DValue info = unit_info("call_helpers.uce"); + DValue relative_info = unit_info("components/../relative-child.uce"); ob_start(); unit_call("call_helpers.uce", "emit_marker"); @@ -30,10 +31,11 @@ RENDER(Request& context) check("units_list()", unit_paths.size() > 0, "count=" + std::to_string(unit_paths.size())); check("unit_info()", info["path"].to_string() != "", json_encode(info)); + check("compiler canonicalizes relative unit paths", relative_info["path"].to_string().find("/../") == String::npos && str_ends_with(relative_info["path"].to_string(), "/site/tests/relative-child.uce"), json_encode(relative_info)); check("unit_compile()", unit_compile("call_helpers.uce"), "call_helpers.uce"); check("unit_call()", call_output.find("UNIT_CALL_EXPORT_OK") != String::npos, call_output); check("unit_render()", render_output.find("data-unit-render=\"ok\"") != String::npos, render_output); site_tests_summary(passed, failed, skipped, "The local fixture call_helpers.uce keeps these checks deterministic and self-contained within site/tests."); site_tests_page_end(); -} \ No newline at end of file +} diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp index 3ece28a..12a8ea1 100644 --- a/src/lib/compiler.cpp +++ b/src/lib/compiler.cpp @@ -38,6 +38,7 @@ struct SharedUnitFilesystemState String compile_output_content; String metadata_build_token; String metadata_input_signature; + String metadata_source_path; String current_input_signature; }; @@ -222,6 +223,7 @@ String compiler_unit_metadata_text(Request* context, SharedUnit* su, String inpu return( "format=uce-unit-metadata-v1\n" "unit_abi_version=" + std::to_string(UCE_UNIT_ABI_VERSION) + "\n" + "source_path=" + su->file_name + "\n" "input_signature=" + input_signature + "\n" "build_token=" + compiler_unit_build_token() + "\n" ); @@ -275,6 +277,8 @@ bool compiler_failure_retry_deferred(Request* context, SharedUnit* su, const Sha return(false); if(!state.metadata_exists || !state.metadata_parsed || !state.abi_compatible || !state.input_signature_matches) return(false); + if(state.metadata_source_path == "" || state.metadata_source_path != su->file_name) + return(false); auto required_failure_inputs_time = std::max({ state.source_time, state.setup_template_time, @@ -374,6 +378,9 @@ String compiler_normalize_unit_path(Request* context, String file_name) return(""); if(file_name[0] != '/') file_name = expand_path(file_name, context->server->config["COMPILER_SYS_PATH"]); + String canonical = path_real(file_name); + if(canonical != "") + return(canonical); return(file_name); } @@ -474,6 +481,9 @@ SharedUnitFilesystemState inspect_shared_unit_filesystem(Request* context, Share auto input_it = metadata.find("input_signature"); if(input_it != metadata.end()) state.metadata_input_signature = input_it->second; + auto source_it = metadata.find("source_path"); + if(source_it != metadata.end()) + state.metadata_source_path = source_it->second; auto build_it = metadata.find("build_token"); if(build_it != metadata.end()) state.metadata_build_token = build_it->second;