feat(composer): Tier 4c -- a season that can actually ship, with a veto page
The composer could invent, measure and show strates. What did not exist was an ARTEFACT a season could ship. Now it does. VF_ComposeSeason: generate N candidates -> measure -> reject failures -> select a descent sequence -> emit a JSON manifest + a review page. ⭐ THE PROPERTY THAT MATTERS: round-trip bit-identity. The manifest was loaded, every selected stack rebuilt, and 393,216 density samples compared BIT-IDENTICALLY. Re-composing the same seed yields byte-identical JSON. A manifest that cannot reproduce its own world is worthless, and that is the one thing that could not be assumed. Floats serialise as readable values PLUS exact IEEE bits, so a season survives a text round trip. Test season: 24 generated, 19 survived the hard gates, 6 selected. 18 not selected -- 4 vacuous, 1 primordial-law failure, 13 policy non-selections. 4 grounded, 2 outliers. EVERY selected slot passes the primordial law, asserted per slot rather than sampled. Selection policy is explicit, named and PROVISIONAL, because Jahni has not defined "good" yet and said so: "it'll be easier once i'm able to see the strates candidates." So no quality score was invented and presented as settled. The knobs are 75/25 grounded-to-outlier (outlier axis = distance from corpus centroid), adjacent-similarity threshold .20 with penalty 1.0, new-archetype bonus .10, new-recipe bonus .05, boss cadence every 5th non-terminal slot. All of them are his to turn. The veto is a review page in DESCENT ORDER -- the season read top to bottom the way it is played, not the survivor/outlier ordering the candidate sheet uses. Reuses VoxelStratePreview rather than a second renderer. Saved/VoxelForge/SeasonTest/season_0000_seed_9320/season_manifest.json .../review/index.html ⚠️ FIVE GAPS CODEX RAISED, recorded not buried: 1. §4's Tier A is strates PLUS passages; only the strate spine is persisted. Manager-generated passage geometry and content placement are not. 2. Authored fixed strates keep scalar vectors + asset paths, not every asset-level passage/biome/disturbance/content field. 3. Boss slots are MARKERS, not arena or content guarantees. 4. WorldRadiusVoxels == 0 is enforced as specced but contradicts a production bounded world -- Jahni's call, still unset by design. 5. Bit identity is proven for the same build and platform. A frozen season spanning engine versions needs an explicit schema contract. Real risk, since seasons freeze generation for months. Build clean, 28 succeeded / 0 failed, verified by me. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJiTcTSDNkKBtnNdiBtdaU
This commit is contained in:
1 parent
0b3ec18b43
commit
42e1f0ec8c
8 files changed
+3351
-5
No files matched your search
@@ -0,0 +1,208 @@
|
||||
// Tier 4c — offline season composition, manifest determinism, and exact rebuild.
|
||||
|
||||
#if WITH_DEV_AUTOMATION_TESTS && WITH_EDITOR
|
||||
|
||||
#include "Misc/AutomationTest.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/Paths.h"
|
||||
|
||||
#include "VoxelDensityOpStack.h"
|
||||
#include "VoxelSeasonManifest.h"
|
||||
#include "VoxelStrateComposer.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool SameDensityBits(float A, float B)
|
||||
{
|
||||
return FMemory::Memcmp(&A, &B, sizeof(float)) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FVoxelForgeComposerSeasonTest,
|
||||
"VoxelForge.Composer.Season",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
||||
|
||||
bool FVoxelForgeComposerSeasonTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
(void)Parameters;
|
||||
|
||||
FVoxelStrateCorpus Corpus;
|
||||
FString CorpusReport;
|
||||
TestTrue(TEXT("season test loads a valid corpus"),
|
||||
Corpus.LoadFromAssetRegistry(CorpusReport) && Corpus.IsValid());
|
||||
if (!Corpus.IsValid())
|
||||
{
|
||||
AddError(CorpusReport);
|
||||
return false;
|
||||
}
|
||||
|
||||
FVoxelSeasonCompositionSettings Settings;
|
||||
Settings.Corpus = &Corpus;
|
||||
Settings.CandidateCount = 24;
|
||||
Settings.SelectedStrateCount = 6;
|
||||
Settings.StrateHeightInChunks = 4;
|
||||
Settings.InterStrateGapChunks = 0;
|
||||
Settings.OriginSpineRadius = 14.0f;
|
||||
Settings.WorldRadiusVoxels = 0.0f;
|
||||
Settings.OutputDirectory = FPaths::Combine(
|
||||
FPaths::ProjectSavedDir(), TEXT("VoxelForge"), TEXT("SeasonTest"));
|
||||
Settings.bWriteArtifacts = true;
|
||||
Settings.bWriteReviewPage = true;
|
||||
Settings.bIncludeCandidateAudit = true;
|
||||
|
||||
const int32 SeasonSeed = 0x2468;
|
||||
const FVoxelSeasonManifest Manifest = VF_ComposeSeason(SeasonSeed, Settings);
|
||||
TestTrue(TEXT("composition produces a usable season manifest"), Manifest.IsUsable());
|
||||
if (!Manifest.IsUsable())
|
||||
{
|
||||
AddError(Manifest.Error);
|
||||
return false;
|
||||
}
|
||||
TestEqual(TEXT("candidate count is the configured number of attempts"),
|
||||
Manifest.CandidateCount, Settings.CandidateCount);
|
||||
TestEqual(TEXT("selected count is the configured spine length"),
|
||||
Manifest.SelectedCount, Settings.SelectedStrateCount);
|
||||
TestEqual(TEXT("candidate audit contains every attempt"),
|
||||
Manifest.CandidateAudit.Num(), Settings.CandidateCount);
|
||||
TestEqual(TEXT("WorldRadiusVoxels remains zero in the artifact"),
|
||||
Manifest.WorldRadiusVoxels, 0.0f);
|
||||
TestEqual(TEXT("selected grounded/outlier counts add to generated slots"),
|
||||
Manifest.GroundedSelectedCount + Manifest.OutlierSelectedCount,
|
||||
Manifest.SelectedCount - Manifest.FixedSelectedCount);
|
||||
|
||||
for (int32 Index = 0; Index < Manifest.Strates.Num(); ++Index)
|
||||
{
|
||||
const FVoxelSeasonStrate& Strate = Manifest.Strates[Index];
|
||||
TestEqual(FString::Printf(TEXT("slot %d keeps descent order"), Index),
|
||||
Strate.DepthIndex, Index);
|
||||
TestTrue(FString::Printf(TEXT("slot %d passed non-vacuous gate"), Index),
|
||||
Strate.bPassedNonVacuous);
|
||||
TestTrue(FString::Printf(TEXT("slot %d passed largest-component gate"), Index),
|
||||
Strate.bPassedLargestComponent);
|
||||
TestTrue(FString::Printf(TEXT("slot %d passed primordial law"), Index),
|
||||
Strate.bPassedPrimordialLaw
|
||||
&& Strate.PrimordialLawResult == EVoxelConnectivityResult::Connected);
|
||||
TestTrue(FString::Printf(TEXT("slot %d has zero world radius"), Index),
|
||||
Manifest.WorldRadiusVoxels == 0.0f);
|
||||
}
|
||||
|
||||
TestTrue(TEXT("season manifest JSON was emitted"), !Manifest.SerializedJson.IsEmpty());
|
||||
TestTrue(TEXT("season manifest file was emitted"), FPaths::FileExists(Manifest.ManifestPath));
|
||||
TestTrue(TEXT("selected-season review page was emitted"),
|
||||
FPaths::FileExists(Manifest.ReviewPagePath));
|
||||
FString ReviewHtml;
|
||||
if (FFileHelper::LoadFileToString(ReviewHtml, *Manifest.ReviewPagePath))
|
||||
{
|
||||
TestTrue(TEXT("review page explains why each selected slot was chosen"),
|
||||
ReviewHtml.Contains(TEXT("Why selected:")));
|
||||
TestTrue(TEXT("review page marks boss slots"), ReviewHtml.Contains(TEXT("Boss slot:")));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddError(FString::Printf(TEXT("could not read review page %s"), *Manifest.ReviewPagePath));
|
||||
}
|
||||
|
||||
// Compose again with the same inputs. SerializedJson excludes derived filesystem paths, so
|
||||
// this is the byte-level determinism assertion for the portable artifact itself.
|
||||
const FVoxelSeasonManifest RepeatManifest = VF_ComposeSeason(SeasonSeed, Settings);
|
||||
TestTrue(TEXT("repeat composition is usable"), RepeatManifest.IsUsable());
|
||||
TestEqual(TEXT("same season seed produces byte-identical JSON"),
|
||||
RepeatManifest.SerializedJson, Manifest.SerializedJson);
|
||||
|
||||
FVoxelSeasonManifest LoadedManifest;
|
||||
FString LoadReport;
|
||||
TestTrue(TEXT("manifest loads from its JSON file"),
|
||||
VF_LoadVoxelSeasonManifest(Manifest.ManifestPath, LoadedManifest, LoadReport));
|
||||
if (!LoadedManifest.IsUsable())
|
||||
{
|
||||
AddError(LoadReport);
|
||||
return false;
|
||||
}
|
||||
TestEqual(TEXT("loaded manifest has the same number of selected strates"),
|
||||
LoadedManifest.Strates.Num(), Manifest.Strates.Num());
|
||||
|
||||
int64 ComparedDensitySamples = 0;
|
||||
bool bAllDensityBitsIdentical = true;
|
||||
for (int32 Index = 0; Index < Manifest.Strates.Num(); ++Index)
|
||||
{
|
||||
const FVoxelSeasonStrate& OriginalStrate = Manifest.Strates[Index];
|
||||
const FVoxelSeasonStrate& LoadedStrate = LoadedManifest.Strates[Index];
|
||||
TestTrue(FString::Printf(TEXT("slot %d parameter vector survives JSON bit-identically"), Index),
|
||||
VF_AreStrateArchetypeParamsBitIdentical(
|
||||
OriginalStrate.Params, LoadedStrate.Params, OriginalStrate.Archetype));
|
||||
TestTrue(FString::Printf(TEXT("slot %d recipe survives JSON identically"), Index),
|
||||
VF_AreStrateStructureRecipesIdentical(
|
||||
OriginalStrate.Recipe, LoadedStrate.Recipe));
|
||||
|
||||
FVoxelOpStack OriginalStack;
|
||||
FVoxelOpContext OriginalContext;
|
||||
FVoxelOpStack LoadedStack;
|
||||
FVoxelOpContext LoadedContext;
|
||||
FString BuildError;
|
||||
TestTrue(FString::Printf(TEXT("slot %d original stack rebuilds"), Index),
|
||||
VF_RebuildVoxelSeasonStrate(
|
||||
OriginalStrate, Manifest.OriginSpineRadius, nullptr,
|
||||
OriginalStack, OriginalContext, &BuildError));
|
||||
TestTrue(FString::Printf(TEXT("slot %d loaded stack rebuilds"), Index),
|
||||
VF_RebuildVoxelSeasonStrate(
|
||||
LoadedStrate, LoadedManifest.OriginSpineRadius, nullptr,
|
||||
LoadedStack, LoadedContext, &BuildError));
|
||||
if (OriginalStack.Num() == 0 || LoadedStack.Num() == 0)
|
||||
{
|
||||
bAllDensityBitsIdentical = false;
|
||||
continue;
|
||||
}
|
||||
TestEqual(FString::Printf(TEXT("slot %d original/rebuilt stack operation count"), Index),
|
||||
LoadedStack.Num(), OriginalStack.Num());
|
||||
TestEqual(FString::Printf(TEXT("slot %d original context radius"), Index),
|
||||
OriginalContext.WorldRadiusVoxels, 0.0f);
|
||||
TestEqual(FString::Printf(TEXT("slot %d loaded context radius"), Index),
|
||||
LoadedContext.WorldRadiusVoxels, 0.0f);
|
||||
OriginalStack.PrepareChunk(OriginalContext);
|
||||
LoadedStack.PrepareChunk(LoadedContext);
|
||||
|
||||
// Compare the complete bounded probe lattice for each selected field at two-voxel
|
||||
// spacing, not a handful of favorable points. Every sampled scalar must retain its
|
||||
// exact IEEE-754 bits after JSON load and stack reconstruction.
|
||||
constexpr int32 ProbeHalfExtent = 32;
|
||||
constexpr int32 ProbeStep = 2;
|
||||
for (int32 Z = OriginalStrate.BottomWorldZ;
|
||||
Z < OriginalStrate.TopWorldZ && bAllDensityBitsIdentical;
|
||||
Z += ProbeStep)
|
||||
{
|
||||
for (int32 Y = -ProbeHalfExtent;
|
||||
Y < ProbeHalfExtent && bAllDensityBitsIdentical;
|
||||
Y += ProbeStep)
|
||||
{
|
||||
for (int32 X = -ProbeHalfExtent;
|
||||
X < ProbeHalfExtent;
|
||||
X += ProbeStep)
|
||||
{
|
||||
const float OriginalDensity = OriginalStack.EvalMC(
|
||||
static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z));
|
||||
const float LoadedDensity = LoadedStack.EvalMC(
|
||||
static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z));
|
||||
++ComparedDensitySamples;
|
||||
if (!SameDensityBits(OriginalDensity, LoadedDensity))
|
||||
{
|
||||
bAllDensityBitsIdentical = false;
|
||||
AddError(FString::Printf(
|
||||
TEXT("slot %d density mismatch at (%d,%d,%d): 0x%08x vs 0x%08x"),
|
||||
Index, X, Y, Z,
|
||||
*reinterpret_cast<const uint32*>(&OriginalDensity),
|
||||
*reinterpret_cast<const uint32*>(&LoadedDensity)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AddInfo(FString::Printf(TEXT("round-trip density probe compared %lld bit-identical samples"),
|
||||
ComparedDensitySamples));
|
||||
TestTrue(TEXT("manifest round-trip density field is bit-identical"),
|
||||
bAllDensityBitsIdentical);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -979,6 +979,18 @@ bool VF_WriteStratePreviewIndex(
|
||||
SortedCandidates.Sort([](const FVoxelStratePreviewCandidate& A,
|
||||
const FVoxelStratePreviewCandidate& B)
|
||||
{
|
||||
if (A.bSeasonOrder != B.bSeasonOrder)
|
||||
{
|
||||
return A.bSeasonOrder;
|
||||
}
|
||||
if (A.bSeasonOrder && B.bSeasonOrder)
|
||||
{
|
||||
if (A.DepthIndex != B.DepthIndex)
|
||||
{
|
||||
return A.DepthIndex < B.DepthIndex;
|
||||
}
|
||||
return A.CandidateIndex < B.CandidateIndex;
|
||||
}
|
||||
if (A.bRejected != B.bRejected)
|
||||
{
|
||||
return !A.bRejected;
|
||||
@@ -1071,11 +1083,23 @@ bool VF_WriteStratePreviewIndex(
|
||||
const FString CardClass = Candidate.bRejected ? TEXT("candidate rejected") : TEXT("candidate");
|
||||
const FString MetricWindow = Candidate.Window.IsValid()
|
||||
? Candidate.Window.Describe() : WindowDescription;
|
||||
const int32 DisplayIndex = Candidate.bSeasonOrder && Candidate.DepthIndex != INDEX_NONE
|
||||
? Candidate.DepthIndex : Candidate.CandidateIndex;
|
||||
Html += FString::Printf(
|
||||
TEXT("<section class=\"%s\"><h2>#%d <span class=\"badge %s\">%s</span></h2>\n"),
|
||||
*CardClass, Candidate.CandidateIndex, *StatusClass, *Status);
|
||||
*CardClass, DisplayIndex, *StatusClass, *Status);
|
||||
Html += FString::Printf(TEXT("<div class=\"recipe\"><code>%s</code></div>\n"),
|
||||
*VF_HtmlEscape(Candidate.RecipeString));
|
||||
if (Candidate.bSeasonOrder)
|
||||
{
|
||||
Html += FString::Printf(
|
||||
TEXT("<p class=\"reason\" style=\"color:#d7e3f4\"><strong>Why selected:</strong> %s"
|
||||
"<br><strong>Boss slot:</strong> %s</p>\n"),
|
||||
*VF_HtmlEscape(Candidate.SelectionReason.IsEmpty()
|
||||
? TEXT("selected by the provisional season policy")
|
||||
: Candidate.SelectionReason),
|
||||
Candidate.bBossSlot ? TEXT("yes") : TEXT("no"));
|
||||
}
|
||||
if (Candidate.bRejected)
|
||||
{
|
||||
Html += FString::Printf(TEXT("<p class=\"reason\"><strong>Why rejected:</strong> %s</p>\n"),
|
||||
|
||||
Reference in new issue
Block a user