vflow2 Documentation

IFC Analysis Tools ← Back to App

Version Compare

Der Compare-Tab vergleicht zwei Versionen desselben Projekts über fünf Kategorien. Der Vergleich basiert ausschließlich auf gecachten Bundles (keine IFC-Parsing beim Compare), ist also schnell und deterministisch. Der gesamte Compare läuft über den Job-Runner (Ultraplan #4 — kein sync-Pfad), damit ein 5-MB-Diff einen Gunicorn-Worker nicht blockiert.

Kategorien

  1. Räume (rooms) — keyed by GlobalId.
  2. added[], removed[], renamed[] (gid retained, name geändert), retained_count.
  3. Heizlast (heizlast) — pro Raum + Gebäudetotal.
  4. per_room[gid] = {a_phi_HL_w, b_phi_HL_w, delta_w, delta_pct, component_deltas: {trans, vent, reheat}, kind}
  5. building = {a_total_w, b_total_w, delta_w, delta_pct}
  6. Auslegung (sizing) — aktiver Heizflächen­kandidat pro Raum.
  7. per_room[gid] = {a_active, b_active, changed, still_covers_load, kind}
  8. Presets (presets) — flacher Key-Value-Diff mit Dotted-Paths.
  9. added{}, removed{}, modified{path: {a, b}}.
  10. Oberflächen (surfaces) — Roll-up pro Raum.
  11. per_room[gid] = {a_count, b_count, a_total_area_m2, b_total_area_m2, delta_area_m2, a_by_type, b_by_type, kind}

Material vs. Cosmetic

Jede Zeile bekommt kind: "material" | "cosmetic". Standard zeigt nur material-Zeilen; ein Toggle blendet cosmetic ein.

Kategorie Schwelle für material
Heizlast abs(delta_w) ≥ 50 W oder abs(delta_pct) ≥ 2 %
Sizing Typ-Wechsel, null↔non-null, covers_load-Grenze überschritten, oder coverage_pct ≥ 1 % Drift
Oberflächen abs(delta_area_m2) ≥ 0.1 m² pro Oberflächen-Typ
Presets Immer material (benutzereditiert)
Räume Added/removed/renamed sind immer material

NaN / Inf

Alle Floats passieren _finite(); serialisiertes JSON enthält niemals NaN, Infinity oder -Infinity. Ein 1000-Run-Fuzz-Test (test_version_diff_fuzz) sichert diese Invariante gegen Regressionen.

Caching

compare_cache/<sha256_hash>.json

wobei hash = sha256(a_vid + a_bundle_mtimes + b_vid + b_bundle_mtimes). Bei erneutem Vergleich derselben zwei Versionen (wenn keine Bundles mutiert wurden) wird der Cache getroffen (200, kein Job). Jede Bundle-Mutation invalidiert den Cache automatisch.

API

POST /projects/<p>/versions/compare?a=<vid>&b=<vid>
  → 200 {cached:true, cache_key} wenn Cache gültig
  → 202 {job_id, cache_key} wenn Job enqueued

GET /projects/<p>/versions/compare?a=<vid>&b=<vid>
  → 200 {full diff} wenn Cache vorhanden
  → 404 wenn kein Cache

Output-Shape (gekürzt)

{
  "schema_version": 1,
  "a_version": "v1", "b_version": "v3",
  "generated_at": "2026-04-21T12:00:00+00:00",
  "summary": {
    "rooms_added": 2, "rooms_removed": 1, "rooms_renamed": 3,
    "heizlast_total_delta_w": -1420, "heizlast_total_delta_pct": -2.9,
    "sizing_changes": 7, "material_heizlast_changes": 6,
    "material_surface_changes": 12, "preset_changes": 4
  },
  "rooms": { "added": [...], "removed": [...], "renamed": [...] },
  "heizlast": { "per_room": {...}, "building": {...} },
  "sizing": { "per_room": {...} },
  "presets": { "added": {...}, "removed": {...}, "modified": {...} },
  "surfaces": { "per_room": {...} },
  "disclaimer": "Vergleich basiert auf gecachten Bundles ..."
}

Mandatory-Disclaimer

Vergleich basiert auf gecachten Bundles. Bei manueller Neuberechnung einer Version können sich Werte verschieben.

Erscheint als Banner oben in der Compare-Ansicht.