diff --git a/docs/wasm-runtime-architecture.md b/docs/wasm-runtime-architecture.md index 071c2aa..ac4005e 100644 --- a/docs/wasm-runtime-architecture.md +++ b/docs/wasm-runtime-architecture.md @@ -358,8 +358,9 @@ header free-functions are `inline`. The wasm backend exposes only declarations cold component that exceeds the development epoch window and proves the parent request still renders it. The dependency-invalidation gate also holds parent and child compile locks across a transitive source edit, proves a - warmed request returns the last atomically published result without waiting, - and then proves the new dependency result appears after rebuild completion. + warmed HTTP request returns the last atomically published result without + waiting, while a CLI request waits and returns only the current dependency + result after rebuild completion. - **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/scripts/test_dependency_invalidation.sh b/scripts/test_dependency_invalidation.sh index 70c5088..f49fec0 100755 --- a/scripts/test_dependency_invalidation.sh +++ b/scripts/test_dependency_invalidation.sh @@ -84,14 +84,24 @@ rebuild_lock_pid=$! sleep 0.2 sed -i 's/dependency-marker-b/dependency-marker-d/' "$source_dir/child.uce" started_at=$(date +%s%N) -assert_marker parent dependency-marker-b +http_during_lock=$(http_marker) elapsed_ms=$(( ($(date +%s%N) - started_at) / 1000000 )) +if [[ "$http_during_lock" != *"dependency-marker-b"* ]]; then + echo "HTTP request did not serve the last complete artifact during rebuild: $http_during_lock" >&2 + exit 1 +fi if (( elapsed_ms >= 2000 )); then - echo "request waited ${elapsed_ms}ms for an active transitive rebuild" >&2 + echo "HTTP request waited ${elapsed_ms}ms for an active transitive rebuild" >&2 + exit 1 +fi +started_at=$(date +%s%N) +assert_marker parent dependency-marker-d +elapsed_ms=$(( ($(date +%s%N) - started_at) / 1000000 )) +if (( elapsed_ms < 2000 )); then + echo "CLI request returned before the locked rebuild published the current artifact (${elapsed_ms}ms)" >&2 exit 1 fi wait "$rebuild_lock_pid" -assert_marker parent dependency-marker-d # Warm every configured worker, then replace the artifact while retaining its # whole-second mtime. The worker cache must notice the nanosecond/ctime change. diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp index 441c45c..c7103df 100644 --- a/src/lib/compiler.cpp +++ b/src/lib/compiler.cpp @@ -850,7 +850,8 @@ SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name SharedUnit* su = new SharedUnit(); setup_unit_paths(context, su, file_name); - int fdlock = compiler_open_lock_file(su->wasm_name + ".lock", "shared-unit:" + file_name, !force_recompile); + bool can_serve_stale = !force_recompile && compiler_request_can_serve_stale_artifact(context); + int fdlock = compiler_open_lock_file(su->wasm_name + ".lock", "shared-unit:" + file_name, can_serve_stale); if(fdlock == -2 && file_exists(su->wasm_name)) { auto state = inspect_shared_unit_filesystem(context, su); diff --git a/src/wasm/backend.cpp b/src/wasm/backend.cpp index 3bb6c3d..984bc25 100644 --- a/src/wasm/backend.cpp +++ b/src/wasm/backend.cpp @@ -100,7 +100,7 @@ static bool wasm_artifact_exists(Request* context, const String& entry_unit) // metadata mismatches, which can leave stale wasm with old imports. bool source_missing = false; if(compiler_unit_needs_recompile(context, entry_unit, &source_missing)) - return(compiler_request_can_serve_stale_artifact(context) || compiler_unit_compile_in_progress(context, entry_unit)); + return(compiler_request_can_serve_stale_artifact(context)); if(source_missing) return(false); return(true);