From c0c903216db9ffe68fb48e8e0eadd3353d596b93 Mon Sep 17 00:00:00 2001 From: isilna Date: Tue, 6 Oct 2026 15:25:36 +0000 Subject: [PATCH 1/2] v0.1.3: violations for drone/fighter bay, cargo and fighter tubes (contract 1.4.7) Resource-bar overloads Pyfa shows as red bars are now reported in violations[]: DRONE_BAY, FIGHTER_BAY, CARGO_OVERLOAD, FIGHTER_TUBES (total + light/support/heavy classes). Gate hashes updated for the intended output change. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- ci/round1-base.sha256 | 2 +- ci/round1.sha256 | 2 +- contract/CONTRACT.md | 7 ++++++- crates/exfa-core/src/stats.rs | 27 +++++++++++++++++++++++++-- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a34f3f..cdc680e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ dependencies = [ [[package]] name = "exfa-cli" -version = "0.1.2" +version = "0.1.3" dependencies = [ "exfa-core", "exfa-formats", @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "exfa-codegen" -version = "0.1.2" +version = "0.1.3" dependencies = [ "flate2", "serde_json", @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "exfa-core" -version = "0.1.2" +version = "0.1.3" dependencies = [ "exfa-codegen", "flate2", @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "exfa-formats" -version = "0.1.2" +version = "0.1.3" dependencies = [ "exfa-core", "serde_json", @@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "exfa-formats-wasm" -version = "0.1.2" +version = "0.1.3" dependencies = [ "exfa-formats", "serde_json", @@ -71,7 +71,7 @@ dependencies = [ [[package]] name = "exfa-optimizer" -version = "0.1.2" +version = "0.1.3" dependencies = [ "exfa-core", "serde", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "exfa-wasm" -version = "0.1.2" +version = "0.1.3" dependencies = [ "exfa-core", "exfa-optimizer", diff --git a/Cargo.toml b/Cargo.toml index a13ac65..850c5f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ default-members = [ ] [workspace.package] -version = "0.1.2" +version = "0.1.3" edition = "2021" license = "LGPL-3.0-or-later" repository = "https://github.com/EX-CT/EXFA-Engine" diff --git a/ci/round1-base.sha256 b/ci/round1-base.sha256 index a250b76..ff054f0 100644 --- a/ci/round1-base.sha256 +++ b/ci/round1-base.sha256 @@ -1 +1 @@ -0a5a98a58365583019c389dc641b7bb41c89975db2e49457234515187e7be353 +a08138f0a08aefdffbe51799fcd11e21f46b01a37819ca69f775d8d0e304d8e0 diff --git a/ci/round1.sha256 b/ci/round1.sha256 index 87f4b29..6caf090 100644 --- a/ci/round1.sha256 +++ b/ci/round1.sha256 @@ -1 +1 @@ -d5bd8a282b17ed6a7e3afbe052d6c62752a7242750264f22b42f62689b12be33 +3b748e84f5679b4715863ed5e3ffc7b6bb99b33752d7dc308752516fda9894a2 diff --git a/contract/CONTRACT.md b/contract/CONTRACT.md index b582ce5..96f332f 100644 --- a/contract/CONTRACT.md +++ b/contract/CONTRACT.md @@ -1,4 +1,4 @@ -# eve-dogma request/response contract (v1, revision 1.4.5) +# eve-dogma request/response contract (v1, revision 1.4.7) Stateless: **one JSON `FitRequest` in → one JSON `FitStats` out.** No hidden state, no clocks, no network. The same request with the same dataset must give byte-identical output. Unknown request fields are ignored. @@ -273,6 +273,9 @@ Existing FitStats fields, now scored against Pyfa (oracle `ORACLE_EXTRA=profile, capacity / chargeSize / chargeGroup1–4 → CHARGE_CAPACITY / CHARGE_SIZE / CHARGE_GROUP (each checked on its own); `checkRequirements` → MISSING_SKILL. A fit with violations is still computed in full ("Disable Fitting Restrictions", ENG-VAL-005): the `val_*` cases also score every bench metric. Cases `val_*`. + Engine-side additions (Pyfa shows these only as red resource bars, not fit problems): drone bay / fighter bay / + cargo volume over capacity → DRONE_BAY / FIGHTER_BAY / CARGO_OVERLOAD; fighter squads over the ship's tubes + (total and per light/support/heavy class) → FIGHTER_TUBES. These fire in addition to the mapped set. - Draft (reported, not part of pass): per-module codes carry the `module_index` of **every** module that breaks the rule (Pyfa flags all modules of an over-limit group, not just the ones past the limit); SLOTS_EXCEEDED may carry `slot`; MISSING_SKILL is one entry per missing skill with `skill_type_id` and `level`, following Pyfa @@ -369,3 +372,5 @@ case's `_fields` param lists the fields it scores). previously warning-side-channel corrections now silent. `type` RPC gains `allowed_states` (additive) for edit-time constraints. `warnings[]` remains for genuine gaps (missing skills, unsupported projected kinds, unknown warfare buff ids, `nothing to optimize`). +- v1.4.7 (2026-10-06, applies on top of 1.4.6): `violations[]` gains DRONE_BAY, FIGHTER_BAY, CARGO_OVERLOAD and + FIGHTER_TUBES for resource-bar overloads (Pyfa shows these as red bars, not fit problems). diff --git a/crates/exfa-core/src/stats.rs b/crates/exfa-core/src/stats.rs index a614fee..0910086 100644 --- a/crates/exfa-core/src/stats.rs +++ b/crates/exfa-core/src/stats.rs @@ -1131,7 +1131,10 @@ impl Fit { out.push_kv("bombing".into(), bombing); out.push_kv("modules".into(), J::A(module_rows)); if req.options.validate { - out.push_kv("violations".into(), J::A(self.validate(cpu_used, pg_used, calib_used, bw_used))); + out.push_kv("violations".into(), J::A(self.validate( + cpu_used, pg_used, calib_used, bw_used, bay_used, fbay_used, cargo_used, + [tubes_used as f64, class_used("light"), class_used("support"), class_used("heavy")], + ))); } if !self.warnings.is_empty() { out.push_kv("warnings".into(), jv!(self.warnings.clone())); @@ -1184,7 +1187,7 @@ impl Fit { J::O(m) } - fn validate(&self, cpu: f64, pg: f64, calib: f64, bw: f64) -> Vec { + fn validate(&self, cpu: f64, pg: f64, calib: f64, bw: f64, bay: f64, fbay: f64, cargo: f64, tubes: [f64; 4]) -> Vec { let ship = self.ship; let g = |i: usize, x: u16| self.get(i, x); let mut v = Vec::new(); @@ -1201,6 +1204,26 @@ impl Fit { if bw > g(ship, a::droneBandwidth) + 1e-9 { push("DRONE_BANDWIDTH", format!("Drone bandwidth used {bw} > {}", g(ship, a::droneBandwidth)), None); } + if bay > g(ship, a::droneCapacity) + 1e-9 { + push("DRONE_BAY", format!("Drone bay used {bay:.1} m3 > capacity {:.1}", g(ship, a::droneCapacity)), None); + } + if fbay > g(ship, a::fighterCapacity) + 1e-9 { + push("FIGHTER_BAY", format!("Fighter bay used {fbay:.1} m3 > capacity {:.1}", g(ship, a::fighterCapacity)), None); + } + if cargo > g(ship, a::capacity) + 1e-9 { + push("CARGO_OVERLOAD", format!("Cargo used {cargo:.1} m3 > capacity {:.1}", g(ship, a::capacity)), None); + } + for (u, attr, label) in [ + (tubes[0], a::fighterTubes, "fighter"), + (tubes[1], a::fighterLightSlots, "light fighter"), + (tubes[2], a::fighterSupportSlots, "support fighter"), + (tubes[3], a::fighterHeavySlots, "heavy fighter"), + ] { + let lim = g(ship, attr); + if u > lim + 1e-9 { + push("FIGHTER_TUBES", format!("{label} squads {u} > tubes {lim}"), None); + } + } let modules: Vec = (0..self.items.len()).filter(|&i| self.items[i].kind == Kind::Module).collect(); for (slot, attr) in [ (Slot::High, a::hiSlots), From 64b988d9563e08fbaa91acfb4e8b0b4d7c07b210 Mon Sep 17 00:00:00 2001 From: isilna Date: Tue, 6 Oct 2026 15:32:16 +0000 Subject: [PATCH 2/2] round1 gates: rebuild hashes against 0.1.3 (engine version string in output) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- ci/round1-base.sha256 | 2 +- ci/round1.sha256 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/round1-base.sha256 b/ci/round1-base.sha256 index ff054f0..0a8432a 100644 --- a/ci/round1-base.sha256 +++ b/ci/round1-base.sha256 @@ -1 +1 @@ -a08138f0a08aefdffbe51799fcd11e21f46b01a37819ca69f775d8d0e304d8e0 +15a7de5171113377fadf902d16fd6470f73431a4a03c7ab7943cc08f87eb7fe2 diff --git a/ci/round1.sha256 b/ci/round1.sha256 index 6caf090..6daebf0 100644 --- a/ci/round1.sha256 +++ b/ci/round1.sha256 @@ -1 +1 @@ -3b748e84f5679b4715863ed5e3ffc7b6bb99b33752d7dc308752516fda9894a2 +2142f097d8c37d25ff094c1e436c687fd20d6ce797b37bdfabd4916b8e3a6b9c