Job workspaces

Status: Milestone B complete — UI job_store + central /api/jobs (SoT when central is up).

A browser session is not the project database. URL/session state is not durable storage.

Layout

workspace/jobs/<job_id>/
  job.json
  mapping/
    role_map.json
    equipment_map.json
  configs/
    session_config.json
    rule_parameters.json
    schedules.json
  datasets/
    dataset_refs.json
  runs/
    <run_id>/
      run.json
      …
  findings/
    findings.json
    dispositions.json
  reports/
  wattlab/
    handoffs/
    runs/
  artifacts/

Telemetry stays in Feather / parquet (site historian). Jobs hold pointers, configs, run outputs, and findings — not full historian copies.

Identifiers

Kind Pattern
Job job-<uuid>
Run run-<uuid>
Finding finding-<uuid> (B6)

Implementation

Piece Path
Store (thin client; central SoT when up) frontend/web/app/job_store.py
Central API services/central/src/jobs.rs
React entry frontend/web/app/ui_jobs.py
Tests frontend/web/app/test_job_store.py

job.json (schema_version 1)

{
  "schema_version": 1,
  "job_id": "job-…",
  "job_name": "Building 100 RCx Study",
  "description": "",
  "status": "active",
  "archived": false,
  "created_at": "",
  "updated_at": "",
  "created_by": "",
  "site_id": "",
  "site_name": null,
  "building_name": null,
  "tags": [],
  "meta_revision": "<opaque>",
  "latest_run_id": null,
  "latest_findings_revision": null,
  "mapping_path": null,
  "revisions": {
    "dataset": null,
    "mapping": null,
    "config": null,
    "engine": null
  }
}

meta_revision enables optimistic concurrency: writers must pass the revision they read; stale writes raise revision_conflict.

Lifecycle

Create · List (active/archived/filters) · Get · Update · Duplicate · Archive · Restore · Delete (confirm only).

Duplicate copies mapping/config/dataset_refs — not runs, findings, or reports.

Findings and dispositions (B6)

findings/findings.json holds machine evidence (SQL row hashes, rule outputs). Each finding requires correlation_key and finding_id. Dispositions live in findings/dispositions.json keyed by correlation_key — human status never overwrites evidence rows.

WattLab (job-native SoT)

Production source of truth is job-native handoffs under wattlab/handoffs/*.json (central POST /api/jobs/{id}/wattlab/handoffs, React helper ui_wattlab_job.py). Zip dumps from Export remain additive for offline / vibe20 / backup — they do not replace the job manifest. External EnergyPlus run metadata (when queued) lands under wattlab/runs/*.json; central tracks status/artifacts only.

Atomicity

Metadata writes use temp file + fsync + rename.