planner: four-strate owner plan spawns (L66); pinned 2-strate regression fixture

- Core caps each passage mouth reach to its own strate's usable content band (owner
  DA_Strate1 exports ReachMax=5000 owner voxels, which put the SW->FI lower mouth 79.5 m
  below FI, inside TN).
- Unreal adapter: SW route search keeps the old 64 m candidates first, then a bounded
  single-mouth search with shorter lengths; logs candidate/rejection counts.
- Internal-chain passage floor/support tweaks (only with >2 strates): ripple 1-2 4.78->2.90 cm,
  2-3 3.57->0.10 cm. Interfaces still 0/3 walkable (59/3/2 unsupported).
- verify.py: legacy tiers use Standalone/data/regression/owner_world_2strate_l61.json; new
  four-strate stage reads its expectations from owner_world.json (currently red on interfaces).
- Unreal trace L14 vs HEAD, same assets (16-chunk FlatPlain): 12.20 vs 12.56 worker-s; no x2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-26 22:13:22 +01:00
1 parent 47148e0a0d
commit 5e2fc53d39
17 files changed
+745 -73

No files matched your search

+3 -3
View File
@@ -10,10 +10,10 @@ taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s python3 -B Standalone/T
taskset -c 0-11 prlimit --as=6442450944 -- timeout 1740s python3 -B Standalone/Tools/verify/verify.py full
```
`fast` checks only canonical `Standalone/data/owner_world.json`, asserts FI Style 2 and SW Style 1 from resolved snapshots, runs passage wall/floor ripple and coverage gates, the adjacent-profile step limit, W1/W12 hash comparisons, and LOD0 ring profiles with the L30/L31 controls. It also exercises stale-source, style-mislabel, black-capture, historical ripple, and L38 step controls.
`fast` runs legacy owner regressions against the pinned two-strate fixture at `Standalone/data/regression/owner_world_2strate_l61.json`, including resolved styles, passage wall/floor ripple and coverage gates, adjacent-profile step, W1/W12 hashes, and LOD0 ring profiles with the L30/L31 controls. It also checks the live four-strate `Standalone/data/owner_world.json`: generator and resolved-style maps are read from that export, then strict layout, transitions, per-strate deterministic generation, arrival-to-departure routes, and spawn costs are audited. The tier also exercises stale-source, style-mislabel, black-capture, historical ripple, and L38 step controls.
`medium` adds the Clang style-override matrix, transitions, route/proof audits, LOD0–8 rings, and canonical-owner captures, shape, near/overview crease, and fragment checks. Run `medium` before `full`. Full reuses that evidence only when the source stamp, verification-tool hashes, binaries, inputs, logs, and audit-script hashes still match; otherwise it reruns the Clang medium work. It adds the owner/style/transition/proof matrix with GCC, the 30-cell determinism matrix, and five interleaved L36/L39 cost pairs per recipe. The final captures stay in the L39 output directory.
`medium` adds the Clang style-override matrix, transitions, route/proof audits, LOD0–8 rings, and pinned two-strate owner captures, shape, near/overview crease, and fragment checks. Run `medium` before `full`. Full reuses that evidence only when the source stamp, verification-tool hashes, binaries, inputs, logs, and audit-script hashes still match; otherwise it reruns the Clang medium work. It adds the owner/style/transition/proof matrix with GCC, the 30-cell determinism matrix, and five interleaved L36/L39 cost pairs per recipe. The final captures stay in the L39 output directory.
`BuildLinux.sh` hashes a sorted manifest of Core inputs, standalone sources and generated wrappers, build files, and optionally the Unreal adapter when `VOXELFORGE_INCLUDE_UNREAL_ADAPTER=1`. The manifest hash is compiled into the headless and offscreen binaries and printed before any other runtime log line. Each tier probes every available built executable at startup and re-probes it at completion, rejecting stale stamps or binary changes. Summaries store tool hashes, binary and JSON SHA-256 values, resolved recipe/style/layout identity, commands, elapsed time, and audit-script hashes.
Each tier stops at its first failed gate. Every process is limited to CPUs 0–11 and 6 GiB of address space; individual build and audit processes time out at 30 minutes. Summary files are `fast-summary.json`, `medium-summary.json`, and `full-summary.json`.
Medium and full stop at their first failed gate. Fast defers a four-strate stage failure until after it has collected the pinned two-strate regression evidence. Every process is limited to CPUs 0–11 and 6 GiB of address space; individual build and audit processes time out at 30 minutes. Summary files are `fast-summary.json`, `medium-summary.json`, and `full-summary.json`.
+249 -8
View File
@@ -29,7 +29,9 @@ LINUX54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54"
LINUX56 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux56"
LINUX58 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux58"
LINUX60 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux60"
OWNER = ROOT / "Standalone/data/owner_world.json"
OWNER = ROOT / "Standalone/data/regression/owner_world_2strate_l61.json"
OWNER_NEW = ROOT / "Standalone/data/owner_world.json"
OWNER_2STRATE_SHA256 = "7b095f9bcc6b90133d5a463f99f0b571133b2c549ce1ecf2d64fe9175e41e183"
OUT_DEFAULT = ROOT / "Saved/Linux/l42"
PARSER = argparse.ArgumentParser(description=__doc__)
@@ -75,6 +77,10 @@ PROFILE_CAMERA_SWEEP_SEED = 0x4C3533
CAVES_CAMERA_SWEEP_SEED = 0x4C3534
LATTICE_CAMERA_SWEEP_SEED = 0x4C3538
PROFILE_NAMES = ("periodicHills", "mirroredRelief", "flatField")
GENERATOR_TYPE_NAMES = {
0: "TunnelNetwork", 1: "FlatPlain", 2: "CrystalChamber", 3: "Maze",
4: "SurfaceWorld", 5: "VerticalShafts", 6: "FloatingIslands", 7: "Underwater",
}
SPEED_MATRIX_REPETITIONS = 5
SPEED_MATRIX_TILE_RANGE = (1800, 2500)
SPEED_MATRIX_LOD_TILE_RANGES = (
@@ -82,6 +88,14 @@ SPEED_MATRIX_LOD_TILE_RANGES = (
(60, 220), (48, 180), (24, 160), (16, 100),
)
SPEED_MATRIX_CAMERA_M = (-12.0, -118.0, -20.0, 0.0, 0.0)
def sha256_file(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as source:
for block in iter(lambda: source.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
RECIPE_RE = re.compile(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", re.M)
@@ -93,6 +107,7 @@ def compiler_name(binary: Path) -> str:
def env_for(*, capture: bool = False) -> dict[str, str]:
result = os.environ.copy()
result["VOXELFORGE_VERIFY_OUT"] = str(OUT)
result["VOXELFORGE_OWNER_DATA"] = str(OWNER)
result["VOXELFORGE_L37_OUT"] = str(OUT)
result["VOXELFORGE_L37_CAPTURE_DIR"] = str(OUT / "captures")
result["VOXELFORGE_L37_HEADLESS"] = str(CLANG)
@@ -113,7 +128,16 @@ def parse_ratio(text: str, name: str) -> float | None:
return int(match.group(1)) / max(1, int(match.group(2))) if match else None
def validate_passage(runner: VerificationRunner, name: str, output: str) -> None:
def defer_requirement(runner: VerificationRunner, name: str, passed: bool,
detail: str = "") -> bool:
runner.steps.append({"name": name, "status": "PASS" if passed else "FAIL",
"detail": detail})
print(f"[{runner.tier}] {name} {'PASS' if passed else 'FAIL'} {detail}", flush=True)
return passed
def validate_passage(runner: VerificationRunner, name: str, output: str,
*, defer: bool = False) -> bool:
required = (
("strict-layout", r"^\[ResolvedLayoutStrict\] accepted=true issues=0 error=$"),
("layout-controls", r"^\[ResolvedLayoutValidatorControls\].*status=PASS$"),
@@ -128,9 +152,15 @@ def validate_passage(runner: VerificationRunner, name: str, output: str) -> None
("ripple-controls", r"^\[PassageRippleAuditSummary\].*status=PASS$"),
("passage-summary", r"^\[ResolvedPassageAuditSummary\].*route_binding_failures=0 .*status=PASS$"),
)
passed_all = True
for gate, pattern in required:
runner.require(f"{name}:{gate}", all_match(output, pattern),
"required resolved-passage gate")
passed = all_match(output, pattern)
passed_all &= passed
if defer:
defer_requirement(runner, f"{name}:{gate}", passed,
"required resolved-passage gate")
else:
runner.require(f"{name}:{gate}", passed, "required resolved-passage gate")
rows = re.findall(r"^\[PassageRippleAudit\].*$", output, re.M)
ripple_ok = bool(rows)
@@ -149,8 +179,13 @@ def validate_passage(runner: VerificationRunner, name: str, output: str) -> None
and float(wall.group(1)) <= float(wall_threshold.group(1))
and float(floor.group(1)) <= float(floor_threshold.group(1))
and wall_coverage >= 0.75 and floor_coverage >= 0.75)
runner.require(f"{name}:wall-floor-ripple-and-coverage", ripple_ok,
f"profiles={len(rows)} wall/floor amplitudes under their thresholds; coverage>=0.75")
passed_all &= ripple_ok
detail = f"profiles={len(rows)} wall/floor amplitudes under their thresholds; coverage>=0.75"
if defer:
defer_requirement(runner, f"{name}:wall-floor-ripple-and-coverage", ripple_ok, detail)
else:
runner.require(f"{name}:wall-floor-ripple-and-coverage", ripple_ok, detail)
return passed_all
def run_passage(runner: VerificationRunner, binary: Path, name: str,
@@ -200,6 +235,198 @@ def run_owner_passages(runner: VerificationRunner, binaries: tuple[Path, ...]) -
return result
def owner_plan_expectations(data_path: Path) -> tuple[dict[str, str], dict[str, int]]:
document = json.loads(data_path.read_text(encoding="utf-8"))
rows = document.get("strates", [])
if not rows:
raise VerificationFailure(f"new owner plan has no strate records: {data_path}")
generators: dict[str, str] = {}
styles: dict[str, int] = {}
for row in rows:
index = str(int(row["index"]))
generator_id = int(row["asset"]["GeneratorType"])
if generator_id not in GENERATOR_TYPE_NAMES:
raise VerificationFailure(
f"new owner plan has unknown GeneratorType={generator_id} at strate {index}")
generators[index] = GENERATOR_TYPE_NAMES[generator_id]
styles[index] = int(row["passage_config"]["Style"])
fixed = {str(int(entry["key"])) for entry in
document.get("settings_asset", {}).get("FixedStrates", [])}
if fixed != set(generators):
raise VerificationFailure(
f"new owner FixedStrates keys differ from its strate records: {fixed} != {set(generators)}")
return generators, styles
def run_new_owner_plan_stage(runner: VerificationRunner, binary: Path) -> None:
"""Audit, generate, and compare the current owner export without legacy expectations."""
deferred_start = len(runner.steps)
expected_generators, expected_styles = owner_plan_expectations(OWNER_NEW)
if len(expected_generators) != 4:
raise VerificationFailure(
f"new owner plan should contain four strata, found {len(expected_generators)}")
document = json.loads(OWNER_NEW.read_text(encoding="utf-8"))
ordered_strates = sorted(document["strates"],
key=lambda row: int(row.get("top_chunk_z", 0)), reverse=True)
upper_styles = {expected_styles[str(int(row["index"]))]
for row in ordered_strates[:-1]}
unique_styles = upper_styles
expected_passage_style = next(iter(unique_styles)) if len(unique_styles) == 1 else None
compiler = compiler_name(binary)
layout_path = OUT / "layouts" / f"owner-new-plan-{compiler}-w1.json"
core_voxel_metres = float(document.get("voxel_size_cm", 25.0)) / 100.0
viewer = document.get("viewer_start", {})
camera_by_index: dict[str, tuple[float, float, float]] = {}
for row in document["strates"]:
index = str(int(row["index"]))
camera_by_index[index] = (
float(viewer.get("x", 0.0)) * core_voxel_metres,
float(viewer.get("y", 0.0)) * core_voxel_metres,
float(viewer.get("z", 0.0)) * core_voxel_metres,
)
def camera_flag(position: tuple[float, float, float]) -> str:
return "--camera=" + ",".join(f"{value:.6f}" for value in (*position, 0.0, 0.0))
common_flags = ["--stream-hash", "--max-clip-level=0",
"--render-distance-chunks=0"]
stride_indices = sorted(expected_generators, key=int)
audit_row, audit_output = runner.run_cpp(
f"owner-new-plan-{compiler}-w1", binary, OWNER_NEW, "surface-world",
[*common_flags, "--audit-resolved-layout-passages",
camera_flag(camera_by_index[stride_indices[0]])],
expected_style=expected_passage_style, expected_strate_styles=expected_styles,
workers=1, max_level=0, clip_radius=1, layout_path=layout_path,
allow_nonzero=True)
validate_passage(runner, f"owner-new-plan-{compiler}-w1", audit_output, defer=True)
actual_generators = audit_row.get("layout", {}).get("strata", {})
defer_requirement(runner, f"owner-new-plan-{compiler}:generator-map",
actual_generators == expected_generators,
f"resolved={actual_generators} expected_from_owner_export={expected_generators}")
audit_layout = json.loads(layout_path.read_text(encoding="utf-8"))
actual_styles = {str(index): int(value) for index, value in
audit_layout.get("resolved_strate_passage_styles", {}).items()}
defer_requirement(runner, f"owner-new-plan-{compiler}:style-map",
actual_styles == expected_styles,
f"resolved={actual_styles} expected_from_owner_export={expected_styles}")
interface_rows = re.findall(r"^\[ResolvedPassageAudit\].*$", audit_output, re.M)
chain_passed = (
len(interface_rows) == max(0, len(expected_generators) - 1)
and all("walkability=PASS" in line and "mouth_content=2/2" in line
and "mouth_radius=2/2" in line for line in interface_rows))
defer_requirement(runner, f"owner-new-plan-{compiler}:arrival-departure-chain",
chain_passed,
f"interfaces={len(interface_rows)}/{max(0, len(expected_generators) - 1)} all_walkable=true")
interface_by_pair: dict[tuple[int, int], str] = {}
for line in interface_rows:
match = re.search(r"interface=(\d+)-(\d+)", line)
if match:
interface_by_pair[(int(match.group(1)), int(match.group(2)))] = line
for index in sorted(expected_generators, key=int):
strate = int(index)
incident_pairs = []
if strate > 0:
incident_pairs.append((strate - 1, strate))
if strate + 1 < len(expected_generators):
incident_pairs.append((strate, strate + 1))
walkable = bool(incident_pairs) and all(
pair in interface_by_pair
and "walkability=PASS" in interface_by_pair[pair]
and "mouth_content=2/2" in interface_by_pair[pair]
and "mouth_radius=2/2" in interface_by_pair[pair]
for pair in incident_pairs)
defer_requirement(runner,
f"owner-new-plan-{compiler}:strate{strate}:arrival-departure-walkable",
walkable, f"adjacent_interfaces={incident_pairs}")
transition_name = f"owner-new-plan-transition-{compiler}"
transition_row, transition_output = runner.run_cpp(
transition_name, binary, OWNER_NEW, "surface-world",
["--max-clip-level=0", "--render-distance-chunks=0",
camera_flag(camera_by_index[stride_indices[0]]),
"--audit-strate-transitions"],
expected_style=expected_passage_style, expected_strate_styles=expected_styles,
workers=1, max_level=0, clip_radius=1,
layout_path=OUT / "layouts" / f"{transition_name}.json",
allow_nonzero=True)
transition_generators = transition_row.get("layout", {}).get("strata", {})
defer_requirement(runner, f"owner-new-plan-{compiler}:transition-generator-map",
transition_generators == expected_generators,
f"resolved={transition_generators} expected={expected_generators}")
transition_rows = re.findall(r"^\[StrateTransitionInterface\].*$", transition_output, re.M)
transition_passed = (
len(transition_rows) == max(0, len(expected_generators) - 1)
and all("status=PASS" in line for line in transition_rows))
defer_requirement(runner, f"owner-new-plan-{compiler}:transition-audit",
transition_passed, f"transition_rows={len(transition_rows)}")
passage_cameras: dict[str, tuple[float, float, float]] = {}
for passage in audit_layout.get("passages", []):
upper = str(int(passage["upper_strate_index"]))
lower = str(int(passage["lower_strate_index"]))
scale = float(audit_layout["core_voxel_size_um"]) / 256_000_000.0
upper_q = passage["upper_mouth_q"]
lower_q = passage["lower_mouth_q"]
passage_cameras.setdefault(upper, tuple(float(value) * scale for value in upper_q))
passage_cameras[lower] = tuple(float(value) * scale for value in lower_q)
for index in stride_indices:
if index in passage_cameras:
camera_by_index[index] = passage_cameras[index]
hashes_by_strate: dict[str, tuple[str, ...]] = {index: tuple() for index in stride_indices}
spawn_rows: list[dict[str, object]] = []
for index in stride_indices:
outputs: dict[int, str] = {}
for workers in (1, 8):
run_name = f"owner-new-plan-{compiler}-strate{index}-w{workers}"
row, output = runner.run_cpp(run_name, binary, OWNER_NEW, "surface-world",
[*common_flags, camera_flag(camera_by_index[index])],
expected_style=expected_passage_style,
expected_strate_styles=expected_styles,
workers=workers, max_level=0, clip_radius=1,
layout_path=OUT / "layouts" / f"{run_name}.json")
generators = row.get("layout", {}).get("strata", {})
defer_requirement(runner, f"{run_name}:generator-map",
generators == expected_generators,
f"resolved={generators} expected={expected_generators}")
hashes = tuple(HASH_RE.findall(output))
outputs[workers] = output
if workers == 1:
hashes_by_strate[index] = hashes
pipeline = re.search(
r"^\[StreamPipeline\].*?first_tile_ready=([0-9.]+)s .*?"
r"neighborhood_ready=([0-9.]+)s .*?whole_view_ready=([0-9.]+)s .*?"
r"whole_tiles=(\d+)/(\d+)", output, re.M)
worker_times = [float(value) for value in re.findall(
r"^\[WorldAssemblerLODWorker\].*?worker_sum_s=([0-9.]+)", output, re.M)]
generated = bool(pipeline) and int(pipeline.group(4)) > 0 and bool(hashes)
defer_requirement(runner,
f"owner-new-plan-{compiler}:strate{index}:generated",
generated,
f"tiles={pipeline.group(4) if pipeline else 0} hashes={len(hashes)}")
spawn_rows.append({
"strate": index,
"generator": expected_generators[index],
"tiles": int(pipeline.group(4)) if pipeline else 0,
"first_tile_s": float(pipeline.group(1)) if pipeline else None,
"neighborhood_ready_s": float(pipeline.group(2)) if pipeline else None,
"whole_view_s": float(pipeline.group(3)) if pipeline else None,
"worker_s": sum(worker_times),
})
worker_hashes = tuple(HASH_RE.findall(outputs[8]))
stable = bool(hashes_by_strate[index]) and hashes_by_strate[index] == worker_hashes
defer_requirement(runner,
f"owner-new-plan-{compiler}:strate{index}:deterministic-w1-w8",
stable,
f"w1_hashes={len(hashes_by_strate[index])} w8_hashes={len(worker_hashes)} stable={stable}")
audit_row["owner_plan_spawn_costs"] = spawn_rows
deferred_failures = [step["name"] for step in runner.steps[deferred_start:]
if step["status"] == "FAIL"]
if deferred_failures:
raise VerificationFailure(
"new owner plan audits failed after per-strata runs: "
+ ", ".join(deferred_failures))
def run_landmark_reachability(runner: VerificationRunner,
binaries: tuple[Path, ...]) -> None:
for binary in binaries:
@@ -1682,7 +1909,7 @@ def build_motif_fixture(runner: VerificationRunner) -> Path:
runner.run_stage("build-style-override-motifs-slice1-r24", script,
["--out", str(fixture_dir)], binary=CLANG, data=OWNER,
recipe="surface-world", style=None,
script_inputs=[OWNER])
env=env_for(), script_inputs=[OWNER])
fixture = fixture_dir / "style-override-motifs-slice1.json"
runner.require("motif-fixture:exists", fixture.is_file(),
"versioned flatField and two fixed-count sparse motifs are present")
@@ -2494,6 +2721,7 @@ def run_speed_matrix(runner: VerificationRunner) -> None:
def run_medium_suite(runner: VerificationRunner, *, both_compilers: bool = False) -> None:
binaries = (CLANG, GCC) if both_compilers else (CLANG,)
run_owner_passages(runner, binaries)
run_new_owner_plan_stage(runner, CLANG)
run_default_profile_identity(runner, CLANG)
run_landmark_reachability(runner, binaries)
run_regression_controls(runner)
@@ -2813,7 +3041,12 @@ def main() -> int:
signal.setitimer(signal.ITIMER_REAL, ARGS.overall_timeout)
try:
if not OWNER.is_file():
raise VerificationFailure(f"canonical owner input is missing: {OWNER}")
raise VerificationFailure(f"pinned two-strate owner input is missing: {OWNER}")
if sha256_file(OWNER) != OWNER_2STRATE_SHA256:
raise VerificationFailure(
f"pinned two-strate owner fixture changed: {OWNER}")
if not OWNER_NEW.is_file():
raise VerificationFailure(f"current four-strate owner input is missing: {OWNER_NEW}")
for binary in (CLANG, GCC, RENDERER):
if binary.is_file():
runner.probe_binary(binary)
@@ -2821,6 +3054,12 @@ def main() -> int:
run_sanitizer_stage(runner)
elif ARGS.tier == "fast":
owners = run_owner_passages(runner, (CLANG,))
new_plan_failure = None
try:
run_new_owner_plan_stage(runner, CLANG)
except VerificationFailure as error:
new_plan_failure = str(error)
print(f"[{runner.tier}] new-owner-plan-stage FAIL {error}", flush=True)
run_landmark_reachability(runner, (CLANG,))
run_regression_controls(runner)
run_hash_pairs(runner, owners)
@@ -2831,6 +3070,8 @@ def main() -> int:
run_native_caves_field_audit(runner, CLANG)
run_native_lattice_field_audit(runner, CLANG)
run_motif_fixture_audits(runner, CLANG)
if new_plan_failure is not None:
runner.require("new-owner-plan-stage", False, new_plan_failure)
elif ARGS.tier == "medium":
run_medium_suite(runner, both_compilers=False)
else: