fix(vtank): TryLoadNav refuses any STATE: block instead of skipping it
Slice 1c review D1 / slice 7 item 7: TryLoadNav tolerated (and silently skipped) STATE:/IF:/DO: rule sections so a route load out of a full Meta .af would still succeed against whichever NAV: block came first. That is exactly the failure mode content-sanity elsewhere in this file already guards against (a misplaced file in the wrong folder silently "succeeding" against the wrong document) — a file with a STATE: block is a Meta profile, possibly one with an embedded nav of its own, and belongs in metas/, not navs/. TryLoadNav now throws (refuses) the instant it sees a STATE: line, with a message naming the metas/ folder, instead of walking past it via the now-deleted SkipState helper. SynthesizedGetOptFollowAndJumpFixtureRoundTrips previously used a STATE:+embedded-NAV: fixture to assert TryLoadNav's OLD skip-and-load behavior; that assertion is now inverted to assert refusal (shown to fail against the prior MetafSerializer.cs: True vs expected False). The "flw" nav-node parsing coverage that assertion also carried is preserved in a new dedicated NAV:-only fixture, FollowNavNodeParsesAsANavOnlyDocument. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
e72a64a311
commit
f6eebf8c50
2 changed files with 45 additions and 26 deletions
|
|
@ -766,15 +766,24 @@ internal static class MetafSerializer
|
|||
{
|
||||
Match lead = LeadIn.Match(cursor.Lines[cursor.L]);
|
||||
if (!lead.Success)
|
||||
throw cursor.Error("expected 'NAV:' (or a STATE: rule section, ignored for a route load).");
|
||||
throw cursor.Error("expected 'NAV:' (or a STATE: rule section, refused for a route load).");
|
||||
if (lead.Groups["type"].Value == "NAV:")
|
||||
{
|
||||
ReadNavBlock(cursor, navs, spells);
|
||||
continue;
|
||||
}
|
||||
// A nav route load tolerates (and ignores) STATE:/IF:/DO:
|
||||
// sections, e.g. loading a route out of a full meta .af.
|
||||
SkipState(cursor);
|
||||
// Slice 1c review D1: a file containing a STATE: rule section
|
||||
// is a Meta profile, possibly one with one or more embedded
|
||||
// NAV: blocks of its own. TryLoadNav previously skipped every
|
||||
// STATE:/IF:/DO: rule and silently loaded whichever embedded
|
||||
// NAV: block happened to come first — a route load that
|
||||
// "succeeds" against the wrong document instead of refusing
|
||||
// it outright. Refuse the whole file the same way the
|
||||
// "no NAV: block found" case below already does.
|
||||
throw cursor.Error(
|
||||
"found a STATE: rule section — this is a Meta profile "
|
||||
+ "(possibly with an embedded nav), not a stand-alone "
|
||||
+ "route; load it from the metas/ folder instead.");
|
||||
}
|
||||
if (navs.Count == 0)
|
||||
throw cursor.Error(
|
||||
|
|
@ -803,26 +812,6 @@ internal static class MetafSerializer
|
|||
return string.Join("\r\n", lines) + "\r\n";
|
||||
}
|
||||
|
||||
private static void SkipState(Cursor cursor)
|
||||
{
|
||||
Match header = LeadIn.Match(cursor.Lines[cursor.L]);
|
||||
_ = header;
|
||||
cursor.L++;
|
||||
cursor.SkipBlank();
|
||||
while (cursor.L < cursor.Lines.Length)
|
||||
{
|
||||
Match lead = LeadIn.Match(cursor.Lines[cursor.L]);
|
||||
if (!lead.Success)
|
||||
throw cursor.Error("expected 'STATE:', 'IF:', or 'NAV:'.");
|
||||
if (lead.Groups["type"].Value is "STATE:" or "NAV:")
|
||||
return;
|
||||
cursor.C = 0;
|
||||
_ = ReadTopLevelCondition(cursor);
|
||||
_ = ReadTopLevelAction(cursor);
|
||||
cursor.SkipBlank();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadNavBlock(
|
||||
Cursor cursor,
|
||||
Dictionary<string, (string NavType, List<RouteWaypoint> Nodes, uint FollowTargetId, string FollowTargetName)> navs,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue