fix: guard STEP-113 empty annotation and expose PBF blockers
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -1200,6 +1200,111 @@ TEST(RenderSegmentLocality, ReadinessAndFadeFollowOnlyDependencies) {
|
||||
EXPECT_FALSE(assessRenderSegmentSources({{}, {}, true}, lookup(true, false)).ready);
|
||||
}
|
||||
|
||||
TEST(Step116Safety, MissingSourceIsNotAnEmptyDependencyEvenWithRevisionTombstone) {
|
||||
const RenderSegmentDependencies dependencies{{"chart", "tide"}, {"symbol/glyph/image/placement"}, false};
|
||||
RenderSegmentRevisionBook book;
|
||||
book.advanceSource("chart");
|
||||
EXPECT_FALSE(book.revisionFor(dependencies));
|
||||
bool exists = false;
|
||||
bool loaded = false;
|
||||
const auto lookup = [&](const std::string& id) -> std::optional<RenderSegmentSourceStatus> {
|
||||
if (id == "chart") return RenderSegmentSourceStatus{true, false};
|
||||
if (id == "tide" && exists) return RenderSegmentSourceStatus{loaded, false};
|
||||
return std::nullopt;
|
||||
};
|
||||
auto assessment = assessRenderSegmentSources(dependencies, lookup);
|
||||
EXPECT_FALSE(assessment.ready);
|
||||
EXPECT_STREQ(assessment.reason, "missing-source");
|
||||
exists = true;
|
||||
book.advanceSource("tide"); // source addition, before async tile delivery
|
||||
const auto created = book.revisionFor(dependencies);
|
||||
ASSERT_TRUE(created);
|
||||
EXPECT_FALSE(assessRenderSegmentSources(dependencies, lookup).ready);
|
||||
loaded = true;
|
||||
book.advanceSource("tide"); // async layout/tile mutation
|
||||
EXPECT_NE(book.revisionFor(dependencies), created);
|
||||
EXPECT_TRUE(assessRenderSegmentSources(dependencies, lookup).stable);
|
||||
exists = false;
|
||||
book.advanceSource("tide"); // tombstone survives removal; readiness must not
|
||||
ASSERT_TRUE(book.revisionFor(dependencies));
|
||||
EXPECT_FALSE(assessRenderSegmentSources(dependencies, lookup).ready);
|
||||
exists = true;
|
||||
book.advanceSource("tide"); // same-name restoration receives a new revision
|
||||
EXPECT_NE(book.revisionFor(dependencies), created);
|
||||
}
|
||||
|
||||
TEST(Step116Safety, MissingSourceAuditDoesNotHidePlacementOrMutateSnapshot) {
|
||||
RenderSegmentDiagnostics snapshot;
|
||||
RenderSegmentDiagnosticsEntry segment;
|
||||
segment.strategy = RenderSegmentStrategy::Retained;
|
||||
segment.dependentSourceIds = {"navsea_delivery", "tide"};
|
||||
segment.placementCapable = true;
|
||||
segment.placementGatePassed = false;
|
||||
segment.cache.emplace();
|
||||
segment.cache->lastFallbackReason = "missing-source";
|
||||
snapshot.segments.push_back(segment);
|
||||
RenderSourceReadinessDiagnostics source;
|
||||
source.sourceId = "navsea_delivery";
|
||||
source.sourceType = "vector";
|
||||
snapshot.sources.push_back(source);
|
||||
auto json = renderSegmentDiagnosticsToJSON(snapshot);
|
||||
EXPECT_NE(json.find("\"missingSourceIds\":[\"tide\"]"), std::string::npos);
|
||||
EXPECT_NE(json.find("\"placementGatePassed\":false"), std::string::npos);
|
||||
EXPECT_EQ(renderSegmentDiagnosticsToJSON(snapshot), json);
|
||||
source.sourceId = "tide";
|
||||
snapshot.sources.push_back(source);
|
||||
EXPECT_NE(renderSegmentDiagnosticsToJSON(snapshot).find("\"missingSourceIds\":[]"), std::string::npos);
|
||||
// Presence alone grants neither a successful Build nor a placement pass.
|
||||
EXPECT_EQ(snapshot.segments[0].cache->build, 0u);
|
||||
EXPECT_FALSE(snapshot.segments[0].placementGatePassed);
|
||||
}
|
||||
|
||||
TEST(Step116Safety, SymbolContinuousBranchesAndResourceChangesRemainProtected) {
|
||||
const std::vector<StyleLayerDiagnostics> layers{
|
||||
{0, "tide-spots", "symbol", false, "tide", std::nullopt}};
|
||||
ASSERT_TRUE(renderSegmentHasPlacementCapableLayer(layers, 0, 1));
|
||||
// Normal Full: recompute => changed; recent => stale/transition.
|
||||
EXPECT_FALSE(renderSegmentPlacementGatePassed(true, true, 0.0f, false));
|
||||
EXPECT_FALSE(renderSegmentPlacementGatePassed(true, false, 0.0f, true));
|
||||
EXPECT_FALSE(renderSegmentPlacementGatePassed(true, true, 1.0f, false)); // transitions disabled
|
||||
const auto dependencies = renderSegmentDependencies(layers, 0, 1);
|
||||
RenderSegmentRevisionBook book;
|
||||
book.advanceSource("tide");
|
||||
const auto unchanged = book.revisionFor(dependencies);
|
||||
EXPECT_EQ(book.revisionFor(dependencies), unchanged);
|
||||
// Test the revision contract, not fabricated glyph/tile events or GPU completion.
|
||||
for (const auto* event : {"style", "glyph", "image", "context/reload"}) {
|
||||
SCOPED_TRACE(event);
|
||||
const auto before = book.revisionFor(dependencies);
|
||||
book.advanceGlobal();
|
||||
EXPECT_NE(book.revisionFor(dependencies), before);
|
||||
}
|
||||
for (const auto* event : {"source-update", "tile/layout"}) {
|
||||
SCOPED_TRACE(event);
|
||||
const auto before = book.revisionFor(dependencies);
|
||||
book.advanceSource("tide");
|
||||
EXPECT_NE(book.revisionFor(dependencies), before);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Step116Safety, AnnotationMutationAndLayerOrderDisableReloadKeepAllShadowFailures) {
|
||||
auto input = fastPathInput();
|
||||
input.cacheValid = false;
|
||||
input.annotationMutation = true;
|
||||
input.unsupportedContinuousLayer = true;
|
||||
input.supportedScene = false;
|
||||
input.topologyMatches = false; // added/reordered layer
|
||||
input.retainedEnabled = false; // explicit disable
|
||||
input.hasPreparedTree = false; // style reload/context replacement
|
||||
const auto decision = evaluateParticleFastPath(input);
|
||||
EXPECT_FALSE(decision.candidate);
|
||||
EXPECT_EQ(decision.reason, ParticleFastPathMissReason::NoPreparedTree);
|
||||
const auto failures = particleFastGateFailureMask(input);
|
||||
for (const auto bit : {0, 1, 2, 10, 21, 22, 23}) EXPECT_NE(failures & (1u << bit), 0u);
|
||||
auto unmodified = fastPathInput();
|
||||
EXPECT_EQ(particleFastGateFailureMask(unmodified), 0u); // predicate-only; no rendered Fast claim
|
||||
}
|
||||
|
||||
TEST(RenderSegmentLocality, MixedExecutionDrawsEachLiveRangeOnceInStyleOrder) {
|
||||
ResolvedRenderSegmentPlan plan;
|
||||
plan.valid = true;
|
||||
|
||||
Reference in New Issue
Block a user