fix(foundry): migrate legacy grid settings safely
This commit is contained in:
@@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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}: \\{`));
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user