# Story 11.14: Danfoss Parser

Status: done

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## Story

As a refrigeration engineer,
I want Danfoss compressor data integration,
so that I can use Danfoss coefficients in simulations.

## Acceptance Criteria

1. **Given** a `DanfossBackend` struct
   **When** constructed via `DanfossBackend::new()`
   **Then** it loads the compressor index from `data/danfoss/compressors/index.json`
   **And** eagerly pre-caches all referenced model JSON files into memory

2. **Given** a valid Danfoss JSON file
   **When** parsed by `DanfossBackend`
   **Then** it yields a `CompressorCoefficients` struct with all 10 capacity and 10 power coefficients
   **And** it supports AHRI 540 format extraction

3. **Given** `DanfossBackend` implements `VendorBackend`
   **When** I call `list_compressor_models()`
   **Then** it returns all model names from the pre-loaded cache in sorted order

4. **Given** a valid model name
   **When** I call `get_compressor_coefficients("some_model")`
   **Then** it returns the full `CompressorCoefficients` struct

5. **Given** a model name not in the catalog
   **When** I call `get_compressor_coefficients("NONEXISTENT")`
   **Then** it returns `VendorError::ModelNotFound("NONEXISTENT")`

6. **Given** `list_bphx_models()` called on `DanfossBackend`
   **When** Danfoss only provides compressor data here
   **Then** it returns `Ok(vec![])` (empty list, not an error)

7. **Given** `get_bphx_parameters("anything")` called on `DanfossBackend`
   **When** Danfoss only provides compressor data here
   **Then** it returns `VendorError::InvalidFormat` with descriptive message

8. **Given** unit tests
   **When** `cargo test -p entropyk-vendors` is run
   **Then** all existing tests still pass
   **And** new Danfoss-specific tests pass (model loading, error cases)

## Tasks / Subtasks

- [x] Task 1: Create sample Danfoss JSON data files (AC: 2)
  - [x] Subtask 1.1: Create `data/danfoss/compressors/index.json` with sample models
  - [x] Subtask 1.2: Create `data/danfoss/compressors/model1.json` with realistic coefficients
  - [x] Subtask 1.3: Create `data/danfoss/compressors/model2.json` as second model
- [x] Task 2: Implement `DanfossBackend` (AC: 1, 3, 4, 5, 6, 7)
  - [x] Subtask 2.1: Create `src/compressors/danfoss.rs` with `DanfossBackend` struct
  - [x] Subtask 2.2: Implement `DanfossBackend::new()` resolving to `ENTROPYK_DATA` with fallback to `CARGO_MANIFEST_DIR`/data
  - [x] Subtask 2.3: Implement `load_index()` and `load_model()` pre-caching logic (incorporating fixes from Swep)
  - [x] Subtask 2.4: Implement `VendorBackend` trait for `DanfossBackend`
- [x] Task 3: Wire up module exports
  - [x] Subtask 3.1: Add `pub mod danfoss;` in `src/compressors/mod.rs`
  - [x] Subtask 3.2: Re-export `DanfossBackend` in `src/lib.rs`
- [x] Task 4: Write unit tests (AC: 8)
  - [x] Subtask 4.1: Test `DanfossBackend::new()` successfully constructs
  - [x] Subtask 4.2: Test `list_compressor_models()` returns sorted models
  - [x] Subtask 4.3: Test `get_compressor_coefficients()` returns valid data
  - [x] Subtask 4.4: Test `ModelNotFound` error for unknown model
  - [x] Subtask 4.5: Test `list_bphx_models()` returns empty
  - [x] Subtask 4.6: Test `get_bphx_parameters()` returns `InvalidFormat`
- [x] Task 5: Verify all tests pass (AC: 8)
  - [x] Subtask 5.1: Run `cargo test -p entropyk-vendors`
  - [x] Subtask 5.2: Run `cargo clippy -p entropyk-vendors -- -D warnings`
- [x] Task 6: Review Follow-ups (AI)
  - [x] Fix Error Swallowing during JSON deserialization to provide contextual file paths
  - [x] Fix Path Traversal vulnerability by sanitizing model parameter
  - [x] Improve Test Quality by asserting multiple coefficients per array
  - [x] Improve Test Coverage by adding test directly validating `DanfossBackend::from_path()`
  - [ ] Address Code Duplication with `CopelandBackend` (deferred to future technical debt story)

## Dev Notes

### Architecture

**This builds entirely on the `VendorBackend` trait pattern** established in epic 11. Similar to `CopelandBackend` and `SwepBackend`, `DanfossBackend` pre-caches JSON files containing coefficients mapping to `CompressorCoefficients`.

### Project Structure Notes

```text
crates/vendors/
├── data/danfoss/compressors/
│   ├── index.json                   # NEW: ["model1", "model2"]
│   ├── model1.json                  # NEW: Ahri 540 coefficients
│   └── model2.json                  # NEW: Ahri 540 coefficients
└── src/
    ├── compressors/
    │   ├── danfoss.rs               # NEW: main implementation
    │   └── mod.rs                   # MODIFY: add `pub mod danfoss;`
    ├── lib.rs                       # MODIFY: export DanfossBackend
```

### Critical Git/Dev Context
- Keep error logging idiomatic: use `log::warn!` instead of `eprintln!` (from recent `SwepBackend` fix `c5a51d8`).
- Maintain an internal sorted `Vec` for models in the struct to guarantee deterministic output from `list_compressor_models()` without resorting every time (Issue M1 from Swep).
- Make sure `data` directory resolution uses standard pattern `ENTROPYK_DATA` with fallback to `CARGO_MANIFEST_DIR` in debug mode.

### Testing Standards
- 100% test coverage for success paths, missing files, invalid formats, and `vendor_name()`.
- Place tests in `src/compressors/danfoss.rs` in `mod tests` block.

### References

- [Source: epics.md#Story-11.14](file:///Users/sepehr/dev/Entropyk/_bmad-output/planning-artifacts/epics.md)
- [Source: copeland.rs](file:///Users/sepehr/dev/Entropyk/crates/vendors/src/compressors/copeland.rs) - Primary implementation reference for compressors
- [Source: swep.rs](file:///Users/sepehr/dev/Entropyk/crates/vendors/src/heat_exchangers/swep.rs) - Reference for the latest architectural best-practices applied

## Dev Agent Record

### Agent Model Used

Antigravity (Gemini)

### Debug Log References

### Completion Notes List

- Comprehensive story details extracted from Epic 11 analysis and previously corrected Swep implementation.
- Status set to ready-for-dev with BMad-compliant Acceptance Criteria list.
- Implemented `DanfossBackend` mimicking the robust pattern of `CopelandBackend`, and applied architectural fixes from `SwepBackend` (idomatic error logging, sorting `list_compressor_models`).
- Created Danfoss JSON data files: `index.json`, `SH090-4.json`, `SH140-4.json`.
- Integrated `danfoss` module into the vendors crate and re-exported `DanfossBackend` inside `lib.rs`.
- Added unit tests mimicking Copeland coverage. Ran `cargo test` and `cargo clippy` to achieve zero warnings with all tests passing.
- Advanced story status to `review`.
- Code review findings addressed: fixed error swallowing during deserialization, sanitized input to prevent path traversal, added `from_path()` test coverage, and tightened test assertions. Deferred code duplication cleanup.
- Advanced story status from `review` to `done`.

### File List

- `crates/vendors/data/danfoss/compressors/index.json` (created)
- `crates/vendors/data/danfoss/compressors/SH090-4.json` (created)
- `crates/vendors/data/danfoss/compressors/SH140-4.json` (created)
- `crates/vendors/src/compressors/danfoss.rs` (created)
- `crates/vendors/src/compressors/mod.rs` (modified)
- `crates/vendors/src/lib.rs` (modified)
