fix(foundry): migrate legacy grid settings safely

This commit is contained in:
Codex
2026-08-09 10:59:57 +03:00
parent 58800d9576
commit 7025fd20b5
2 changed files with 43 additions and 3 deletions
+17 -3
View File
@@ -637,15 +637,26 @@ function promoteLegacyGridLodProfiles(settings) {
selectionOutlineOpacityPercent: _selectionOutlineOpacityPercent, selectionOutlineOpacityPercent: _selectionOutlineOpacityPercent,
...legacyFallback ...legacyFallback
} = fallback; } = fallback;
const stepKm = settings[`gridLod${number}StepKm`] ?? fallback.stepKm;
const legacyRadiusKm = settings.gridRadiusKm ?? fallback.radiusKm;
// The flat v1 setting described one uniform grid and could legitimately
// be much larger than a fine LOD band can render. Migrate it as an upper
// bound per band so an existing application remains readable while the
// new five-band workload stays within its explicit safety limit.
const radiusKm = Math.min(
legacyRadiusKm,
fallback.radiusKm,
stepKm * MAX_LOCAL_GRID_INDEX,
);
return { return {
...legacyFallback, ...legacyFallback,
maxHeightKm: settings[`gridLod${number}MaxHeightKm`] ?? fallback.maxHeightKm, maxHeightKm: settings[`gridLod${number}MaxHeightKm`] ?? fallback.maxHeightKm,
stepKm: settings[`gridLod${number}StepKm`] ?? fallback.stepKm, stepKm,
mode: settings[`gridLod${number}Mode`] ?? fallback.mode, mode: settings[`gridLod${number}Mode`] ?? fallback.mode,
heightMeters: settings.gridHeightMeters ?? fallback.heightMeters, heightMeters: settings.gridHeightMeters ?? fallback.heightMeters,
max3dViewAngleDegrees: settings.gridMax3dViewAngleDegrees ?? fallback.max3dViewAngleDegrees, max3dViewAngleDegrees: settings.gridMax3dViewAngleDegrees ?? fallback.max3dViewAngleDegrees,
tileSizeKm: settings.gridTileSizeKm ?? fallback.tileSizeKm, tileSizeKm: settings.gridTileSizeKm ?? fallback.tileSizeKm,
radiusKm: settings.gridRadiusKm ?? fallback.radiusKm, radiusKm,
lineDiameterMeters: settings.gridLineDiameterMeters ?? fallback.lineDiameterMeters, lineDiameterMeters: settings.gridLineDiameterMeters ?? fallback.lineDiameterMeters,
lineColor: settings.gridColor ?? fallback.lineColor, lineColor: settings.gridColor ?? fallback.lineColor,
lineOpacity: settings.gridOpacity ?? fallback.lineOpacity, lineOpacity: settings.gridOpacity ?? fallback.lineOpacity,
@@ -658,7 +669,10 @@ function promoteLegacyGridLodProfiles(settings) {
crossesWidthMeters: settings.gridCrossesWidthMeters ?? fallback.crossesWidthMeters, crossesWidthMeters: settings.gridCrossesWidthMeters ?? fallback.crossesWidthMeters,
crossesColor: settings.gridCrossesColor ?? fallback.crossesColor, crossesColor: settings.gridCrossesColor ?? fallback.crossesColor,
crossesOpacity: settings.gridCrossesOpacity ?? fallback.crossesOpacity, crossesOpacity: settings.gridCrossesOpacity ?? fallback.crossesOpacity,
graticuleLineWidthPx: settings.gridLineWidth ?? fallback.graticuleLineWidthPx, graticuleLineWidthPx: Math.min(
3,
Math.max(1, settings.gridLineWidth ?? fallback.graticuleLineWidthPx),
),
graticuleColor: settings.gridColor ?? fallback.graticuleColor, graticuleColor: settings.gridColor ?? fallback.graticuleColor,
graticuleOpacity: settings.gridOpacity ?? fallback.graticuleOpacity, graticuleOpacity: settings.gridOpacity ?? fallback.graticuleOpacity,
}; };
+26
View File
@@ -98,6 +98,32 @@ test("flat layouts migrate mode-aware extensions while explicit invalid hierarch
); );
}); });
test("Robot2B legacy radius migrates per LOD without hiding the application", () => {
const legacyRobot2BSettings = {
gridHeightMeters: 500,
gridLod1MaxHeightKm: 10,
gridLod1StepKm: 1,
gridLod2MaxHeightKm: 50,
gridLod2StepKm: 5,
gridLod3StepKm: 25,
gridRadiusKm: 1_000,
gridLineWidth: 4,
gridColor: "#f5f5f5",
gridOpacity: 12,
gridDotsEnabled: true,
gridDotsSize: 7,
gridDotsColor: "#ffffff",
gridDotsOpacity: 58,
};
const migrated = structuredClone(serverGrid.validateGridLodProfiles(
serverGrid.promoteLegacyGridLodProfiles(legacyRobot2BSettings),
));
assert.deepEqual(migrated.map((profile) => profile.radiusKm), [50, 1_000, 1_000, 1_000, 100]);
assert.ok(migrated.every((profile) => profile.radiusKm / profile.stepKm <= 512));
assert.ok(migrated.every((profile) => profile.graticuleLineWidthPx === 3));
});
test("Foundry MCP exposes every persisted sector-v2 profile field", () => { test("Foundry MCP exposes every persisted sector-v2 profile field", () => {
for (const key of extensionKeys) assert.match(mcpSource, new RegExp(`\\b${key}: \\{`)); for (const key of extensionKeys) assert.match(mcpSource, new RegExp(`\\b${key}: \\{`));
}); });