rnd(M03): introduce renderer facade seam

Work-Package: M03-RND-FACADE-001
Agent: sindo-main-codex
Tests: facade/focus/coordinate/manifest contracts, renderer dry-run, coordination and documentation gates
Fidelity: focus targets, budgets, queues, caches and visible renderer behavior remain unchanged
This commit is contained in:
2026-07-15 23:48:53 +04:00
parent a629bedccf
commit 3d528e3bbf
12 changed files with 335 additions and 37 deletions
+117
View File
@@ -0,0 +1,117 @@
extends SceneTree
## Headless contract and wiring regression for the first M03 renderer facade seam.
const WORLD_RENDER_FACADE_SCRIPT := preload("res://src/render/world_render_facade.gd")
const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd")
const STREAMING_FOCUS_SCRIPT := preload("res://src/domain/streaming/streaming_focus.gd")
const RUNTIME_SCENE_PATHS: Array[String] = [
"res://src/scenes/streaming/eastern_kingdoms_streaming.tscn",
"res://src/scenes/streaming/kalimdor_streaming.tscn",
]
const TOOL_PATHS: Array[String] = [
"res://src/tools/capture_render_checkpoints.gd",
"res://src/tools/probe_render_camera_occluders.gd",
"res://src/tools/probe_render_terrain_height.gd",
]
class StreamingWorldLoaderDouble extends Node:
var current_focus: StreamingFocus
var refresh_count := 0
var metrics := {"tiles": 2, "queues": {"tile": 1}}
func set_streaming_focus(streaming_focus: StreamingFocus) -> void:
current_focus = streaming_focus
func refresh_streaming_focus(_force: bool = false) -> bool:
refresh_count += 1
return current_focus != null
func render_baseline_snapshot() -> Dictionary:
return metrics
func _initialize() -> void:
var failures: Array[String] = []
await _verify_delegation_and_snapshot_isolation(failures)
_verify_repository_wiring(failures)
if not failures.is_empty():
for failure in failures:
push_error("WORLD_RENDER_FACADE: %s" % failure)
quit(1)
return
print("WORLD_RENDER_FACADE PASS delegation=3 runtime_scenes=2 tools=3")
quit(0)
func _verify_delegation_and_snapshot_isolation(failures: Array[String]) -> void:
var test_root := Node.new()
var loader := StreamingWorldLoaderDouble.new()
loader.name = "StreamingWorldLoaderDouble"
var source := Node3D.new()
source.name = "FocusSource"
source.position = Vector3(10.0, 20.0, 30.0)
var facade = WORLD_RENDER_FACADE_SCRIPT.new()
facade.name = "WorldRenderFacade"
facade.streaming_world_loader_path = NodePath("../StreamingWorldLoaderDouble")
facade.streaming_focus_source_path = NodePath("../FocusSource")
test_root.add_child(loader)
test_root.add_child(source)
test_root.add_child(facade)
get_root().add_child(test_root)
await process_frame
_expect_true(loader.current_focus != null, "ready captures explicit source", failures)
if loader.current_focus != null:
_expect_near(loader.current_focus.world_position.x_units, 10.0, "source X", failures)
_expect_near(loader.current_focus.world_position.y_units, 20.0, "source Y", failures)
_expect_near(loader.current_focus.world_position.z_units, 30.0, "source Z", failures)
var typed_focus = STREAMING_FOCUS_SCRIPT.new(GODOT_WORLD_POSITION_SCRIPT.new(40.0, 50.0, 60.0))
facade.streaming_focus_source_path = NodePath()
facade.set_streaming_focus(typed_focus)
_expect_true(facade.refresh_streaming_focus(true), "typed focus refresh delegates", failures)
_expect_true(loader.current_focus == typed_focus, "typed focus reference delegates", failures)
var snapshot: Dictionary = facade.renderer_metrics_snapshot()
snapshot["tiles"] = 999
(snapshot["queues"] as Dictionary)["tile"] = 999
_expect_true(int(loader.metrics.tiles) == 2, "top-level metrics are detached", failures)
_expect_true(int(loader.metrics.queues.tile) == 1, "nested metrics are detached", failures)
test_root.queue_free()
func _verify_repository_wiring(failures: Array[String]) -> void:
for scene_path in RUNTIME_SCENE_PATHS:
var scene_source := _read_text(scene_path, failures)
_expect_true(scene_source.contains('path="res://src/render/world_render_facade.gd"'), "%s loads facade" % scene_path, failures)
_expect_true(scene_source.contains('[node name="WorldRenderFacade" type="Node" parent="."]'), "%s owns facade node" % scene_path, failures)
_expect_true(scene_source.contains('streaming_focus_source_path = NodePath("../ThirdPersonPlayer")'), "%s facade uses player focus" % scene_path, failures)
for tool_path in TOOL_PATHS:
var tool_source := _read_text(tool_path, failures)
_expect_true(tool_source.contains('get_node_or_null("WorldRenderFacade")'), "%s resolves facade" % tool_path, failures)
_expect_true(not tool_source.contains('world.call("refresh_streaming_focus"'), "%s avoids direct streamer refresh" % tool_path, failures)
_expect_true(not tool_source.contains('world.set("streaming_focus_source_path"'), "%s avoids direct streamer focus config" % tool_path, failures)
func _read_text(path: String, failures: Array[String]) -> String:
var file := FileAccess.open(path, FileAccess.READ)
if file == null:
failures.append("cannot open %s" % path)
return ""
return file.get_as_text()
func _expect_near(actual_value: float, expected_value: float, label: String, failures: Array[String]) -> void:
if not is_equal_approx(actual_value, expected_value):
failures.append("%s expected %.3f, got %.3f" % [label, expected_value, actual_value])
func _expect_true(actual_value: bool, label: String, failures: Array[String]) -> void:
if not actual_value:
failures.append("%s expected true" % label)