# Changelog

All notable changes to Foundation Forensics.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

## [3.7.0] — 2026-09-03

### Changed — the public build is an evaluation build

The full platform had been deployed publicly and the repository was public, so the product
being sold by monthly subscription was also being given away from its own home page. The
public build now keeps **one project at a time**, with the bundled worked example exempt so
nothing is hidden: every section, every exhibit and the finished PDF remain reachable. Both
the create and import paths are gated. A licence key stored in `localStorage` (set once via
`?unlock=`) lifts the limit.

The check is client-side and honour-based. It states the boundary and makes casual commercial
use inconvenient; it does not defeat anyone willing to edit the file. Combined with taking the
repository private, that is the intended level of friction — not DRM.

---

## [3.6.0] — 2026-09-02

### Added — the platform no longer opens as a blank screen

- **"Load the worked example" on the empty dashboard.** A first-time user arrived at an empty
  grid and a Create New Project button, with nothing to show what a finished evaluation looks
  like. The empty state now offers the complete two-visit demonstration case — twelve
  measurement points, a traced sewer line, six coded observations and a monitoring comparison —
  fetched from `example_project.json` and inserted as an ordinary project that can be opened,
  edited, exported or deleted. It is marked `isExample` and never touches the user's own work.
- The example is fetched once and cached; if it cannot be reached the message says so and
  starting a new project still works offline.

---

## [3.5.2] — 2026-09-02

### Fixed — the dashboard called every project empty

- **Project cards read the pre-v3 data shape.** The dashboard computed each card's readings from
  `project.points`, which has not held measurements since multi-visit support moved them into
  `visits[]`. Every card therefore rendered "NO DATA" and "0 pts" no matter how complete the
  project was — including the preloaded demonstration file used in sales conversations, which
  advertised itself as empty while holding two visits of twelve points each. Cards now resolve
  the active visit (falling back to the most recent, then to the legacy top-level shape) and
  compute severity from its survey settings. The demo card now reads
  *"In Progress · Δ 1.80 in. — CRITICAL · 12 pts · 2 visits."*
- Found by screenshotting the running app rather than reading its stored state; the data was
  correct in storage the whole time and only the display was wrong.

---

## [3.5.1] — 2026-08-31

### Fixed

- **Page-header text collision.** The running header drew the firm name from the left
  margin and the report number and address right-aligned, with no width allocation
  between them. With a long firm name the two strings overlapped and both became
  unreadable on every page after the cover. The header now divides the available line
  between the two, capping the right-hand string at 60% and ellipsizing whichever does
  not fit. Found by rasterising the rendered PDF rather than reading the code.
- **Stray rule fragment removed from the reference list.** The ASCE entry ended with
  "§304.100", a leftover from an earlier citation of Texas Residential Construction
  Commission Rule 10 TAC §304.100. That rule never adopted the ASCE guidelines — the
  Commission expressly declined to incorporate them in its 2004 adoption preamble — and
  the TRCC itself was abolished on 1 September 2009, when its Act expired and Chapter 304
  left the Texas Administrative Code. The reference now reads "(superseding Versions 1
  and 2)" with no implied regulatory adoption.

---

## [3.5.0] — 2026-08-20

### Fixed — the deflection ratio now matches the definition it cites

The tool cited the ASCE Texas Section *Guidelines for the Evaluation and Repair of
Residential Foundations* and then computed something the guidelines do not define.
The source document was obtained and read; three findings followed.

- **Deflection ratio recomputed to the § 5.4 definition.** The guidelines define it as
  *"the maximum deviation of a third point from a straight line between two points
  divided by the distance (L) between the two points"* — a chord construction on a
  profile. The tool had been reporting the peak-to-trough departure from a
  least-squares plane divided by the distance between those two extremes, which is a
  different quantity and gave a different number. Every pair of plan-located points is
  now searched as a candidate chord, an intermediate point is accepted when its plan
  projection falls between the endpoints and within 10% of the chord length of the
  line, and the governing (worst) triple is reported. On the demonstration file the
  reported figure moves from L/419 to L/618 — the previous convention overstated
  deflection. The plane fit is retained as a clearly labelled secondary planarity
  diagnostic and is no longer called the deflection ratio.
- **L/240, L/180, L/120 and L/80 removed.** None of them appear in the guidelines. The
  string "L/240" is absent from Versions 1, 2 and 3. The six-tier classification scale
  built on them has been replaced with the single comparison the source actually makes:
  § 5.5 offers L/360 — the IRC allowable live-load deflection for a structural floor
  member — as an analogy in which the whole foundation is treated as one member, and
  states that below it a foundation is unlikely to be materially deflected *unless
  visible indications show otherwise*.
- **Tilt reframed.** § 5.6 states that a tilt greater than 1 percent is *usually
  noticeable* and that the ADA considers a 2 percent slope too large. Neither is a
  damage threshold. The 1% figure had been rendered as a severity trigger; it is now
  stated as what it is — perceptibility — with the ADA figure alongside it.

### Changed
- **Citations updated from Version 1 (2002) to Version 3, adopted 1 April 2022** — the
  current edition, two revisions newer than the one cited throughout the application,
  PDF report, and documentation.
- **The 0.5 / 1.0 / 1.5 in. bands in § 5.2 are now disclosed as this firm's own
  screening convention.** The guidelines contain no numeric severity or damage
  classification table in any version, and the report now says so rather than letting
  the banding read as a criterion drawn from them.

### Verified
- The chord search was reimplemented independently in Python and reproduces the
  application's governing triple exactly: chord M-05 → M-07, 18.66 ft, intermediate
  point M-03 deviating 0.363 in., L/617.6.
- Source: ASCE Texas Section, *Guidelines for the Evaluation and Repair of Residential
  Foundations*, Version 3 (adopted 1 April 2022), §§ 3.1, 5.4, 5.5, 5.6. Published free
  at texasce.org; Versions 1 (2002) and 2 (2008) were read alongside it and agree on
  every point above.

## [3.4.0] — 2026-08-20

Verification pass over the calculation engine. Every figure below was recomputed
independently and compared against the application's output; the entries are the
places the two disagreed, or where the application computed a quantity other than
the one it named.

### Fixed — tilt was being reported as deflection
- **§ 5.2.1 computed tilt, labelled it deflection, and classified it against deflection
  limits.** The ratio was `span / (max reading − min reading)`, where the span was the
  bounding-box diagonal of the plan points. The elevation range includes rigid-body
  rotation, so a slab that is perfectly flat but out of level produced a finite
  "deflection" and could be classified as distressed with no bending present at all;
  conversely a dished slab whose extreme readings happen to sit at similar elevations
  under-reported. The L/360 and L/240 limits refer to bending, not to range.
- **§ 5.2.1 and § 5.2.2 were the same measurement.** Both divided the same elevation
  range by a length — the bounding-box diagonal in one case, the distance between the
  extreme readings in the other — and the results were presented as two independent
  findings. On the demo they read L/293 and 0.50%: one number, two denominators.
- Deflection is now the departure of the elevation field from a **least-squares plane**
  fitted through every plan-located point, which removes the rigid-body component and
  leaves only the departure from planarity. Reported with the two points carrying the
  peak and trough residual, over both the local span (peak to trough, the more
  conservative) and the full plan extent, because the span used in the Δ/L convention
  varies between practices and the choice moves the answer a long way. On the demo:
  deflection 0.59 in., L/419 local and L/1336 overall.
- Tilt is now the gradient of that same fitted plane rather than a rise/run between two
  extreme readings, so a single outlying point no longer sets it. Where no plan
  positions exist the previous living-area estimate remains, explicitly labelled as an
  estimate. Deflection returns nothing at all below three plan-located points — a plane
  cannot be fitted to fewer, and deflection is undefined without one.
- The 1% tilt note no longer asserts what the ASCE Texas Section guidelines say. It
  states the computed value and directs the reader to verify the threshold against the
  current document.

### Fixed — distances in feet were never measured
- **The pixel-to-foot scale was hardcoded.** `PIXELS_PER_FOOT_SEWER = 20` governed every
  § 3.6 segment run, and the same figure appeared again as a bare `0.05` in two other
  functions, so the three could silently diverge. Plan images are uploaded at arbitrary
  resolution: 20 px/ft is an assumption, and a report stating a run of "11.7 ft" was
  asserting a measurement nobody took.
  In the application's own demo the assumed scale put the plan at 836 sq ft against a
  stated living area of 1,850 — a linear error of about 1.5x.
- **§ 3.5.2 Plan Scale Calibration** added: enter pixels per foot directly, or select two
  measurement points and give the distance between them on site. Until calibrated, the
  § 3.5 status line and both § 3.6 and § 5.1 in the report state plainly that derived
  lengths rest on an assumed scale and are not measured values.
- One `getPixelsPerFoot()` now feeds segment runs, the deflection span, and the plane
  fit. Calibrating the demo from 20 to 13.44 px/ft moves segment runs from 11.7–13.8 ft
  to 15.7–20.5 ft, slopes from 0.01547 to 0.01723 on the worst segment, tilt from 0.46%
  to 0.31%, and the deflection ratio from L/281 to L/419 — across a classification
  boundary. The scale is not a cosmetic setting.

### Fixed — joint-stress index jumped at a breakpoint
- The index is a piecewise-linear ramp on movement ÷ joint tolerance with breakpoints at
  0.3, 1 and 2 tolerances. The first piece divided by the full tolerance instead of
  0.3 × tolerance, so it reached 7.5 where the second piece begins at 25: for cast iron
  the index jumped from 5.6 to 18.8 across a movement difference of half a thousandth of
  an inch. The remaining breakpoints were already continuous. All four pieces now meet,
  and the top piece saturates at 95 before the material leak factor is applied instead of
  adding an unscaled term.

### Fixed — five implementations of one reference elevation
- The § 3.2 table, the plan-view contours, the § 3.6 interpolation, the dashboard card,
  the PDF cover and the PDF § 3.2 table each resolved the survey reference mode
  separately, and they did not agree: three of them ignored `manual` mode and fell back
  to the first reading or the highest, and two disagreed on what an unrecognized mode
  should do. A survey set to a manual datum reported one reference elevation on screen
  and a different one in the report. There is now a single `referenceElevationFor()`
  and every consumer calls it.
- The PDF computed its own § 5.1 deflection and tilt from living area alone, ignoring the
  plan positions the screen used — a sixth implementation, and the reason the printed
  metrics differed from the screen. It now calls the same functions.

### Verified — no change required
- IPC Table 704.1 minimum slopes: ¼ in./ft (0.02083) for ≤ 2½ in., ⅛ in./ft (0.01042)
  for 3–6 in., 1⁄16 in./ft (0.00521) above. Correct as implemented.
- Inverse-distance-squared interpolation of settlement at sewer nodes: plan points and
  sewer nodes share one coordinate space, and the weighting is correctly formed.
- Segment slope sign convention: settlement at the downstream end increases fall, at the
  upstream end reduces it. Correct.
- Movement-rate and datum normalization in § 7.0 (added in 3.3.0) reproduce independently.

### Changed
- The demo build now ships with its plan scale calibrated to the stated 1,850 sq ft
  living area, so the briefing file no longer contradicts itself.
- **The version string is defined once.** It had been written by hand in the page footer
  and again inside the PDF footer, and the two drifted: every report generated between
  3.2.0 and 3.4.0 printed "Generated by Foundation Forensics v3.2.0" whatever build
  produced it. Both now read `APP_VERSION`.

### Known limitation, documented rather than fixed
- Each § 3.6 segment is modelled as a straight line between its endpoints. A settlement
  bowl that dips between two nodes is not represented; place additional nodes through the
  low point to capture it.

## [3.3.0] — 2026-08-20

### Fixed — the report did not match the software
- **§ 7.0 Visit Comparison now prints in the PDF report.** The flagship v3 feature — multi-visit
  movement rate — existed only on screen and in the raw CSV export; the PDF generator had no such
  section, while the README, overview, and this changelog all described it as a report section.
  The PDF now carries § 7.0 with visits compared, datum basis, movement-rate summary, peak
  joint-stress index delta, interpretation, and the full per-point delta table.
- **Section numbering collision resolved.** On-screen § 7.0 was Visit Comparison while the PDF's
  § 7.0 was Limitations & Certification, so § 7.1–7.3 meant two different things depending on
  where you read them. Limitations & Certification moved to § 8.0 and the table of contents was
  corrected; the TOC also listed "5.0 Engineering Analysis" against a body heading of "5.0
  Analysis" — a discrepancy that also read against the not-an-engineering-opinion frame.
- **Non-WinAnsi characters rendered as mojibake in every PDF ever produced.** jsPDF's built-in
  fonts are WinAnsi-encoded: the § 3.2 measurement table's `Δ` column header printed as `”`, and
  the § 3.6 segment table's `FROM → TO` printed as `FROM !’ TO`. Affected literals were replaced,
  and `pdf.text` / `pdf.splitTextToSize` are now wrapped in a central sanitizer so an out-of-set
  character substitutes visibly instead of failing silently.

### Fixed — cross-visit calculation
- **A change of survey datum could masquerade as structural movement.** § 7.0 differenced raw
  readings between visits. A relative elevation survey carries no absolute benchmark, so if the
  reference point or instrument setup differed between visits, the whole grid shifted and the
  shift was reported as movement. Each visit is now reduced to deviations from its own reference
  point (the same `refMode` § 3.0 and § 5.0 classify against) before differencing, so only the
  change in *shape* of the elevation field survives. The per-point table shows Δ raw alongside
  Δ rel. datum, a stat box reports the reference shift that was removed, and a datum notice fires
  when that shift reaches 0.25 in.
- **Comparison math extracted to `computeVisitComparison()`**, called by both the on-screen § 7.0
  and the PDF § 7.0, so the two cannot drift apart again. `peakJointStressIndex()` likewise
  replaces the inline duplicate, and now restores `project` state in a `finally` block.

### Fixed — demo build
- **`build_demo.js` multiplied absolute elevation readings by 1.35** where it meant to grow each
  point's deviation from the survey reference by 35%. The synthesized six-month monitoring visit
  therefore sat ~35 in. above the baseline, and the briefing file — the build shown to property
  owners, public adjusters, and counsel — reported 35.00 in. of movement at 5.886 in/month with a
  "Rapid movement rate" banner. The growth is now applied to the deviation, and the demo reports
  0.68 in. of shape change at 0.114 in/month over 181 days.
- **The build is reproducible from a fresh clone.** `build_demo.js` read its v2 source from a
  hardcoded `/mnt/project/` path that existed only on the original author's machine. The input now
  resolves to `legacy/foundation_v2_demo_preloaded.html` relative to the script, overridable with
  `FF_V2_DEMO`, and that file is committed.

### Changed — offline operation is now real
- **jsPDF 2.5.1 (MIT) is bundled into the application file.** It was loaded from cdnjs on first
  PDF export, so a tablet with no signal — the actual field condition this tool is built for —
  could not produce a report, despite "offline-capable" appearing in the README, the tagline, and
  the comparison table. The license header is retained inline. Web fonts still load from Google
  Fonts when the network is present and fall back to system stacks when it is not.

### Changed — forensic positioning (language the v3.2.0 pass missed)
- PDF cover **Principal Finding** classified 1.0–1.5 in. as "Significant Movement — Foundation
  Repair Recommended" and >1.5 in. as "Critical Differential — Immediate Foundation Repair
  Required". Both now state the measured range without prescribing work.
- Property-owner summary headlines "REPAIR RECOMMENDED" / "REPAIR REQUIRED" became "EXCEEDS COMMON
  TOLERANCE" / "CRITICAL MEASURED RANGE", and the corresponding bottom-line paragraph — which
  ended "Repair before damage progresses is advised." — now refers the question of what work is
  warranted to a licensed engineer.
- § 3.6.3 findings no longer say a CCTV scope is indicated "before finalizing remediation scope"
  or that "no plumbing intervention is indicated"; § 6.4 heading "Structural Remediation" now
  matches its on-screen label, "Structural Recommendations".
- Remaining **"joint risk" / "%" labels** from the v3.2.0 rename were carried over: § 7.0's "Peak
  Joint Risk … 65% … Δ 1 pp" stat boxes, the § 3.6 screen table header and metric tile, the PDF
  § 3.6.2 column header, the property-owner summary's "PLUMBING JOINT RISK 65%", and the raw
  export's `joint_risk_pct` column (now `joint_stress_index`).

### Added
- **`index.html`** — a landing page for GitHub Pages. The Pages root returned 404 because no
  index existed; the application was reachable only by typing the HTML filename directly.
- **`.gitignore`** — the repository had none. Notably excludes project JSON exports, which contain
  client names, property addresses, and inspection photographs.
- **`legacy/foundation_v2_demo_preloaded.html`** — the demo build input, previously uncommitted.

### Removed from the roadmap
- **"Auto-generated recommendations from analysis + evidence data."** Generating remedial
  recommendations is engineering judgment reserved to a licensed P.E. under Texas Occupations Code
  Ch. 1001; shipping it would place the firm outside the scope of practice the rest of the product
  is built to hold. Recorded as excluded rather than deferred, alongside load calculation and soils
  analysis in `docs/forensic_positioning.md`.

## [3.2.0] — 2026-08-20

### Changed — forensic positioning (report language)
- **All auto-generated repair-prescriptive language replaced with forensic-neutral findings.**
  §5.2 is now "Classification of Measured Condition" rather than "Diagnosis"; tier text states
  what was measured and refers causation and remedial scoping to a licensed P.E. Removed
  auto-generated piling specifications, "remediation is required/recommended", and
  "schedule a repair consultation" from the screen analysis, PDF report, and client summary.
  *All input fields are preserved* — an inspector may still enter any narrative manually.
- **"Joint separation probability (%)" renamed to "joint-stress index"** throughout (table,
  exhibits, PDF, methodology). The value is a comparative screening scale used to prioritize
  field verification, and is now explicitly stated not to be a statistical probability.
- Client-summary next steps reordered around engineer review, evidence preservation, and
  claim-process orientation; explicit statement that this firm does not negotiate claims.
- Insurance note reframed: the index indicates a line warranting verification, not a finding
  that a leak exists.

### Changed — license
- **MIT → proprietary license.** All rights reserved; software is licensed, not sold.
  Report output remains the property of the licensee/client. Prior MIT-published versions
  are unaffected (that grant cannot be retroactively revoked).

### Added
- Copyright banner in the application source header; copyright and scope-of-practice line in
  the application footer; per-page copyright and work-product notice in the PDF footer.
- Demo/simulation file enriched: §2.3.1 geology populated (Houston Black clay, PI 40–60,
  LEP 9.5, Very High shrink-swell, dated SSURGO-style source citation), firm-own report
  numbering (FF-20260119-001), and the full §1/§5 narrative rewritten in forensic-neutral
  voice so the briefing file demonstrates the correct positioning end to end.

## [3.1.0] — 2026-07-05

### Added
- **Discrete settlement bands + iso-settlement contours** (screen sewer canvas + PDF
  Exhibit A): 0.25" fixed bands with a divergent palette (blue = heave, neutral,
  yellow→red = settlement); marching-squares contour lines at 0.25" intervals with
  bold labeled 0.50" contours and a dashed zero-movement line; two-row legend on
  Exhibit A including the band scale.
- **Site Geology (§2.3.1)** — hybrid published-soil-data integration:
  - Embedded regional database (~24 Bexar-and-adjacent NRCS soil series with
    representative shrink-swell class, PI range, LEP, drainage, geologic notes).
  - One-click **USDA SSURGO fetch**: geocodes the property address (US Census
    geocoder) → queries Soil Data Access for the parcel's dominant map unit
    (map unit name, component, PI min–max, LEP, drainage) → caches into the
    project with a dated source citation.
  - Geology fields persist per project, carry forward automatically to new visits,
    and print in the PDF as §2.3.1 with a fixed non-geotechnical disclaimer.

## [3.0.2] — 2026-07-03

### Added
- **Visual Exhibits** for §3.6 (screen + PDF), auto-generated from segment data:
  - *Exhibit A* — Plan overlay: sewer routing color-coded by slope classification with legend.
  - *Exhibit B* — Per-segment side-view slope profiles: as-designed (dashed) vs. current
    (solid, severity-colored) vs. IPC minimum (dotted); settlement arrows with Δ values at
    each end; auto vertical-exaggeration note; back-pitch pooling zone shading.
  - *Exhibit C* — Bell-and-spigot joint separation principle diagram with the property's
    worst-segment values (material joint tolerance vs. measured movement, separation %).
- Exhibits render in §3.6.4 on screen and as PDF subsection "3.6.4 Visual Exhibits".

## [3.0.1] — 2026-07-02

### Fixed
- **§7.0 Visit Comparison** now matches measurement points by their actual field names
  (`code` / `reading`); previously matched on nonexistent `label` / `elevation`, so no
  points ever matched between visits.
- **+ Monitoring Visit** point-grid seeding copies `code`/`location` and resets `reading`
  (previously produced undefined labels).
- **Raw Data Export (P.E. Review)** elevation CSV now emits real point codes and readings.

### Added
- `foundation_forensics_v3_demo_preloaded.html` — briefing/simulation build with two
  preloaded visits (Initial Evaluation + 6-Month Monitoring), sample hydrostatic/CCTV
  field-test evidence, and demo-scoped localStorage key (does not touch real app data).
  Firm rebranded to a neutral forensic-evaluator placeholder (repair-company logo/seal removed).
- `build_demo.js` — reproducible demo build script (extracts v2 demo data, migrates to
  v3 schema, synthesizes the monitoring visit).
- Mobile-responsive layout: horizontally scrollable tables, single-column forms,
  44px touch targets, 16px inputs (prevents iOS focus zoom), stacked toolbars,
  full-width dashboard cards, and a 480px small-phone tier.

## [3.0.0] — 2026

Foundation Forensics v3.0 is a re-architecture of the earlier Foundation Inspection System v2, oriented around independent forensic evaluation rather than repair-contractor pre-repair documentation.

### Added

- **Multi-visit time-series data model.** Every project now supports an array of visits (`project.visits[]`), each with its own report, site conditions, survey, scope, elevation points, observations, plan points, and plumbing analysis. House-level fields (property, client, foundation) remain shared across visits. Three visit types are supported: `initial`, `monitoring`, `post-repair`.
- **Visit Bar UI.** New selector between the back-bar and the section-nav lets the inspector switch visits, add a Monitoring Visit or a Post-Repair Survey, and edit visit metadata. Follow-up visits are pre-seeded with the previous visit's plan image, sewer routing, and measurement-point positions (with elevations reset to zero for re-measurement).
- **§ 7.0 Visit Comparison.** New report section computes interval days/months, per-point elevation delta, per-point rate (in/month), peak movement rate, mean movement rate, and peak plumbing joint-risk delta between any two selected visits. Includes an interpretation banner tuned to Texas expansive-soil residential context.
- **Per-segment field-test evidence.** § 3.6 Plumbing Impact table now has an Evidence column. Attachments per segment: CCTV footage/still, hydrostatic test PDF, smoke test photo, or free-text field note. Each attachment is bound to a specific sewer segment.
- **Raw-data export for P.E. review.** New "Export Raw Data (P.E. Review)" button in § 6.7 emits elevation grid + plumbing segments as a CSV bundle wrapped in a header identifying property, firm, and inspector. Explicit statement in the export file that no engineering opinion is asserted — the file is designed for a licensed Texas Professional Engineer to review and issue a separate signed and sealed opinion.
- **Automatic v2 migration.** Legacy `localStorage` key `foundation_inspection_v2_data` is detected on load and migrated into the v3 schema. Legacy JSON export types (`foundation_inspection_single_project`, `foundation_inspection_full_backup`) are accepted by the import dialog and migrated in place.

### Changed

- **Report disclaimer rewritten** to declare three explicit legal frames: non-repair, not-engineering-opinion (Texas Occupations Code Ch. 1001; TBPE), not-claim-negotiation (Texas Insurance Code). Texas DTPA § 17.49(c) exemption preserved.
- **Branding.** "Foundation Inspection System" → "Foundation Forensics". Subtitle now reads: "ASCE Level B Evaluation · Independent Technical Documentation · Multi-Visit Monitoring".
- **Storage key.** `foundation_inspection_v2_data` → `foundation_forensics_v3_data`. v2 key is retained as read-only legacy source for migration.
- **JSON export type strings.** `foundation_inspection_single_project` → `foundation_forensics_single_project`; `foundation_inspection_full_backup` → `foundation_forensics_full_backup`. v2 strings still accepted on import.
- **`createEmptyProjectData()`** restructured. Visit-scoped fields moved into the new `visits[]` array; house-level fields remain at project level.
- **`snapshotCurrentProject()`** / **`loadProjectIntoActive()`** rewritten to be visit-aware.

### Preserved

- All existing v2 functionality: dashboard, § 0.0 through § 6.0 sections, live calculation engine, plan-view contour rendering, sub-slab plumbing impact modeling, PDF report generation, JSON single-project export, full-backup export, browser localStorage auto-save.
- The `project` global variable retains its flat structure (the currently-loaded visit's data is on it directly), so all existing UI code and PDF export logic works unchanged.

### Migration Path from v2

No user action required. On first load, if v3 storage is empty and v2 storage exists, v2 projects are silently wrapped into v3 shape with a single "Initial Evaluation (migrated from v2)" visit each. v2 JSON files can be imported directly and are migrated on the way in.

See [`docs/migration_from_v2.md`](docs/migration_from_v2.md) for full details.

---

## [2.0.0] — 2026 (baseline — Foundation Inspection System)

- Multi-project dashboard, ASCE Level B 9-section workflow (§ 0.0 – § 6.0), sub-slab plumbing impact module, live calculation engine, PDF report generator, DTPA § 17.49(c) disclaimer.
