Changelog¶
All notable changes to S2DCartographer are documented here. For the complete history see the root CHANGELOG.md in the repository.
The format follows Keep a Changelog and this project uses Semantic Versioning.
[1.10.1] — 2026-06-30¶
Fixed¶
- ImportExcel is now an optional runtime dependency. Removed
ImportExcelfrom the manifestRequiredModuleslist soTest-ModuleManifestandImport-Modulesucceed in CI without ImportExcel pre-installed.Export-S2DExcelReportloads ImportExcel on demand; other report formats (HTML, Word, PDF, JSON) are completely unaffected.
[1.10.0] — 2026-06-30¶
Added¶
-
Graduated health-check scoring engine (#57, AB#267).
Get-S2DHealthStatusnow addsWeight,MaxPoints,AwardedPoints,ScoreBand, andScorePercentto everyS2DHealthCheck. ACollectedData['HealthScore']rollup carries the weightedOverallScore(0–100),ScoreStatus(Excellent/Good/Fair/Needs Improvement),TotalAwarded,TotalMax, and the legacyOverallHealthstring. All existing output fields are unchanged — fully backward-compatible. -
Named calculation references via
config/health-checks.json(#58, AB#268). All 12 check definitions (weights, thresholds, named bands) externalized to a JSON config file shipped with the module. Thresholds and weights are editable without code changes. Mirrors Ranger'swaf-rules.jsonschema shape. -
Export-S2DHealthConfigandImport-S2DHealthConfig(#59, AB#269). Export writes the active config to JSON; Import validates and activates an override for the session. Use-Validatefor a dry-run schema check; use-Defaultto reset to shipped defaults. Mirrors Ranger'sExport-RangerWafConfig/Import-RangerWafConfighot-swap pattern.
[1.9.0] — 2026-06-30¶
Added¶
-
Provisioning-aware 70% headroom presentation — the 70% amber/warning treatment in the HTML KPI tile, capacity-waterfall planning-line row, and expansion-headroom table now fires only when thin-provisioned volumes are present (a full pool takes thin volumes offline). When all volumes are fixed/thick, the 70% row is rendered as advisory/neutral (blue label, "Advisory — fixed volumes commit footprint up front") because footprint is committed at creation time. The
Get-S2DExpansionHeadroomfunction gains aHasThinVolumesboolean on its output to drive this. Reworded all 70% prose to: "70% is a recommended operational headroom guideline — mainly relevant for thin-provisioned volumes, where a full pool takes thin volumes offline. Not a Microsoft hard limit. The firm storage limits are footprints fitting the pool and the rebuild reserve staying intact." -
"Size to enter (New-Volume / WAC)" column in all expansion-headroom tables (HTML, Word/PDF). PowerShell
New-Volume -Sizeand WAC parse size suffixes as binary (typing2TBmeans 2 TiB). Each headroom row now shows the exact value to type, rendered as{value}TB(e.g.0.65TB), computed asNewUsableData.TiBrounded down to 2 decimal places so the new volume always fits. Past-line rows show—. A footnote explains the binary-suffix convention. TheSizeToEnterTiBproperty flows through to the JSON snapshot automatically. Identical wording and rounding to Surveyor 2.6.0 so the two tools match exactly.
Fixed / Correction¶
- N+1/N+2 maintenance reserve re-framed as compute-advisory — the v1.8.0 implementation
incorrectly treated N+1/N+2 as a storage-pool capacity check. Microsoft WAF documents it as a
COMPUTE resiliency target (reserve CPU + RAM so a node can be drained for updates or lost
without dropping VMs), listed separately from storage.
Get-S2DMaintenanceReserveAssessmentnow returnsStatus='Info',Meets=$null, and surfacesLargestNodeCapacityas informational context. Check 12 (MaintenanceReserveN1) always emitsStatus='Pass'atSeverity='Info'and never contributes a storage Warning or Fail to the health rollup. HTML and Word report sections re-labelled as compute advisory. All 70% prose corrected to not imply N+1 is a firm storage limit.
[1.8.0] — 2026-06-30¶
Added¶
- Maintenance reserve (N+1) assessment — reports whether the scanned cluster currently has enough free
capacity (beyond the rebuild reserve) to drain a node for updates, per Microsoft's Well-Architected
guidance. Surfaced as a new
MaintenanceReserveN1health check and a report indicator (Meets / Does not meet, with the required vs available headroom in TB and TiB). Configurable target via-MaintenanceReserveTarget None|N+1|N+2(default N+1). This is assessment only — it does not change any measured capacity number. On two-node two-way-mirror clusters it notes that each node already holds a full copy, so a drained node keeps data available.
[1.7.1] — 2026-06-30¶
Added¶
- Expansion Headroom report section (HTML, Word, PDF, JSON) — at 70% / 80% / 90% / 100% pool-fill targets, shows the remaining pool footprint and the new usable data you can still store (footprint ÷ resiliency copies), in both TB and TiB, with a Chart.js chart. The 70% row is styled as the recommended planning line. Math is identical to Surveyor's so the two tools reconcile by construction.
Fixed¶
- Per-volume capacity efficiency is now derived from the measured
FootprintOnPool ÷ Sizeratio (ground truth) when available. A two-copy mirror correctly reports 50% efficiency; the previous logic mislabeled it as 25% ("nested two-way mirror") on two-node clusters. Nested two-way mirror, which writes four copies, correctly reports 25%.
[1.7.0] — 2026-06-30¶
Wave 3 — Validation & report correctness. Locks accuracy against regression and fixes the PDF/Word report rendering defects, plus collection robustness on empty or contended clusters.
Added¶
- Cross-tool reconciliation keystone. A byte-valued golden-cluster fixture
(
tests/maproom/Fixtures/golden-clusters.json), identical to Surveyor's, drives a Pester suite that runs the Cartographer engine and asserts reconciliation within the ±2% gate. 24 Pester cases across 4 clusters. (AB#4633) - Concurrent collection guard — a module-scoped flag set at the start of
Invoke-S2DCartographerand released in afinally; a second concurrent collection throws a clear terminating error instead of corrupting shared state. (AB#279) - Empty-data safeguards —
Get-S2DCapacityWaterfall,Get-S2DHealthStatus, andGet-S2DStoragePoolInfonow handle null/empty disk, pool, and volume data gracefully (warn + zeroed result) rather than throwing on an empty cluster. (AB#279)
Fixed¶
- PDF capacity-model waterfall bar graph now uses exact byte-derived TB values instead of a
truncated
1.0995approximation. (AB#263) - PDF pool allocation reserve boundary line is positioned at
poolTotal − reserve(start of the reserve zone) instead of the reserve value, and the pool health bar's x-axis max now includes every segment so healthy clusters no longer clip. (AB#264) - Word executive summary table given explicit column widths (35/65), fixed layout, and cell
padding so values like
22.44 TiB (24.65 TB)are no longer cramped. (AB#265) - Word document overall layout — 1-inch margins, page-width tables with fixed layout, section- header cell margins, and hand-tuned column widths for the wide disk/volume tables. (AB#266)
[1.6.0] — 2026-06-29¶
Wave 2 — Legibility. Capacity figures are now unambiguous in unit and space. No capacity math changed.
Added¶
- The capacity waterfall and HTML report label every figure with both its unit (decimal TB and
binary TiB) and its space — each stage is badged
FOOTPRINT,DATA (usable), orINFORMATIONAL. (AB#4645) - 70% planning line — 70% of available-for-volumes, compared against consumed volume
footprint (matches Surveyor's definition exactly). Surfaced as
PlanningLine70Pct/IsAbove70PctLineonS2DCapacityWaterfall, as a KPI tile (amber when crossed) and a dashed plan-line on the HTML report chart. (AB#4644)
[1.5.0] — 2026-06-29¶
Wave 1 — Capacity accuracy. The capacity waterfall is reconciled to the canonical model (
docs/capacity-model.md) shared with Azure Local Surveyor.
Changed¶
- Resiliency factor is now always derived from each volume's actual
NumberOfDataCopieswhen present. When that value is unavailable, the unsafe default fallback changed from3.0to2.0(two-way mirror) and the waterfall stage is labeled[ASSUMED — actual NumberOfDataCopies not available]via the new-ResiliencyIsAssumedswitch. A real pool value is always preferred over the assumption. (AB#4642)
Confirmed¶
- Reserve calculation confirmed canonical — one capacity drive per server, up to 4 drives (raw-byte basis). No change required. (AB#4643)
[1.4.2] — 2026-04-14¶
Fixed¶
RebuildCapacityhealth check fired false Critical when pool-member disk deduplication could not assign correctNodeNameviaStorageNodeassociations — all disks landed on one node making the check compare pool free against the full pool total instead of one node's capacity. Fix: fall back topool.TotalSize / nodeCountwhenNodeNamegroup count is less thannodeCount.
For versions 1.4.1 and earlier, see the root CHANGELOG.md.