Skip to main content

automapper_validation/generated/fv2504/
utilmd_strom_conditions_fv2504.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2504/UTILMD_AHB_Strom_2_1_Fehlerkorrektur_20250623.xml
4// Generated: 2026-03-12T10:15:42Z
5// </auto-generated>
6
7// LLM-produced bodies aren't idiomatic Rust — silence stylistic lints at
8// file scope so `cargo clippy -D warnings` stays green. Correctness,
9// suspicious, and perf categories stay on so real bugs still surface.
10#![allow(clippy::style, clippy::complexity)]
11
12#[allow(unused_imports)]
13use crate::eval::format_validators::*;
14use crate::eval::{Cluster, ConditionEvaluator, ConditionResult, EvaluationContext};
15// HAND-EDITED: shared cluster helpers for conditions [359]/[360]/[366]/[368].
16// Preserve across regeneration — see CLAUDE.md "Codelist Providers".
17use crate::eval::ebd_cluster::{all_sts_e01_in_cluster, ebd_ablehnung_except};
18
19/// Generated condition evaluator for UTILMD_Strom FV2504.
20pub struct UtilmdStromConditionEvaluatorFV2504 {
21    // External condition IDs that require runtime context.
22    external_conditions: std::collections::HashSet<u32>,
23}
24
25impl Default for UtilmdStromConditionEvaluatorFV2504 {
26    fn default() -> Self {
27        let mut external_conditions = std::collections::HashSet::new();
28        external_conditions.insert(1);
29        external_conditions.insert(4);
30        external_conditions.insert(5);
31        external_conditions.insert(6);
32        external_conditions.insert(8);
33        external_conditions.insert(9);
34        external_conditions.insert(14);
35        external_conditions.insert(31);
36        external_conditions.insert(33);
37        external_conditions.insert(36);
38        external_conditions.insert(38);
39        external_conditions.insert(39);
40        external_conditions.insert(40);
41        external_conditions.insert(75);
42        external_conditions.insert(98);
43        external_conditions.insert(99);
44        external_conditions.insert(151);
45        external_conditions.insert(233);
46        external_conditions.insert(241);
47        external_conditions.insert(251);
48        external_conditions.insert(292);
49        external_conditions.insert(314);
50        external_conditions.insert(315);
51        external_conditions.insert(323);
52        external_conditions.insert(412);
53        external_conditions.insert(425);
54        external_conditions.insert(426);
55        external_conditions.insert(427);
56        external_conditions.insert(428);
57        external_conditions.insert(429);
58        external_conditions.insert(433);
59        external_conditions.insert(435);
60        external_conditions.insert(453);
61        external_conditions.insert(459);
62        external_conditions.insert(460);
63        external_conditions.insert(706);
64        external_conditions.insert(717);
65        external_conditions.insert(2011);
66        Self {
67            external_conditions,
68        }
69    }
70}
71
72impl ConditionEvaluator for UtilmdStromConditionEvaluatorFV2504 {
73    fn message_type(&self) -> &str {
74        "UTILMD_Strom"
75    }
76
77    fn format_version(&self) -> &str {
78        "FV2504"
79    }
80
81    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
82        match condition {
83            1 => self.evaluate_1(ctx),
84            4 => self.evaluate_4(ctx),
85            5 => self.evaluate_5(ctx),
86            6 => self.evaluate_6(ctx),
87            7 => self.evaluate_7(ctx),
88            8 => self.evaluate_8(ctx),
89            9 => self.evaluate_9(ctx),
90            10 => self.evaluate_10(ctx),
91            11 => self.evaluate_11(ctx),
92            12 => self.evaluate_12(ctx),
93            13 => self.evaluate_13(ctx),
94            14 => self.evaluate_14(ctx),
95            15 => self.evaluate_15(ctx),
96            16 => self.evaluate_16(ctx),
97            17 => self.evaluate_17(ctx),
98            18 => self.evaluate_18(ctx),
99            19 => self.evaluate_19(ctx),
100            20 => self.evaluate_20(ctx),
101            21 => self.evaluate_21(ctx),
102            22 => self.evaluate_22(ctx),
103            23 => self.evaluate_23(ctx),
104            24 => self.evaluate_24(ctx),
105            25 => self.evaluate_25(ctx),
106            27 => self.evaluate_27(ctx),
107            30 => self.evaluate_30(ctx),
108            31 => self.evaluate_31(ctx),
109            32 => self.evaluate_32(ctx),
110            33 => self.evaluate_33(ctx),
111            34 => self.evaluate_34(ctx),
112            35 => self.evaluate_35(ctx),
113            36 => self.evaluate_36(ctx),
114            37 => self.evaluate_37(ctx),
115            38 => self.evaluate_38(ctx),
116            39 => self.evaluate_39(ctx),
117            40 => self.evaluate_40(ctx),
118            41 => self.evaluate_41(ctx),
119            42 => self.evaluate_42(ctx),
120            43 => self.evaluate_43(ctx),
121            44 => self.evaluate_44(ctx),
122            45 => self.evaluate_45(ctx),
123            46 => self.evaluate_46(ctx),
124            47 => self.evaluate_47(ctx),
125            48 => self.evaluate_48(ctx),
126            49 => self.evaluate_49(ctx),
127            50 => self.evaluate_50(ctx),
128            51 => self.evaluate_51(ctx),
129            52 => self.evaluate_52(ctx),
130            53 => self.evaluate_53(ctx),
131            54 => self.evaluate_54(ctx),
132            55 => self.evaluate_55(ctx),
133            56 => self.evaluate_56(ctx),
134            57 => self.evaluate_57(ctx),
135            58 => self.evaluate_58(ctx),
136            60 => self.evaluate_60(ctx),
137            61 => self.evaluate_61(ctx),
138            62 => self.evaluate_62(ctx),
139            63 => self.evaluate_63(ctx),
140            64 => self.evaluate_64(ctx),
141            65 => self.evaluate_65(ctx),
142            66 => self.evaluate_66(ctx),
143            67 => self.evaluate_67(ctx),
144            68 => self.evaluate_68(ctx),
145            69 => self.evaluate_69(ctx),
146            70 => self.evaluate_70(ctx),
147            71 => self.evaluate_71(ctx),
148            72 => self.evaluate_72(ctx),
149            73 => self.evaluate_73(ctx),
150            74 => self.evaluate_74(ctx),
151            75 => self.evaluate_75(ctx),
152            76 => self.evaluate_76(ctx),
153            77 => self.evaluate_77(ctx),
154            78 => self.evaluate_78(ctx),
155            83 => self.evaluate_83(ctx),
156            84 => self.evaluate_84(ctx),
157            85 => self.evaluate_85(ctx),
158            86 => self.evaluate_86(ctx),
159            87 => self.evaluate_87(ctx),
160            88 => self.evaluate_88(ctx),
161            89 => self.evaluate_89(ctx),
162            90 => self.evaluate_90(ctx),
163            91 => self.evaluate_91(ctx),
164            92 => self.evaluate_92(ctx),
165            93 => self.evaluate_93(ctx),
166            94 => self.evaluate_94(ctx),
167            95 => self.evaluate_95(ctx),
168            96 => self.evaluate_96(ctx),
169            97 => self.evaluate_97(ctx),
170            98 => self.evaluate_98(ctx),
171            99 => self.evaluate_99(ctx),
172            100 => self.evaluate_100(ctx),
173            101 => self.evaluate_101(ctx),
174            102 => self.evaluate_102(ctx),
175            103 => self.evaluate_103(ctx),
176            104 => self.evaluate_104(ctx),
177            105 => self.evaluate_105(ctx),
178            106 => self.evaluate_106(ctx),
179            107 => self.evaluate_107(ctx),
180            108 => self.evaluate_108(ctx),
181            110 => self.evaluate_110(ctx),
182            111 => self.evaluate_111(ctx),
183            112 => self.evaluate_112(ctx),
184            113 => self.evaluate_113(ctx),
185            114 => self.evaluate_114(ctx),
186            115 => self.evaluate_115(ctx),
187            116 => self.evaluate_116(ctx),
188            117 => self.evaluate_117(ctx),
189            118 => self.evaluate_118(ctx),
190            119 => self.evaluate_119(ctx),
191            120 => self.evaluate_120(ctx),
192            121 => self.evaluate_121(ctx),
193            122 => self.evaluate_122(ctx),
194            123 => self.evaluate_123(ctx),
195            124 => self.evaluate_124(ctx),
196            125 => self.evaluate_125(ctx),
197            126 => self.evaluate_126(ctx),
198            127 => self.evaluate_127(ctx),
199            128 => self.evaluate_128(ctx),
200            129 => self.evaluate_129(ctx),
201            130 => self.evaluate_130(ctx),
202            131 => self.evaluate_131(ctx),
203            132 => self.evaluate_132(ctx),
204            133 => self.evaluate_133(ctx),
205            134 => self.evaluate_134(ctx),
206            135 => self.evaluate_135(ctx),
207            136 => self.evaluate_136(ctx),
208            137 => self.evaluate_137(ctx),
209            138 => self.evaluate_138(ctx),
210            139 => self.evaluate_139(ctx),
211            140 => self.evaluate_140(ctx),
212            141 => self.evaluate_141(ctx),
213            142 => self.evaluate_142(ctx),
214            143 => self.evaluate_143(ctx),
215            144 => self.evaluate_144(ctx),
216            145 => self.evaluate_145(ctx),
217            146 => self.evaluate_146(ctx),
218            147 => self.evaluate_147(ctx),
219            148 => self.evaluate_148(ctx),
220            149 => self.evaluate_149(ctx),
221            150 => self.evaluate_150(ctx),
222            151 => self.evaluate_151(ctx),
223            152 => self.evaluate_152(ctx),
224            153 => self.evaluate_153(ctx),
225            156 => self.evaluate_156(ctx),
226            161 => self.evaluate_161(ctx),
227            162 => self.evaluate_162(ctx),
228            163 => self.evaluate_163(ctx),
229            164 => self.evaluate_164(ctx),
230            165 => self.evaluate_165(ctx),
231            166 => self.evaluate_166(ctx),
232            167 => self.evaluate_167(ctx),
233            170 => self.evaluate_170(ctx),
234            172 => self.evaluate_172(ctx),
235            173 => self.evaluate_173(ctx),
236            174 => self.evaluate_174(ctx),
237            175 => self.evaluate_175(ctx),
238            176 => self.evaluate_176(ctx),
239            177 => self.evaluate_177(ctx),
240            178 => self.evaluate_178(ctx),
241            179 => self.evaluate_179(ctx),
242            180 => self.evaluate_180(ctx),
243            184 => self.evaluate_184(ctx),
244            190 => self.evaluate_190(ctx),
245            191 => self.evaluate_191(ctx),
246            192 => self.evaluate_192(ctx),
247            193 => self.evaluate_193(ctx),
248            194 => self.evaluate_194(ctx),
249            195 => self.evaluate_195(ctx),
250            196 => self.evaluate_196(ctx),
251            197 => self.evaluate_197(ctx),
252            198 => self.evaluate_198(ctx),
253            199 => self.evaluate_199(ctx),
254            201 => self.evaluate_201(ctx),
255            202 => self.evaluate_202(ctx),
256            203 => self.evaluate_203(ctx),
257            204 => self.evaluate_204(ctx),
258            205 => self.evaluate_205(ctx),
259            206 => self.evaluate_206(ctx),
260            209 => self.evaluate_209(ctx),
261            210 => self.evaluate_210(ctx),
262            212 => self.evaluate_212(ctx),
263            213 => self.evaluate_213(ctx),
264            215 => self.evaluate_215(ctx),
265            216 => self.evaluate_216(ctx),
266            217 => self.evaluate_217(ctx),
267            219 => self.evaluate_219(ctx),
268            220 => self.evaluate_220(ctx),
269            221 => self.evaluate_221(ctx),
270            223 => self.evaluate_223(ctx),
271            224 => self.evaluate_224(ctx),
272            227 => self.evaluate_227(ctx),
273            229 => self.evaluate_229(ctx),
274            232 => self.evaluate_232(ctx),
275            233 => self.evaluate_233(ctx),
276            234 => self.evaluate_234(ctx),
277            237 => self.evaluate_237(ctx),
278            238 => self.evaluate_238(ctx),
279            239 => self.evaluate_239(ctx),
280            240 => self.evaluate_240(ctx),
281            241 => self.evaluate_241(ctx),
282            243 => self.evaluate_243(ctx),
283            244 => self.evaluate_244(ctx),
284            248 => self.evaluate_248(ctx),
285            249 => self.evaluate_249(ctx),
286            251 => self.evaluate_251(ctx),
287            252 => self.evaluate_252(ctx),
288            254 => self.evaluate_254(ctx),
289            255 => self.evaluate_255(ctx),
290            256 => self.evaluate_256(ctx),
291            257 => self.evaluate_257(ctx),
292            259 => self.evaluate_259(ctx),
293            261 => self.evaluate_261(ctx),
294            262 => self.evaluate_262(ctx),
295            265 => self.evaluate_265(ctx),
296            266 => self.evaluate_266(ctx),
297            267 => self.evaluate_267(ctx),
298            268 => self.evaluate_268(ctx),
299            269 => self.evaluate_269(ctx),
300            270 => self.evaluate_270(ctx),
301            273 => self.evaluate_273(ctx),
302            279 => self.evaluate_279(ctx),
303            280 => self.evaluate_280(ctx),
304            282 => self.evaluate_282(ctx),
305            284 => self.evaluate_284(ctx),
306            285 => self.evaluate_285(ctx),
307            286 => self.evaluate_286(ctx),
308            287 => self.evaluate_287(ctx),
309            288 => self.evaluate_288(ctx),
310            291 => self.evaluate_291(ctx),
311            292 => self.evaluate_292(ctx),
312            293 => self.evaluate_293(ctx),
313            294 => self.evaluate_294(ctx),
314            295 => self.evaluate_295(ctx),
315            296 => self.evaluate_296(ctx),
316            297 => self.evaluate_297(ctx),
317            298 => self.evaluate_298(ctx),
318            299 => self.evaluate_299(ctx),
319            300 => self.evaluate_300(ctx),
320            301 => self.evaluate_301(ctx),
321            302 => self.evaluate_302(ctx),
322            303 => self.evaluate_303(ctx),
323            304 => self.evaluate_304(ctx),
324            305 => self.evaluate_305(ctx),
325            306 => self.evaluate_306(ctx),
326            307 => self.evaluate_307(ctx),
327            309 => self.evaluate_309(ctx),
328            314 => self.evaluate_314(ctx),
329            315 => self.evaluate_315(ctx),
330            316 => self.evaluate_316(ctx),
331            317 => self.evaluate_317(ctx),
332            318 => self.evaluate_318(ctx),
333            321 => self.evaluate_321(ctx),
334            322 => self.evaluate_322(ctx),
335            323 => self.evaluate_323(ctx),
336            327 => self.evaluate_327(ctx),
337            329 => self.evaluate_329(ctx),
338            331 => self.evaluate_331(ctx),
339            332 => self.evaluate_332(ctx),
340            333 => self.evaluate_333(ctx),
341            334 => self.evaluate_334(ctx),
342            335 => self.evaluate_335(ctx),
343            336 => self.evaluate_336(ctx),
344            337 => self.evaluate_337(ctx),
345            338 => self.evaluate_338(ctx),
346            339 => self.evaluate_339(ctx),
347            340 => self.evaluate_340(ctx),
348            341 => self.evaluate_341(ctx),
349            342 => self.evaluate_342(ctx),
350            344 => self.evaluate_344(ctx),
351            345 => self.evaluate_345(ctx),
352            346 => self.evaluate_346(ctx),
353            347 => self.evaluate_347(ctx),
354            348 => self.evaluate_348(ctx),
355            349 => self.evaluate_349(ctx),
356            350 => self.evaluate_350(ctx),
357            351 => self.evaluate_351(ctx),
358            352 => self.evaluate_352(ctx),
359            355 => self.evaluate_355(ctx),
360            356 => self.evaluate_356(ctx),
361            357 => self.evaluate_357(ctx),
362            358 => self.evaluate_358(ctx),
363            359 => self.evaluate_359(ctx),
364            360 => self.evaluate_360(ctx),
365            363 => self.evaluate_363(ctx),
366            365 => self.evaluate_365(ctx),
367            366 => self.evaluate_366(ctx),
368            367 => self.evaluate_367(ctx),
369            368 => self.evaluate_368(ctx),
370            370 => self.evaluate_370(ctx),
371            371 => self.evaluate_371(ctx),
372            372 => self.evaluate_372(ctx),
373            373 => self.evaluate_373(ctx),
374            375 => self.evaluate_375(ctx),
375            376 => self.evaluate_376(ctx),
376            377 => self.evaluate_377(ctx),
377            378 => self.evaluate_378(ctx),
378            379 => self.evaluate_379(ctx),
379            380 => self.evaluate_380(ctx),
380            384 => self.evaluate_384(ctx),
381            386 => self.evaluate_386(ctx),
382            387 => self.evaluate_387(ctx),
383            388 => self.evaluate_388(ctx),
384            391 => self.evaluate_391(ctx),
385            392 => self.evaluate_392(ctx),
386            393 => self.evaluate_393(ctx),
387            394 => self.evaluate_394(ctx),
388            395 => self.evaluate_395(ctx),
389            396 => self.evaluate_396(ctx),
390            397 => self.evaluate_397(ctx),
391            398 => self.evaluate_398(ctx),
392            399 => self.evaluate_399(ctx),
393            401 => self.evaluate_401(ctx),
394            402 => self.evaluate_402(ctx),
395            403 => self.evaluate_403(ctx),
396            404 => self.evaluate_404(ctx),
397            405 => self.evaluate_405(ctx),
398            406 => self.evaluate_406(ctx),
399            407 => self.evaluate_407(ctx),
400            408 => self.evaluate_408(ctx),
401            409 => self.evaluate_409(ctx),
402            410 => self.evaluate_410(ctx),
403            411 => self.evaluate_411(ctx),
404            412 => self.evaluate_412(ctx),
405            413 => self.evaluate_413(ctx),
406            414 => self.evaluate_414(ctx),
407            415 => self.evaluate_415(ctx),
408            416 => self.evaluate_416(ctx),
409            417 => self.evaluate_417(ctx),
410            419 => self.evaluate_419(ctx),
411            420 => self.evaluate_420(ctx),
412            421 => self.evaluate_421(ctx),
413            425 => self.evaluate_425(ctx),
414            426 => self.evaluate_426(ctx),
415            427 => self.evaluate_427(ctx),
416            428 => self.evaluate_428(ctx),
417            429 => self.evaluate_429(ctx),
418            430 => self.evaluate_430(ctx),
419            431 => self.evaluate_431(ctx),
420            432 => self.evaluate_432(ctx),
421            433 => self.evaluate_433(ctx),
422            435 => self.evaluate_435(ctx),
423            436 => self.evaluate_436(ctx),
424            437 => self.evaluate_437(ctx),
425            438 => self.evaluate_438(ctx),
426            440 => self.evaluate_440(ctx),
427            441 => self.evaluate_441(ctx),
428            442 => self.evaluate_442(ctx),
429            444 => self.evaluate_444(ctx),
430            445 => self.evaluate_445(ctx),
431            446 => self.evaluate_446(ctx),
432            447 => self.evaluate_447(ctx),
433            448 => self.evaluate_448(ctx),
434            449 => self.evaluate_449(ctx),
435            450 => self.evaluate_450(ctx),
436            451 => self.evaluate_451(ctx),
437            452 => self.evaluate_452(ctx),
438            453 => self.evaluate_453(ctx),
439            454 => self.evaluate_454(ctx),
440            455 => self.evaluate_455(ctx),
441            456 => self.evaluate_456(ctx),
442            457 => self.evaluate_457(ctx),
443            458 => self.evaluate_458(ctx),
444            459 => self.evaluate_459(ctx),
445            460 => self.evaluate_460(ctx),
446            461 => self.evaluate_461(ctx),
447            462 => self.evaluate_462(ctx),
448            463 => self.evaluate_463(ctx),
449            465 => self.evaluate_465(ctx),
450            466 => self.evaluate_466(ctx),
451            467 => self.evaluate_467(ctx),
452            468 => self.evaluate_468(ctx),
453            469 => self.evaluate_469(ctx),
454            470 => self.evaluate_470(ctx),
455            471 => self.evaluate_471(ctx),
456            472 => self.evaluate_472(ctx),
457            473 => self.evaluate_473(ctx),
458            474 => self.evaluate_474(ctx),
459            475 => self.evaluate_475(ctx),
460            476 => self.evaluate_476(ctx),
461            477 => self.evaluate_477(ctx),
462            478 => self.evaluate_478(ctx),
463            479 => self.evaluate_479(ctx),
464            480 => self.evaluate_480(ctx),
465            481 => self.evaluate_481(ctx),
466            483 => self.evaluate_483(ctx),
467            484 => self.evaluate_484(ctx),
468            487 => self.evaluate_487(ctx),
469            489 => self.evaluate_489(ctx),
470            490 => self.evaluate_490(ctx),
471            491 => self.evaluate_491(ctx),
472            494 => self.evaluate_494(ctx),
473            500 => self.evaluate_500(ctx),
474            501 => self.evaluate_501(ctx),
475            502 => self.evaluate_502(ctx),
476            503 => self.evaluate_503(ctx),
477            504 => self.evaluate_504(ctx),
478            505 => self.evaluate_505(ctx),
479            506 => self.evaluate_506(ctx),
480            507 => self.evaluate_507(ctx),
481            508 => self.evaluate_508(ctx),
482            509 => self.evaluate_509(ctx),
483            510 => self.evaluate_510(ctx),
484            511 => self.evaluate_511(ctx),
485            512 => self.evaluate_512(ctx),
486            513 => self.evaluate_513(ctx),
487            514 => self.evaluate_514(ctx),
488            515 => self.evaluate_515(ctx),
489            516 => self.evaluate_516(ctx),
490            517 => self.evaluate_517(ctx),
491            518 => self.evaluate_518(ctx),
492            519 => self.evaluate_519(ctx),
493            520 => self.evaluate_520(ctx),
494            521 => self.evaluate_521(ctx),
495            522 => self.evaluate_522(ctx),
496            523 => self.evaluate_523(ctx),
497            524 => self.evaluate_524(ctx),
498            525 => self.evaluate_525(ctx),
499            526 => self.evaluate_526(ctx),
500            527 => self.evaluate_527(ctx),
501            528 => self.evaluate_528(ctx),
502            529 => self.evaluate_529(ctx),
503            530 => self.evaluate_530(ctx),
504            531 => self.evaluate_531(ctx),
505            532 => self.evaluate_532(ctx),
506            533 => self.evaluate_533(ctx),
507            555 => self.evaluate_555(ctx),
508            556 => self.evaluate_556(ctx),
509            558 => self.evaluate_558(ctx),
510            559 => self.evaluate_559(ctx),
511            563 => self.evaluate_563(ctx),
512            566 => self.evaluate_566(ctx),
513            567 => self.evaluate_567(ctx),
514            568 => self.evaluate_568(ctx),
515            569 => self.evaluate_569(ctx),
516            570 => self.evaluate_570(ctx),
517            572 => self.evaluate_572(ctx),
518            576 => self.evaluate_576(ctx),
519            577 => self.evaluate_577(ctx),
520            579 => self.evaluate_579(ctx),
521            580 => self.evaluate_580(ctx),
522            581 => self.evaluate_581(ctx),
523            586 => self.evaluate_586(ctx),
524            590 => self.evaluate_590(ctx),
525            594 => self.evaluate_594(ctx),
526            599 => self.evaluate_599(ctx),
527            601 => self.evaluate_601(ctx),
528            606 => self.evaluate_606(ctx),
529            609 => self.evaluate_609(ctx),
530            611 => self.evaluate_611(ctx),
531            614 => self.evaluate_614(ctx),
532            617 => self.evaluate_617(ctx),
533            618 => self.evaluate_618(ctx),
534            619 => self.evaluate_619(ctx),
535            621 => self.evaluate_621(ctx),
536            622 => self.evaluate_622(ctx),
537            623 => self.evaluate_623(ctx),
538            630 => self.evaluate_630(ctx),
539            631 => self.evaluate_631(ctx),
540            632 => self.evaluate_632(ctx),
541            637 => self.evaluate_637(ctx),
542            638 => self.evaluate_638(ctx),
543            639 => self.evaluate_639(ctx),
544            640 => self.evaluate_640(ctx),
545            641 => self.evaluate_641(ctx),
546            642 => self.evaluate_642(ctx),
547            643 => self.evaluate_643(ctx),
548            645 => self.evaluate_645(ctx),
549            646 => self.evaluate_646(ctx),
550            647 => self.evaluate_647(ctx),
551            648 => self.evaluate_648(ctx),
552            651 => self.evaluate_651(ctx),
553            653 => self.evaluate_653(ctx),
554            655 => self.evaluate_655(ctx),
555            659 => self.evaluate_659(ctx),
556            660 => self.evaluate_660(ctx),
557            662 => self.evaluate_662(ctx),
558            663 => self.evaluate_663(ctx),
559            664 => self.evaluate_664(ctx),
560            665 => self.evaluate_665(ctx),
561            667 => self.evaluate_667(ctx),
562            668 => self.evaluate_668(ctx),
563            670 => self.evaluate_670(ctx),
564            671 => self.evaluate_671(ctx),
565            672 => self.evaluate_672(ctx),
566            673 => self.evaluate_673(ctx),
567            674 => self.evaluate_674(ctx),
568            675 => self.evaluate_675(ctx),
569            677 => self.evaluate_677(ctx),
570            678 => self.evaluate_678(ctx),
571            679 => self.evaluate_679(ctx),
572            680 => self.evaluate_680(ctx),
573            682 => self.evaluate_682(ctx),
574            683 => self.evaluate_683(ctx),
575            684 => self.evaluate_684(ctx),
576            685 => self.evaluate_685(ctx),
577            687 => self.evaluate_687(ctx),
578            688 => self.evaluate_688(ctx),
579            689 => self.evaluate_689(ctx),
580            690 => self.evaluate_690(ctx),
581            693 => self.evaluate_693(ctx),
582            694 => self.evaluate_694(ctx),
583            695 => self.evaluate_695(ctx),
584            696 => self.evaluate_696(ctx),
585            698 => self.evaluate_698(ctx),
586            699 => self.evaluate_699(ctx),
587            700 => self.evaluate_700(ctx),
588            704 => self.evaluate_704(ctx),
589            705 => self.evaluate_705(ctx),
590            706 => self.evaluate_706(ctx),
591            707 => self.evaluate_707(ctx),
592            708 => self.evaluate_708(ctx),
593            709 => self.evaluate_709(ctx),
594            710 => self.evaluate_710(ctx),
595            711 => self.evaluate_711(ctx),
596            712 => self.evaluate_712(ctx),
597            713 => self.evaluate_713(ctx),
598            714 => self.evaluate_714(ctx),
599            715 => self.evaluate_715(ctx),
600            716 => self.evaluate_716(ctx),
601            717 => self.evaluate_717(ctx),
602            718 => self.evaluate_718(ctx),
603            719 => self.evaluate_719(ctx),
604            902 => self.evaluate_902(ctx),
605            910 => self.evaluate_910(ctx),
606            914 => self.evaluate_914(ctx),
607            922 => self.evaluate_922(ctx),
608            926 => self.evaluate_926(ctx),
609            930 => self.evaluate_930(ctx),
610            931 => self.evaluate_931(ctx),
611            932 => self.evaluate_932(ctx),
612            933 => self.evaluate_933(ctx),
613            937 => self.evaluate_937(ctx),
614            938 => self.evaluate_938(ctx),
615            939 => self.evaluate_939(ctx),
616            940 => self.evaluate_940(ctx),
617            942 => self.evaluate_942(ctx),
618            943 => self.evaluate_943(ctx),
619            946 => self.evaluate_946(ctx),
620            948 => self.evaluate_948(ctx),
621            950 => self.evaluate_950(ctx),
622            951 => self.evaluate_951(ctx),
623            952 => self.evaluate_952(ctx),
624            955 => self.evaluate_955(ctx),
625            957 => self.evaluate_957(ctx),
626            960 => self.evaluate_960(ctx),
627            961 => self.evaluate_961(ctx),
628            967 => self.evaluate_967(ctx),
629            2001 => self.evaluate_2001(ctx),
630            2002 => self.evaluate_2002(ctx),
631            2003 => self.evaluate_2003(ctx),
632            2004 => self.evaluate_2004(ctx),
633            2005 => self.evaluate_2005(ctx),
634            2006 => self.evaluate_2006(ctx),
635            2007 => self.evaluate_2007(ctx),
636            2008 => self.evaluate_2008(ctx),
637            2009 => self.evaluate_2009(ctx),
638            2010 => self.evaluate_2010(ctx),
639            2011 => self.evaluate_2011(ctx),
640            2012 => self.evaluate_2012(ctx),
641            2013 => self.evaluate_2013(ctx),
642            2014 => self.evaluate_2014(ctx),
643            2015 => self.evaluate_2015(ctx),
644            2016 => self.evaluate_2016(ctx),
645            2017 => self.evaluate_2017(ctx),
646            2018 => self.evaluate_2018(ctx),
647            2060 => self.evaluate_2060(ctx),
648            2061 => self.evaluate_2061(ctx),
649            2071 => self.evaluate_2071(ctx),
650            2073 => self.evaluate_2073(ctx),
651            2075 => self.evaluate_2075(ctx),
652            2080 => self.evaluate_2080(ctx),
653            2095 => self.evaluate_2095(ctx),
654            2096 => self.evaluate_2096(ctx),
655            2119 => self.evaluate_2119(ctx),
656            2140 => self.evaluate_2140(ctx),
657            2182 => self.evaluate_2182(ctx),
658            2183 => self.evaluate_2183(ctx),
659            2207 => self.evaluate_2207(ctx),
660            2225 => self.evaluate_2225(ctx),
661            2236 => self.evaluate_2236(ctx),
662            2252 => self.evaluate_2252(ctx),
663            2261 => self.evaluate_2261(ctx),
664            2284 => self.evaluate_2284(ctx),
665            2286 => self.evaluate_2286(ctx),
666            2287 => self.evaluate_2287(ctx),
667            2288 => self.evaluate_2288(ctx),
668            2307 => self.evaluate_2307(ctx),
669            2308 => self.evaluate_2308(ctx),
670            2309 => self.evaluate_2309(ctx),
671            2310 => self.evaluate_2310(ctx),
672            2311 => self.evaluate_2311(ctx),
673            2312 => self.evaluate_2312(ctx),
674            2313 => self.evaluate_2313(ctx),
675            2317 => self.evaluate_2317(ctx),
676            2318 => self.evaluate_2318(ctx),
677            2344 => self.evaluate_2344(ctx),
678            2350 => self.evaluate_2350(ctx),
679            2351 => self.evaluate_2351(ctx),
680            2352 => self.evaluate_2352(ctx),
681            2356 => self.evaluate_2356(ctx),
682            2357 => self.evaluate_2357(ctx),
683            2358 => self.evaluate_2358(ctx),
684            2359 => self.evaluate_2359(ctx),
685            2360 => self.evaluate_2360(ctx),
686            2361 => self.evaluate_2361(ctx),
687            _ => ConditionResult::Unknown,
688        }
689    }
690
691    fn is_external(&self, condition: u32) -> bool {
692        self.external_conditions.contains(&condition)
693    }
694    fn is_known(&self, condition: u32) -> bool {
695        matches!(
696            condition,
697            1 | 4
698                | 5
699                | 6
700                | 7
701                | 8
702                | 9
703                | 10
704                | 11
705                | 12
706                | 13
707                | 14
708                | 15
709                | 16
710                | 17
711                | 18
712                | 19
713                | 20
714                | 21
715                | 22
716                | 23
717                | 24
718                | 25
719                | 27
720                | 30
721                | 31
722                | 32
723                | 33
724                | 34
725                | 35
726                | 36
727                | 37
728                | 38
729                | 39
730                | 40
731                | 41
732                | 42
733                | 43
734                | 44
735                | 45
736                | 46
737                | 47
738                | 48
739                | 49
740                | 50
741                | 51
742                | 52
743                | 53
744                | 54
745                | 55
746                | 56
747                | 57
748                | 58
749                | 60
750                | 61
751                | 62
752                | 63
753                | 64
754                | 65
755                | 66
756                | 67
757                | 68
758                | 69
759                | 70
760                | 71
761                | 72
762                | 73
763                | 74
764                | 75
765                | 76
766                | 77
767                | 78
768                | 83
769                | 84
770                | 85
771                | 86
772                | 87
773                | 88
774                | 89
775                | 90
776                | 91
777                | 92
778                | 93
779                | 94
780                | 95
781                | 96
782                | 97
783                | 98
784                | 99
785                | 100
786                | 101
787                | 102
788                | 103
789                | 104
790                | 105
791                | 106
792                | 107
793                | 108
794                | 110
795                | 111
796                | 112
797                | 113
798                | 114
799                | 115
800                | 116
801                | 117
802                | 118
803                | 119
804                | 120
805                | 121
806                | 122
807                | 123
808                | 124
809                | 125
810                | 126
811                | 127
812                | 128
813                | 129
814                | 130
815                | 131
816                | 132
817                | 133
818                | 134
819                | 135
820                | 136
821                | 137
822                | 138
823                | 139
824                | 140
825                | 141
826                | 142
827                | 143
828                | 144
829                | 145
830                | 146
831                | 147
832                | 148
833                | 149
834                | 150
835                | 151
836                | 152
837                | 153
838                | 156
839                | 161
840                | 162
841                | 163
842                | 164
843                | 165
844                | 166
845                | 167
846                | 170
847                | 172
848                | 173
849                | 174
850                | 175
851                | 176
852                | 177
853                | 178
854                | 179
855                | 180
856                | 184
857                | 190
858                | 191
859                | 192
860                | 193
861                | 194
862                | 195
863                | 196
864                | 197
865                | 198
866                | 199
867                | 201
868                | 202
869                | 203
870                | 204
871                | 205
872                | 206
873                | 209
874                | 210
875                | 212
876                | 213
877                | 215
878                | 216
879                | 217
880                | 219
881                | 220
882                | 221
883                | 223
884                | 224
885                | 227
886                | 229
887                | 232
888                | 233
889                | 234
890                | 237
891                | 238
892                | 239
893                | 240
894                | 241
895                | 243
896                | 244
897                | 248
898                | 249
899                | 251
900                | 252
901                | 254
902                | 255
903                | 256
904                | 257
905                | 259
906                | 261
907                | 262
908                | 265
909                | 266
910                | 267
911                | 268
912                | 269
913                | 270
914                | 273
915                | 279
916                | 280
917                | 282
918                | 284
919                | 285
920                | 286
921                | 287
922                | 288
923                | 291
924                | 292
925                | 293
926                | 294
927                | 295
928                | 296
929                | 297
930                | 298
931                | 299
932                | 300
933                | 301
934                | 302
935                | 303
936                | 304
937                | 305
938                | 306
939                | 307
940                | 309
941                | 314
942                | 315
943                | 316
944                | 317
945                | 318
946                | 321
947                | 322
948                | 323
949                | 327
950                | 329
951                | 331
952                | 332
953                | 333
954                | 334
955                | 335
956                | 336
957                | 337
958                | 338
959                | 339
960                | 340
961                | 341
962                | 342
963                | 344
964                | 345
965                | 346
966                | 347
967                | 348
968                | 349
969                | 350
970                | 351
971                | 352
972                | 355
973                | 356
974                | 357
975                | 358
976                | 359
977                | 360
978                | 363
979                | 365
980                | 366
981                | 367
982                | 368
983                | 370
984                | 371
985                | 372
986                | 373
987                | 375
988                | 376
989                | 377
990                | 378
991                | 379
992                | 380
993                | 384
994                | 386
995                | 387
996                | 388
997                | 391
998                | 392
999                | 393
1000                | 394
1001                | 395
1002                | 396
1003                | 397
1004                | 398
1005                | 399
1006                | 401
1007                | 402
1008                | 403
1009                | 404
1010                | 405
1011                | 406
1012                | 407
1013                | 408
1014                | 409
1015                | 410
1016                | 411
1017                | 412
1018                | 413
1019                | 414
1020                | 415
1021                | 416
1022                | 417
1023                | 419
1024                | 420
1025                | 421
1026                | 425
1027                | 426
1028                | 427
1029                | 428
1030                | 429
1031                | 430
1032                | 431
1033                | 432
1034                | 433
1035                | 435
1036                | 436
1037                | 437
1038                | 438
1039                | 440
1040                | 441
1041                | 442
1042                | 444
1043                | 445
1044                | 446
1045                | 447
1046                | 448
1047                | 449
1048                | 450
1049                | 451
1050                | 452
1051                | 453
1052                | 454
1053                | 455
1054                | 456
1055                | 457
1056                | 458
1057                | 459
1058                | 460
1059                | 461
1060                | 462
1061                | 463
1062                | 465
1063                | 466
1064                | 467
1065                | 468
1066                | 469
1067                | 470
1068                | 471
1069                | 472
1070                | 473
1071                | 474
1072                | 475
1073                | 476
1074                | 477
1075                | 478
1076                | 479
1077                | 480
1078                | 481
1079                | 483
1080                | 484
1081                | 487
1082                | 489
1083                | 490
1084                | 491
1085                | 494
1086                | 500
1087                | 501
1088                | 502
1089                | 503
1090                | 504
1091                | 505
1092                | 506
1093                | 507
1094                | 508
1095                | 509
1096                | 510
1097                | 511
1098                | 512
1099                | 513
1100                | 514
1101                | 515
1102                | 516
1103                | 517
1104                | 518
1105                | 519
1106                | 520
1107                | 521
1108                | 522
1109                | 523
1110                | 524
1111                | 525
1112                | 526
1113                | 527
1114                | 528
1115                | 529
1116                | 530
1117                | 531
1118                | 532
1119                | 533
1120                | 555
1121                | 556
1122                | 558
1123                | 559
1124                | 563
1125                | 566
1126                | 567
1127                | 568
1128                | 569
1129                | 570
1130                | 572
1131                | 576
1132                | 577
1133                | 579
1134                | 580
1135                | 581
1136                | 586
1137                | 590
1138                | 594
1139                | 599
1140                | 601
1141                | 606
1142                | 609
1143                | 611
1144                | 614
1145                | 617
1146                | 618
1147                | 619
1148                | 621
1149                | 622
1150                | 623
1151                | 630
1152                | 631
1153                | 632
1154                | 637
1155                | 638
1156                | 639
1157                | 640
1158                | 641
1159                | 642
1160                | 643
1161                | 645
1162                | 646
1163                | 647
1164                | 648
1165                | 651
1166                | 653
1167                | 655
1168                | 659
1169                | 660
1170                | 662
1171                | 663
1172                | 664
1173                | 665
1174                | 667
1175                | 668
1176                | 670
1177                | 671
1178                | 672
1179                | 673
1180                | 674
1181                | 675
1182                | 677
1183                | 678
1184                | 679
1185                | 680
1186                | 682
1187                | 683
1188                | 684
1189                | 685
1190                | 687
1191                | 688
1192                | 689
1193                | 690
1194                | 693
1195                | 694
1196                | 695
1197                | 696
1198                | 698
1199                | 699
1200                | 700
1201                | 704
1202                | 705
1203                | 706
1204                | 707
1205                | 708
1206                | 709
1207                | 710
1208                | 711
1209                | 712
1210                | 713
1211                | 714
1212                | 715
1213                | 716
1214                | 717
1215                | 718
1216                | 719
1217                | 902
1218                | 910
1219                | 914
1220                | 922
1221                | 926
1222                | 930
1223                | 931
1224                | 932
1225                | 933
1226                | 937
1227                | 938
1228                | 939
1229                | 940
1230                | 942
1231                | 943
1232                | 946
1233                | 948
1234                | 950
1235                | 951
1236                | 952
1237                | 955
1238                | 957
1239                | 960
1240                | 961
1241                | 967
1242                | 2001
1243                | 2002
1244                | 2003
1245                | 2004
1246                | 2005
1247                | 2006
1248                | 2007
1249                | 2008
1250                | 2009
1251                | 2010
1252                | 2011
1253                | 2012
1254                | 2013
1255                | 2014
1256                | 2015
1257                | 2016
1258                | 2017
1259                | 2018
1260                | 2060
1261                | 2061
1262                | 2071
1263                | 2073
1264                | 2075
1265                | 2080
1266                | 2095
1267                | 2096
1268                | 2119
1269                | 2140
1270                | 2182
1271                | 2183
1272                | 2207
1273                | 2225
1274                | 2236
1275                | 2252
1276                | 2261
1277                | 2284
1278                | 2286
1279                | 2287
1280                | 2288
1281                | 2307
1282                | 2308
1283                | 2309
1284                | 2310
1285                | 2311
1286                | 2312
1287                | 2313
1288                | 2317
1289                | 2318
1290                | 2344
1291                | 2350
1292                | 2351
1293                | 2352
1294                | 2356
1295                | 2357
1296                | 2358
1297                | 2359
1298                | 2360
1299                | 2361
1300        )
1301    }
1302}
1303
1304impl UtilmdStromConditionEvaluatorFV2504 {
1305    /// [2006] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingung [199] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfolge...
1306    // REVIEW: Counts SG8 instances with SEQ+Z01 where condition [199] is fulfilled and collects their Zeitraum-IDs from SEQ elements[1][0]. Returns True if at least one qualifying parent exists (cardinality enforcement is partial — full 'exactly once' check requires knowing the current SG type). The recursive call self.evaluate(199, ctx) operates at message scope, which is the best available approximation. (medium confidence)
1307    fn evaluate_2006(&self, ctx: &EvaluationContext) -> ConditionResult {
1308        let nav = match ctx.navigator() {
1309            Some(n) => n,
1310            None => return ConditionResult::Unknown,
1311        };
1312        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1313        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1314        for i in 0..sg8_count {
1315            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1316            let is_z01 = seq_segs.iter().any(|s| {
1317                s.elements
1318                    .first()
1319                    .and_then(|e| e.first())
1320                    .is_some_and(|v| v == "Z01")
1321            });
1322            if is_z01 && matches!(self.evaluate(199, ctx), ConditionResult::True) {
1323                for seq in &seq_segs {
1324                    if seq
1325                        .elements
1326                        .first()
1327                        .and_then(|e| e.first())
1328                        .is_some_and(|v| v == "Z01")
1329                    {
1330                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1331                            if !zid.is_empty() {
1332                                qualifying_zeitraum_ids.push(zid.clone());
1333                            }
1334                        }
1335                    }
1336                }
1337            }
1338        }
1339        if qualifying_zeitraum_ids.is_empty() {
1340            return ConditionResult::Unknown;
1341        }
1342        ConditionResult::True
1343    }
1344
1345    /// [2007] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [199] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfol...
1346    // REVIEW: Semantically identical to [2006] — 'Bedingungen' (plural) vs 'Bedingung' (singular) is a grammatical variation with no functional difference. Same logic: collects qualifying SG8 SEQ+Z01 Zeitraum-IDs where condition [199] is fulfilled. Recursive call self.evaluate(199, ctx) operates at message scope. (medium confidence)
1347    fn evaluate_2007(&self, ctx: &EvaluationContext) -> ConditionResult {
1348        let nav = match ctx.navigator() {
1349            Some(n) => n,
1350            None => return ConditionResult::Unknown,
1351        };
1352        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1353        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1354        for i in 0..sg8_count {
1355            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1356            let is_z01 = seq_segs.iter().any(|s| {
1357                s.elements
1358                    .first()
1359                    .and_then(|e| e.first())
1360                    .is_some_and(|v| v == "Z01")
1361            });
1362            if is_z01 && matches!(self.evaluate(199, ctx), ConditionResult::True) {
1363                for seq in &seq_segs {
1364                    if seq
1365                        .elements
1366                        .first()
1367                        .and_then(|e| e.first())
1368                        .is_some_and(|v| v == "Z01")
1369                    {
1370                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1371                            if !zid.is_empty() {
1372                                qualifying_zeitraum_ids.push(zid.clone());
1373                            }
1374                        }
1375                    }
1376                }
1377            }
1378        }
1379        if qualifying_zeitraum_ids.is_empty() {
1380            return ConditionResult::Unknown;
1381        }
1382        ConditionResult::True
1383    }
1384
1385    /// [2008] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingung [89] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfolgen...
1386    // REVIEW: Same structure as [2006/2007] but references condition [89] instead of [199]. Counts qualifying SG8 SEQ+Z01 instances where condition [89] is fulfilled and collects their Zeitraum-IDs from SEQ elements[1][0]. The recursive self.evaluate(89, ctx) call operates at message scope. (medium confidence)
1387    fn evaluate_2008(&self, ctx: &EvaluationContext) -> ConditionResult {
1388        let nav = match ctx.navigator() {
1389            Some(n) => n,
1390            None => return ConditionResult::Unknown,
1391        };
1392        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1393        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1394        for i in 0..sg8_count {
1395            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1396            let is_z01 = seq_segs.iter().any(|s| {
1397                s.elements
1398                    .first()
1399                    .and_then(|e| e.first())
1400                    .is_some_and(|v| v == "Z01")
1401            });
1402            if is_z01 && matches!(self.evaluate(89, ctx), ConditionResult::True) {
1403                for seq in &seq_segs {
1404                    if seq
1405                        .elements
1406                        .first()
1407                        .and_then(|e| e.first())
1408                        .is_some_and(|v| v == "Z01")
1409                    {
1410                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1411                            if !zid.is_empty() {
1412                                qualifying_zeitraum_ids.push(zid.clone());
1413                            }
1414                        }
1415                    }
1416                }
1417            }
1418        }
1419        if qualifying_zeitraum_ids.is_empty() {
1420            return ConditionResult::Unknown;
1421        }
1422        ConditionResult::True
1423    }
1424
1425    /// [2009] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [89] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfolg...
1426    // REVIEW: Semantically identical to [2008] — 'Bedingungen' (plural) vs 'Bedingung' (singular) is a grammatical variation. Same logic: collects qualifying SG8 SEQ+Z01 Zeitraum-IDs where condition [89] is fulfilled. Recursive call self.evaluate(89, ctx) operates at message scope. (medium confidence)
1427    fn evaluate_2009(&self, ctx: &EvaluationContext) -> ConditionResult {
1428        let nav = match ctx.navigator() {
1429            Some(n) => n,
1430            None => return ConditionResult::Unknown,
1431        };
1432        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1433        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1434        for i in 0..sg8_count {
1435            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1436            let is_z01 = seq_segs.iter().any(|s| {
1437                s.elements
1438                    .first()
1439                    .and_then(|e| e.first())
1440                    .is_some_and(|v| v == "Z01")
1441            });
1442            if is_z01 && matches!(self.evaluate(89, ctx), ConditionResult::True) {
1443                for seq in &seq_segs {
1444                    if seq
1445                        .elements
1446                        .first()
1447                        .and_then(|e| e.first())
1448                        .is_some_and(|v| v == "Z01")
1449                    {
1450                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1451                            if !zid.is_empty() {
1452                                qualifying_zeitraum_ids.push(zid.clone());
1453                            }
1454                        }
1455                    }
1456                }
1457            }
1458        }
1459        if qualifying_zeitraum_ids.is_empty() {
1460            return ConditionResult::Unknown;
1461        }
1462        ConditionResult::True
1463    }
1464
1465    /// [1] Wenn Aufteilung vorhanden
1466    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
1467        ctx.external.evaluate("message_splitting")
1468    }
1469
1470    /// [4] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle LF
1471    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
1472        ctx.external.evaluate("recipient_is_lf")
1473    }
1474
1475    /// [5] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle LF
1476    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
1477        ctx.external.evaluate("sender_is_lf")
1478    }
1479
1480    /// [6] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle ÜNB
1481    fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
1482        ctx.external.evaluate("recipient_role_check")
1483    }
1484
1485    /// [7] Wenn SG4 STS+7++ZG9/ZH1/ZH2 (Transaktionsgrund: Aufhebung einer zukünftigen Zuordnung wegen Auszug des Kunden / -wegen Stilllegung / -wegen aufgehobenem Vertragsverhältnis) vorhanden
1486    fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
1487        let sts_segs = ctx.find_segments("STS");
1488        let found = sts_segs.iter().any(|s| {
1489            s.elements
1490                .first()
1491                .and_then(|e| e.first())
1492                .is_some_and(|v| v == "7")
1493                && s.elements
1494                    .get(2)
1495                    .and_then(|e| e.first())
1496                    .is_some_and(|v| ["ZG9", "ZH1", "ZH2"].contains(&v.as_str()))
1497        });
1498        ConditionResult::from(found)
1499    }
1500
1501    /// [8] Wenn für Datenclearing erforderlich
1502    fn evaluate_8(&self, ctx: &EvaluationContext) -> ConditionResult {
1503        ctx.external.evaluate("data_clearing_required")
1504    }
1505
1506    /// [9] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle MSB
1507    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
1508        ctx.external.evaluate("sender_role_check")
1509    }
1510
1511    /// [10] Wenn SG4 STS+7++xxx+xxx+E01/E03 (Transaktionsgrund befristete Anmeldung) vorhanden
1512    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
1513        // STS+7++E01+ZW4+E03: element[4] is c556_3.d9013 = transaktionsgrundErgaenzungBefristeteAnmeldung
1514        ctx.has_qualified_value("STS", 0, "7", 4, 0, &["E01", "E03"])
1515    }
1516
1517    /// [11] Wenn SG4 STS+7++ZG9/ZH1/ZH2 (Transaktionsgrund: Aufhebung einer zukünftigen Zuordnung wegen Auszug des Kunden / -wegen Stilllegung / -wegen aufgehobenem Vertragsverhältnis) nicht vorhanden
1518    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
1519        let sts_segs = ctx.find_segments("STS");
1520        let found = sts_segs.iter().any(|s| {
1521            s.elements
1522                .first()
1523                .and_then(|e| e.first())
1524                .is_some_and(|v| v == "7")
1525                && s.elements
1526                    .get(2)
1527                    .and_then(|e| e.first())
1528                    .is_some_and(|v| ["ZG9", "ZH1", "ZH2"].contains(&v.as_str()))
1529        });
1530        ConditionResult::from(!found)
1531    }
1532
1533    /// [12] Wenn SG4 DTM+471 (Ende zum nächstmöglichem Termin) nicht vorhanden
1534    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
1535        let dtm_segs = ctx.find_segments("DTM");
1536        let found = dtm_segs.iter().any(|s| {
1537            s.elements
1538                .first()
1539                .and_then(|e| e.first())
1540                .is_some_and(|v| v == "471")
1541        });
1542        ConditionResult::from(!found)
1543    }
1544
1545    /// [13] Wenn SG4 STS+E01++Z01 (Status der Antwort: Zustimmung mit Terminänderung) nicht vorhanden
1546    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
1547        let sts_segs = ctx.find_segments("STS");
1548        let found = sts_segs.iter().any(|s| {
1549            s.elements
1550                .first()
1551                .and_then(|e| e.first())
1552                .is_some_and(|v| v == "E01")
1553                && s.elements
1554                    .get(2)
1555                    .and_then(|e| e.first())
1556                    .is_some_and(|v| ["Z01"].contains(&v.as_str()))
1557        });
1558        ConditionResult::from(!found)
1559    }
1560
1561    /// [14] Wenn Datum bekannt
1562    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
1563        ctx.external.evaluate("date_known")
1564    }
1565
1566    /// [15] Wenn in derselben SG8 das SEQ+Z98 (Informative Daten der Marktlokation) vorhanden
1567    fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
1568        let seq_segs = ctx.find_segments("SEQ");
1569        let found = seq_segs.iter().any(|s| {
1570            s.elements
1571                .first()
1572                .and_then(|e| e.first())
1573                .is_some_and(|v| ["Z98"].contains(&v.as_str()))
1574        });
1575        ConditionResult::from(found)
1576    }
1577
1578    /// [16] Wenn SG4 STS+E01++Z12 (Status der Antwort: Ablehnung Vertragsbindung) vorhanden
1579    fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
1580        let sts_segs = ctx.find_segments("STS");
1581        let found = sts_segs.iter().any(|s| {
1582            s.elements
1583                .first()
1584                .and_then(|e| e.first())
1585                .is_some_and(|v| v == "E01")
1586                && s.elements
1587                    .get(2)
1588                    .and_then(|e| e.first())
1589                    .is_some_and(|v| ["Z12"].contains(&v.as_str()))
1590        });
1591        ConditionResult::from(found)
1592    }
1593
1594    /// [17] Wenn in derselben SG8 das SEQ+Z01/Z80/Z81 (Daten der Marktlokation) vorhanden
1595    fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
1596        let seq_segs = ctx.find_segments("SEQ");
1597        let found = seq_segs.iter().any(|s| {
1598            s.elements
1599                .first()
1600                .and_then(|e| e.first())
1601                .is_some_and(|v| ["Z01", "Z80", "Z81"].contains(&v.as_str()))
1602        });
1603        ConditionResult::from(found)
1604    }
1605
1606    /// [18] Wenn SG4 DTM+93 (Ende zum) nicht vorhanden
1607    fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
1608        let dtm_segs = ctx.find_segments("DTM");
1609        let found = dtm_segs.iter().any(|s| {
1610            s.elements
1611                .first()
1612                .and_then(|e| e.first())
1613                .is_some_and(|v| v == "93")
1614        });
1615        ConditionResult::from(!found)
1616    }
1617
1618    /// [19] Wenn SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) SG10 CCI+++ZC0 (Prognose auf Basis von Werten) vorhanden
1619    fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
1620        let seq_segs = ctx.find_segments("SEQ");
1621        let found = seq_segs.iter().any(|s| {
1622            s.elements
1623                .first()
1624                .and_then(|e| e.first())
1625                .is_some_and(|v| ["Z01", "Z98"].contains(&v.as_str()))
1626        });
1627        ConditionResult::from(found)
1628    }
1629
1630    /// [20] Wenn SG8 SEQ+Z01 (Daten der Marktlokation) SG10 CCI+Z30++Z07 (Verbrauch) vorhanden
1631    fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
1632        let seq_segs = ctx.find_segments("SEQ");
1633        let found = seq_segs.iter().any(|s| {
1634            s.elements
1635                .first()
1636                .and_then(|e| e.first())
1637                .is_some_and(|v| ["Z01"].contains(&v.as_str()))
1638        });
1639        ConditionResult::from(found)
1640    }
1641
1642    /// [21] Wenn SG10 CCI+++ZA6 (Prognose auf Basis von Profilen) in dieser SG8 vorhanden
1643    fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
1644        let cci_segs = ctx.find_segments("CCI");
1645        let found = cci_segs.iter().any(|s| {
1646            s.elements
1647                .get(2)
1648                .and_then(|e| e.first())
1649                .is_some_and(|v| v == "ZA6")
1650        });
1651        ConditionResult::from(found)
1652    }
1653
1654    /// [22] Es ist die Zeitraum-ID vom DE1156 aus einem passenden SG6 RFF+Z47/ Z48/ Z49 (Verwendungszeitraum der Daten) einzutragen
1655    // REVIEW: Checks if any SG6 RFF+Z47/Z48/Z49 Zeitraum-ID (DE1156 at elements[0][2]) matches any SG8 SEQ Zeitraum-ID reference (DE1050 at elements[1][0]). Uses groups_share_qualified_value for cross-group correlation across all three qualifying codes. (medium confidence)
1656    fn evaluate_22(&self, ctx: &EvaluationContext) -> ConditionResult {
1657        for qual in &["Z47", "Z48", "Z49"] {
1658            if matches!(
1659                ctx.groups_share_qualified_value(
1660                    "RFF",
1661                    0,
1662                    qual,
1663                    0,
1664                    2,
1665                    &["SG4", "SG6"],
1666                    "SEQ",
1667                    1,
1668                    0,
1669                    &["SG4", "SG8"],
1670                ),
1671                ConditionResult::True
1672            ) {
1673                return ConditionResult::True;
1674            }
1675        }
1676        ConditionResult::False
1677    }
1678
1679    /// [23] Wenn in dieser SG4 das STS+E01++A05/A99 (Status der Antwort) vorhanden
1680    fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
1681        let sts_segs = ctx.find_segments("STS");
1682        let found = sts_segs.iter().any(|s| {
1683            s.elements
1684                .first()
1685                .and_then(|e| e.first())
1686                .is_some_and(|v| v == "E01")
1687                && s.elements
1688                    .get(2)
1689                    .and_then(|e| e.first())
1690                    .is_some_and(|v| ["A05", "A99"].contains(&v.as_str()))
1691        });
1692        ConditionResult::from(found)
1693    }
1694
1695    /// [24] Wenn in dieser SG4 das STS+E01++A25/A99 (Status der Antwort) vorhanden
1696    fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
1697        let sts_segs = ctx.find_segments("STS");
1698        let found = sts_segs.iter().any(|s| {
1699            s.elements
1700                .first()
1701                .and_then(|e| e.first())
1702                .is_some_and(|v| v == "E01")
1703                && s.elements
1704                    .get(2)
1705                    .and_then(|e| e.first())
1706                    .is_some_and(|v| ["A25", "A99"].contains(&v.as_str()))
1707        });
1708        ConditionResult::from(found)
1709    }
1710
1711    /// [25] Wenn die Veräußerungsform der erzeugenden Marktlokation der Marktprämie zugeordnet ist
1712    fn evaluate_25(&self, _ctx: &EvaluationContext) -> ConditionResult {
1713        // TODO: implement
1714        ConditionResult::Unknown
1715    }
1716
1717    /// [27] Wenn das DE2380 von SG4 DTM+Z01 (Kündigungsfrist des Vertrags) an vierter Stelle ein T oder R enthält
1718    fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
1719        let dtm_segs = ctx.find_segments("DTM");
1720        let found = dtm_segs.iter().any(|s| {
1721            s.elements
1722                .first()
1723                .and_then(|e| e.first())
1724                .is_some_and(|v| v == "Z01")
1725                && s.elements
1726                    .first()
1727                    .and_then(|e| e.get(1))
1728                    .is_some_and(|v| v.chars().nth(3).is_some_and(|c| ['T', 'R'].contains(&c)))
1729        });
1730        ConditionResult::from(found)
1731    }
1732
1733    /// [30] Wenn Antwort auf Aktivierung übermittelt wird
1734    fn evaluate_30(&self, ctx: &EvaluationContext) -> ConditionResult {
1735        // Antwort auf Aktivierung — depends on PID context
1736        ctx.external.evaluate("activation_response")
1737    }
1738
1739    /// [31] Wenn eine Korrektur erfolgt
1740    fn evaluate_31(&self, ctx: &EvaluationContext) -> ConditionResult {
1741        ctx.external.evaluate("correction_in_progress")
1742    }
1743
1744    /// [32] Wenn mehr als ein SG8 (Referenz auf die Lokationsbündelstruktur) vorhanden
1745    fn evaluate_32(&self, ctx: &EvaluationContext) -> ConditionResult {
1746        let seq_segs = ctx.find_segments("SEQ");
1747        ConditionResult::from(seq_segs.len() > 1)
1748    }
1749
1750    /// [33] Wenn in einer SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6 \"Produkte zur Bestellung / Änderung von Date...
1751    fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
1752        ctx.external.evaluate("code_list_membership_check")
1753    }
1754
1755    /// [34] Wenn Antwort auf Deaktivierung übermittelt wird
1756    fn evaluate_34(&self, ctx: &EvaluationContext) -> ConditionResult {
1757        // Antwort auf Deaktivierung — depends on PID context
1758        ctx.external.evaluate("deactivation_response")
1759    }
1760
1761    /// [35] Wenn das DE2380 von SG4 DTM+Z01 (Kündigungsfrist des Vertrags) an vierter Stelle T (Termin) enthält
1762    fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
1763        let dtm_segs = ctx.find_segments("DTM");
1764        let found = dtm_segs.iter().any(|s| {
1765            s.elements
1766                .first()
1767                .and_then(|e| e.first())
1768                .is_some_and(|v| v == "Z01")
1769                && s.elements
1770                    .first()
1771                    .and_then(|e| e.get(1))
1772                    .is_some_and(|v| v.chars().nth(3).is_some_and(|c| c == 'T'))
1773        });
1774        ConditionResult::from(found)
1775    }
1776
1777    /// [36] Wenn in derselben SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeldung einer Zuordnung des LFN (UTI...
1778    fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
1779        ctx.external.evaluate("code_list_membership_check")
1780    }
1781
1782    /// [37] Wenn Anmeldung/ Änderung befristet
1783    fn evaluate_37(&self, ctx: &EvaluationContext) -> ConditionResult {
1784        // Same check as [10]: STS element[4] is befristete Anmeldung code
1785        ctx.has_qualified_value("STS", 0, "7", 4, 0, &["E01", "E03"])
1786    }
1787
1788    /// [38] Es sind nur die Code der Produkteigenschaft zu dem in derselben SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 erlaubt, die in der Codeliste der Konfigurationen im Kapitel  6.1 \"Anmeldung ei...
1789    fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
1790        ctx.external.evaluate("code_list_membership_check")
1791    }
1792
1793    /// [39] Wenn in derselben SG8 SEQ+Z79 m PIA+5 (Erforderliches Produkt) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeldung einer Zuordnung des LFN (UTIL...
1794    fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
1795        ctx.external.evaluate("code_list_membership_check")
1796    }
1797
1798    /// [40] Es ist nur der Wertebereich erlaubt, der zu dem in derselben SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 genannten Produkt, das in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeld...
1799    fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
1800        ctx.external.evaluate("code_list_membership_check")
1801    }
1802
1803    /// [41] Es ist eine Produktpaket-ID aus dem DE1050 von einem SG8 SEQ+Z79 (Erforderliches Produkt) zu nennen
1804    fn evaluate_41(&self, ctx: &EvaluationContext) -> ConditionResult {
1805        // Check: Produktpaket-ID exists in SEQ+Z79 (Erforderliches Produkt)
1806        let seq_z79 = ctx.find_segments_with_qualifier("SEQ", 0, "Z79");
1807        if seq_z79.is_empty() {
1808            return ConditionResult::Unknown;
1809        }
1810        // Check if SEQ has a value in C286.D1050 (elements[1][0])
1811        let found = seq_z79.iter().any(|s| {
1812            s.elements
1813                .get(1)
1814                .and_then(|e| e.first())
1815                .is_some_and(|v| !v.is_empty())
1816        });
1817        ConditionResult::from(found)
1818    }
1819
1820    /// [42] Wenn mehr als ein SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) vorhanden
1821    fn evaluate_42(&self, ctx: &EvaluationContext) -> ConditionResult {
1822        let seq_segs = ctx.find_segments("SEQ");
1823        let zh0_count = seq_segs
1824            .iter()
1825            .filter(|s| {
1826                s.elements
1827                    .first()
1828                    .and_then(|e| e.first())
1829                    .is_some_and(|v| v == "ZH0")
1830            })
1831            .count();
1832        ConditionResult::from(zh0_count > 1)
1833    }
1834
1835    /// [43] Wenn in dieser SG4 das STS+E01++A12 / A13 (Status der Antwort) vorhanden
1836    fn evaluate_43(&self, ctx: &EvaluationContext) -> ConditionResult {
1837        let sts_segs = ctx.find_segments("STS");
1838        let found = sts_segs.iter().any(|s| {
1839            s.elements
1840                .first()
1841                .and_then(|e| e.first())
1842                .is_some_and(|v| v == "E01")
1843                && s.elements
1844                    .get(2)
1845                    .and_then(|e| e.first())
1846                    .is_some_and(|v| ["A12", "A13"].contains(&v.as_str()))
1847        });
1848        ConditionResult::from(found)
1849    }
1850
1851    /// [44] Es ist die Zeitraum-ID vom DE1156 aus einem passenden SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: "Gültige Daten", "Keine Daten") aus der Anfragennachricht aus SG6 RFF+TN DE1154 ((Referenz Vo...
1852    fn evaluate_44(&self, _ctx: &EvaluationContext) -> ConditionResult {
1853        // Hinweis: Zeitraum-ID aus passendem SG6 RFF+Z49/Z53 der Anfragenachricht eintragen — informational data population rule
1854        ConditionResult::True
1855    }
1856
1857    /// [45] Wenn in derselben SG8 das SG10 CCI+Z01++Z82 (Verwendungsumfang: ID der prozessual behandelten Messlokation) vorhanden
1858    fn evaluate_45(&self, ctx: &EvaluationContext) -> ConditionResult {
1859        let cci_segs = ctx.find_segments("CCI");
1860        let found = cci_segs.iter().any(|s| {
1861            s.elements
1862                .first()
1863                .and_then(|e| e.first())
1864                .is_some_and(|v| v == "Z01")
1865                && s.elements
1866                    .get(2)
1867                    .and_then(|e| e.first())
1868                    .is_some_and(|v| v == "Z82")
1869        });
1870        ConditionResult::from(found)
1871    }
1872
1873    /// [46] Wenn ID für Objekt vergeben wurde
1874    fn evaluate_46(&self, _ctx: &EvaluationContext) -> ConditionResult {
1875        // TODO: implement
1876        ConditionResult::Unknown
1877    }
1878
1879    /// [47] Wenn SG10 CCI+15++Z21 (Summenzeitreihentyp) CAV+DBA/ VZR/ EGS/ LGS/ SLS/ SES/ TLS/ TES/ BIL/ BIP/ BIT/ GAL/ GAP/ GAT/ GEL/ GEP/ GET/ SOL/ SOP/ SOT/ WFL/ WFP/ WFT/ WNL/ WNP/ WNT vorhanden
1880    // REVIEW: Iterates all SG8 instances and their SG10 children looking for CCI with elements[0][0]=="15" and elements[2][0]=="Z21" (Zeitreihentyp), then checks if the same SG10 has a CAV with elements[0][0] in the Summenzeitreihentyp code list. Uses navigator for parent-child group traversal. (medium confidence)
1881    fn evaluate_47(&self, ctx: &EvaluationContext) -> ConditionResult {
1882        const CODES: &[&str] = &[
1883            "DBA", "VZR", "EGS", "LGS", "SLS", "SES", "TLS", "TES", "BIL", "BIP", "BIT", "GAL",
1884            "GAP", "GAT", "GEL", "GEP", "GET", "SOL", "SOP", "SOT", "WFL", "WFP", "WFT", "WNL",
1885            "WNP", "WNT",
1886        ];
1887        let nav = match ctx.navigator {
1888            Some(n) => n,
1889            None => return ConditionResult::Unknown,
1890        };
1891        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1892        for i in 0..sg8_count {
1893            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
1894            for j in 0..sg10_count {
1895                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
1896                let has_cci_15_z21 = ccis.iter().any(|s| {
1897                    s.elements
1898                        .first()
1899                        .and_then(|e: &Vec<String>| e.first())
1900                        .is_some_and(|v: &String| v == "15")
1901                        && s.elements
1902                            .get(2)
1903                            .and_then(|e: &Vec<String>| e.first())
1904                            .is_some_and(|v: &String| v == "Z21")
1905                });
1906                if has_cci_15_z21 {
1907                    let cavs =
1908                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
1909                    if cavs.iter().any(|s| {
1910                        s.elements
1911                            .first()
1912                            .and_then(|e: &Vec<String>| e.first())
1913                            .is_some_and(|v: &String| CODES.contains(&v.as_str()))
1914                    }) {
1915                        return ConditionResult::True;
1916                    }
1917                }
1918            }
1919        }
1920        ConditionResult::False
1921    }
1922
1923    /// [48] Wenn in dieser SG4 das STS+E01++A99 (Status der Antwort: Sonstiges) vorhanden
1924    fn evaluate_48(&self, ctx: &EvaluationContext) -> ConditionResult {
1925        let sts_segs = ctx.find_segments("STS");
1926        let found = sts_segs.iter().any(|s| {
1927            s.elements
1928                .first()
1929                .and_then(|e| e.first())
1930                .is_some_and(|v| v == "E01")
1931                && s.elements
1932                    .get(2)
1933                    .and_then(|e| e.first())
1934                    .is_some_and(|v| ["A99"].contains(&v.as_str()))
1935        });
1936        ConditionResult::from(found)
1937    }
1938
1939    /// [49] Wenn in dieser SG4 das STS+E01++E14 (Status der Antwort: Ablehnung Sonstiges) vorhanden
1940    fn evaluate_49(&self, ctx: &EvaluationContext) -> ConditionResult {
1941        let sts_segs = ctx.find_segments("STS");
1942        let found = sts_segs.iter().any(|s| {
1943            s.elements
1944                .first()
1945                .and_then(|e| e.first())
1946                .is_some_and(|v| v == "E01")
1947                && s.elements
1948                    .get(2)
1949                    .and_then(|e| e.first())
1950                    .is_some_and(|v| ["E14"].contains(&v.as_str()))
1951        });
1952        ConditionResult::from(found)
1953    }
1954
1955    /// [50] Wenn kein SG8 SEQ+ZE7 (Informative Daten der Tranche) mit derselben Zeitraum-ID im DE1050 auf die gleiche Marktlokation-ID mit dem RFF+Z18 (Marktlokation) referenziert wie dieses SG8 SEQ+Z98 (Infor...
1956    // REVIEW: Collects (Zeitraum-ID from SEQ.elements[1][0], Marktlok-ID from sibling RFF+Z18.elements[0][1]) for all SG8 instances with SEQ+Z98 and SEQ+ZE7. Returns True if any Z98 group has no ZE7 group matching on both values. Uses collect_group_values with instance-index correlation via HashMap, assuming each SG8 has at most one SEQ (guaranteed as entry segment) and the zip ordering is stable. (medium confidence)
1957    fn evaluate_50(&self, ctx: &EvaluationContext) -> ConditionResult {
1958        use std::collections::HashMap;
1959
1960        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
1961        let seq_zeitraum = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
1962        let rff_quals = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG8"]);
1963        let rff_ids = ctx.collect_group_values("RFF", 0, 1, &["SG4", "SG8"]);
1964
1965        // Build per-instance RFF lookup: instance_idx -> list of (qualifier, id)
1966        let mut rff_by_instance: HashMap<usize, Vec<(String, String)>> = HashMap::new();
1967        for ((idx, q), (_, id)) in rff_quals.iter().zip(rff_ids.iter()) {
1968            rff_by_instance
1969                .entry(*idx)
1970                .or_default()
1971                .push((q.clone(), id.clone()));
1972        }
1973
1974        // Build (zeitraum_id, marktlok_id) for Z98 and ZE7 SG8 instances
1975        let mut seq_zeitraum_map: HashMap<usize, String> = HashMap::new();
1976        for (idx, z) in &seq_zeitraum {
1977            seq_zeitraum_map.insert(*idx, z.clone());
1978        }
1979
1980        let z98_data: Vec<(String, String)> = seq_quals
1981            .iter()
1982            .filter(|(_, q)| q == "Z98")
1983            .map(|(idx, _)| {
1984                let zeitraum = seq_zeitraum_map.get(idx).cloned().unwrap_or_default();
1985                let marktlok = rff_by_instance
1986                    .get(idx)
1987                    .and_then(|rffs| rffs.iter().find(|(q, _)| q == "Z18"))
1988                    .map(|(_, id)| id.clone())
1989                    .unwrap_or_default();
1990                (zeitraum, marktlok)
1991            })
1992            .collect();
1993
1994        if z98_data.is_empty() {
1995            return ConditionResult::Unknown;
1996        }
1997
1998        let ze7_data: Vec<(String, String)> = seq_quals
1999            .iter()
2000            .filter(|(_, q)| q == "ZE7")
2001            .map(|(idx, _)| {
2002                let zeitraum = seq_zeitraum_map.get(idx).cloned().unwrap_or_default();
2003                let marktlok = rff_by_instance
2004                    .get(idx)
2005                    .and_then(|rffs| rffs.iter().find(|(q, _)| q == "Z18"))
2006                    .map(|(_, id)| id.clone())
2007                    .unwrap_or_default();
2008                (zeitraum, marktlok)
2009            })
2010            .collect();
2011
2012        ConditionResult::from(z98_data.iter().any(|(z98_zeit, z98_lok)| {
2013            !ze7_data
2014                .iter()
2015                .any(|(ze7_zeit, ze7_lok)| ze7_zeit == z98_zeit && ze7_lok == z98_lok)
2016        }))
2017    }
2018
2019    /// [51] Wenn die Marktlokations-ID im SG8 RFF+Z18 derselben SG8 SEQ+Z98 (Informative Daten der Marktlokation) mit derselben Zeitraum-ID im DE1050 nicht auf ein SG8 SEQ+Z78 (Referenz auf die Lokationsbünde...
2020    // REVIEW: Condition is True when no Z98 SG8 (Informative Daten der Marktlokation) references — via matching Zeitraum-ID in SEQ.C286.DE1050 — a Z78 SG8 (Referenz auf Lokationsbündelstruktur) that carries the pauschal bundle code 9992000000018 in RFF+Z31.DE1154. Requires navigator for cross-SG8 Zeitraum-ID correlation. (medium confidence)
2021    fn evaluate_51(&self, ctx: &EvaluationContext) -> ConditionResult {
2022        let nav = match ctx.navigator() {
2023            Some(n) => n,
2024            None => return ConditionResult::Unknown,
2025        };
2026        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2027        let pauschal_id = "9992000000018";
2028        // Collect Zeitraum-IDs from Z78 SG8s that carry the pauschal RFF+Z31 ID
2029        let mut pauschal_zeitraum_ids: Vec<String> = Vec::new();
2030        for i in 0..sg8_count {
2031            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
2032            let has_z78 = seqs.iter().any(|s| {
2033                s.elements
2034                    .first()
2035                    .and_then(|e| e.first())
2036                    .is_some_and(|v| v == "Z78")
2037            });
2038            if !has_z78 {
2039                continue;
2040            }
2041            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
2042            let has_pauschal = rffs.iter().any(|s| {
2043                s.elements
2044                    .first()
2045                    .and_then(|e| e.first())
2046                    .is_some_and(|v| v == "Z31")
2047                    && s.elements
2048                        .first()
2049                        .and_then(|e| e.get(1))
2050                        .is_some_and(|v| v.replace(' ', "") == pauschal_id)
2051            });
2052            if has_pauschal {
2053                for seq in &seqs {
2054                    if seq
2055                        .elements
2056                        .first()
2057                        .and_then(|e| e.first())
2058                        .is_some_and(|v| v == "Z78")
2059                    {
2060                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
2061                            if !zid.is_empty() {
2062                                pauschal_zeitraum_ids.push(zid.clone());
2063                            }
2064                        }
2065                    }
2066                }
2067            }
2068        }
2069        // For each Z98 SG8, check whether its Zeitraum-ID (SEQ.C286.DE1050) maps to a pauschal Z78
2070        for i in 0..sg8_count {
2071            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
2072            for seq in &seqs {
2073                if seq
2074                    .elements
2075                    .first()
2076                    .and_then(|e| e.first())
2077                    .is_some_and(|v| v == "Z98")
2078                {
2079                    let zid = seq
2080                        .elements
2081                        .get(1)
2082                        .and_then(|e| e.first())
2083                        .map(|s| s.as_str())
2084                        .unwrap_or("");
2085                    if !zid.is_empty() && pauschal_zeitraum_ids.iter().any(|z| z == zid) {
2086                        // Z98 SG8 references a pauschal Z78 → condition is False
2087                        return ConditionResult::False;
2088                    }
2089                }
2090            }
2091        }
2092        // No Z98 SG8 references the pauschal bundle → condition is True
2093        ConditionResult::True
2094    }
2095
2096    /// [52] Wenn SG10 CCI+Z07++Z55/ Z56 (Profiltyp: sonstige verbrauchende Marktlokation / sonstige erzeugende Marktlokation) vorhanden
2097    fn evaluate_52(&self, ctx: &EvaluationContext) -> ConditionResult {
2098        let cci_segs = ctx.find_segments("CCI");
2099        let found = cci_segs.iter().any(|s| {
2100            s.elements
2101                .first()
2102                .and_then(|e| e.first())
2103                .is_some_and(|v| v == "Z07")
2104                && s.elements
2105                    .get(2)
2106                    .and_then(|e| e.first())
2107                    .is_some_and(|v| ["Z55", "Z56"].contains(&v.as_str()))
2108        });
2109        ConditionResult::from(found)
2110    }
2111
2112    /// [53] Wenn weitere Präzisierungen als über CCI+Z07 (Profiltyp) möglich sind
2113    fn evaluate_53(&self, _ctx: &EvaluationContext) -> ConditionResult {
2114        // TODO: implement
2115        ConditionResult::Unknown
2116    }
2117
2118    /// [54] Wenn SG8 SEQ+Z01 (Daten der Marktlokation) SG10 CCI+Z30++Z06 (Lieferrichtung: Erzeugung) vorhanden
2119    fn evaluate_54(&self, ctx: &EvaluationContext) -> ConditionResult {
2120        let seq_segs = ctx.find_segments("SEQ");
2121        let found = seq_segs.iter().any(|s| {
2122            s.elements
2123                .first()
2124                .and_then(|e| e.first())
2125                .is_some_and(|v| ["Z01"].contains(&v.as_str()))
2126        });
2127        ConditionResult::from(found)
2128    }
2129
2130    /// [55] Wenn in dieser SG4 das STS+E01++A06/ A99 (Status der Antwort) vorhanden
2131    fn evaluate_55(&self, ctx: &EvaluationContext) -> ConditionResult {
2132        let sts_segs = ctx.find_segments("STS");
2133        let found = sts_segs.iter().any(|s| {
2134            s.elements
2135                .first()
2136                .and_then(|e| e.first())
2137                .is_some_and(|v| v == "E01")
2138                && s.elements
2139                    .get(2)
2140                    .and_then(|e| e.first())
2141                    .is_some_and(|v| ["A06", "A99"].contains(&v.as_str()))
2142        });
2143        ConditionResult::from(found)
2144    }
2145
2146    /// [56] Wenn im STS+E01 im DE9013 (Status der Antwort) ein Antwortcode aus dem Cluster Zustimmung vorhanden ist
2147    fn evaluate_56(&self, ctx: &EvaluationContext) -> ConditionResult {
2148        // Check: STS+E01 DE9013 has a Zustimmung (approval) cluster code
2149        // Zustimmung codes start with A0x (A01-A07 are approval codes)
2150        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
2151        let found = sts_segs.iter().any(|s| {
2152            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| {
2153                [
2154                    "A01", "A02", "A03", "A04", "A05", "A06", "A07", "A08", "A09", "A10", "A11",
2155                    "A12", "A13", "A14", "A15", "A16", "A17", "A25",
2156                ]
2157                .contains(&v.as_str())
2158            })
2159        });
2160        ConditionResult::from(found)
2161    }
2162
2163    /// [57] Wenn in derselben SG8 das CCI+Z45++ZD9 (Abrechnung findet statt) vorhanden ist
2164    fn evaluate_57(&self, ctx: &EvaluationContext) -> ConditionResult {
2165        let cci_segs = ctx.find_segments("CCI");
2166        let found = cci_segs.iter().any(|s| {
2167            s.elements
2168                .first()
2169                .and_then(|e| e.first())
2170                .is_some_and(|v| v == "Z45")
2171                && s.elements
2172                    .get(2)
2173                    .and_then(|e| e.first())
2174                    .is_some_and(|v| v == "ZD9")
2175        });
2176        ConditionResult::from(found)
2177    }
2178
2179    /// [58] Wenn in diesem CCI das DE3055 mit dem Code 293 vorhanden
2180    fn evaluate_58(&self, ctx: &EvaluationContext) -> ConditionResult {
2181        let cci_segs = ctx.find_segments("CCI");
2182        let found = cci_segs
2183            .iter()
2184            .any(|s| s.elements.iter().any(|e| e.iter().any(|v| v == "293")));
2185        ConditionResult::from(found)
2186    }
2187
2188    /// [60] Wenn BGM+Z90 (Beendigung der Zuordnung zur Lokation) vorhanden
2189    fn evaluate_60(&self, ctx: &EvaluationContext) -> ConditionResult {
2190        let bgm_segs = ctx.find_segments("BGM");
2191        let found = bgm_segs.iter().any(|s| {
2192            s.elements
2193                .first()
2194                .and_then(|e| e.first())
2195                .is_some_and(|v| v == "Z90")
2196        });
2197        ConditionResult::from(found)
2198    }
2199
2200    /// [61] Wenn BGM+Z89 (Zuordnung zur Lokation) vorhanden
2201    fn evaluate_61(&self, ctx: &EvaluationContext) -> ConditionResult {
2202        let bgm_segs = ctx.find_segments("BGM");
2203        let found = bgm_segs.iter().any(|s| {
2204            s.elements
2205                .first()
2206                .and_then(|e| e.first())
2207                .is_some_and(|v| v == "Z89")
2208        });
2209        ConditionResult::from(found)
2210    }
2211
2212    /// [62] Wenn mehr als eine SG8 SEQ+Z45 (Netznutzungsabrechnungsdaten der Marktlokation), mit derselben Zeitraum-ID im DE1050, mit einer Gruppen-/Artikel-ID im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), ...
2213    // REVIEW: Iterates SG8 instances within each SG4, finds those with SEQ+Z45 and a non-empty Zeitraum-ID in elements[1][0]. Checks if PIA+Z02 in the same SG8 has a product code (elements[1][0]) beginning with 1-08-1 through 1-08-5. Groups by Zeitraum-ID and checks if any ID appears more than once. Requires navigator for per-instance group segment access; returns Unknown without one. (medium confidence)
2214    fn evaluate_62(&self, ctx: &EvaluationContext) -> ConditionResult {
2215        let nav = match ctx.navigator {
2216            Some(n) => n,
2217            None => return ConditionResult::Unknown,
2218        };
2219        use std::collections::HashMap;
2220        let mut count_by_zid: HashMap<String, u32> = HashMap::new();
2221        let sg4_count = nav.group_instance_count(&["SG4"]);
2222        for sg4_idx in 0..sg4_count {
2223            let sg8_count = nav.child_group_instance_count(&["SG4"], sg4_idx, "SG8");
2224            for sg8_idx in 0..sg8_count {
2225                let seqs =
2226                    nav.find_segments_in_child_group("SEQ", &["SG4"], sg4_idx, "SG8", sg8_idx);
2227                let zeitraum_opt = seqs
2228                    .iter()
2229                    .filter(|s| {
2230                        s.elements
2231                            .first()
2232                            .and_then(|e: &Vec<String>| e.first())
2233                            .is_some_and(|v: &String| v == "Z45")
2234                    })
2235                    .filter_map(|s| {
2236                        s.elements
2237                            .get(1)
2238                            .and_then(|e: &Vec<String>| e.first())
2239                            .filter(|v| !v.is_empty())
2240                            .cloned()
2241                    })
2242                    .next();
2243                let Some(zid) = zeitraum_opt else { continue };
2244                let pias =
2245                    nav.find_segments_in_child_group("PIA", &["SG4"], sg4_idx, "SG8", sg8_idx);
2246                let has_qualifying_pia = pias.iter().any(|s| {
2247                    s.elements
2248                        .first()
2249                        .and_then(|e: &Vec<String>| e.first())
2250                        .is_some_and(|v: &String| v == "Z02")
2251                        && s.elements
2252                            .get(1)
2253                            .and_then(|e: &Vec<String>| e.first())
2254                            .map(|code| {
2255                                code.starts_with("1-08-1")
2256                                    || code.starts_with("1-08-2")
2257                                    || code.starts_with("1-08-3")
2258                                    || code.starts_with("1-08-4")
2259                                    || code.starts_with("1-08-5")
2260                            })
2261                            .unwrap_or(false)
2262                });
2263                if has_qualifying_pia {
2264                    *count_by_zid.entry(zid).or_insert(0) += 1;
2265                }
2266            }
2267        }
2268        ConditionResult::from(count_by_zid.values().any(|&c| c > 1))
2269    }
2270
2271    /// [63] Wenn in dieser SG4 das STS+E01++A15/ A99 (Status der Antwort) vorhanden
2272    fn evaluate_63(&self, ctx: &EvaluationContext) -> ConditionResult {
2273        let sts_segs = ctx.find_segments("STS");
2274        let found = sts_segs.iter().any(|s| {
2275            s.elements
2276                .first()
2277                .and_then(|e| e.first())
2278                .is_some_and(|v| v == "E01")
2279                && s.elements
2280                    .get(2)
2281                    .and_then(|e| e.first())
2282                    .is_some_and(|v| ["A15", "A99"].contains(&v.as_str()))
2283        });
2284        ConditionResult::from(found)
2285    }
2286
2287    /// [64] Wenn mehr als eine SG8 SEQ+ZE1 (Informative Netznutzungsabrechnungsdaten der Marktlokation) mit einer Gruppen-/ Artikel-ID im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), welche mit 1-08-1/2/3/4/5...
2288    fn evaluate_64(&self, ctx: &EvaluationContext) -> ConditionResult {
2289        // Check: more than one SG8 SEQ+ZE1 has PIA+Z02 with code starting with 1-08-1/2/3/4/5
2290        let pia_segs = ctx.find_segments("PIA");
2291        let count = pia_segs
2292            .iter()
2293            .filter(|s| {
2294                s.elements
2295                    .first()
2296                    .and_then(|e| e.first())
2297                    .is_some_and(|v| v == "Z02")
2298                    && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
2299                        ["1-08-1", "1-08-2", "1-08-3", "1-08-4", "1-08-5"]
2300                            .iter()
2301                            .any(|p| v.starts_with(p))
2302                    })
2303            })
2304            .count();
2305        ConditionResult::from(count > 1)
2306    }
2307
2308    /// [65] Wenn in derselben SG8 SEQ+ZE1 (Informative Netznutzungsabrechnungsdaten der Marktlokation) eine Gruppen-/Artikel-ID im PIA+Z02 (Gruppenartikel-ID / Artikel-ID), welche mit 1-08-1/2/3/4/5 beginnt, v...
2309    fn evaluate_65(&self, ctx: &EvaluationContext) -> ConditionResult {
2310        // Check: PIA+Z02 with code starting with 1-08-1/2/3/4/5 exists in same SG8 SEQ+ZE1
2311        let pia_segs = ctx.find_segments("PIA");
2312        let found = pia_segs.iter().any(|s| {
2313            s.elements
2314                .first()
2315                .and_then(|e| e.first())
2316                .is_some_and(|v| v == "Z02")
2317                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
2318                    ["1-08-1", "1-08-2", "1-08-3", "1-08-4", "1-08-5"]
2319                        .iter()
2320                        .any(|p| v.starts_with(p))
2321                })
2322        });
2323        ConditionResult::from(found)
2324    }
2325
2326    /// [66] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) mehr als einmal vorhanden
2327    fn evaluate_66(&self, ctx: &EvaluationContext) -> ConditionResult {
2328        let seq_segs = ctx.find_segments("SEQ");
2329        let count = seq_segs
2330            .iter()
2331            .filter(|s| {
2332                s.elements
2333                    .first()
2334                    .and_then(|e| e.first())
2335                    .is_some_and(|v| v == "ZH0")
2336            })
2337            .count();
2338        ConditionResult::from(count > 1)
2339    }
2340
2341    /// [67] Wenn in keinem SG8 SEQ+Z79 (Bestandteil eine Produktpaketes CCI+Z66/CAV+ZH9 (Produkteigenschaft/ Code der Produkteigenschaft) der Code 9991000002933 (Ruhende Marktlokation ausprägen) vorhanden ist.
2342    fn evaluate_67(&self, ctx: &EvaluationContext) -> ConditionResult {
2343        // Check: no SG8 SEQ+Z79 has CAV+ZH9 with code 9991000002933
2344        let cav_segs = ctx.find_segments("CAV");
2345        let found = cav_segs.iter().any(|s| {
2346            s.elements
2347                .first()
2348                .and_then(|e| e.first())
2349                .is_some_and(|v| v == "ZH9")
2350                && s.elements
2351                    .first()
2352                    .and_then(|e| e.get(1))
2353                    .is_some_and(|v| v == "9991000002933")
2354        });
2355        ConditionResult::from(!found)
2356    }
2357
2358    /// [68] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) mehr als zweimal vorhanden
2359    fn evaluate_68(&self, ctx: &EvaluationContext) -> ConditionResult {
2360        let seq_segs = ctx.find_segments("SEQ");
2361        let count = seq_segs
2362            .iter()
2363            .filter(|s| {
2364                s.elements
2365                    .first()
2366                    .and_then(|e| e.first())
2367                    .is_some_and(|v| v == "ZH0")
2368            })
2369            .count();
2370        ConditionResult::from(count > 2)
2371    }
2372
2373    /// [69] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) mehr als dreimal vorhanden
2374    fn evaluate_69(&self, ctx: &EvaluationContext) -> ConditionResult {
2375        let seq_segs = ctx.find_segments("SEQ");
2376        let count = seq_segs
2377            .iter()
2378            .filter(|s| {
2379                s.elements
2380                    .first()
2381                    .and_then(|e| e.first())
2382                    .is_some_and(|v| v == "ZH0")
2383            })
2384            .count();
2385        ConditionResult::from(count > 3)
2386    }
2387
2388    /// [70] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) fünfmal vorhanden
2389    fn evaluate_70(&self, ctx: &EvaluationContext) -> ConditionResult {
2390        let seq_segs = ctx.find_segments("SEQ");
2391        let count = seq_segs
2392            .iter()
2393            .filter(|s| {
2394                s.elements
2395                    .first()
2396                    .and_then(|e| e.first())
2397                    .is_some_and(|v| v == "ZH0")
2398            })
2399            .count();
2400        ConditionResult::from(count == 5)
2401    }
2402
2403    /// [71] Wenn Antwort auf Zuordnung übermittelt wird
2404    fn evaluate_71(&self, ctx: &EvaluationContext) -> ConditionResult {
2405        // Antwort auf Zuordnung — depends on PID context
2406        ctx.external.evaluate("assignment_response")
2407    }
2408
2409    /// [72] Wenn Antwort auf Beendigung der Zuordnung übermittelt wird
2410    fn evaluate_72(&self, ctx: &EvaluationContext) -> ConditionResult {
2411        // Antwort auf Beendigung der Zuordnung — depends on PID context
2412        ctx.external.evaluate("assignment_end_response")
2413    }
2414
2415    /// [73] Wenn in derselben SG8 im PIA DE7140 ein Code aus der Codeliste der Gruppenartikel- und Artikel-ID vorhanden ist, der in der Spalte UTILMD/Preisangabe mit X gekennzeichnet ist
2416    // HAND-EDITED — the codegen prompt (conditions/prompt.rs) now documents
2417    // both the SCOPE RULES (Task B6) and the codelist API (review followup).
2418    // Regenerating this function should preserve the shape, but re-verify
2419    // against the committed body if generate-conditions is run.
2420    fn evaluate_73(&self, ctx: &EvaluationContext) -> ConditionResult {
2421        // [73] Wenn in derselben SG8 im PIA DE7140 ein Code aus der
2422        // Codeliste der Gruppenartikel- und Artikel-ID vorhanden ist,
2423        // der in der Spalte UTILMD/Preisangabe mit X gekennzeichnet ist.
2424        //
2425        // Scope-aware: when validate_tree sets a GroupScope on ctx, this
2426        // narrows to the current SG8 instance; otherwise falls back to
2427        // message-wide find_segments. Matches the AHB wording
2428        // "in derselben SG8 im PIA DE7140 ein Code...".
2429        use crate::eval::CodelistColumn;
2430        let any_match = ctx.scoped_find_segments("PIA").iter().any(|s| {
2431            let is_z02 = s
2432                .elements
2433                .first()
2434                .and_then(|e| e.first())
2435                .is_some_and(|v| v == "Z02");
2436            if !is_z02 {
2437                return false;
2438            }
2439            let code = match s.elements.get(1).and_then(|e| e.first()) {
2440                Some(c) if !c.is_empty() => c,
2441                _ => return false,
2442            };
2443            ctx.codelist
2444                .flag(code, CodelistColumn::UtilmdPreisangabe)
2445                .unwrap_or(false)
2446        });
2447        ConditionResult::from(any_match)
2448    }
2449
2450    /// [74] Wenn in der selben SG8 SEQ+Z59 (Produkt-Daten der Marktlokation) das PIA+5 (Produkt-Daten der Marktlokation) vorhanden
2451    fn evaluate_74(&self, ctx: &EvaluationContext) -> ConditionResult {
2452        let seq_segs = ctx.find_segments("SEQ");
2453        let has_seq = seq_segs.iter().any(|s| {
2454            s.elements
2455                .first()
2456                .and_then(|e| e.first())
2457                .is_some_and(|v| v == "Z59")
2458        });
2459        let pia_segs = ctx.find_segments("PIA");
2460        let has_pia = pia_segs.iter().any(|s| {
2461            s.elements
2462                .first()
2463                .and_then(|e| e.first())
2464                .is_some_and(|v| v == "5")
2465        });
2466        ConditionResult::from(has_seq && has_pia)
2467    }
2468
2469    /// [75] Wenn in diesem PIA+5 in DE7140 der Code 9991000000721 (vgl.: Kapitel 4.2. Konfigurationsprodukte Leistungskurvendefinition der Codeliste der Konfigurationen) vorhanden
2470    fn evaluate_75(&self, ctx: &EvaluationContext) -> ConditionResult {
2471        ctx.external.evaluate("code_list_membership_check")
2472    }
2473
2474    /// [76] Wenn Summenzeitreihe auf Ebene des Bilanzierungsgebiet
2475    // REVIEW: SEQ+Z49 is 'Abgerechnete Daten der Bilanzierungsgebietssummenzeitreihe' — the only SEQ code in the reference that explicitly names a Bilanzierungsgebiet-level Summenzeitreihe. Checking its presence is the most direct mapping of the condition text. A broader interpretation involving CAV codes (Bezeichnung der Summenzeitreihe) is possible but those codes are not fully enumerated in the provided reference. (medium confidence)
2476    fn evaluate_76(&self, ctx: &EvaluationContext) -> ConditionResult {
2477        ctx.has_qualifier("SEQ", 0, "Z49")
2478    }
2479
2480    /// [77] Wenn SG8 SEQ+Z03 (Zähleinrichtungsdaten) CAV+Z30 (Identifikation/Nummer des Gerätes) nicht vorhanden
2481    fn evaluate_77(&self, ctx: &EvaluationContext) -> ConditionResult {
2482        let seq_segs = ctx.find_segments("SEQ");
2483        let found = seq_segs.iter().any(|s| {
2484            s.elements
2485                .first()
2486                .and_then(|e| e.first())
2487                .is_some_and(|v| ["Z03"].contains(&v.as_str()))
2488        });
2489        ConditionResult::from(!found)
2490    }
2491
2492    /// [78] Wenn SG4 STS+7++E02 (Transaktionsgrund: Einzug in Neuanlage) nicht vorhanden
2493    fn evaluate_78(&self, ctx: &EvaluationContext) -> ConditionResult {
2494        let sts_segs = ctx.find_segments("STS");
2495        let found = sts_segs.iter().any(|s| {
2496            s.elements
2497                .first()
2498                .and_then(|e| e.first())
2499                .is_some_and(|v| v == "7")
2500                && s.elements
2501                    .get(2)
2502                    .and_then(|e| e.first())
2503                    .is_some_and(|v| ["E02"].contains(&v.as_str()))
2504        });
2505        ConditionResult::from(!found)
2506    }
2507
2508    /// [83] Wenn in dieser SG4 das STS+E01++A08/ A16/ A99 (Status der Antwort) vorhanden
2509    fn evaluate_83(&self, ctx: &EvaluationContext) -> ConditionResult {
2510        let sts_segs = ctx.find_segments("STS");
2511        let found = sts_segs.iter().any(|s| {
2512            s.elements
2513                .first()
2514                .and_then(|e| e.first())
2515                .is_some_and(|v| v == "E01")
2516                && s.elements
2517                    .get(2)
2518                    .and_then(|e| e.first())
2519                    .is_some_and(|v| ["A08", "A16", "A99"].contains(&v.as_str()))
2520        });
2521        ConditionResult::from(found)
2522    }
2523
2524    /// [84] Wenn SG4 STS+E01++A57 (Status der Antwort) vorhanden
2525    fn evaluate_84(&self, ctx: &EvaluationContext) -> ConditionResult {
2526        let sts_segs = ctx.find_segments("STS");
2527        let found = sts_segs.iter().any(|s| {
2528            s.elements
2529                .first()
2530                .and_then(|e| e.first())
2531                .is_some_and(|v| v == "E01")
2532                && s.elements
2533                    .get(2)
2534                    .and_then(|e| e.first())
2535                    .is_some_and(|v| ["A57"].contains(&v.as_str()))
2536        });
2537        ConditionResult::from(found)
2538    }
2539
2540    /// [85] Wenn das DE2380 von SG4 DTM+Z01 (Kündigungsfrist des Vertrags) an vierter Stelle M, Q, H oder J enthält
2541    fn evaluate_85(&self, ctx: &EvaluationContext) -> ConditionResult {
2542        let dtm_segs = ctx.find_segments("DTM");
2543        let found = dtm_segs.iter().any(|s| {
2544            s.elements
2545                .first()
2546                .and_then(|e| e.first())
2547                .is_some_and(|v| v == "Z01")
2548                && s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| {
2549                    v.chars()
2550                        .nth(3)
2551                        .is_some_and(|c| ['M', 'Q', 'H', 'J'].contains(&c))
2552                })
2553        });
2554        ConditionResult::from(found)
2555    }
2556
2557    /// [86] Wenn das RFF+Z50 (Termine der Marktlokation) aus dieser SG6 (Termine der Marktlokation) auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der...
2558    fn evaluate_86(&self, ctx: &EvaluationContext) -> ConditionResult {
2559        // Check: RFF+Z50 references same LOC as RFF+Z18 in another SG8
2560        ctx.groups_share_qualified_value(
2561            "RFF",
2562            0,
2563            "Z50",
2564            0,
2565            2,
2566            &["SG4", "SG6"],
2567            "RFF",
2568            0,
2569            2,
2570            &["SG4", "SG8"],
2571        )
2572    }
2573
2574    /// [87] Es ist ein Monatserster 0 Uhr (gem. deutscher Zeit) anzugeben
2575    fn evaluate_87(&self, ctx: &EvaluationContext) -> ConditionResult {
2576        // Check: date value is 1st of month at 00:00 (format 303: CCYYMMDDHHmm)
2577        let dtm_segs = ctx.find_segments("DTM");
2578        let found = dtm_segs.iter().any(|s| {
2579            s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| {
2580                v.len() >= 12
2581                    && &v[6..8] == "01"  // day = 01
2582                    && &v[8..12] == "0000" // time = 00:00
2583            })
2584        });
2585        if !found {
2586            // Check if any DTM has a non-matching date (definite False) vs no DTM at all (Unknown)
2587            if dtm_segs.is_empty() {
2588                return ConditionResult::Unknown;
2589            }
2590        }
2591        ConditionResult::from(found)
2592    }
2593
2594    /// [88] Wert muss identisch mit DE2380 aus dem SG4 DTM+157 (Änderung zum) sein
2595    fn evaluate_88(&self, ctx: &EvaluationContext) -> ConditionResult {
2596        // Check: value matches DTM+157 (Änderung zum)
2597        let dtm157 = ctx.find_segments_with_qualifier("DTM", 0, "157");
2598        if dtm157.is_empty() {
2599            return ConditionResult::Unknown;
2600        }
2601        // Condition is True when DTM+157 exists (the value check is structural)
2602        ConditionResult::True
2603    }
2604
2605    /// [89] Wenn im SG8 SEQ+Z01 (Daten der Marktlokation) mit identischer Zeitraum-ID im DE1050 wie in diesem SG8, das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+...
2606    // REVIEW: Checks whether any SG8 instance contains an SG10 child with CCI at elements[2][0]=ZA6 and CAV at elements[0][0]=E14. The condition text requires the Zeitraum-ID in DE1050 to match 'this SG8', but a per-group evaluation context is not available in the current API — the Zeitraum-ID cross-reference is therefore not enforced and is instead approximated as a message-wide check. The CCI qualifier position (elements[2][0]) is confirmed by the MIG reference for CCI segments in SG10. (medium confidence)
2607    fn evaluate_89(&self, ctx: &EvaluationContext) -> ConditionResult {
2608        let nav = match ctx.navigator {
2609            Some(n) => n,
2610            None => {
2611                return ctx.filtered_parent_child_has_qualifier(
2612                    &["SG4", "SG8"],
2613                    "SEQ",
2614                    0,
2615                    "Z01",
2616                    "SG10",
2617                    "CCI",
2618                    2,
2619                    "ZA6",
2620                )
2621            }
2622        };
2623        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2624        for i in 0..sg8_count {
2625            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2626            for j in 0..sg10_count {
2627                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2628                let has_cci_za6 = ccis.iter().any(|s| {
2629                    s.elements
2630                        .get(2)
2631                        .and_then(|e: &Vec<String>| e.first())
2632                        .is_some_and(|v: &String| v == "ZA6")
2633                });
2634                if !has_cci_za6 {
2635                    continue;
2636                }
2637                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2638                if cavs.iter().any(|s| {
2639                    s.elements
2640                        .first()
2641                        .and_then(|e: &Vec<String>| e.first())
2642                        .is_some_and(|v: &String| v == "E14")
2643                }) {
2644                    return ConditionResult::True;
2645                }
2646            }
2647        }
2648        ConditionResult::False
2649    }
2650
2651    /// [90] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) einmal mit CAV+E14 (TLP/TEP) und einmal mit CAV+E02 (SLP/SEP) in dieser SG8 vorhanden
2652    // REVIEW: Within each SG8, iterates all SG10 child instances. For each SG10 that has a CCI with elements[2][0]=ZA6, checks the CAV elements[0][0] value. Tracks whether E14 and E02 have both been seen within the same SG8. Returns True when both are found in a single SG8, satisfying the requirement that both Prognosegrundlage options appear 'in dieser SG8'. (medium confidence)
2653    fn evaluate_90(&self, ctx: &EvaluationContext) -> ConditionResult {
2654        let nav = match ctx.navigator {
2655            Some(n) => n,
2656            None => return ConditionResult::Unknown,
2657        };
2658        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2659        for i in 0..sg8_count {
2660            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2661            let mut has_za6_e14 = false;
2662            let mut has_za6_e02 = false;
2663            for j in 0..sg10_count {
2664                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2665                let has_cci_za6 = ccis.iter().any(|s| {
2666                    s.elements
2667                        .get(2)
2668                        .and_then(|e: &Vec<String>| e.first())
2669                        .is_some_and(|v: &String| v == "ZA6")
2670                });
2671                if !has_cci_za6 {
2672                    continue;
2673                }
2674                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2675                for cav in &cavs {
2676                    if let Some(code) = cav.elements.first().and_then(|e: &Vec<String>| e.first()) {
2677                        if code == "E14" {
2678                            has_za6_e14 = true;
2679                        }
2680                        if code == "E02" {
2681                            has_za6_e02 = true;
2682                        }
2683                    }
2684                }
2685            }
2686            if has_za6_e14 && has_za6_e02 {
2687                return ConditionResult::True;
2688            }
2689        }
2690        ConditionResult::False
2691    }
2692
2693    /// [91] Wenn nicht SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) einmal mit CAV+E14 (TLP/ TEP) und einmal mit CAV+E02 (SLP/SEP) in dieser SG8 vorhanden
2694    // REVIEW: Logical negation of condition 90. Condition 91 is explicitly defined as 'Wenn NICHT (CCI+++ZA6 einmal mit CAV+E14 und einmal mit CAV+E02 in dieser SG8 vorhanden)', which is the exact complement of condition 90. Preserving Unknown propagation handles the no-navigator fallback case correctly. (medium confidence)
2695    fn evaluate_91(&self, ctx: &EvaluationContext) -> ConditionResult {
2696        match self.evaluate_90(ctx) {
2697            ConditionResult::True => ConditionResult::False,
2698            ConditionResult::False => ConditionResult::True,
2699            ConditionResult::Unknown => ConditionResult::Unknown,
2700        }
2701    }
2702
2703    /// [92] Wenn Wert innerhalb SG bzw. Segment geändert wird
2704    fn evaluate_92(&self, _ctx: &EvaluationContext) -> ConditionResult {
2705        // TODO: implement
2706        ConditionResult::Unknown
2707    }
2708
2709    /// [93] Erlaubte Codes aus der PRICAT BGM+Z32 (Preisblatt Messstellenbetrieb) des verantwortlichen MSB
2710    fn evaluate_93(&self, _ctx: &EvaluationContext) -> ConditionResult {
2711        // TODO: implement
2712        ConditionResult::Unknown
2713    }
2714
2715    /// [94] Wenn ein Segment innerhalb der SG vorhanden
2716    fn evaluate_94(&self, _ctx: &EvaluationContext) -> ConditionResult {
2717        // Structural: segment exists within SG (always true for valid messages)
2718        ConditionResult::True
2719    }
2720
2721    /// [95] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) CAV+ZE5 (E-Mobilität) vorhanden
2722    fn evaluate_95(&self, ctx: &EvaluationContext) -> ConditionResult {
2723        let cci_segs = ctx.find_segments("CCI");
2724        let has_cci = cci_segs.iter().any(|s| {
2725            s.elements
2726                .first()
2727                .and_then(|e| e.first())
2728                .is_some_and(|v| v == "Z17")
2729        });
2730        let cav_segs = ctx.find_segments("CAV");
2731        let has_cav = cav_segs.iter().any(|s| {
2732            s.elements
2733                .first()
2734                .and_then(|e| e.first())
2735                .is_some_and(|v| ["ZE5"].contains(&v.as_str()))
2736        });
2737        ConditionResult::from(has_cci && has_cav)
2738    }
2739
2740    /// [96] Wenn SG4 STS+7++xxx+ZAP (Transaktionsgrundergänzung ruhende Marktlokation) vorhanden
2741    fn evaluate_96(&self, ctx: &EvaluationContext) -> ConditionResult {
2742        let sts_segs = ctx.find_segments("STS");
2743        let found = sts_segs.iter().any(|s| {
2744            s.elements
2745                .first()
2746                .and_then(|e| e.first())
2747                .is_some_and(|v| v == "7")
2748                && s.elements
2749                    .get(3)
2750                    .and_then(|e| e.first())
2751                    .is_some_and(|v| ["ZAP"].contains(&v.as_str()))
2752        });
2753        ConditionResult::from(found)
2754    }
2755
2756    /// [97] Wenn in einem SG10 CAV+ZH9 DE7110 der Code der Produkteigenschaft (Wertebereich) 9991000002420 (Marktprämie) vorhanden ist
2757    fn evaluate_97(&self, ctx: &EvaluationContext) -> ConditionResult {
2758        // Check: CAV+ZH9 has code 9991000002420 (Marktprämie)
2759        let cav_segs = ctx.find_segments("CAV");
2760        let found = cav_segs.iter().any(|s| {
2761            s.elements
2762                .first()
2763                .and_then(|e| e.first())
2764                .is_some_and(|v| v == "ZH9")
2765                && s.elements
2766                    .first()
2767                    .and_then(|e| e.get(1))
2768                    .is_some_and(|v| v == "9991000002420")
2769        });
2770        ConditionResult::from(found)
2771    }
2772
2773    /// [98] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle NB
2774    fn evaluate_98(&self, ctx: &EvaluationContext) -> ConditionResult {
2775        ctx.external.evaluate("sender_role_check")
2776    }
2777
2778    /// [99] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle ÜNB
2779    fn evaluate_99(&self, ctx: &EvaluationContext) -> ConditionResult {
2780        ctx.external.evaluate("sender_role_check")
2781    }
2782
2783    /// [100] Wenn SG10 CAV+TLS/ TES/ BIT/ GET/ GAT/ SOT/ WNT/ WFT/ WAT vorhanden
2784    fn evaluate_100(&self, ctx: &EvaluationContext) -> ConditionResult {
2785        let cav_segs = ctx.find_segments("CAV");
2786        let found = cav_segs.iter().any(|s| {
2787            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
2788                [
2789                    "TLS", "TES", "BIT", "GET", "GAT", "SOT", "WNT", "WFT", "WAT",
2790                ]
2791                .contains(&v.as_str())
2792            })
2793        });
2794        ConditionResult::from(found)
2795    }
2796
2797    /// [101] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E14/ Z36 (TLP/ TEP/ TEP mit Ref.messung) in dieser SG8 vorhanden
2798    fn evaluate_101(&self, ctx: &EvaluationContext) -> ConditionResult {
2799        let cci_segs = ctx.find_segments("CCI");
2800        let found = cci_segs.iter().any(|s| {
2801            s.elements
2802                .get(2)
2803                .and_then(|e| e.first())
2804                .is_some_and(|v| v == "ZA6")
2805        });
2806        ConditionResult::from(found)
2807    }
2808
2809    /// [102] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+Z36 (TEP mit Ref.messung) in dieser SG8 vorhanden
2810    fn evaluate_102(&self, ctx: &EvaluationContext) -> ConditionResult {
2811        let cci_segs = ctx.find_segments("CCI");
2812        let found = cci_segs.iter().any(|s| {
2813            s.elements
2814                .get(2)
2815                .and_then(|e| e.first())
2816                .is_some_and(|v| v == "ZA6")
2817        });
2818        ConditionResult::from(found)
2819    }
2820
2821    /// [103] Wenn SG9 QTY+265 (Arbeit / Leistung für tagesparameterabhängig e Marktlokation: Veranschlagte Jahresmenge Gesamt) in dieser SG8 vorhanden
2822    fn evaluate_103(&self, ctx: &EvaluationContext) -> ConditionResult {
2823        let qty_segs = ctx.find_segments("QTY");
2824        let found = qty_segs.iter().any(|s| {
2825            s.elements
2826                .first()
2827                .and_then(|e| e.first())
2828                .is_some_and(|v| v == "265")
2829        });
2830        ConditionResult::from(found)
2831    }
2832
2833    /// [104] Wenn SG9 QTY+Z08 (Arbeit / Leistung für tagesparameterabhängige Marktlokation: angepasste elektrische Arbeit nach Anhang D) in dieser SG8 vorhanden
2834    fn evaluate_104(&self, ctx: &EvaluationContext) -> ConditionResult {
2835        let qty_segs = ctx.find_segments("QTY");
2836        let found = qty_segs.iter().any(|s| {
2837            s.elements
2838                .first()
2839                .and_then(|e| e.first())
2840                .is_some_and(|v| v == "Z08")
2841        });
2842        ConditionResult::from(found)
2843    }
2844
2845    /// [105] Wenn SG9 QTY+Z10 (Arbeit / Leistung für tagesparameterabhängige Marktlokation: Leistung der Marktlokation) in dieser SG8 vorhanden
2846    fn evaluate_105(&self, ctx: &EvaluationContext) -> ConditionResult {
2847        let qty_segs = ctx.find_segments("QTY");
2848        let found = qty_segs.iter().any(|s| {
2849            s.elements
2850                .first()
2851                .and_then(|e| e.first())
2852                .is_some_and(|v| v == "Z10")
2853        });
2854        ConditionResult::from(found)
2855    }
2856
2857    /// [106] Wenn in dieser SG8 SEQ+Z01 SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E02 (SLP/SEP) vorhanden
2858    fn evaluate_106(&self, ctx: &EvaluationContext) -> ConditionResult {
2859        // Check: in SG8 with SEQ+Z01, SG10 has CCI+++ZA6 and CAV+E02
2860        ctx.filtered_parent_child_has_qualifier(
2861            &["SG4", "SG8"],
2862            "SEQ",
2863            0,
2864            "Z01",
2865            "SG10",
2866            "CAV",
2867            0,
2868            "E02",
2869        )
2870    }
2871
2872    /// [107] Wenn in derselben SG8 das SG10 CAV+SLS/ SES/ BIP/ GEP/ GAP/ SOP/ WNP/ WFP/ WAP vorhanden
2873    fn evaluate_107(&self, ctx: &EvaluationContext) -> ConditionResult {
2874        let cav_segs = ctx.find_segments("CAV");
2875        let found = cav_segs.iter().any(|s| {
2876            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
2877                [
2878                    "SLS", "SES", "BIP", "GEP", "GAP", "SOP", "WNP", "WFP", "WAP",
2879                ]
2880                .contains(&v.as_str())
2881            })
2882        });
2883        ConditionResult::from(found)
2884    }
2885
2886    /// [108] Wenn in derselben SG8 (Netznutzungsabrechnungsdaten der Marktlokation) eine Gruppen-/Artikel-ID im PIA+Z02 (Gruppenartikel-ID / Artikel-ID), welche mit 1-08-1/2/3/4/5 beginnt, vorhanden
2887    // HAND-EDITED — do not let generate-conditions regenerate this function
2888    // without first confirming prompt.rs B6 SCOPE RULES section is in the
2889    // system prompt. Regeneration without that guidance would emit
2890    // ctx.has_qualifier (message-wide) and silently reintroduce the
2891    // per-instance bug this function fixes.
2892    // See: docs/plans/2026-04-23-ahb-codelist-and-per-instance-plan.md B7.
2893    fn evaluate_108(&self, ctx: &EvaluationContext) -> ConditionResult {
2894        // [108] Wenn in derselben SG8 ein PIA+Z02 mit einem Code aus
2895        // 1-08-1/2/3/4/5 vorhanden. Scope-aware: narrows to the current
2896        // SG8 instance when GroupScope is set; falls back to message-wide.
2897        const PREFIXES: &[&str] = &["1-08-1", "1-08-2", "1-08-3", "1-08-4", "1-08-5"];
2898        let found = ctx
2899            .scoped_find_segments_with_qualifier("PIA", 0, "Z02")
2900            .iter()
2901            .any(|s| {
2902                s.elements
2903                    .get(1)
2904                    .and_then(|e| e.first())
2905                    .is_some_and(|v| PREFIXES.iter().any(|p| v.starts_with(p)))
2906            });
2907        ConditionResult::from(found)
2908    }
2909
2910    /// [110] Wenn SG10 CAV+LGS/ EGS/ BIL/ GEL/ GAL/ SOL/ WNL/ WFL / WAL vorhanden
2911    fn evaluate_110(&self, ctx: &EvaluationContext) -> ConditionResult {
2912        let cav_segs = ctx.find_segments("CAV");
2913        let found = cav_segs.iter().any(|s| {
2914            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
2915                [
2916                    "LGS", "EGS", "BIL", "GEL", "GAL", "SOL", "WNL", "WFL", "WAL",
2917                ]
2918                .contains(&v.as_str())
2919            })
2920        });
2921        ConditionResult::from(found)
2922    }
2923
2924    /// [111] Wenn in derselben SG8 SEQ+Z59 (Produkt-Daten der Marktlokation) das PIA+5 (Produkt-Daten der Marktlokation) nicht vorhanden
2925    fn evaluate_111(&self, ctx: &EvaluationContext) -> ConditionResult {
2926        ctx.any_group_has_qualifier_without("SEQ", 0, "Z59", "PIA", 0, "5", &["SG4", "SG8"])
2927    }
2928
2929    /// [112] Wenn in derselben SG8 SEQ+Z59 (Produkt-Daten der Marktlokation) das SG10 CCI+11 (Details zum Produkt der Marktlokation) nicht vorhanden
2930    fn evaluate_112(&self, ctx: &EvaluationContext) -> ConditionResult {
2931        let result = ctx.filtered_parent_child_has_qualifier(
2932            &["SG4", "SG8"],
2933            "SEQ",
2934            0,
2935            "Z59",
2936            "SG10",
2937            "CCI",
2938            0,
2939            "11",
2940        );
2941        match result {
2942            ConditionResult::True => ConditionResult::False,
2943            ConditionResult::False => ConditionResult::True,
2944            ConditionResult::Unknown => ConditionResult::Unknown,
2945        }
2946    }
2947
2948    /// [113] Wenn es sich um eine Antwort auf die Bestellung einer Zählzeit handelt
2949    fn evaluate_113(&self, ctx: &EvaluationContext) -> ConditionResult {
2950        // Antwort auf Bestellung einer Zählzeit — depends on PID context
2951        ctx.external.evaluate("counting_time_order_response")
2952    }
2953
2954    /// [114] Wenn das SG10 CCI+E03 (Spannungsebene der Marktlokation) CAV E06 (Niederspannung) in dieser SG vorhanden
2955    // REVIEW: Checks that CCI+E03 (Spannungsebene, elements[0][0]='E03' per AHB hint) and CAV+E06 (Niederspannung, elements[0][0]='E06') co-occur in the same SG10 child instance of some SG8. Uses navigator to iterate SG8→SG10 pairs and verify both segments within the same SG10 instance. Confidence medium because navigator availability is runtime-dependent and fallback is message-wide only. (medium confidence)
2956    fn evaluate_114(&self, ctx: &EvaluationContext) -> ConditionResult {
2957        let nav = match ctx.navigator {
2958            Some(n) => n,
2959            None => {
2960                return match (
2961                    ctx.has_qualifier("CCI", 0, "E03"),
2962                    ctx.has_qualifier("CAV", 0, "E06"),
2963                ) {
2964                    (ConditionResult::True, ConditionResult::True) => ConditionResult::True,
2965                    (ConditionResult::False, _) | (_, ConditionResult::False) => {
2966                        ConditionResult::False
2967                    }
2968                    _ => ConditionResult::Unknown,
2969                };
2970            }
2971        };
2972        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2973        for i in 0..sg8_count {
2974            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2975            for j in 0..sg10_count {
2976                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2977                let has_cci_e03 = ccis.iter().any(|s| {
2978                    s.elements
2979                        .first()
2980                        .and_then(|e: &Vec<String>| e.first())
2981                        .is_some_and(|v: &String| v == "E03")
2982                });
2983                if has_cci_e03 {
2984                    let cavs =
2985                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2986                    if cavs.iter().any(|s| {
2987                        s.elements
2988                            .first()
2989                            .and_then(|e: &Vec<String>| e.first())
2990                            .is_some_and(|v: &String| v == "E06")
2991                    }) {
2992                        return ConditionResult::True;
2993                    }
2994                }
2995            }
2996        }
2997        ConditionResult::False
2998    }
2999
3000    /// [115] Wenn das SG10 CCI+E03 (Spannungsebene der Marktlokation) CAV E05 (Mittelspannung) in dieser SG vorhanden
3001    fn evaluate_115(&self, ctx: &EvaluationContext) -> ConditionResult {
3002        let cci_segs = ctx.find_segments("CCI");
3003        let has_cci = cci_segs.iter().any(|s| {
3004            s.elements
3005                .first()
3006                .and_then(|e| e.first())
3007                .is_some_and(|v| v == "E03")
3008        });
3009        let cav_segs = ctx.find_segments("CAV");
3010        let has_cav = cav_segs.iter().any(|s| {
3011            s.elements
3012                .first()
3013                .and_then(|e| e.first())
3014                .is_some_and(|v| v == "E05")
3015        });
3016        ConditionResult::from(has_cci && has_cav)
3017    }
3018
3019    /// [116] Wenn das SG10 CCI+E03 (Spannungsebene der Marktlokation) CAV E04 (Hochspannung) in dieser SG vorhanden
3020    fn evaluate_116(&self, ctx: &EvaluationContext) -> ConditionResult {
3021        let cci_segs = ctx.find_segments("CCI");
3022        let has_cci = cci_segs.iter().any(|s| {
3023            s.elements
3024                .first()
3025                .and_then(|e| e.first())
3026                .is_some_and(|v| v == "E03")
3027        });
3028        let cav_segs = ctx.find_segments("CAV");
3029        let has_cav = cav_segs.iter().any(|s| {
3030            s.elements
3031                .first()
3032                .and_then(|e| e.first())
3033                .is_some_and(|v| v == "E04")
3034        });
3035        ConditionResult::from(has_cci && has_cav)
3036    }
3037
3038    /// [117] Wenn das RFF+Z18 (Marktlokation) aus dieser SG8 auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der Marktlokation), in dem SG10 CCI+++ZA6 (...
3039    // REVIEW: Full condition requires: (1) current SG8 has RFF+Z18=X, (2) another SG8 with SEQ+Z01 also has RFF+Z18=X, (3) that SG8 has SG10 with CCI elements[2][0]='ZA6' AND CAV elements[0][0]='E14'. Implementation simplifies to checking whether any SG8 has SG10 with both CCI+++ZA6 and CAV+E14 co-occurring in the same SG10 instance. The cross-SG RFF+Z18 value correlation and SEQ+Z01 parent check are omitted because the navigator API only exposes child-group segments (SG10 within SG8), not SG8's own entry segments. Medium confidence due to this structural limitation. (medium confidence)
3040    fn evaluate_117(&self, ctx: &EvaluationContext) -> ConditionResult {
3041        let nav = match ctx.navigator {
3042            Some(n) => n,
3043            None => return ConditionResult::Unknown,
3044        };
3045        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3046        for i in 0..sg8_count {
3047            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
3048            for j in 0..sg10_count {
3049                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
3050                let has_cci_za6 = ccis.iter().any(|s| {
3051                    s.elements
3052                        .get(2)
3053                        .and_then(|e: &Vec<String>| e.first())
3054                        .is_some_and(|v: &String| v == "ZA6")
3055                });
3056                if has_cci_za6 {
3057                    let cavs =
3058                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
3059                    if cavs.iter().any(|s| {
3060                        s.elements
3061                            .first()
3062                            .and_then(|e: &Vec<String>| e.first())
3063                            .is_some_and(|v: &String| v == "E14")
3064                    }) {
3065                        return ConditionResult::True;
3066                    }
3067                }
3068            }
3069        }
3070        ConditionResult::False
3071    }
3072
3073    /// [118] Wenn in dieser SG8 SEQ+Z98 SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E02 (SLP/ SEP) vorhanden
3074    fn evaluate_118(&self, ctx: &EvaluationContext) -> ConditionResult {
3075        let has_cci = ctx.filtered_parent_child_has_qualifier(
3076            &["SG4", "SG8"],
3077            "SEQ",
3078            0,
3079            "Z98",
3080            "SG10",
3081            "CCI",
3082            2,
3083            "ZA6",
3084        );
3085        if has_cci != ConditionResult::True {
3086            return has_cci;
3087        }
3088        ctx.filtered_parent_child_has_qualifier(
3089            &["SG4", "SG8"],
3090            "SEQ",
3091            0,
3092            "Z98",
3093            "SG10",
3094            "CAV",
3095            0,
3096            "E02",
3097        )
3098    }
3099
3100    /// [119] Wenn in der SG8 SEQ+Z01/ Z98 SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E02 (SLP/SEP) vorhanden
3101    fn evaluate_119(&self, ctx: &EvaluationContext) -> ConditionResult {
3102        // Check: in SG8 with SEQ+Z01 or Z98, SG10 has CCI+++ZA6 and CAV+E02
3103        let r1 = ctx.filtered_parent_child_has_qualifier(
3104            &["SG4", "SG8"],
3105            "SEQ",
3106            0,
3107            "Z01",
3108            "SG10",
3109            "CAV",
3110            0,
3111            "E02",
3112        );
3113        if r1 == ConditionResult::True {
3114            return ConditionResult::True;
3115        }
3116        ctx.filtered_parent_child_has_qualifier(
3117            &["SG4", "SG8"],
3118            "SEQ",
3119            0,
3120            "Z98",
3121            "SG10",
3122            "CAV",
3123            0,
3124            "E02",
3125        )
3126    }
3127
3128    /// [120] Wenn von NB Abtretungserklärung benötigt wird
3129    fn evaluate_120(&self, _ctx: &EvaluationContext) -> ConditionResult {
3130        // TODO: implement
3131        ConditionResult::Unknown
3132    }
3133
3134    /// [121] Wenn in dem SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) das SG8 RFF+Z14 (Referenz auf das Smartmeter-Gateway) nicht vorhanden
3135    fn evaluate_121(&self, ctx: &EvaluationContext) -> ConditionResult {
3136        let z03 =
3137            ctx.any_group_has_qualifier_without("SEQ", 0, "Z03", "RFF", 0, "Z14", &["SG4", "SG8"]);
3138        if z03 == ConditionResult::True {
3139            return ConditionResult::True;
3140        }
3141        ctx.any_group_has_qualifier_without("SEQ", 0, "ZF5", "RFF", 0, "Z14", &["SG4", "SG8"])
3142    }
3143
3144    /// [122] Wenn in dieser SG8 SEQ+Z98 SG10 CCI+++E03 (Spannungsebene der Marktlokation) CAV+E06 (Niederspannung) vorhanden
3145    // REVIEW: Uses filtered_parent_child_has_qualifier to find SG8 instances where SEQ+Z98 has an SG10 child with CCI at elements[2]='E03' (Spannungsebene der Marktlokation). Then confirms CAV+E06 (Niederspannung) exists in an SG8 group. The CAV check is group-scoped rather than strictly same-SG10-instance because the navigator API does not directly expose parent-group (SG8) segment access alongside child-group (SG10) checks in one call. (medium confidence)
3146    fn evaluate_122(&self, ctx: &EvaluationContext) -> ConditionResult {
3147        // Check: in SG8 with SEQ+Z98, SG10 child has CCI+++E03 (Spannungsebene, elements[2][0]="E03")
3148        let has_cci_e03 = ctx.filtered_parent_child_has_qualifier(
3149            &["SG4", "SG8"],
3150            "SEQ",
3151            0,
3152            "Z98",
3153            "SG10",
3154            "CCI",
3155            2,
3156            "E03",
3157        );
3158        if has_cci_e03 != ConditionResult::True {
3159            return has_cci_e03;
3160        }
3161        // Also verify CAV+E06 (Niederspannung, elements[0][0]="E06") exists in the same SG8 scope
3162        ctx.any_group_has_qualifier("CAV", 0, "E06", &["SG4", "SG8"])
3163    }
3164
3165    /// [123] Wenn noch mindestens eine weitere SG8 SEQ+Z20 (OBIS-Daten der Zähleinrichtung Smartmeter-Gateway) mit dem SG8 RFF+MG (Gerätenummer des Zählers) auf die gleiche Identifikation/Nummer des Gerätes...
3166    // REVIEW: Scans segments linearly to collect RFF+MG device IDs from each SG8 group with SEQ+Z20 (OBIS-Daten der Zähleinrichtung/Smartmeter-Gateway). A new SEQ starts a new SG8 context; RFF+MG within that context records the device number. Returns True if any device ID appears in 2+ different SG8 groups (indicating multiple OBIS datasets reference the same device). Linear scan is used because the navigator API does not expose a direct method to retrieve segments within a parent SG8 instance by absolute index. (medium confidence)
3167    fn evaluate_123(&self, ctx: &EvaluationContext) -> ConditionResult {
3168        struct Sg8Z20Entry {
3169            mg_id: Option<String>,
3170        }
3171        let mut entries: Vec<Sg8Z20Entry> = Vec::new();
3172        let mut current: Option<Sg8Z20Entry> = None;
3173        for seg in ctx.segments {
3174            match seg.id.as_str() {
3175                "SEQ" => {
3176                    if let Some(entry) = current.take() {
3177                        entries.push(entry);
3178                    }
3179                    if seg
3180                        .elements
3181                        .first()
3182                        .and_then(|e: &Vec<String>| e.first())
3183                        .is_some_and(|v: &String| v == "Z20")
3184                    {
3185                        current = Some(Sg8Z20Entry { mg_id: None });
3186                    }
3187                }
3188                "RFF" if current.is_some() => {
3189                    if seg
3190                        .elements
3191                        .first()
3192                        .and_then(|e: &Vec<String>| e.first())
3193                        .is_some_and(|v: &String| v == "MG")
3194                    {
3195                        if let Some(ref mut entry) = current {
3196                            if entry.mg_id.is_none() {
3197                                entry.mg_id = seg.elements.first().and_then(|e| e.get(1)).cloned();
3198                            }
3199                        }
3200                    }
3201                }
3202                _ => {}
3203            }
3204        }
3205        if let Some(entry) = current {
3206            entries.push(entry);
3207        }
3208        let ids: Vec<&str> = entries
3209            .iter()
3210            .filter_map(|e| e.mg_id.as_deref().filter(|s| !s.is_empty()))
3211            .collect();
3212        for i in 0..ids.len() {
3213            for j in (i + 1)..ids.len() {
3214                if ids[i] == ids[j] {
3215                    return ConditionResult::True;
3216                }
3217            }
3218        }
3219        ConditionResult::False
3220    }
3221
3222    /// [124] Wenn noch mindestens eine weitere SG8 SEQ+Z20 (OBIS-Daten der Zähleinrichtung Smartmeter-Gateway) mit derselben Zeitraum-ID aus dem DE1050 dieser SG8 mit dem SG8 RFF+MG (Gerätenummer des Zählers...
3223    // REVIEW: Extends condition 123 by also requiring that the matching SG8 groups share the same Zeitraum-ID (from SEQ.elements[1][0] = DE1050 / C286.d1050). Both the Zeitraum-ID and the RFF+MG device number must be identical across at least two different SG8 instances with SEQ+Z20 for the condition to be True. (medium confidence)
3224    fn evaluate_124(&self, ctx: &EvaluationContext) -> ConditionResult {
3225        struct Sg8Z20Entry {
3226            zeitraum_id: String,
3227            mg_id: Option<String>,
3228        }
3229        let mut entries: Vec<Sg8Z20Entry> = Vec::new();
3230        let mut current: Option<Sg8Z20Entry> = None;
3231        for seg in ctx.segments {
3232            match seg.id.as_str() {
3233                "SEQ" => {
3234                    if let Some(entry) = current.take() {
3235                        entries.push(entry);
3236                    }
3237                    if seg
3238                        .elements
3239                        .first()
3240                        .and_then(|e: &Vec<String>| e.first())
3241                        .is_some_and(|v: &String| v == "Z20")
3242                    {
3243                        let zeitraum_id = seg
3244                            .elements
3245                            .get(1)
3246                            .and_then(|e: &Vec<String>| e.first())
3247                            .cloned()
3248                            .unwrap_or_default();
3249                        current = Some(Sg8Z20Entry {
3250                            zeitraum_id,
3251                            mg_id: None,
3252                        });
3253                    }
3254                }
3255                "RFF" if current.is_some() => {
3256                    if seg
3257                        .elements
3258                        .first()
3259                        .and_then(|e: &Vec<String>| e.first())
3260                        .is_some_and(|v: &String| v == "MG")
3261                    {
3262                        if let Some(ref mut entry) = current {
3263                            if entry.mg_id.is_none() {
3264                                entry.mg_id = seg.elements.first().and_then(|e| e.get(1)).cloned();
3265                            }
3266                        }
3267                    }
3268                }
3269                _ => {}
3270            }
3271        }
3272        if let Some(entry) = current {
3273            entries.push(entry);
3274        }
3275        for i in 0..entries.len() {
3276            for j in (i + 1)..entries.len() {
3277                let ei = &entries[i];
3278                let ej = &entries[j];
3279                if !ei.zeitraum_id.is_empty()
3280                    && ei.zeitraum_id == ej.zeitraum_id
3281                    && ei.mg_id.is_some()
3282                    && !ei.mg_id.as_deref().unwrap_or("").is_empty()
3283                    && ei.mg_id == ej.mg_id
3284                {
3285                    return ConditionResult::True;
3286                }
3287            }
3288        }
3289        ConditionResult::False
3290    }
3291
3292    /// [125] Wenn in derselben SG8 SEQ+Z76/ ZC5/ ZC6 (Messstellenbetriebsabrechnungsdaten der Marktlokation) im DE4347 des PIA Z02 (Gruppenartikel-ID / Artikel-ID) vorhanden
3293    fn evaluate_125(&self, ctx: &EvaluationContext) -> ConditionResult {
3294        let seq_segs = ctx.find_segments("SEQ");
3295        let found = seq_segs.iter().any(|s| {
3296            s.elements
3297                .first()
3298                .and_then(|e| e.first())
3299                .is_some_and(|v| ["Z76", "ZC5", "ZC6"].contains(&v.as_str()))
3300        });
3301        ConditionResult::from(found)
3302    }
3303
3304    /// [126] Es ist der Wert einzutragen, der sich aus der Wiederholungshäufigkeit des SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: Gültige Daten/ Keine Daten) ergibt. Bedeutet: Das erste SG6 RFF+Z49/ Z53...
3305    fn evaluate_126(&self, ctx: &EvaluationContext) -> ConditionResult {
3306        // Check: RFF+Z49 or Z53 repetition count determines value
3307        // Approximate: check if RFF+Z49 or Z53 exists (counter is structural)
3308        let count = ctx.find_segments_with_qualifier("RFF", 0, "Z49").len()
3309            + ctx.find_segments_with_qualifier("RFF", 0, "Z53").len();
3310        ConditionResult::from(count > 0)
3311    }
3312
3313    /// [127] Es ist der Wert einzutragen, der sich aus der Wiederholungshäufigkeit des SG6 RFF+Z48/ Z55 (Verwendungszeitraum der Daten: Erwartete Daten/ Keine Daten erwartet) ergibt. Bedeutet: Das erste SG6  R...
3314    fn evaluate_127(&self, ctx: &EvaluationContext) -> ConditionResult {
3315        // Check: RFF+Z48 or Z55 repetition count determines value
3316        let count = ctx.find_segments_with_qualifier("RFF", 0, "Z48").len()
3317            + ctx.find_segments_with_qualifier("RFF", 0, "Z55").len();
3318        ConditionResult::from(count > 0)
3319    }
3320
3321    /// [128] Es ist der Wert einzutragen, der sich aus der Wiederholungshäufigkeit des SG6 RFF+Z47/ Z54 (Verwendungszeitraum der Daten: Im System vorhandene Daten/ Im System keine Daten vorhanden) ergibt. Bede...
3322    fn evaluate_128(&self, ctx: &EvaluationContext) -> ConditionResult {
3323        // Check: RFF+Z47 or Z54 repetition count determines value
3324        let count = ctx.find_segments_with_qualifier("RFF", 0, "Z47").len()
3325            + ctx.find_segments_with_qualifier("RFF", 0, "Z54").len();
3326        ConditionResult::from(count > 0)
3327    }
3328
3329    /// [129] Innerhalb eines SG4 IDE müssen alle DE3225 der SG5 LOC+Z16 (Marktlokation) den identischen Wert enthalten
3330    fn evaluate_129(&self, ctx: &EvaluationContext) -> ConditionResult {
3331        // Check: all LOC+Z16 DE3225 values are identical
3332        let loc_segs = ctx.find_segments_with_qualifier("LOC", 0, "Z16");
3333        if loc_segs.len() <= 1 {
3334            return ConditionResult::True;
3335        }
3336        let first_val = loc_segs[0].elements.get(1).and_then(|e| e.first());
3337        let all_same = loc_segs
3338            .iter()
3339            .all(|s| s.elements.get(1).and_then(|e| e.first()) == first_val);
3340        ConditionResult::from(all_same)
3341    }
3342
3343    /// [130] Wenn an Messlokation vorhanden
3344    fn evaluate_130(&self, _ctx: &EvaluationContext) -> ConditionResult {
3345        // TODO: implement
3346        ConditionResult::Unknown
3347    }
3348
3349    /// [131] Wenn dieses DTM+Z25 (Verwendung der Daten ab) im SG6 RFF (Verwendungszeitraum der Daten) mit der Zeitraum ID \"1\" im DE1156 gekennzeichnet ist, muss das Datum in diesem DE2380 der direkt auf DTM+1...
3350    fn evaluate_131(&self, ctx: &EvaluationContext) -> ConditionResult {
3351        // Check: DTM+Z25 is in SG6 RFF with Zeitraum-ID "1" in DE1156
3352        let has_zeitraum_id_1 = ctx.find_segments("RFF").iter().any(|s| {
3353            s.elements
3354                .first()
3355                .and_then(|e| e.get(2))
3356                .is_some_and(|v| v == "1")
3357        });
3358        ConditionResult::from(has_zeitraum_id_1)
3359    }
3360
3361    /// [132] Wenn dieses DTM+Z25 (Verwendung der Daten ab) im SG6 RFF (Verwendungszeitraum der Daten) mit der Zeitraum ID "1" im DE1156 gekennzeichnet ist, muss das Datum in diesem DE2380 der direkt auf DTM+137...
3362    // REVIEW: Validates that when RFF in SG6 has Zeitraum-ID '1' (elements[0][2] = DE1156), the DTM+Z25 date must equal the day immediately following DTM+137 (Nachrichtendatum) at 00:00. Parses the YYYYMMDD portion of DTM+137, computes next calendar day with correct month/year rollover, then checks that DTM+Z25's first 12 characters match YYYYMMDDHHMM with HHMM=0000. Note: German timezone offset (CET/CEST) validation is not performed — this checks the stored datetime value directly, which is the common encoding in EDIFACT 303 format for this use case. (medium confidence)
3363    fn evaluate_132(&self, ctx: &EvaluationContext) -> ConditionResult {
3364        // Condition applies only when RFF in SG6 has Zeitraum-ID "1" in DE1156 (elements[0][2])
3365        let has_zeitraum_id_1 = ctx.find_segments("RFF").iter().any(|s| {
3366            s.elements
3367                .first()
3368                .and_then(|e| e.get(2))
3369                .is_some_and(|v: &String| v == "1")
3370        });
3371        if !has_zeitraum_id_1 {
3372            return ConditionResult::False;
3373        }
3374        // Get message date from DTM+137 (format 303: CCYYMMDDHHmm...)
3375        let msg_date_str = match ctx
3376            .find_segments_with_qualifier("DTM", 0, "137")
3377            .into_iter()
3378            .next()
3379        {
3380            Some(seg) => match seg.elements.first().and_then(|e| e.get(1)) {
3381                Some(v) if v.len() >= 8 => v.clone(),
3382                _ => return ConditionResult::Unknown,
3383            },
3384            None => return ConditionResult::Unknown,
3385        };
3386        // Get DTM+Z25 (Verwendung der Daten ab) value
3387        let usage_date_str = match ctx
3388            .find_segments_with_qualifier("DTM", 0, "Z25")
3389            .into_iter()
3390            .next()
3391        {
3392            Some(seg) => match seg.elements.first().and_then(|e| e.get(1)) {
3393                Some(v) if v.len() >= 12 => v.clone(),
3394                _ => return ConditionResult::Unknown,
3395            },
3396            None => return ConditionResult::Unknown,
3397        };
3398        // Parse YYYYMMDD from DTM+137 value
3399        let year: u32 = match msg_date_str[..4].parse() {
3400            Ok(v) => v,
3401            Err(_) => return ConditionResult::Unknown,
3402        };
3403        let month: u32 = match msg_date_str[4..6].parse() {
3404            Ok(v) => v,
3405            Err(_) => return ConditionResult::Unknown,
3406        };
3407        let day: u32 = match msg_date_str[6..8].parse() {
3408            Ok(v) => v,
3409            Err(_) => return ConditionResult::Unknown,
3410        };
3411        let days_in_month: u32 = match month {
3412            1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
3413            4 | 6 | 9 | 11 => 30,
3414            2 => {
3415                if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) {
3416                    29
3417                } else {
3418                    28
3419                }
3420            }
3421            _ => return ConditionResult::Unknown,
3422        };
3423        let (next_year, next_month, next_day): (u32, u32, u32) = if day >= days_in_month {
3424            if month == 12 {
3425                (year + 1, 1, 1)
3426            } else {
3427                (year, month + 1, 1)
3428            }
3429        } else {
3430            (year, month, day + 1)
3431        };
3432        // Expected DTM+Z25: next day at 00:00 — format 303 prefix YYYYMMDDHHMM = 12 chars
3433        let expected_prefix = format!("{:04}{:02}{:02}0000", next_year, next_month, next_day);
3434        let actual_len = usage_date_str.len().min(12);
3435        let actual_prefix = &usage_date_str[..actual_len];
3436        ConditionResult::from(actual_prefix == expected_prefix.as_str())
3437    }
3438
3439    /// [133] Wenn an der übermittelten Marktlokation / Messlokation vorhanden
3440    fn evaluate_133(&self, _ctx: &EvaluationContext) -> ConditionResult {
3441        // TODO: implement
3442        ConditionResult::Unknown
3443    }
3444
3445    /// [134] Wenn dieses DTM+Z25 (Verwendung der Daten ab) nicht im SG6 RFF+Z48/ Z55 (Verwendungszeitraum der Daten: Erwartete Daten/ Keine Daten erwartet) mit der Zeitraum ID "1" im DE1156 ist, muss das Datum ...
3446    // REVIEW: Validates time-slice continuity for Z48/Z55 (Erwartete Daten/Keine Daten erwartet) SG6 groups: every slice with Zeitraum-ID > 1 must have its DTM+Z25 (start date) equal to the DTM+Z26 (end date) of the preceding slice. Zeitraum-ID is in RFF.C506.DE1156 = elements[0][2]. Requires navigator for per-SG6-instance DTM extraction. (medium confidence)
3447    fn evaluate_134(&self, ctx: &EvaluationContext) -> ConditionResult {
3448        let nav = match ctx.navigator() {
3449            Some(n) => n,
3450            None => return ConditionResult::Unknown,
3451        };
3452        let sg6_count = nav.group_instance_count(&["SG4", "SG6"]);
3453        // Collect (zeitraum_id, dtm_z25_value, dtm_z26_value) for every Z48/Z55 SG6
3454        let mut slices: Vec<(u32, Option<String>, Option<String>)> = Vec::new();
3455        for i in 0..sg6_count {
3456            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG6"], i);
3457            // RFF C506: [0][0]=qualifier, [0][1]=ref-id, [0][2]=Zeitraum-ID
3458            let maybe_zid = rffs.iter().find_map(|s| {
3459                let qual = s
3460                    .elements
3461                    .first()
3462                    .and_then(|e| e.first())
3463                    .map(|v| v.as_str())?;
3464                if qual == "Z48" || qual == "Z55" {
3465                    s.elements
3466                        .first()
3467                        .and_then(|e| e.get(2))
3468                        .and_then(|v| v.parse::<u32>().ok())
3469                } else {
3470                    None
3471                }
3472            });
3473            if let Some(zid) = maybe_zid {
3474                let dtms = nav.find_segments_in_group("DTM", &["SG4", "SG6"], i);
3475                let z25 = dtms.iter().find_map(|s| {
3476                    if s.elements
3477                        .first()
3478                        .and_then(|e| e.first())
3479                        .map(|v| v.as_str())
3480                        == Some("Z25")
3481                    {
3482                        s.elements.first().and_then(|e| e.get(1)).cloned()
3483                    } else {
3484                        None
3485                    }
3486                });
3487                let z26 = dtms.iter().find_map(|s| {
3488                    if s.elements
3489                        .first()
3490                        .and_then(|e| e.first())
3491                        .map(|v| v.as_str())
3492                        == Some("Z26")
3493                    {
3494                        s.elements.first().and_then(|e| e.get(1)).cloned()
3495                    } else {
3496                        None
3497                    }
3498                });
3499                slices.push((zid, z25, z26));
3500            }
3501        }
3502        if slices.is_empty() {
3503            return ConditionResult::Unknown;
3504        }
3505        // For each slice with Zeitraum-ID > 1: its DTM+Z25 must equal DTM+Z26 of the previous slice
3506        for i in 0..slices.len() {
3507            let (zid, ref z25, _) = slices[i];
3508            if zid <= 1 {
3509                continue;
3510            }
3511            let prev_id = zid - 1;
3512            match slices.iter().find(|(id, _, _)| *id == prev_id) {
3513                Some((_, _, prev_z26)) => match (z25, prev_z26) {
3514                    (Some(curr), Some(prev_end)) => {
3515                        if curr != prev_end {
3516                            return ConditionResult::False;
3517                        }
3518                    }
3519                    _ => return ConditionResult::Unknown,
3520                },
3521                None => return ConditionResult::Unknown,
3522            }
3523        }
3524        ConditionResult::True
3525    }
3526
3527    /// [135] Wenn dieses DTM+Z25 (Verwendung der Daten ab) nicht im SG6 RFF+Z47/ Z54 (Verwendungszeitraum der Daten: Im System vorhandene Daten/ Im System keine Daten vorhanden) mit der Zeitraum ID "1" im DE115...
3528    // REVIEW: Identical time-slice continuity logic as condition 134 but applied to Z47/Z54 (Im System vorhandene Daten/Im System keine Daten vorhanden) SG6 groups. Same structural rule: DTM+Z25 of slice N must equal DTM+Z26 of slice N-1 for all N > 1. (medium confidence)
3529    fn evaluate_135(&self, ctx: &EvaluationContext) -> ConditionResult {
3530        let nav = match ctx.navigator() {
3531            Some(n) => n,
3532            None => return ConditionResult::Unknown,
3533        };
3534        let sg6_count = nav.group_instance_count(&["SG4", "SG6"]);
3535        // Collect (zeitraum_id, dtm_z25_value, dtm_z26_value) for every Z47/Z54 SG6
3536        let mut slices: Vec<(u32, Option<String>, Option<String>)> = Vec::new();
3537        for i in 0..sg6_count {
3538            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG6"], i);
3539            // RFF C506: [0][0]=qualifier, [0][1]=ref-id, [0][2]=Zeitraum-ID
3540            let maybe_zid = rffs.iter().find_map(|s| {
3541                let qual = s
3542                    .elements
3543                    .first()
3544                    .and_then(|e| e.first())
3545                    .map(|v| v.as_str())?;
3546                if qual == "Z47" || qual == "Z54" {
3547                    s.elements
3548                        .first()
3549                        .and_then(|e| e.get(2))
3550                        .and_then(|v| v.parse::<u32>().ok())
3551                } else {
3552                    None
3553                }
3554            });
3555            if let Some(zid) = maybe_zid {
3556                let dtms = nav.find_segments_in_group("DTM", &["SG4", "SG6"], i);
3557                let z25 = dtms.iter().find_map(|s| {
3558                    if s.elements
3559                        .first()
3560                        .and_then(|e| e.first())
3561                        .map(|v| v.as_str())
3562                        == Some("Z25")
3563                    {
3564                        s.elements.first().and_then(|e| e.get(1)).cloned()
3565                    } else {
3566                        None
3567                    }
3568                });
3569                let z26 = dtms.iter().find_map(|s| {
3570                    if s.elements
3571                        .first()
3572                        .and_then(|e| e.first())
3573                        .map(|v| v.as_str())
3574                        == Some("Z26")
3575                    {
3576                        s.elements.first().and_then(|e| e.get(1)).cloned()
3577                    } else {
3578                        None
3579                    }
3580                });
3581                slices.push((zid, z25, z26));
3582            }
3583        }
3584        if slices.is_empty() {
3585            return ConditionResult::Unknown;
3586        }
3587        // For each slice with Zeitraum-ID > 1: its DTM+Z25 must equal DTM+Z26 of the previous slice
3588        for i in 0..slices.len() {
3589            let (zid, ref z25, _) = slices[i];
3590            if zid <= 1 {
3591                continue;
3592            }
3593            let prev_id = zid - 1;
3594            match slices.iter().find(|(id, _, _)| *id == prev_id) {
3595                Some((_, _, prev_z26)) => match (z25, prev_z26) {
3596                    (Some(curr), Some(prev_end)) => {
3597                        if curr != prev_end {
3598                            return ConditionResult::False;
3599                        }
3600                    }
3601                    _ => return ConditionResult::Unknown,
3602                },
3603                None => return ConditionResult::Unknown,
3604            }
3605        }
3606        ConditionResult::True
3607    }
3608
3609    /// [136] Wenn SG10 CCI+++E13 (Zählertyp) CAV+EHZ (elektronischer Haushaltszähler) vorhanden
3610    fn evaluate_136(&self, ctx: &EvaluationContext) -> ConditionResult {
3611        let cci_segs = ctx.find_segments("CCI");
3612        let found = cci_segs.iter().any(|s| {
3613            s.elements
3614                .get(2)
3615                .and_then(|e| e.first())
3616                .is_some_and(|v| v == "E13")
3617        });
3618        ConditionResult::from(found)
3619    }
3620
3621    /// [137] Nicht bei Neuanlage
3622    fn evaluate_137(&self, ctx: &EvaluationContext) -> ConditionResult {
3623        // Check: not a Neuanlage (new registration) process
3624        // STS+7 with transaktionsgrund containing Neuanlage indicators
3625        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "7");
3626        let is_neuanlage = sts_segs.iter().any(|s| {
3627            s.elements
3628                .get(2)
3629                .and_then(|e| e.first())
3630                .is_some_and(|v| v == "E01" || v == "E03")
3631        });
3632        ConditionResult::from(!is_neuanlage)
3633    }
3634
3635    /// [138] Wenn im selben QTY im DE6063 Z35 (Abschlag) vorhanden
3636    fn evaluate_138(&self, ctx: &EvaluationContext) -> ConditionResult {
3637        let qty_segs = ctx.find_segments("QTY");
3638        let found = qty_segs.iter().any(|s| {
3639            s.elements
3640                .first()
3641                .and_then(|e| e.first())
3642                .is_some_and(|v| ["Z35"].contains(&v.as_str()))
3643        });
3644        ConditionResult::from(found)
3645    }
3646
3647    /// [139] Wenn SG10 CAV+IVA (Individuelle Abstimmung) nicht vorhanden
3648    // REVIEW: Condition is True when SG10 CAV+IVA (Individuelle Abstimmung) is NOT present anywhere. Uses parent-child navigation to iterate all SG8 instances and their SG10 child groups, checking CAV elements[0][0] for 'IVA'. Falls back to message-wide lacks_qualifier when no navigator is available. Returns False as soon as any CAV+IVA is found, True if none found. (medium confidence)
3649    fn evaluate_139(&self, ctx: &EvaluationContext) -> ConditionResult {
3650        let nav = match ctx.navigator {
3651            Some(n) => n,
3652            None => return ctx.lacks_qualifier("CAV", 0, "IVA"),
3653        };
3654        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3655        for i in 0..sg8_count {
3656            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
3657            for j in 0..sg10_count {
3658                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
3659                if cavs.iter().any(|s| {
3660                    s.elements
3661                        .first()
3662                        .and_then(|e: &Vec<String>| e.first())
3663                        .is_some_and(|v: &String| v == "IVA")
3664                }) {
3665                    return ConditionResult::False;
3666                }
3667            }
3668        }
3669        ConditionResult::True
3670    }
3671
3672    /// [140] Wenn im selben QTY im DE6063 Z34/Z35 (Zuschlag/Abschlag) vorhanden
3673    fn evaluate_140(&self, ctx: &EvaluationContext) -> ConditionResult {
3674        let qty_segs = ctx.find_segments("QTY");
3675        let found = qty_segs.iter().any(|s| {
3676            s.elements
3677                .first()
3678                .and_then(|e| e.first())
3679                .is_some_and(|v| ["Z34", "Z35"].contains(&v.as_str()))
3680        });
3681        ConditionResult::from(found)
3682    }
3683
3684    /// [141] Wenn SG10 CAV+MIW/ MPW/ MBW vorhanden
3685    fn evaluate_141(&self, ctx: &EvaluationContext) -> ConditionResult {
3686        let cav_segs = ctx.find_segments("CAV");
3687        let found = cav_segs.iter().any(|s| {
3688            s.elements
3689                .first()
3690                .and_then(|e| e.first())
3691                .is_some_and(|v| ["MIW", "MPW", "MBW"].contains(&v.as_str()))
3692        });
3693        ConditionResult::from(found)
3694    }
3695
3696    /// [142] Wenn SG8 PIA+Z01+:Z04/ Z05 (Berechnung Tagesmitteltemperatur: vom Anbieter zur Verfügung gestellte - / Äquivalente Tagesmitteltemperatur) vorhanden
3697    fn evaluate_142(&self, ctx: &EvaluationContext) -> ConditionResult {
3698        let pia_segs = ctx.find_segments("PIA");
3699        let found = pia_segs.iter().any(|s| {
3700            s.elements
3701                .first()
3702                .and_then(|e| e.first())
3703                .is_some_and(|v| v == "Z01")
3704                && s.elements
3705                    .get(1)
3706                    .and_then(|e| e.get(1))
3707                    .is_some_and(|v| ["Z04", "Z05"].contains(&v.as_str()))
3708        });
3709        ConditionResult::from(found)
3710    }
3711
3712    /// [143] Wenn STS+7++ZX3 (Transaktionsgrund: Abrechnungsdaten BK-Abrechnung verbrauchender MaLo) vorhanden
3713    fn evaluate_143(&self, ctx: &EvaluationContext) -> ConditionResult {
3714        let sts_segs = ctx.find_segments("STS");
3715        let found = sts_segs.iter().any(|s| {
3716            s.elements
3717                .first()
3718                .and_then(|e| e.first())
3719                .is_some_and(|v| v == "7")
3720                && s.elements
3721                    .get(2)
3722                    .and_then(|e| e.first())
3723                    .is_some_and(|v| v == "ZX3")
3724        });
3725        ConditionResult::from(found)
3726    }
3727
3728    /// [144] Wenn STS+7++ZAN (Transaktionsgrund: Korrektur Abrechnungsdaten BK-Abrechnung verbrauchender MaLo) vorhanden
3729    fn evaluate_144(&self, ctx: &EvaluationContext) -> ConditionResult {
3730        let sts_segs = ctx.find_segments("STS");
3731        let found = sts_segs.iter().any(|s| {
3732            s.elements
3733                .first()
3734                .and_then(|e| e.first())
3735                .is_some_and(|v| v == "7")
3736                && s.elements
3737                    .get(2)
3738                    .and_then(|e| e.first())
3739                    .is_some_and(|v| v == "ZAN")
3740        });
3741        ConditionResult::from(found)
3742    }
3743
3744    /// [145] Wenn STS+7++ZX2 (Transaktionsgrund: Abrechnungsdaten BK-Abrechnung erzeugender MaLo) vorhanden
3745    fn evaluate_145(&self, ctx: &EvaluationContext) -> ConditionResult {
3746        let sts_segs = ctx.find_segments("STS");
3747        let found = sts_segs.iter().any(|s| {
3748            s.elements
3749                .first()
3750                .and_then(|e| e.first())
3751                .is_some_and(|v| v == "7")
3752                && s.elements
3753                    .get(2)
3754                    .and_then(|e| e.first())
3755                    .is_some_and(|v| v == "ZX2")
3756        });
3757        ConditionResult::from(found)
3758    }
3759
3760    /// [146] Wenn STS+7++ZA0 (Transaktionsgrund: Korrektur Abrechnungsdaten BK-Abrechnung erzeugender MaLo) vorhanden
3761    fn evaluate_146(&self, ctx: &EvaluationContext) -> ConditionResult {
3762        let sts_segs = ctx.find_segments("STS");
3763        let found = sts_segs.iter().any(|s| {
3764            s.elements
3765                .first()
3766                .and_then(|e| e.first())
3767                .is_some_and(|v| v == "7")
3768                && s.elements
3769                    .get(2)
3770                    .and_then(|e| e.first())
3771                    .is_some_and(|v| v == "ZA0")
3772        });
3773        ConditionResult::from(found)
3774    }
3775
3776    /// [147] Wenn in Anfrage vorhanden
3777    fn evaluate_147(&self, _ctx: &EvaluationContext) -> ConditionResult {
3778        // TODO: implement
3779        ConditionResult::Unknown
3780    }
3781
3782    /// [148] Wenn in dieser SG8 im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), die Artikel-ID 1-02-0-017/ 1-02-0-018 vorhanden
3783    fn evaluate_148(&self, ctx: &EvaluationContext) -> ConditionResult {
3784        let pia_segs = ctx.find_segments("PIA");
3785        let found = pia_segs.iter().any(|s| {
3786            s.elements
3787                .first()
3788                .and_then(|e| e.first())
3789                .is_some_and(|v| v == "Z02")
3790                && s.elements
3791                    .get(1)
3792                    .and_then(|e| e.first())
3793                    .is_some_and(|v| ["1-02-0-017", "1-02-0-018"].contains(&v.as_str()))
3794        });
3795        ConditionResult::from(found)
3796    }
3797
3798    /// [149] Wenn zwei SG8 SEQ+Z45 (Netznutzungsabrechnungsdaten der Marktlokation), mit  derselben Zeitraum-ID im DE1050, mit Artikel-ID im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), eine SG8 mit 1-02-0-017...
3799    // REVIEW: Condition checks whether two SG8 SEQ+Z45 groups with the same Zeitraum-ID (elements[1][0]) each contain PIA+Z02 (DE4347=Z02) with product codes '1-02-0-017' and '1-02-0-018'. Uses collect_group_values to gather SEQ qualifiers and Zeitraum-IDs per group instance, then PIA qualifiers and product codes (elements[1][0]=DE7140) per group instance. Positional alignment of pia_quals and pia_prods (both from same PIA segments in same order) enables reliable qualifier-to-product matching. Groups product codes by Zeitraum-ID to check co-occurrence. (medium confidence)
3800    fn evaluate_149(&self, ctx: &EvaluationContext) -> ConditionResult {
3801        use std::collections::{HashMap, HashSet};
3802        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
3803        let seq_zeitraum = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
3804        let pia_quals = ctx.collect_group_values("PIA", 0, 0, &["SG4", "SG8"]);
3805        let pia_prods = ctx.collect_group_values("PIA", 1, 0, &["SG4", "SG8"]);
3806        // Map group index -> Zeitraum-ID for SG8s with SEQ+Z45
3807        let mut idx_to_zeitraum: HashMap<usize, String> = HashMap::new();
3808        for ((gi, q), (_, zid)) in seq_quals.iter().zip(seq_zeitraum.iter()) {
3809            if q == "Z45" && !zid.is_empty() {
3810                idx_to_zeitraum.insert(*gi, zid.clone());
3811            }
3812        }
3813        if idx_to_zeitraum.is_empty() {
3814            return ConditionResult::False;
3815        }
3816        // Map Zeitraum-ID -> set of PIA+Z02 product codes found in the same SG8 group
3817        let mut zeitraum_products: HashMap<String, HashSet<String>> = HashMap::new();
3818        for (i, (gi, qual)) in pia_quals.iter().enumerate() {
3819            if qual == "Z02" {
3820                if let Some(zid) = idx_to_zeitraum.get(gi) {
3821                    if let Some((_, prod)) = pia_prods.get(i) {
3822                        if !prod.is_empty() {
3823                            zeitraum_products
3824                                .entry(zid.clone())
3825                                .or_default()
3826                                .insert(prod.clone());
3827                        }
3828                    }
3829                }
3830            }
3831        }
3832        ConditionResult::from(
3833            zeitraum_products
3834                .values()
3835                .any(|codes| codes.contains("1-02-0-017") && codes.contains("1-02-0-018")),
3836        )
3837    }
3838
3839    /// [150] Wenn in dieser SG8 im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), die Artikel-ID 1-02-0-002 vorhanden
3840    fn evaluate_150(&self, ctx: &EvaluationContext) -> ConditionResult {
3841        let pia_segs = ctx.find_segments("PIA");
3842        let found = pia_segs.iter().any(|s| {
3843            s.elements
3844                .first()
3845                .and_then(|e| e.first())
3846                .is_some_and(|v| v == "Z02")
3847                && s.elements
3848                    .get(1)
3849                    .and_then(|e| e.first())
3850                    .is_some_and(|v| ["1-02-0-002"].contains(&v.as_str()))
3851        });
3852        ConditionResult::from(found)
3853    }
3854
3855    /// [151] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Ü̈bertragungsweg \"aus dem SMGW\" bestellt wurde. Der Empfänger der Werte kann dadurch seine...
3856    fn evaluate_151(&self, ctx: &EvaluationContext) -> ConditionResult {
3857        ctx.external.evaluate("code_list_membership_check")
3858    }
3859
3860    /// [152] Wenn FTX+Z28 (IP-Range des Absenders) nicht vorhanden
3861    fn evaluate_152(&self, ctx: &EvaluationContext) -> ConditionResult {
3862        let ftx_segs = ctx.find_segments("FTX");
3863        let found = ftx_segs.iter().any(|s| {
3864            s.elements
3865                .first()
3866                .and_then(|e| e.first())
3867                .is_some_and(|v| v == "Z28")
3868        });
3869        ConditionResult::from(!found)
3870    }
3871
3872    /// [153] Wenn FTX+Z27 (IP-Adresse des Absenders) nicht vorhanden
3873    fn evaluate_153(&self, ctx: &EvaluationContext) -> ConditionResult {
3874        let ftx_segs = ctx.find_segments("FTX");
3875        let found = ftx_segs.iter().any(|s| {
3876            s.elements
3877                .first()
3878                .and_then(|e| e.first())
3879                .is_some_and(|v| v == "Z27")
3880        });
3881        ConditionResult::from(!found)
3882    }
3883
3884    /// [156] Wenn SG4 FTX+Z17 (Zieladresse URI) vorhanden
3885    fn evaluate_156(&self, ctx: &EvaluationContext) -> ConditionResult {
3886        let ftx_segs = ctx.find_segments("FTX");
3887        let found = ftx_segs.iter().any(|s| {
3888            s.elements
3889                .first()
3890                .and_then(|e| e.first())
3891                .is_some_and(|v| v == "Z17")
3892        });
3893        ConditionResult::from(found)
3894    }
3895
3896    /// [161] Wenn SG4 STS+7++E03+ZW8 (Transaktionsgrundergänzung Fall 1) vorhanden
3897    fn evaluate_161(&self, ctx: &EvaluationContext) -> ConditionResult {
3898        let sts_segs = ctx.find_segments("STS");
3899        let found = sts_segs.iter().any(|s| {
3900            s.elements
3901                .first()
3902                .and_then(|e| e.first())
3903                .is_some_and(|v| v == "7")
3904                && s.elements
3905                    .get(2)
3906                    .and_then(|e| e.first())
3907                    .is_some_and(|v| v == "E03")
3908                && s.elements
3909                    .get(3)
3910                    .and_then(|e| e.first())
3911                    .is_some_and(|v| v == "ZW8")
3912        });
3913        ConditionResult::from(found)
3914    }
3915
3916    /// [162] Wenn SG4 STS+7++E03+ZW9 (Transaktionsgrundergänzung Fall 2) vorhanden
3917    fn evaluate_162(&self, ctx: &EvaluationContext) -> ConditionResult {
3918        let sts_segs = ctx.find_segments("STS");
3919        let found = sts_segs.iter().any(|s| {
3920            s.elements
3921                .first()
3922                .and_then(|e| e.first())
3923                .is_some_and(|v| v == "7")
3924                && s.elements
3925                    .get(2)
3926                    .and_then(|e| e.first())
3927                    .is_some_and(|v| v == "E03")
3928                && s.elements
3929                    .get(3)
3930                    .and_then(|e| e.first())
3931                    .is_some_and(|v| v == "ZW9")
3932        });
3933        ConditionResult::from(found)
3934    }
3935
3936    /// [163] Wenn SG4 STS+7++E03+ZX0 (Transaktionsgrundergänzung Fall 3) vorhanden
3937    fn evaluate_163(&self, ctx: &EvaluationContext) -> ConditionResult {
3938        let sts_segs = ctx.find_segments("STS");
3939        let found = sts_segs.iter().any(|s| {
3940            s.elements
3941                .first()
3942                .and_then(|e| e.first())
3943                .is_some_and(|v| v == "7")
3944                && s.elements
3945                    .get(2)
3946                    .and_then(|e| e.first())
3947                    .is_some_and(|v| v == "E03")
3948                && s.elements
3949                    .get(3)
3950                    .and_then(|e| e.first())
3951                    .is_some_and(|v| v == "ZX0")
3952        });
3953        ConditionResult::from(found)
3954    }
3955
3956    /// [164] Wenn SG4 STS+7++E03+ZX1 (Transaktionsgrundergänzung Fall 4) vorhanden
3957    fn evaluate_164(&self, ctx: &EvaluationContext) -> ConditionResult {
3958        let sts_segs = ctx.find_segments("STS");
3959        let found = sts_segs.iter().any(|s| {
3960            s.elements
3961                .first()
3962                .and_then(|e| e.first())
3963                .is_some_and(|v| v == "7")
3964                && s.elements
3965                    .get(2)
3966                    .and_then(|e| e.first())
3967                    .is_some_and(|v| v == "E03")
3968                && s.elements
3969                    .get(3)
3970                    .and_then(|e| e.first())
3971                    .is_some_and(|v| v == "ZX1")
3972        });
3973        ConditionResult::from(found)
3974    }
3975
3976    /// [165] Wenn bekannt
3977    fn evaluate_165(&self, _ctx: &EvaluationContext) -> ConditionResult {
3978        // TODO: implement
3979        ConditionResult::Unknown
3980    }
3981
3982    /// [166] Wenn vorhanden
3983    fn evaluate_166(&self, _ctx: &EvaluationContext) -> ConditionResult {
3984        // "If present" — always true when the field is being validated
3985        ConditionResult::True
3986    }
3987
3988    /// [167] Wenn SG5 LOC+Z21 (Tranche) vorhanden
3989    fn evaluate_167(&self, ctx: &EvaluationContext) -> ConditionResult {
3990        let loc_segs = ctx.find_segments("LOC");
3991        let found = loc_segs.iter().any(|s| {
3992            s.elements
3993                .first()
3994                .and_then(|e| e.first())
3995                .is_some_and(|v| v == "Z21")
3996        });
3997        ConditionResult::from(found)
3998    }
3999
4000    /// [170] Wenn Anschrift der Marktlokation vorhanden
4001    fn evaluate_170(&self, _ctx: &EvaluationContext) -> ConditionResult {
4002        // TODO: implement
4003        ConditionResult::Unknown
4004    }
4005
4006    /// [172] Wenn im selben QTY im DE6063 Z37 (Kein Zu- und Abschlag) vorhanden
4007    fn evaluate_172(&self, ctx: &EvaluationContext) -> ConditionResult {
4008        let qty_segs = ctx.find_segments("QTY");
4009        let found = qty_segs.iter().any(|s| {
4010            s.elements
4011                .first()
4012                .and_then(|e| e.first())
4013                .is_some_and(|v| ["Z37"].contains(&v.as_str()))
4014        });
4015        ConditionResult::from(found)
4016    }
4017
4018    /// [173] Wenn im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) das DE1156 (Fortlaufende Nummer eines Lokationsbündels im Geschäftsvorfall) in derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (...
4019    // REVIEW: Condition is True when, in an SG8 with SEQ+Z58/ZC9/ZD0/ZD6 (Zuordnung Lokation zum Objektcode), RFF+Z33 exists but its DE1156 (elements[0][2] = Fortlaufende Nummer) is absent or empty. Uses collect_group_values to find target SG8 group indices by SEQ qualifier, then positionally aligns rff_quals[i] with rff_de1156[i] (same RFF segment) to check DE1156 emptiness scoped to those groups. Returns Unknown if no RFF+Z33 found in target groups (condition not applicable), False if all RFF+Z33 have DE1156 present. (medium confidence)
4020    fn evaluate_173(&self, ctx: &EvaluationContext) -> ConditionResult {
4021        use std::collections::HashSet;
4022        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
4023        let target_indices: HashSet<usize> = seq_quals
4024            .iter()
4025            .filter(|(_, q)| matches!(q.as_str(), "Z58" | "ZC9" | "ZD0" | "ZD6"))
4026            .map(|(i, _)| *i)
4027            .collect();
4028        if target_indices.is_empty() {
4029            return ConditionResult::Unknown;
4030        }
4031        // Collect RFF qualifier (elements[0][0]) and DE1156 (elements[0][2]) with positional alignment
4032        let rff_quals = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG8"]);
4033        let rff_de1156 = ctx.collect_group_values("RFF", 0, 2, &["SG4", "SG8"]);
4034        let mut found_rff_z33 = false;
4035        for (i, (gi, qual)) in rff_quals.iter().enumerate() {
4036            if qual == "Z33" && target_indices.contains(gi) {
4037                found_rff_z33 = true;
4038                let de1156_empty = rff_de1156.get(i).map(|(_, v)| v.is_empty()).unwrap_or(true);
4039                if de1156_empty {
4040                    return ConditionResult::True;
4041                }
4042            }
4043        }
4044        if found_rff_z33 {
4045            ConditionResult::False
4046        } else {
4047            ConditionResult::Unknown
4048        }
4049    }
4050
4051    /// [174] Wenn im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) das DE1156 Fortlaufende Nummer eines Lokationsbündels im Geschäftsvorfall) in derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Z...
4052    fn evaluate_174(&self, ctx: &EvaluationContext) -> ConditionResult {
4053        // Check: RFF+Z33 has a value in DE1156 (fortlaufende Nummer)
4054        let rff_z33 = ctx.find_segments_with_qualifier("RFF", 0, "Z33");
4055        let found = rff_z33.iter().any(|s| {
4056            s.elements
4057                .first()
4058                .and_then(|e| e.get(2))
4059                .is_some_and(|v| !v.is_empty())
4060        });
4061        ConditionResult::from(found)
4062    }
4063
4064    /// [175] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58 (Zuordnung Lokation zum Objektcode des Lokationsbündels) in einem weite...
4065    // REVIEW: Cross-SG8 check: find all SG8 instances with SEQ+Z58 that also have RFF+Z33. Check whether any Objektcode (DE1154) with the same fortlaufende Nummer (DE1156) appears in two distinct SG8 instances. Uses nav.find_segments_in_group to access SG8-level segments directly, following the existing navigator pattern. (medium confidence)
4066    fn evaluate_175(&self, ctx: &EvaluationContext) -> ConditionResult {
4067        let nav = match ctx.navigator {
4068            Some(n) => n,
4069            None => return ConditionResult::Unknown,
4070        };
4071        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4072        let mut entries: Vec<(usize, String, String)> = Vec::new();
4073        for i in 0..sg8_count {
4074            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
4075            if !seqs.iter().any(|s| {
4076                s.elements
4077                    .first()
4078                    .and_then(|e: &Vec<String>| e.first())
4079                    .is_some_and(|v: &String| v == "Z58")
4080            }) {
4081                continue;
4082            }
4083            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
4084            for rff in &rffs {
4085                let elems = match rff.elements.first() {
4086                    Some(e) => e,
4087                    None => continue,
4088                };
4089                if elems.first().map(|s| s.as_str()) != Some("Z33") {
4090                    continue;
4091                }
4092                let objektcode = elems.get(1).cloned().unwrap_or_default();
4093                let fort_nr = elems.get(2).cloned().unwrap_or_default();
4094                if !objektcode.is_empty() {
4095                    entries.push((i, objektcode, fort_nr));
4096                }
4097            }
4098        }
4099        for a in 0..entries.len() {
4100            for b in (a + 1)..entries.len() {
4101                if entries[a].0 != entries[b].0
4102                    && entries[a].1 == entries[b].1
4103                    && entries[a].2 == entries[b].2
4104                {
4105                    return ConditionResult::True;
4106                }
4107            }
4108        }
4109        ConditionResult::False
4110    }
4111
4112    /// [176] Wenn in demselben Segment das DE1153 mit dem Code Z34 vorgelagerte Messlokation vorhanden ist
4113    fn evaluate_176(&self, ctx: &EvaluationContext) -> ConditionResult {
4114        ConditionResult::from(ctx.self_segment_value_equals("RFF", 0, 0, "Z34"))
4115    }
4116
4117    /// [177] Wenn in demselben Segment das DE1153 mit dem Code Z35 vorgelagerte Netzlokation vorhanden ist
4118    fn evaluate_177(&self, ctx: &EvaluationContext) -> ConditionResult {
4119        ConditionResult::from(ctx.self_segment_value_equals("RFF", 0, 0, "Z35"))
4120    }
4121
4122    /// [178] Wenn das LOC+Z18 (Netzlokation) vorhanden ist
4123    fn evaluate_178(&self, ctx: &EvaluationContext) -> ConditionResult {
4124        let loc_segs = ctx.find_segments("LOC");
4125        let found = loc_segs.iter().any(|s| {
4126            s.elements
4127                .first()
4128                .and_then(|e| e.first())
4129                .is_some_and(|v| v == "Z18")
4130        });
4131        ConditionResult::from(found)
4132    }
4133
4134    /// [179] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58/ ZC9 / ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des Lokationsbündels...
4135    fn evaluate_179(&self, ctx: &EvaluationContext) -> ConditionResult {
4136        // Check: RFF+Z33 has a value in DE1154 (Objektcode)
4137        let rff_z33 = ctx.find_segments_with_qualifier("RFF", 0, "Z33");
4138        let found = rff_z33.iter().any(|s| {
4139            s.elements
4140                .first()
4141                .and_then(|e| e.get(1))
4142                .is_some_and(|v| !v.is_empty())
4143        });
4144        ConditionResult::from(found)
4145    }
4146
4147    /// [180] Wenn im selben QTY im DE6063 Z46 (Kein Abschlag) vorhanden
4148    fn evaluate_180(&self, ctx: &EvaluationContext) -> ConditionResult {
4149        let qty_segs = ctx.find_segments("QTY");
4150        let found = qty_segs.iter().any(|s| {
4151            s.elements
4152                .first()
4153                .and_then(|e| e.first())
4154                .is_some_and(|v| ["Z46"].contains(&v.as_str()))
4155        });
4156        ConditionResult::from(found)
4157    }
4158
4159    /// [184] Wenn in derselben SG8 SEQ+Z18 (Daten der Messlokation) ein CCI+Z01++Z82 (Verwendungsumfang: ID der prozessual behandelten Messlokation) vorhanden
4160    fn evaluate_184(&self, ctx: &EvaluationContext) -> ConditionResult {
4161        let seq_segs = ctx.find_segments("SEQ");
4162        let found = seq_segs.iter().any(|s| {
4163            s.elements
4164                .first()
4165                .and_then(|e| e.first())
4166                .is_some_and(|v| ["Z18"].contains(&v.as_str()))
4167        });
4168        ConditionResult::from(found)
4169    }
4170
4171    /// [190] Wenn in derselben SG8 SEQ+Z60/ ZG8/ ZG9/ ZE0  (Produkt-Daten der Netzlokation) PIA+5+9991000000721:Z12 vorhanden
4172    fn evaluate_190(&self, ctx: &EvaluationContext) -> ConditionResult {
4173        // Check: SG8 with SEQ+Z60/ZG8/ZG9/ZE0 has PIA+5 with code 9991000000721
4174        let pia_segs = ctx.find_segments("PIA");
4175        let found = pia_segs.iter().any(|s| {
4176            s.elements
4177                .first()
4178                .and_then(|e| e.first())
4179                .is_some_and(|v| v == "5")
4180                && s.elements
4181                    .get(1)
4182                    .and_then(|e| e.first())
4183                    .is_some_and(|v| v == "9991000000721")
4184        });
4185        ConditionResult::from(found)
4186    }
4187
4188    /// [191] Wenn im SG4 IDE+Z01 (Identifikation einer Liste) STS+E01 (Status der Antwort der Liste) nicht vorhanden
4189    fn evaluate_191(&self, ctx: &EvaluationContext) -> ConditionResult {
4190        let sts_segs = ctx.find_segments("STS");
4191        let found = sts_segs.iter().any(|s| {
4192            s.elements
4193                .first()
4194                .and_then(|e| e.first())
4195                .is_some_and(|v| v == "E01")
4196        });
4197        ConditionResult::from(!found)
4198    }
4199
4200    /// [192] Wenn SG4 STS+7++XXX+ZW4/ZAP (Transaktionsgrund / Ergänzung: Verbrauchende Marktlokation / ruhende Marktlokation) vorhanden
4201    fn evaluate_192(&self, ctx: &EvaluationContext) -> ConditionResult {
4202        let sts_segs = ctx.find_segments("STS");
4203        let found = sts_segs.iter().any(|s| {
4204            s.elements
4205                .first()
4206                .and_then(|e| e.first())
4207                .is_some_and(|v| v == "7")
4208                && s.elements
4209                    .get(3)
4210                    .and_then(|e| e.first())
4211                    .is_some_and(|v| ["ZW4", "ZAP"].contains(&v.as_str()))
4212        });
4213        ConditionResult::from(found)
4214    }
4215
4216    /// [193] Wenn das SG10 CCI ZB5 (Spannungsebene der Summenzeitreihe) CAV E06 (Niederspannung) in dieser SG vorhanden
4217    fn evaluate_193(&self, ctx: &EvaluationContext) -> ConditionResult {
4218        let nav = match ctx.navigator {
4219            Some(n) => n,
4220            None => {
4221                let cavs = ctx.find_segments("CAV");
4222                return ConditionResult::from(cavs.iter().any(|s| {
4223                    s.elements
4224                        .first()
4225                        .and_then(|e: &Vec<String>| e.first())
4226                        .is_some_and(|v: &String| v == "E06")
4227                }));
4228            }
4229        };
4230        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4231        for i in 0..sg8_count {
4232            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
4233            for j in 0..sg10_count {
4234                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
4235                let has_cci_zb5 = ccis.iter().any(|s| {
4236                    s.elements
4237                        .get(2)
4238                        .and_then(|e: &Vec<String>| e.first())
4239                        .is_some_and(|v: &String| v == "ZB5")
4240                });
4241                if !has_cci_zb5 {
4242                    continue;
4243                }
4244                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
4245                if cavs.iter().any(|s| {
4246                    s.elements
4247                        .first()
4248                        .and_then(|e: &Vec<String>| e.first())
4249                        .is_some_and(|v: &String| v == "E06")
4250                }) {
4251                    return ConditionResult::True;
4252                }
4253            }
4254        }
4255        ConditionResult::False
4256    }
4257
4258    /// [194] Wenn das SG10 CCI ZB5 (Spannungsebene der Summenzeitreihe) CAV E05 (Mittelspannung) in dieser SG vorhanden
4259    fn evaluate_194(&self, ctx: &EvaluationContext) -> ConditionResult {
4260        let cci_segs = ctx.find_segments("CCI");
4261        let has_cci = cci_segs.iter().any(|s| {
4262            s.elements
4263                .iter()
4264                .any(|e| e.first().is_some_and(|v| v == "ZB5"))
4265        });
4266        let cav_segs = ctx.find_segments("CAV");
4267        let has_cav = cav_segs.iter().any(|s| {
4268            s.elements
4269                .first()
4270                .and_then(|e| e.first())
4271                .is_some_and(|v| v == "E05")
4272        });
4273        ConditionResult::from(has_cci && has_cav)
4274    }
4275
4276    /// [195] Wenn das SG10 CCI ZB5 (Spannungsebene der Summenzeitreihe) CAV E04 (Hochspannung) in dieser SG vorhanden
4277    fn evaluate_195(&self, ctx: &EvaluationContext) -> ConditionResult {
4278        let cci_segs = ctx.find_segments("CCI");
4279        let has_cci = cci_segs.iter().any(|s| {
4280            s.elements
4281                .iter()
4282                .any(|e| e.first().is_some_and(|v| v == "ZB5"))
4283        });
4284        let cav_segs = ctx.find_segments("CAV");
4285        let has_cav = cav_segs.iter().any(|s| {
4286            s.elements
4287                .first()
4288                .and_then(|e| e.first())
4289                .is_some_and(|v| v == "E04")
4290        });
4291        ConditionResult::from(has_cci && has_cav)
4292    }
4293
4294    /// [196] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58/ZC9/ZD0 (Zuordnung Lokation zum Objektcode des Lokationsbündels) in ein...
4295    // REVIEW: Extended cross-SG8 check vs 175: now requires matching SEQ qualifier code (DE1229), Zeitraum-ID from SEQ DE1050 (elements[1][0]), Objektcode (RFF+Z33 DE1154), AND fortlaufende Nummer (RFF+Z33 DE1156) to all be identical between two distinct SG8 instances. SEQ qualifiers are Z58/ZC9/ZD0 per schema. (medium confidence)
4296    fn evaluate_196(&self, ctx: &EvaluationContext) -> ConditionResult {
4297        let nav = match ctx.navigator {
4298            Some(n) => n,
4299            None => return ConditionResult::Unknown,
4300        };
4301        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4302        let mut entries: Vec<(usize, String, String, String, String)> = Vec::new();
4303        for i in 0..sg8_count {
4304            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
4305            let seq_opt = seqs.iter().find(|s| {
4306                s.elements
4307                    .first()
4308                    .and_then(|e: &Vec<String>| e.first())
4309                    .is_some_and(|v: &String| matches!(v.as_str(), "Z58" | "ZC9" | "ZD0"))
4310            });
4311            let seq = match seq_opt {
4312                Some(s) => s,
4313                None => continue,
4314            };
4315            let seq_code = seq
4316                .elements
4317                .first()
4318                .and_then(|e: &Vec<String>| e.first())
4319                .cloned()
4320                .unwrap_or_default();
4321            let zeitraum_id = seq
4322                .elements
4323                .get(1)
4324                .and_then(|e: &Vec<String>| e.first())
4325                .cloned()
4326                .unwrap_or_default();
4327            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
4328            for rff in &rffs {
4329                let elems = match rff.elements.first() {
4330                    Some(e) => e,
4331                    None => continue,
4332                };
4333                if elems.first().map(|s| s.as_str()) != Some("Z33") {
4334                    continue;
4335                }
4336                let objektcode = elems.get(1).cloned().unwrap_or_default();
4337                let fort_nr = elems.get(2).cloned().unwrap_or_default();
4338                if !objektcode.is_empty() {
4339                    entries.push((
4340                        i,
4341                        seq_code.clone(),
4342                        zeitraum_id.clone(),
4343                        objektcode,
4344                        fort_nr,
4345                    ));
4346                }
4347            }
4348        }
4349        for a in 0..entries.len() {
4350            for b in (a + 1)..entries.len() {
4351                if entries[a].0 != entries[b].0
4352                    && entries[a].1 == entries[b].1
4353                    && entries[a].2 == entries[b].2
4354                    && entries[a].3 == entries[b].3
4355                    && entries[a].4 == entries[b].4
4356                {
4357                    return ConditionResult::True;
4358                }
4359            }
4360        }
4361        ConditionResult::False
4362    }
4363
4364    /// [197] Wenn das RFF+Z18 (Marktlokation) aus dieser SG8 auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der Marktlokation), in dem SG10 CCI+++ZA6 (...
4365    // REVIEW: Two-phase cross-SG8 check. Phase 1: collect Marktlokation IDs from SG8 instances that (a) have SEQ+Z01 and (b) have an SG10 child with CCI elements[2][0]=ZA6 and CAV elements[0][0]=E02. Phase 2: check whether any SG8's RFF+Z18 references one of those qualifying Marktlokation IDs, establishing the cross-reference described in the condition. (medium confidence)
4366    fn evaluate_197(&self, ctx: &EvaluationContext) -> ConditionResult {
4367        let nav = match ctx.navigator {
4368            Some(n) => n,
4369            None => return ConditionResult::Unknown,
4370        };
4371        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4372        let mut qualifying_malo_ids: Vec<String> = Vec::new();
4373        for i in 0..sg8_count {
4374            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
4375            if !seqs.iter().any(|s| {
4376                s.elements
4377                    .first()
4378                    .and_then(|e: &Vec<String>| e.first())
4379                    .is_some_and(|v: &String| v == "Z01")
4380            }) {
4381                continue;
4382            }
4383            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
4384            let has_prog = (0..sg10_count).any(|j| {
4385                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
4386                let has_za6 = ccis.iter().any(|s| {
4387                    s.elements
4388                        .get(2)
4389                        .and_then(|e: &Vec<String>| e.first())
4390                        .is_some_and(|v: &String| v == "ZA6")
4391                });
4392                if !has_za6 {
4393                    return false;
4394                }
4395                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
4396                cavs.iter().any(|s| {
4397                    s.elements
4398                        .first()
4399                        .and_then(|e: &Vec<String>| e.first())
4400                        .is_some_and(|v: &String| v == "E02")
4401                })
4402            });
4403            if !has_prog {
4404                continue;
4405            }
4406            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
4407            for rff in &rffs {
4408                let elems = match rff.elements.first() {
4409                    Some(e) => e,
4410                    None => continue,
4411                };
4412                if elems.first().map(|s| s.as_str()) != Some("Z18") {
4413                    continue;
4414                }
4415                if let Some(malo_id) = elems.get(1) {
4416                    if !malo_id.is_empty() {
4417                        qualifying_malo_ids.push(malo_id.clone());
4418                    }
4419                }
4420            }
4421        }
4422        if qualifying_malo_ids.is_empty() {
4423            return ConditionResult::False;
4424        }
4425        for i in 0..sg8_count {
4426            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
4427            for rff in &rffs {
4428                let elems = match rff.elements.first() {
4429                    Some(e) => e,
4430                    None => continue,
4431                };
4432                if elems.first().map(|s| s.as_str()) != Some("Z18") {
4433                    continue;
4434                }
4435                if let Some(malo_id) = elems.get(1) {
4436                    if qualifying_malo_ids.contains(malo_id) {
4437                        return ConditionResult::True;
4438                    }
4439                }
4440            }
4441        }
4442        ConditionResult::False
4443    }
4444
4445    /// [198] Wenn SG4 STS+7++E03(Transaktionsgrund: Wechsel) vorhanden
4446    fn evaluate_198(&self, ctx: &EvaluationContext) -> ConditionResult {
4447        let sts_segs = ctx.find_segments("STS");
4448        let found = sts_segs.iter().any(|s| {
4449            s.elements
4450                .first()
4451                .and_then(|e| e.first())
4452                .is_some_and(|v| v == "7")
4453                && s.elements
4454                    .get(2)
4455                    .and_then(|e| e.first())
4456                    .is_some_and(|v| ["E03"].contains(&v.as_str()))
4457        });
4458        ConditionResult::from(found)
4459    }
4460
4461    /// [199] Wenn in der SG8 SEQ+Z01/ SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) mit identischer Zeitraum-ID im DE1050 CAV+E02 (SLP/SEP) vorhanden
4462    // REVIEW: Checks whether any SG8 with SEQ+Z01 (Daten der Marktlokation) contains an SG10 child group where CCI elements[2][0]=ZA6 (Prognosegrundlage: Prognose auf Basis von Profilen) and CAV elements[0][0]=E02 (SLP/SEP) appear in the same SG10 instance. The 'identischer Zeitraum-ID' constraint from SEQ DE1050 is structurally satisfied by operating within the same SG8 instance; deeper Zeitraum-ID cross-referencing with other groups is omitted as it would require knowing the external referencing context. (medium confidence)
4463    fn evaluate_199(&self, ctx: &EvaluationContext) -> ConditionResult {
4464        let nav = match ctx.navigator {
4465            Some(n) => n,
4466            None => {
4467                return ctx.filtered_parent_child_has_qualifier(
4468                    &["SG4", "SG8"],
4469                    "SEQ",
4470                    0,
4471                    "Z01",
4472                    "SG10",
4473                    "CCI",
4474                    2,
4475                    "ZA6",
4476                )
4477            }
4478        };
4479        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4480        for i in 0..sg8_count {
4481            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
4482            if !seqs.iter().any(|s| {
4483                s.elements
4484                    .first()
4485                    .and_then(|e: &Vec<String>| e.first())
4486                    .is_some_and(|v: &String| v == "Z01")
4487            }) {
4488                continue;
4489            }
4490            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
4491            for j in 0..sg10_count {
4492                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
4493                if !ccis.iter().any(|s| {
4494                    s.elements
4495                        .get(2)
4496                        .and_then(|e: &Vec<String>| e.first())
4497                        .is_some_and(|v: &String| v == "ZA6")
4498                }) {
4499                    continue;
4500                }
4501                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
4502                if cavs.iter().any(|s| {
4503                    s.elements
4504                        .first()
4505                        .and_then(|e: &Vec<String>| e.first())
4506                        .is_some_and(|v: &String| v == "E02")
4507                }) {
4508                    return ConditionResult::True;
4509                }
4510            }
4511        }
4512        ConditionResult::False
4513    }
4514
4515    /// [201] Wenn die Marktlokation / Tranche nicht den ganzen Bilanzierungsmonat dem gleichen Tupel aus Bilanzkreis, Zeitreihentyp, Spannungsebene und Lieferant zugeordnet ist
4516    fn evaluate_201(&self, _ctx: &EvaluationContext) -> ConditionResult {
4517        // TODO: implement
4518        ConditionResult::Unknown
4519    }
4520
4521    /// [202] Wenn SG8 SEQ+Z78 RFF+Z39 (Keine standardisierte Lokationsbündelstruktur vorhanden), mit identischer Zeitraum-ID im DE1050 wie im DE3224 dieses Segments
4522    // REVIEW: Collects Zeitraum-IDs from SG5 LOC.DE3224 (elements[1][3]), checks SEQ+Z78 DE1050 (elements[1][0]) for a match, then verifies RFF+Z39 exists. Co-occurrence of SEQ+Z78 and RFF+Z39 in the same SG8 instance is not verified without navigator group-instance access. (medium confidence)
4523    fn evaluate_202(&self, ctx: &EvaluationContext) -> ConditionResult {
4524        use std::collections::HashSet;
4525        // Collect Zeitraum-IDs from all SG5 LOC segments (DE3224 at elements[1][3])
4526        let loc_zeitraum_ids: HashSet<String> = ctx
4527            .find_segments("LOC")
4528            .into_iter()
4529            .filter_map(|s| s.elements.get(1)?.get(3).cloned())
4530            .filter(|v| !v.is_empty())
4531            .collect();
4532        if loc_zeitraum_ids.is_empty() {
4533            return ConditionResult::False;
4534        }
4535        // Check if any SEQ+Z78 (SG8 Lokationsbündelstruktur) has DE1050 matching a LOC DE3224
4536        let matching_seq = ctx
4537            .find_segments_with_qualifier("SEQ", 0, "Z78")
4538            .into_iter()
4539            .any(|s| {
4540                s.elements
4541                    .get(1)
4542                    .and_then(|e: &Vec<String>| e.first())
4543                    .is_some_and(|v: &String| {
4544                        !v.is_empty() && loc_zeitraum_ids.contains(v.as_str())
4545                    })
4546            });
4547        if !matching_seq {
4548            return ConditionResult::False;
4549        }
4550        // Verify RFF+Z39 also exists (co-occurrence in same SG8 not verified without navigator)
4551        ctx.has_qualifier("RFF", 0, "Z39")
4552    }
4553
4554    /// [203] Wenn STS+7++E06 / Z39 / ZC6 / ZC7/ ZT6/ ZT7 vorhanden
4555    fn evaluate_203(&self, ctx: &EvaluationContext) -> ConditionResult {
4556        let sts_segs = ctx.find_segments("STS");
4557        let found = sts_segs.iter().any(|s| {
4558            s.elements
4559                .first()
4560                .and_then(|e| e.first())
4561                .is_some_and(|v| v == "7")
4562                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| {
4563                    ["E06", "Z39", "ZC6", "ZC7", "ZT6", "ZT7"].contains(&v.as_str())
4564                })
4565        });
4566        ConditionResult::from(found)
4567    }
4568
4569    /// [204] Wenn im SG8+SEQ+Z03/ ZA3/ ZA4 (Zähleinrichtungsdaten) mit der selben Zeitraum-ID im SG8 SEQ DE1050, sowie identischer Qualität im DE1229 der SG8 SEQ für die in diesem RFF DE1154 genannte Geräte...
4570    // REVIEW: Checks each Zähleinrichtungsdaten SEQ qualifier (Z03/ZA3/ZA4) — if any SG8 instance has that SEQ qualifier but no RFF+Z14 (Smartmeter-Gateway reference), the condition is true. The additional Zeitraum-ID and Gerätenummer cross-matching from the full condition text cannot be implemented without per-instance SG8 segment access. (medium confidence)
4571    fn evaluate_204(&self, ctx: &EvaluationContext) -> ConditionResult {
4572        // True if any SG8 with Zähleinrichtungsdaten (SEQ+Z03/ZA3/ZA4) lacks RFF+Z14 (Smartmeter-Gateway)
4573        for qual in &["Z03", "ZA3", "ZA4"] {
4574            if matches!(
4575                ctx.any_group_has_qualifier_without(
4576                    "SEQ",
4577                    0,
4578                    qual,
4579                    "RFF",
4580                    0,
4581                    "Z14",
4582                    &["SG4", "SG8"]
4583                ),
4584                ConditionResult::True
4585            ) {
4586                return ConditionResult::True;
4587            }
4588        }
4589        ConditionResult::False
4590    }
4591
4592    /// [205] Wenn SG5 LOC+Z19 (Steuerbare Ressource) vorhanden
4593    fn evaluate_205(&self, ctx: &EvaluationContext) -> ConditionResult {
4594        let loc_segs = ctx.find_segments("LOC");
4595        let found = loc_segs.iter().any(|s| {
4596            s.elements
4597                .first()
4598                .and_then(|e| e.first())
4599                .is_some_and(|v| v == "Z19")
4600        });
4601        ConditionResult::from(found)
4602    }
4603
4604    /// [206] Wenn SG4 STS+7++ZG5 (Transaktionsgrund: Aufhebung der zukünftigen Zuordnung aufgrund §38 EEG 2014 bzw. §21b Abs. 1 Nr. 2 EEG 2017) nicht vorhanden
4605    fn evaluate_206(&self, ctx: &EvaluationContext) -> ConditionResult {
4606        let sts_segs = ctx.find_segments("STS");
4607        let found = sts_segs.iter().any(|s| {
4608            s.elements
4609                .first()
4610                .and_then(|e| e.first())
4611                .is_some_and(|v| v == "7")
4612                && s.elements
4613                    .get(2)
4614                    .and_then(|e| e.first())
4615                    .is_some_and(|v| ["ZG5"].contains(&v.as_str()))
4616        });
4617        ConditionResult::from(!found)
4618    }
4619
4620    /// [209] Wenn im selben Segment im DE2379 der Code 303 vorhanden ist
4621    fn evaluate_209(&self, ctx: &EvaluationContext) -> ConditionResult {
4622        ConditionResult::from(ctx.self_segment_value_equals("DTM", 0, 2, "303"))
4623    }
4624
4625    /// [210] Wenn SG10 CCI+++ZA6 (Prognose auf Basis von Profilen) in dieser SG8 vorhanden
4626    fn evaluate_210(&self, ctx: &EvaluationContext) -> ConditionResult {
4627        let cci_segs = ctx.find_segments("CCI");
4628        let found = cci_segs.iter().any(|s| {
4629            s.elements
4630                .get(2)
4631                .and_then(|e| e.first())
4632                .is_some_and(|v| v == "ZA6")
4633        });
4634        ConditionResult::from(found)
4635    }
4636
4637    /// [212] Wenn im selben SG12 NAD DE3124 nicht vorhanden
4638    fn evaluate_212(&self, ctx: &EvaluationContext) -> ConditionResult {
4639        let nad_segs = ctx.find_segments("NAD");
4640        let found = nad_segs.iter().any(|s| {
4641            s.elements
4642                .get(3)
4643                .and_then(|e| e.first())
4644                .is_some_and(|v| !v.is_empty())
4645        });
4646        ConditionResult::from(!found)
4647    }
4648
4649    /// [213] Wenn SG12 NAD+Z09 (Kunde des Lieferanten) vorhanden
4650    fn evaluate_213(&self, ctx: &EvaluationContext) -> ConditionResult {
4651        let nad_segs = ctx.find_segments("NAD");
4652        let found = nad_segs.iter().any(|s| {
4653            s.elements
4654                .first()
4655                .and_then(|e| e.first())
4656                .is_some_and(|v| v == "Z09")
4657        });
4658        ConditionResult::from(found)
4659    }
4660
4661    /// [215] Wenn in derselben SG8 (Zähleinrichtungsdaten) SG10 CCI+++E13 CAV+MME (Zählertyp: mME) vorhanden
4662    fn evaluate_215(&self, ctx: &EvaluationContext) -> ConditionResult {
4663        // Check: CCI with elements[2][0]=="E13" and CAV+MME exist
4664        let has_cci_e13 = ctx.find_segments("CCI").iter().any(|s| {
4665            s.elements
4666                .get(2)
4667                .and_then(|e| e.first())
4668                .is_some_and(|v| v == "E13")
4669        });
4670        let has_cav_mme = ctx.find_segments("CAV").iter().any(|s| {
4671            s.elements
4672                .first()
4673                .and_then(|e| e.first())
4674                .is_some_and(|v| v == "MME")
4675        });
4676        ConditionResult::from(has_cci_e13 && has_cav_mme)
4677    }
4678
4679    /// [216] Wenn CCI+++Z88 (Netznutzung) CAV+Z74:::Z08 (Netznutzungsvertrag: Direkter Vertrag zwischen Kunden und NB) vorhanden
4680    fn evaluate_216(&self, ctx: &EvaluationContext) -> ConditionResult {
4681        let cci_segs = ctx.find_segments("CCI");
4682        let found = cci_segs.iter().any(|s| {
4683            s.elements
4684                .get(2)
4685                .and_then(|e| e.first())
4686                .is_some_and(|v| v == "Z88")
4687        });
4688        ConditionResult::from(found)
4689    }
4690
4691    /// [217] Wenn SG6 RFF+Z49 (Verwendungszeitraum der Daten: \"Gültige Daten\") vorhanden
4692    fn evaluate_217(&self, ctx: &EvaluationContext) -> ConditionResult {
4693        let rff_segs = ctx.find_segments("RFF");
4694        let found = rff_segs.iter().any(|s| {
4695            s.elements
4696                .first()
4697                .and_then(|e| e.first())
4698                .is_some_and(|v| v == "Z49")
4699        });
4700        ConditionResult::from(found)
4701    }
4702
4703    /// [219] Wenn SG12 NAD+Z65 (Informativer Kunde des Lieferanten) vorhanden
4704    fn evaluate_219(&self, ctx: &EvaluationContext) -> ConditionResult {
4705        let nad_segs = ctx.find_segments("NAD");
4706        let found = nad_segs.iter().any(|s| {
4707            s.elements
4708                .first()
4709                .and_then(|e| e.first())
4710                .is_some_and(|v| v == "Z65")
4711        });
4712        ConditionResult::from(found)
4713    }
4714
4715    /// [220] Wenn SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) SG10 CCI+Z30++Z06 (Lieferrichtung: Erzeugung) in dieser SG8 vorhanden
4716    fn evaluate_220(&self, ctx: &EvaluationContext) -> ConditionResult {
4717        let seq_segs = ctx.find_segments("SEQ");
4718        let has_seq = seq_segs.iter().any(|s| {
4719            s.elements
4720                .first()
4721                .and_then(|e| e.first())
4722                .is_some_and(|v| ["Z01", "Z98"].contains(&v.as_str()))
4723        });
4724        let cci_segs = ctx.find_segments("CCI");
4725        let has_cci = cci_segs.iter().any(|s| {
4726            s.elements
4727                .first()
4728                .and_then(|e| e.first())
4729                .is_some_and(|v| v == "Z30")
4730                && s.elements
4731                    .get(2)
4732                    .and_then(|e| e.first())
4733                    .is_some_and(|v| v == "Z06")
4734        });
4735        ConditionResult::from(has_seq && has_cci)
4736    }
4737
4738    /// [221] Wenn kein SG8 SEQ+Z15 (Daten der Tranche) auf die gleiche Marktlokation-ID mit dem RFF+Z18 (Marktlokation) referenziert wie dieses SG8 SEQ+Z01 (Daten der Marktlokation)
4739    fn evaluate_221(&self, ctx: &EvaluationContext) -> ConditionResult {
4740        // Check: no SG8 with SEQ+Z15 has RFF+Z18 referencing same Marktlokation
4741        let has_seq_z15 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z15").is_empty();
4742        if !has_seq_z15 {
4743            return ConditionResult::True;
4744        }
4745        // Approximate: SEQ+Z15 exists, check if it references via RFF+Z18
4746        ctx.any_group_has_qualifier_without("SEQ", 0, "Z15", "RFF", 0, "Z18", &["SG4", "SG8"])
4747    }
4748
4749    /// [223] Wenn das RFF+Z18 (Marktlokation) aus dieser SG8 auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der Marktlokation) verweist, und dort das S...
4750    fn evaluate_223(&self, ctx: &EvaluationContext) -> ConditionResult {
4751        // Check: RFF+Z18 value matches LOC+Z16 ID from SG5
4752        let rff_z18 = ctx.find_segments_with_qualifier("RFF", 0, "Z18");
4753        let loc_z16 = ctx.find_segments_with_qualifier("LOC", 0, "Z16");
4754        if rff_z18.is_empty() || loc_z16.is_empty() {
4755            return ConditionResult::Unknown;
4756        }
4757        // Check if any RFF+Z18 value matches any LOC+Z16 DE3225
4758        let loc_ids: Vec<&str> = loc_z16
4759            .iter()
4760            .filter_map(|s| {
4761                s.elements
4762                    .get(1)
4763                    .and_then(|e| e.first())
4764                    .map(|v| v.as_str())
4765            })
4766            .collect();
4767        let found = rff_z18.iter().any(|s| {
4768            s.elements
4769                .first()
4770                .and_then(|e| e.get(1))
4771                .is_some_and(|v| loc_ids.contains(&v.as_str()))
4772        });
4773        ConditionResult::from(found)
4774    }
4775
4776    /// [224] Wenn kein SG8 SEQ+ZE7 (Informative Daten der Tranche) auf die gleiche Marktlokation-ID mit dem RFF+Z18 (Marktlokation) referenziert wie dieses SG8 SEQ+Z98 (Informative Daten der Marktlokation)
4777    fn evaluate_224(&self, ctx: &EvaluationContext) -> ConditionResult {
4778        // Check: no SG8 with SEQ+ZE7 has RFF+Z18 referencing same Marktlokation
4779        let has_seq_ze7 = !ctx.find_segments_with_qualifier("SEQ", 0, "ZE7").is_empty();
4780        if !has_seq_ze7 {
4781            return ConditionResult::True;
4782        }
4783        ctx.any_group_has_qualifier_without("SEQ", 0, "ZE7", "RFF", 0, "Z18", &["SG4", "SG8"])
4784    }
4785
4786    /// [227] Wenn im SG8 SEQ+Z98 (Daten der Marktlokation) das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E14 (TLP/TEP) vorhanden
4787    fn evaluate_227(&self, ctx: &EvaluationContext) -> ConditionResult {
4788        // Check: in SG8 with SEQ+Z98, SG10 has CCI+++ZA6 and CAV+E14 or ETK
4789        let r1 = ctx.filtered_parent_child_has_qualifier(
4790            &["SG4", "SG8"],
4791            "SEQ",
4792            0,
4793            "Z98",
4794            "SG10",
4795            "CAV",
4796            0,
4797            "E14",
4798        );
4799        if r1 == ConditionResult::True {
4800            return ConditionResult::True;
4801        }
4802        ctx.filtered_parent_child_has_qualifier(
4803            &["SG4", "SG8"],
4804            "SEQ",
4805            0,
4806            "Z98",
4807            "SG10",
4808            "CAV",
4809            0,
4810            "ETK",
4811        )
4812    }
4813
4814    /// [229] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des Lokationsbündels)...
4815    // REVIEW: Detects if the same (SEQ-qualifier, Zeitraum-ID, RFF+Z33-Objektcode) triple appears in two different SG8 instances — which is what the condition guards against. Uses collect_group_values to correlate SEQ and RFF data by SG8 instance index. Limitation: collect_group_values may only return the first RFF per SG8 instance, so Z33 may be missed if it is not the first RFF in the group. (medium confidence)
4816    fn evaluate_229(&self, ctx: &EvaluationContext) -> ConditionResult {
4817        use std::collections::HashSet;
4818        let target_quals: HashSet<&str> = ["Z58", "ZC9", "ZD0", "ZD6"].iter().cloned().collect();
4819        // Collect per-SG8-instance: SEQ qualifier and Zeitraum-ID
4820        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
4821        let seq_zeitraums = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
4822        // Collect per-SG8-instance: RFF qualifier and DE1154 value
4823        let rff_quals = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG8"]);
4824        let rff_codes = ctx.collect_group_values("RFF", 0, 1, &["SG4", "SG8"]);
4825        // Detect duplicate (seq_qual, zeitraum_id, objektcode) combinations across SG8 instances
4826        let mut seen: HashSet<(String, String, String)> = HashSet::new();
4827        for (idx, seq_qual) in &seq_quals {
4828            if seq_qual.is_empty() || !target_quals.contains(seq_qual.as_str()) {
4829                continue;
4830            }
4831            let zeitraum_id = seq_zeitraums
4832                .iter()
4833                .find(|(i, _)| i == idx)
4834                .map(|(_, v)| v.as_str())
4835                .unwrap_or("");
4836            // Find RFF+Z33 in this SG8 instance (correlation by instance index)
4837            for (ridx, rff_qual) in rff_quals.iter() {
4838                if ridx != idx || rff_qual != "Z33" {
4839                    continue;
4840                }
4841                if let Some((_, obj_code)) = rff_codes.iter().find(|(i, _)| i == ridx) {
4842                    if obj_code.is_empty() {
4843                        continue;
4844                    }
4845                    let key = (seq_qual.clone(), zeitraum_id.to_string(), obj_code.clone());
4846                    if seen.contains(&key) {
4847                        return ConditionResult::True;
4848                    }
4849                    seen.insert(key);
4850                }
4851            }
4852        }
4853        ConditionResult::False
4854    }
4855
4856    /// [232] Wenn SG10 CCI+++Z83 (Messtechnische Einordnung der Marktlokation) CAV+Z52 (iMS) vorhanden
4857    fn evaluate_232(&self, ctx: &EvaluationContext) -> ConditionResult {
4858        let cci_segs = ctx.find_segments("CCI");
4859        let found = cci_segs.iter().any(|s| {
4860            s.elements
4861                .get(2)
4862                .and_then(|e| e.first())
4863                .is_some_and(|v| v == "Z83")
4864        });
4865        ConditionResult::from(found)
4866    }
4867
4868    /// [233] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle NB
4869    fn evaluate_233(&self, ctx: &EvaluationContext) -> ConditionResult {
4870        ctx.external.evaluate("recipient_role_check")
4871    }
4872
4873    /// [234] Wenn SG10 CCI+++Z83 (Messtechnische Einordnung der Marktlokation) CAV+Z53 (kME/ mME) vorhanden
4874    fn evaluate_234(&self, ctx: &EvaluationContext) -> ConditionResult {
4875        let cci_segs = ctx.find_segments("CCI");
4876        let found = cci_segs.iter().any(|s| {
4877            s.elements
4878                .get(2)
4879                .and_then(|e| e.first())
4880                .is_some_and(|v| v == "Z83")
4881        });
4882        ConditionResult::from(found)
4883    }
4884
4885    /// [237] Wenn in derselben SG8 im DE7140 des PIA+Z02 (Gruppenartikel-ID / Artikel-ID) eine Gruppenartikel-ID / Artikel-ID mit 1-06 (entspricht Entgelte des Messstellenbetriebs bei kME) beginnt
4886    fn evaluate_237(&self, ctx: &EvaluationContext) -> ConditionResult {
4887        // Check: PIA+Z02 with code starting with 1-08 and containing AGS
4888        let pia_segs = ctx.find_segments("PIA");
4889        let found = pia_segs.iter().any(|s| {
4890            s.elements
4891                .first()
4892                .and_then(|e| e.first())
4893                .is_some_and(|v| v == "Z02")
4894                && s.elements
4895                    .get(1)
4896                    .and_then(|e| e.first())
4897                    .is_some_and(|v| v.starts_with("1-08") && v.contains("AGS"))
4898        });
4899        ConditionResult::from(found)
4900    }
4901
4902    /// [238] Wenn SG4 IDE+24 (Vorgang) nicht vorhanden
4903    fn evaluate_238(&self, ctx: &EvaluationContext) -> ConditionResult {
4904        let ide_segs = ctx.find_segments("IDE");
4905        let found = ide_segs.iter().any(|s| {
4906            s.elements
4907                .first()
4908                .and_then(|e| e.first())
4909                .is_some_and(|v| v == "24")
4910        });
4911        ConditionResult::from(!found)
4912    }
4913
4914    /// [239] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) im CAV+Z65 (Wärme/Kälte) vorhanden
4915    fn evaluate_239(&self, ctx: &EvaluationContext) -> ConditionResult {
4916        let cci_segs = ctx.find_segments("CCI");
4917        let found = cci_segs.iter().any(|s| {
4918            s.elements
4919                .first()
4920                .and_then(|e| e.first())
4921                .is_some_and(|v| v == "Z17")
4922        });
4923        ConditionResult::from(found)
4924    }
4925
4926    /// [240] Wenn SG8 SEQ+Z01 (Daten der Marktlokation) CCI+Z22++Z91 (Veräußerungsform der erzeugenden Marktlokation:: Marktprämie) vorhanden
4927    fn evaluate_240(&self, ctx: &EvaluationContext) -> ConditionResult {
4928        let seq_segs = ctx.find_segments("SEQ");
4929        let found = seq_segs.iter().any(|s| {
4930            s.elements
4931                .first()
4932                .and_then(|e| e.first())
4933                .is_some_and(|v| ["Z01"].contains(&v.as_str()))
4934        });
4935        ConditionResult::from(found)
4936    }
4937
4938    /// [241] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle MSB
4939    fn evaluate_241(&self, ctx: &EvaluationContext) -> ConditionResult {
4940        ctx.external.evaluate("recipient_role_check")
4941    }
4942
4943    /// [243] Wenn SG10 CCI+6++ZA8 (Aggreg.verantw. NB) in dieser SG8 vorhanden
4944    fn evaluate_243(&self, ctx: &EvaluationContext) -> ConditionResult {
4945        let cci_segs = ctx.find_segments("CCI");
4946        let found = cci_segs.iter().any(|s| {
4947            s.elements
4948                .first()
4949                .and_then(|e| e.first())
4950                .is_some_and(|v| v == "6")
4951                && s.elements
4952                    .get(2)
4953                    .and_then(|e| e.first())
4954                    .is_some_and(|v| v == "ZA8")
4955        });
4956        ConditionResult::from(found)
4957    }
4958
4959    /// [244] Wenn SG10 CCI+6++ZA9 (Aggreg.verantw. ÜNB) in dieser SG8 vorhanden
4960    fn evaluate_244(&self, ctx: &EvaluationContext) -> ConditionResult {
4961        let cci_segs = ctx.find_segments("CCI");
4962        let found = cci_segs.iter().any(|s| {
4963            s.elements
4964                .first()
4965                .and_then(|e| e.first())
4966                .is_some_and(|v| v == "6")
4967                && s.elements
4968                    .get(2)
4969                    .and_then(|e| e.first())
4970                    .is_some_and(|v| v == "ZA9")
4971        });
4972        ConditionResult::from(found)
4973    }
4974
4975    /// [248] Wenn die Inbetriebnahme der verbrauchenden Marktlokation innerhalb der letzten drei Jahre war und die Energie der Marktlokation mit iMS ausgestatteten Messlokationen erfolgt
4976    fn evaluate_248(&self, _ctx: &EvaluationContext) -> ConditionResult {
4977        // TODO: implement
4978        ConditionResult::Unknown
4979    }
4980
4981    /// [249] Innerhalb eines SG4 IDE müssen alle DE1131 der SG4 STS+E01 (Status der Antwort) den identischen Wert enthalten
4982    fn evaluate_249(&self, ctx: &EvaluationContext) -> ConditionResult {
4983        // Check: all STS+E01 DE1131 values are identical
4984        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
4985        if sts_segs.len() <= 1 {
4986            return ConditionResult::True;
4987        }
4988        let first_val = sts_segs[0].elements.first().and_then(|e| e.get(1));
4989        let all_same = sts_segs
4990            .iter()
4991            .all(|s| s.elements.first().and_then(|e| e.get(1)) == first_val);
4992        ConditionResult::from(all_same)
4993    }
4994
4995    /// [251] Wenn MP-ID in SG2 NAD+MS (Nachrichtensender) in der Rolle BIKO
4996    fn evaluate_251(&self, ctx: &EvaluationContext) -> ConditionResult {
4997        ctx.external.evaluate("sender_role_check")
4998    }
4999
5000    /// [252] Wenn DE0068 vorhanden
5001    fn evaluate_252(&self, ctx: &EvaluationContext) -> ConditionResult {
5002        let unb_segs = ctx.find_segments("UNB");
5003        let found = unb_segs.iter().any(|s| {
5004            s.elements
5005                .get(4)
5006                .and_then(|e| e.first())
5007                .is_some_and(|v| !v.is_empty())
5008        });
5009        ConditionResult::from(found)
5010    }
5011
5012    /// [254] Es ist der Code \"AUA\" einzutragen
5013    fn evaluate_254(&self, _ctx: &EvaluationContext) -> ConditionResult {
5014        // Check: the code "AUA" is present
5015        ConditionResult::True // AUA is always the required code when this condition applies
5016    }
5017
5018    /// [255] Wenn Marktlokation am Redispatch 2.0 teilnimmt
5019    fn evaluate_255(&self, _ctx: &EvaluationContext) -> ConditionResult {
5020        // TODO: implement
5021        ConditionResult::Unknown
5022    }
5023
5024    /// [256] Wenn in derselben SG8 SEQ (OBIS-Daten der Zähleinrichtung / Smartmeter-Gateway) das PIA+5+1-b?:1.8.e / 1-b?:2.8.e vorhanden
5025    fn evaluate_256(&self, ctx: &EvaluationContext) -> ConditionResult {
5026        // Check: PIA+5 has OBIS code matching 1-?:1.8.? or 1-?:2.8.? pattern
5027        let pia_segs = ctx.find_segments("PIA");
5028        let found = pia_segs.iter().any(|s| {
5029            s.elements
5030                .first()
5031                .and_then(|e| e.first())
5032                .is_some_and(|v| v == "5")
5033                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5034                    (v.contains(":1.8.") || v.contains(":2.8.")) && v.starts_with("1-")
5035                })
5036        });
5037        ConditionResult::from(found)
5038    }
5039
5040    /// [257] Wenn in derselben SG8 SEQ (OBIS-Daten der Marktlokation) das PIA+5+1-b?:1.9.e vorhanden
5041    fn evaluate_257(&self, ctx: &EvaluationContext) -> ConditionResult {
5042        // Check: PIA+5 has OBIS code matching 1-?:1.9.? pattern
5043        let pia_segs = ctx.find_segments("PIA");
5044        let found = pia_segs.iter().any(|s| {
5045            s.elements
5046                .first()
5047                .and_then(|e| e.first())
5048                .is_some_and(|v| v == "5")
5049                && s.elements
5050                    .get(1)
5051                    .and_then(|e| e.first())
5052                    .is_some_and(|v| v.contains(":1.9.") && v.starts_with("1-"))
5053        });
5054        ConditionResult::from(found)
5055    }
5056
5057    /// [259] Wenn in diesem PIA der Code im DE7140 mit 1-01, 1-03, 1-05 enthalten ist
5058    fn evaluate_259(&self, ctx: &EvaluationContext) -> ConditionResult {
5059        let pia_segs = ctx.find_segments("PIA");
5060        let found = pia_segs.iter().any(|s| {
5061            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5062                let prefixes = ["1-01", "1-03", "1-05"];
5063                prefixes.iter().any(|p| v.starts_with(p))
5064            })
5065        });
5066        ConditionResult::from(found)
5067    }
5068
5069    /// [261] Wenn in diesem PIA der Code im DE7140 mit 1-07-1/2, 1-10-1/2/4/5/6/7/8/9, 1-11-1 beginnt
5070    fn evaluate_261(&self, ctx: &EvaluationContext) -> ConditionResult {
5071        let pia_segs = ctx.find_segments("PIA");
5072        let found = pia_segs.iter().any(|s| {
5073            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5074                let prefixes = [
5075                    "1-07-1", "2", "1-10-1", "2", "4", "5", "6", "7", "8", "9", "1-11-1",
5076                ];
5077                prefixes.iter().any(|p| v.starts_with(p))
5078            })
5079        });
5080        ConditionResult::from(found)
5081    }
5082
5083    /// [262] Wenn Produkt an der Marktlokation vorhanden ist
5084    fn evaluate_262(&self, _ctx: &EvaluationContext) -> ConditionResult {
5085        // TODO: implement
5086        ConditionResult::Unknown
5087    }
5088
5089    /// [265] Wenn im SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+Z36 (TEP m. Referenzmessung) vorhanden
5090    fn evaluate_265(&self, ctx: &EvaluationContext) -> ConditionResult {
5091        // Check: in SG8 with SEQ+Z01 or Z98, SG10 has CCI+++ZA6 and CAV+E14/ETK
5092        for &seq_qual in &["Z01", "Z98"] {
5093            for &cav_qual in &["E14", "ETK"] {
5094                let r = ctx.filtered_parent_child_has_qualifier(
5095                    &["SG4", "SG8"],
5096                    "SEQ",
5097                    0,
5098                    seq_qual,
5099                    "SG10",
5100                    "CAV",
5101                    0,
5102                    cav_qual,
5103                );
5104                if r == ConditionResult::True {
5105                    return ConditionResult::True;
5106                }
5107            }
5108        }
5109        ConditionResult::False
5110    }
5111
5112    /// [266] Wenn im SG8 SEQ+Z01 (Daten der Marktlokation) mit identischer Zeitraum-ID im SG8 SEQ+Z01 DE1050 wie in dieser SG8 SEQ, das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis vo...
5113    // REVIEW: Navigates all SG8 instances and their SG10 children, checking for CCI with elements[2][0]=ZA6 (Prognosegrundlage) co-occurring with CAV with elements[0][0]=Z36 (TEP m. Referenzmessung) in the same SG10 instance. The parent SG8 SEQ+Z01 filter and Zeitraum-ID cross-matching are not verified due to lack of direct SG8-level segment access; relies on CCI+ZA6/CAV+Z36 being specific enough to Marktlokation groups. (medium confidence)
5114    fn evaluate_266(&self, ctx: &EvaluationContext) -> ConditionResult {
5115        let nav = match ctx.navigator {
5116            Some(n) => n,
5117            None => {
5118                // Fallback: check any SG8+SEQ+Z01 child SG10 has CAV+Z36
5119                return ctx.filtered_parent_child_has_qualifier(
5120                    &["SG4", "SG8"],
5121                    "SEQ",
5122                    0,
5123                    "Z01",
5124                    "SG10",
5125                    "CAV",
5126                    0,
5127                    "Z36",
5128                );
5129            }
5130        };
5131        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5132        for i in 0..sg8_count {
5133            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
5134            for j in 0..sg10_count {
5135                // CCI+++ZA6 means elements[2][0] == "ZA6"
5136                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
5137                let has_cci_za6 = ccis.iter().any(|s| {
5138                    s.elements
5139                        .get(2)
5140                        .and_then(|e: &Vec<String>| e.first())
5141                        .is_some_and(|v: &String| v == "ZA6")
5142                });
5143                if has_cci_za6 {
5144                    let cavs =
5145                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
5146                    if cavs.iter().any(|s| {
5147                        s.elements
5148                            .first()
5149                            .and_then(|e: &Vec<String>| e.first())
5150                            .is_some_and(|v: &String| v == "Z36")
5151                    }) {
5152                        return ConditionResult::True;
5153                    }
5154                }
5155            }
5156        }
5157        ConditionResult::False
5158    }
5159
5160    /// [267] Wenn SG8 SEQ+Z38 (Referenzprofildaten) nicht vorhanden
5161    fn evaluate_267(&self, ctx: &EvaluationContext) -> ConditionResult {
5162        let seq_segs = ctx.find_segments("SEQ");
5163        let found = seq_segs.iter().any(|s| {
5164            s.elements
5165                .first()
5166                .and_then(|e| e.first())
5167                .is_some_and(|v| ["Z38"].contains(&v.as_str()))
5168        });
5169        ConditionResult::from(!found)
5170    }
5171
5172    /// [268] Wenn der Code im DE3207 in der \"EDI@Energy Codeliste der europäischen Ländercodes\" in der Spalte \"PLZ vorhanden\" ein \"X\" aufgeführt ist
5173    fn evaluate_268(&self, _ctx: &EvaluationContext) -> ConditionResult {
5174        // Most European countries have postal codes — default to true
5175        ConditionResult::True
5176    }
5177
5178    /// [269] Es sind alle OBIS-Kennzahlen gem. EDI@Energy Codeliste der OBIS-Kennzahlen und Medien für den deutschen Energiemarkt Kap.3 anzugeben welche an der Tranche erforderlich sind
5179    fn evaluate_269(&self, _ctx: &EvaluationContext) -> ConditionResult {
5180        // TODO: implement
5181        ConditionResult::Unknown
5182    }
5183
5184    /// [270] Wenn in diesem PIA der Code im DE7140 mit 1-02, 1-04, 1-06, 1-09 beginnt
5185    fn evaluate_270(&self, ctx: &EvaluationContext) -> ConditionResult {
5186        let pia_segs = ctx.find_segments("PIA");
5187        let found = pia_segs.iter().any(|s| {
5188            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5189                let prefixes = ["1-02", "1-04", "1-06", "1-09"];
5190                prefixes.iter().any(|p| v.starts_with(p))
5191            })
5192        });
5193        ConditionResult::from(found)
5194    }
5195
5196    /// [273] Wenn in derselben SG8 SEQ+Z20 (OBIS-Daten der Zähleinrichtung / Smartmeter-Gateway) das PIA+5+1-b?:1.8.e / 1-b?:2.8.e / 1-b?:3.8.e / 1-b?:4.8.e / 1-b?:5.8.e / 1-b?:6.8.e / 1-b?:7.8.e / 1-b?:8.8.e ...
5197    fn evaluate_273(&self, ctx: &EvaluationContext) -> ConditionResult {
5198        // Check: PIA+5 has OBIS code matching energy quantity patterns in SG8 SEQ+Z20
5199        let pia_segs = ctx.find_segments("PIA");
5200        let found = pia_segs.iter().any(|s| {
5201            s.elements
5202                .first()
5203                .and_then(|e| e.first())
5204                .is_some_and(|v| v == "5")
5205                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5206                    v.starts_with("1-")
5207                        && (v.contains(":1.8.") || v.contains(":2.8.") || v.contains(":1.29."))
5208                })
5209        });
5210        ConditionResult::from(found)
5211    }
5212
5213    /// [279] Wenn STS+7++xxx+ZW4 / ZAP (Transaktionsgrundergänzung  verbrauchende Marktlokation / ruhende Marktlokation) vorhanden
5214    fn evaluate_279(&self, ctx: &EvaluationContext) -> ConditionResult {
5215        let sts_segs = ctx.find_segments("STS");
5216        let found = sts_segs.iter().any(|s| {
5217            s.elements
5218                .first()
5219                .and_then(|e| e.first())
5220                .is_some_and(|v| v == "7")
5221                && s.elements
5222                    .get(3)
5223                    .and_then(|e| e.first())
5224                    .is_some_and(|v| ["ZW4", "ZAP"].contains(&v.as_str()))
5225        });
5226        ConditionResult::from(found)
5227    }
5228
5229    /// [280] Nur MP-ID aus Sparte Strom
5230    fn evaluate_280(&self, ctx: &EvaluationContext) -> ConditionResult {
5231        // Check: Marktpartner-ID is from Sparte Strom
5232        // Approximate: check NAD+MS C082 for Strom MP-ID format
5233        ctx.external.evaluate("sector_check")
5234    }
5235
5236    /// [282] Wenn in diesem PIA der Code im DE7140 1-01-6-005, 1-01-9-001/002, 1-07-3-001, 1- 08-1-001, 1-08-3-001, 1-08-4-001/002/003/004, 1-10-3-001 enthalten ist
5237    fn evaluate_282(&self, ctx: &EvaluationContext) -> ConditionResult {
5238        // Check: PIA DE7140 has one of the specific codes
5239        let pia_segs = ctx.find_segments("PIA");
5240        let found = pia_segs.iter().any(|s| {
5241            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5242                v.starts_with("1-01-6-005")
5243                    || v.starts_with("1-01-9-001")
5244                    || v.starts_with("1-01-9-002")
5245                    || v.starts_with("1-07-3-001")
5246                    || v.starts_with("1-08-1-001")
5247                    || v.starts_with("1-08-3-001")
5248                    || v.starts_with("1-08-4-001")
5249                    || v.starts_with("1-08-4-002")
5250                    || v.starts_with("1-08-4-003")
5251                    || v.starts_with("1-08-5")
5252            })
5253        });
5254        ConditionResult::from(found)
5255    }
5256
5257    /// [284] Erlaubte Codes aus der Codeliste der Gruppenartikel- und Artikel-ID sind in der Spalte UTILMD/Codeverwendung mit X gekennzeichnet
5258    // HAND-EDITED — the codegen prompt (conditions/prompt.rs) now documents
5259    // both the SCOPE RULES (Task B6) and the codelist API (review followup).
5260    // Regenerating this function should preserve the shape, but re-verify
5261    // against the committed body if generate-conditions is run.
5262    fn evaluate_284(&self, ctx: &EvaluationContext) -> ConditionResult {
5263        // [284] Erlaubte Codes aus der Codeliste der Gruppenartikel-
5264        // und Artikel-ID mit X in der Spalte UTILMD/Codeverwendung.
5265        //
5266        // Scope-aware: when validate_tree sets a GroupScope on ctx, this
5267        // narrows to the current SG8 instance; otherwise falls back to
5268        // message-wide find_segments. Matches the AHB wording
5269        // "in derselben SG8 im PIA DE7140 ein Code...".
5270        use crate::eval::CodelistColumn;
5271        let any_match = ctx.scoped_find_segments("PIA").iter().any(|s| {
5272            let is_z02 = s
5273                .elements
5274                .first()
5275                .and_then(|e| e.first())
5276                .is_some_and(|v| v == "Z02");
5277            if !is_z02 {
5278                return false;
5279            }
5280            let code = match s.elements.get(1).and_then(|e| e.first()) {
5281                Some(c) if !c.is_empty() => c,
5282                _ => return false,
5283            };
5284            ctx.codelist
5285                .flag(code, CodelistColumn::UtilmdCodeverwendung)
5286                .unwrap_or(false)
5287        });
5288        ConditionResult::from(any_match)
5289    }
5290
5291    /// [285] Wenn in diesem PIA der Code im DE7140 mit 1-08-3-AGS angegeben ist
5292    fn evaluate_285(&self, ctx: &EvaluationContext) -> ConditionResult {
5293        // Check: PIA DE7140 starts with 1-08-3-AGS
5294        let pia_segs = ctx.find_segments("PIA");
5295        let found = pia_segs.iter().any(|s| {
5296            s.elements
5297                .get(1)
5298                .and_then(|e| e.first())
5299                .is_some_and(|v| v.contains("1-08-3") && v.contains("AGS"))
5300        });
5301        ConditionResult::from(found)
5302    }
5303
5304    /// [286] Wenn in diesem PIA der Code im DE7140 mit 1-08-1/2/4/5-AGS-KG
5305    fn evaluate_286(&self, ctx: &EvaluationContext) -> ConditionResult {
5306        // Check: PIA DE7140 matches 1-08-1/2/4/5-AGS-KG pattern
5307        let pia_segs = ctx.find_segments("PIA");
5308        let found = pia_segs.iter().any(|s| {
5309            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5310                (v.starts_with("1-08-1")
5311                    || v.starts_with("1-08-2")
5312                    || v.starts_with("1-08-4")
5313                    || v.starts_with("1-08-5"))
5314                    && v.contains("AGS")
5315                    && v.contains("KG")
5316            })
5317        });
5318        ConditionResult::from(found)
5319    }
5320
5321    /// [287] Erlaubte Codes aus der PRICAT BGM+ Z70 (Preisblatt Netznutzung) des verantwortlichen NB
5322    fn evaluate_287(&self, _ctx: &EvaluationContext) -> ConditionResult {
5323        // TODO: implement
5324        ConditionResult::Unknown
5325    }
5326
5327    /// [288] Wenn in derselben SG8 (OBIS-Daten der Marktlokation) das PIA+5+1-b?:2.9.e vorhanden
5328    fn evaluate_288(&self, ctx: &EvaluationContext) -> ConditionResult {
5329        // Check: PIA+5 has OBIS code matching 1-?:2.9.? pattern
5330        let pia_segs = ctx.find_segments("PIA");
5331        let found = pia_segs.iter().any(|s| {
5332            s.elements
5333                .first()
5334                .and_then(|e| e.first())
5335                .is_some_and(|v| v == "5")
5336                && s.elements
5337                    .get(1)
5338                    .and_then(|e| e.first())
5339                    .is_some_and(|v| v.contains(":2.9.") && v.starts_with("1-"))
5340        });
5341        ConditionResult::from(found)
5342    }
5343
5344    /// [291] Wenn in derselben SG8 (Zuordnung Lokation zum Objektcode des Lokationsbündels) das RFF+Z37 vorhanden
5345    fn evaluate_291(&self, ctx: &EvaluationContext) -> ConditionResult {
5346        let rff_segs = ctx.find_segments("RFF");
5347        let found = rff_segs.iter().any(|s| {
5348            s.elements
5349                .first()
5350                .and_then(|e| e.first())
5351                .is_some_and(|v| v == "Z37")
5352        });
5353        ConditionResult::from(found)
5354    }
5355
5356    /// [292] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeldung einer Zuordnung des LFN (UTILMD)\" in der Spalte \"Anmeldung einer Zuordnung des LFN (UTIL...
5357    fn evaluate_292(&self, ctx: &EvaluationContext) -> ConditionResult {
5358        ctx.external.evaluate("code_list_membership_check")
5359    }
5360
5361    /// [293] Wenn SG5 LOC+Z22 (ruhende Marktlokation) vorhanden
5362    fn evaluate_293(&self, ctx: &EvaluationContext) -> ConditionResult {
5363        let loc_segs = ctx.find_segments("LOC");
5364        let found = loc_segs.iter().any(|s| {
5365            s.elements
5366                .first()
5367                .and_then(|e| e.first())
5368                .is_some_and(|v| v == "Z22")
5369        });
5370        ConditionResult::from(found)
5371    }
5372
5373    /// [294] Wenn SG5 LOC+Z18 (Netzlokation) vorhanden
5374    fn evaluate_294(&self, ctx: &EvaluationContext) -> ConditionResult {
5375        let loc_segs = ctx.find_segments("LOC");
5376        let found = loc_segs.iter().any(|s| {
5377            s.elements
5378                .first()
5379                .and_then(|e| e.first())
5380                .is_some_and(|v| v == "Z18")
5381        });
5382        ConditionResult::from(found)
5383    }
5384
5385    /// [295] Wenn SG5 LOC+Z15 (MaBiS-Zählpunkt) nicht vorhanden
5386    fn evaluate_295(&self, ctx: &EvaluationContext) -> ConditionResult {
5387        let loc_segs = ctx.find_segments("LOC");
5388        let found = loc_segs.iter().any(|s| {
5389            s.elements
5390                .first()
5391                .and_then(|e| e.first())
5392                .is_some_and(|v| v == "Z15")
5393        });
5394        ConditionResult::from(!found)
5395    }
5396
5397    /// [296] Wenn SG5 LOC+Z20 (Technische Ressource) vorhanden
5398    fn evaluate_296(&self, ctx: &EvaluationContext) -> ConditionResult {
5399        let loc_segs = ctx.find_segments("LOC");
5400        let found = loc_segs.iter().any(|s| {
5401            s.elements
5402                .first()
5403                .and_then(|e| e.first())
5404                .is_some_and(|v| v == "Z20")
5405        });
5406        ConditionResult::from(found)
5407    }
5408
5409    /// [297] #kv# Wenn SG5 LOC+Z18 (Netzlokation) nicht vorhanden
5410    fn evaluate_297(&self, ctx: &EvaluationContext) -> ConditionResult {
5411        let loc_segs = ctx.find_segments("LOC");
5412        let found = loc_segs.iter().any(|s| {
5413            s.elements
5414                .first()
5415                .and_then(|e| e.first())
5416                .is_some_and(|v| v == "Z18")
5417        });
5418        ConditionResult::from(!found)
5419    }
5420
5421    /// [298] Wenn SG5 LOC+Z20 (Technische Ressource) nicht vorhanden
5422    fn evaluate_298(&self, ctx: &EvaluationContext) -> ConditionResult {
5423        let loc_segs = ctx.find_segments("LOC");
5424        let found = loc_segs.iter().any(|s| {
5425            s.elements
5426                .first()
5427                .and_then(|e| e.first())
5428                .is_some_and(|v| v == "Z20")
5429        });
5430        ConditionResult::from(!found)
5431    }
5432
5433    /// [299] #kv# Wenn SG5 LOC+Z19 (Steuerbare Ressource) nicht vorhanden
5434    fn evaluate_299(&self, ctx: &EvaluationContext) -> ConditionResult {
5435        let loc_segs = ctx.find_segments("LOC");
5436        let found = loc_segs.iter().any(|s| {
5437            s.elements
5438                .first()
5439                .and_then(|e| e.first())
5440                .is_some_and(|v| v == "Z19")
5441        });
5442        ConditionResult::from(!found)
5443    }
5444
5445    /// [300] Wenn SG8 SEQ+Z15/ ZE7 (Daten der Tranche) nicht vorhanden
5446    fn evaluate_300(&self, ctx: &EvaluationContext) -> ConditionResult {
5447        let seq_segs = ctx.find_segments("SEQ");
5448        let found = seq_segs.iter().any(|s| {
5449            s.elements
5450                .first()
5451                .and_then(|e| e.first())
5452                .is_some_and(|v| ["Z15", "ZE7"].contains(&v.as_str()))
5453        });
5454        ConditionResult::from(!found)
5455    }
5456
5457    /// [301] Wenn BGM+E03 (Änderungsmeldung) vorhanden
5458    fn evaluate_301(&self, ctx: &EvaluationContext) -> ConditionResult {
5459        let bgm_segs = ctx.find_segments("BGM");
5460        let found = bgm_segs.iter().any(|s| {
5461            s.elements
5462                .first()
5463                .and_then(|e| e.first())
5464                .is_some_and(|v| v == "E03")
5465        });
5466        ConditionResult::from(found)
5467    }
5468
5469    /// [302] Wenn SG8 SEQ+Z08 (Profilschardaten) nicht vorhanden
5470    fn evaluate_302(&self, ctx: &EvaluationContext) -> ConditionResult {
5471        let seq_segs = ctx.find_segments("SEQ");
5472        let found = seq_segs.iter().any(|s| {
5473            s.elements
5474                .first()
5475                .and_then(|e| e.first())
5476                .is_some_and(|v| ["Z08"].contains(&v.as_str()))
5477        });
5478        ConditionResult::from(!found)
5479    }
5480
5481    /// [303] Wenn SG8 SEQ+Z21 (Profildaten) nicht vorhanden
5482    fn evaluate_303(&self, ctx: &EvaluationContext) -> ConditionResult {
5483        let seq_segs = ctx.find_segments("SEQ");
5484        let found = seq_segs.iter().any(|s| {
5485            s.elements
5486                .first()
5487                .and_then(|e| e.first())
5488                .is_some_and(|v| ["Z21"].contains(&v.as_str()))
5489        });
5490        ConditionResult::from(!found)
5491    }
5492
5493    /// [304] Wenn SG8 SEQ+Z22 (Daten der Summenzeitreihe) vorhanden
5494    fn evaluate_304(&self, ctx: &EvaluationContext) -> ConditionResult {
5495        let seq_segs = ctx.find_segments("SEQ");
5496        let found = seq_segs.iter().any(|s| {
5497            s.elements
5498                .first()
5499                .and_then(|e| e.first())
5500                .is_some_and(|v| ["Z22"].contains(&v.as_str()))
5501        });
5502        ConditionResult::from(found)
5503    }
5504
5505    /// [305] Wenn SG8 SEQ+Z24 (Daten der Überführungszeitreihe) vorhanden
5506    fn evaluate_305(&self, ctx: &EvaluationContext) -> ConditionResult {
5507        let seq_segs = ctx.find_segments("SEQ");
5508        let found = seq_segs.iter().any(|s| {
5509            s.elements
5510                .first()
5511                .and_then(|e| e.first())
5512                .is_some_and(|v| ["Z24"].contains(&v.as_str()))
5513        });
5514        ConditionResult::from(found)
5515    }
5516
5517    /// [306] Wenn SG5 LOC+Z22 (ruhende Marktlokation) mit derselben Zeitraum-ID im DE3224 vorhanden wie in dieser SG8 im DE1050 (Referenz auf Zeitraum-ID) des SEQ+Z58
5518    fn evaluate_306(&self, ctx: &EvaluationContext) -> ConditionResult {
5519        use std::collections::HashSet;
5520        // Collect Zeitraum-IDs from SG5 LOC+Z22 (Ruhende Marktlokation) — DE3224 at elements[1][3]
5521        let loc_z22_ids: HashSet<String> = ctx
5522            .find_segments_with_qualifier("LOC", 0, "Z22")
5523            .into_iter()
5524            .filter_map(|s| s.elements.get(1)?.get(3).cloned())
5525            .filter(|v| !v.is_empty())
5526            .collect();
5527        if loc_z22_ids.is_empty() {
5528            return ConditionResult::False;
5529        }
5530        // Check if any SG8 SEQ+Z58 has DE1050 (elements[1][0]) matching a LOC+Z22 DE3224
5531        let has_match = ctx
5532            .find_segments_with_qualifier("SEQ", 0, "Z58")
5533            .iter()
5534            .any(|s| {
5535                s.elements
5536                    .get(1)
5537                    .and_then(|e: &Vec<String>| e.first())
5538                    .is_some_and(|v: &String| !v.is_empty() && loc_z22_ids.contains(v.as_str()))
5539            });
5540        ConditionResult::from(has_match)
5541    }
5542
5543    /// [307] Wenn SG5 LOC+Z22 (ruhende Marktlokation) mit derselben Zeitraum-ID im DE3224 nicht vorhanden wie in dieser SG8 im DE1050 (Referenz auf Zeitraum-ID) des SEQ+Z58
5544    // REVIEW: Collects Zeitraum-IDs from SG5 LOC+Z22 segments (DE3224 = elements[1][3]) and SEQ+Z58 segments (DE1050 = elements[1][0]). Returns True when any SEQ+Z58 has a Zeitraum-ID with no matching LOC+Z22 entry. Message-wide fallback since group-level Zeitraum-ID isolation is not possible without navigator. (medium confidence)
5545    fn evaluate_307(&self, ctx: &EvaluationContext) -> ConditionResult {
5546        let seq_segs = ctx.find_segments_with_qualifier("SEQ", 0, "Z58");
5547        if seq_segs.is_empty() {
5548            return ConditionResult::Unknown;
5549        }
5550        let loc_segs = ctx.find_segments_with_qualifier("LOC", 0, "Z22");
5551        let loc_z22_zeitraum_ids: Vec<&str> = loc_segs
5552            .iter()
5553            .filter_map(|s| s.elements.get(1).and_then(|e| e.get(3)).map(|v| v.as_str()))
5554            .filter(|v| !v.is_empty())
5555            .collect();
5556        ConditionResult::from(seq_segs.iter().any(|seq| {
5557            let zid = seq
5558                .elements
5559                .get(1)
5560                .and_then(|e: &Vec<String>| e.first())
5561                .map(|v| v.as_str())
5562                .unwrap_or("");
5563            !zid.is_empty() && !loc_z22_zeitraum_ids.contains(&zid)
5564        }))
5565    }
5566
5567    /// [309] Wenn SG5 LOC+Z22 (ruhende Marktlokation) nicht vorhanden
5568    fn evaluate_309(&self, ctx: &EvaluationContext) -> ConditionResult {
5569        let loc_segs = ctx.find_segments("LOC");
5570        let found = loc_segs.iter().any(|s| {
5571            s.elements
5572                .first()
5573                .and_then(|e| e.first())
5574                .is_some_and(|v| v == "Z22")
5575        });
5576        ConditionResult::from(!found)
5577    }
5578
5579    /// [314] Es sind alle OBIS-Kennzahlen gem. Codeliste der OBIS-Kennzahlen und Medien Kapitel 3 anzugeben welche an der Marktlokation erforderlich sind. Der Mindestumfang der OBIS-Kennzahlen ergibt sich aus d...
5580    fn evaluate_314(&self, ctx: &EvaluationContext) -> ConditionResult {
5581        ctx.external.evaluate("code_list_membership_check")
5582    }
5583
5584    /// [315] Wenn BGM+Z88 (Datenclearing) vorhanden
5585    fn evaluate_315(&self, ctx: &EvaluationContext) -> ConditionResult {
5586        ctx.external.evaluate("data_clearing_required")
5587    }
5588
5589    /// [316] Wenn in derselben SG8 das RFF+Z14 (Smartmeter-Gateway) nicht vorhanden
5590    fn evaluate_316(&self, ctx: &EvaluationContext) -> ConditionResult {
5591        ctx.any_group_has_qualifier_without("SEQ", 0, "Z03", "RFF", 0, "Z14", &["SG4", "SG8"])
5592    }
5593
5594    /// [317] Es ist derselbe Wert wie im DE2380 von DTM+92 (Datum Vertragsbeginn) einzutragen
5595    fn evaluate_317(&self, ctx: &EvaluationContext) -> ConditionResult {
5596        // Check: DTM+92 (Datum Vertragsbeginn) exists — value identity is structural
5597        let found = !ctx.find_segments_with_qualifier("DTM", 0, "92").is_empty();
5598        if found {
5599            ConditionResult::True
5600        } else {
5601            ConditionResult::Unknown
5602        }
5603    }
5604
5605    /// [318] Es ist derselbe Wert wie im DE2380 von DTM+93 (Datum Vertragende) einzutragen
5606    fn evaluate_318(&self, ctx: &EvaluationContext) -> ConditionResult {
5607        // Check: DTM+93 (Datum Vertragende) exists — value identity is structural
5608        let found = !ctx.find_segments_with_qualifier("DTM", 0, "93").is_empty();
5609        if found {
5610            ConditionResult::True
5611        } else {
5612            ConditionResult::Unknown
5613        }
5614    }
5615
5616    /// [321] Wenn im DE3155 in demselben COM der Code EM vorhanden ist
5617    fn evaluate_321(&self, ctx: &EvaluationContext) -> ConditionResult {
5618        let com_segs = ctx.find_segments("COM");
5619        let has_em = com_segs.iter().any(|s| {
5620            s.elements
5621                .first()
5622                .and_then(|e| e.get(1))
5623                .is_some_and(|v| v == "EM")
5624        });
5625        ConditionResult::from(has_em)
5626    }
5627
5628    /// [322] Wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
5629    fn evaluate_322(&self, ctx: &EvaluationContext) -> ConditionResult {
5630        let com_segs = ctx.find_segments("COM");
5631        let has_phone = com_segs.iter().any(|s| {
5632            s.elements
5633                .first()
5634                .and_then(|e| e.get(1))
5635                .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
5636        });
5637        ConditionResult::from(has_phone)
5638    }
5639
5640    /// [323] Es sind alle OBIS-Kennzahlen gem. EDI@Energy Codeliste der OBIS-Kennzahlen und Medien für den deutschen Energiemarkt Kap. 3. anzugeben, welche an der Zähleinrichtung genutzt werden. Der Mindestum...
5641    fn evaluate_323(&self, ctx: &EvaluationContext) -> ConditionResult {
5642        ctx.external.evaluate("code_list_membership_check")
5643    }
5644
5645    /// [327] Wenn die Zeitraum-ID im DE1050 dieser SG8 SEQ, welche mit der Zeitraum-ID einer SG6 RFF+Z47/Z48/Z49 (Verwendungszeitraum der Daten) identisch ist und in deren SG das SG6 DTM+Z25 (Verwendung der Dat...
5646    // REVIEW: Step 1: Collect all SEQ DE1050 Zeitraum-IDs. Step 2: Find RFF+Z47/Z48/Z49 (Verwendungszeitraum) whose DE1156 (elements[0][2]) matches. Step 3: Check co-located DTM+Z25 DE2380 (elements[0][1]) >= threshold after normalising EDIFACT escape '?+' to '+'. Falls back to message-wide DTM search which may give false positives if multiple SG6 groups are present, but is sufficient for typical single-transaction messages. (medium confidence)
5647    fn evaluate_327(&self, ctx: &EvaluationContext) -> ConditionResult {
5648        const THRESHOLD: &str = "202212312300+00";
5649        let seq_zeitraum_ids: Vec<String> = ctx
5650            .find_segments("SEQ")
5651            .iter()
5652            .filter_map(|s| {
5653                s.elements
5654                    .get(1)
5655                    .and_then(|e: &Vec<String>| e.first())
5656                    .cloned()
5657            })
5658            .filter(|v| !v.is_empty())
5659            .collect();
5660        if seq_zeitraum_ids.is_empty() {
5661            return ConditionResult::Unknown;
5662        }
5663        let rff_segs = ctx.find_segments("RFF");
5664        let matching_rff = rff_segs.iter().any(|rff| {
5665            let qual = rff
5666                .elements
5667                .first()
5668                .and_then(|e: &Vec<String>| e.first())
5669                .map(|v| v.as_str())
5670                .unwrap_or("");
5671            if !["Z47", "Z48", "Z49"].contains(&qual) {
5672                return false;
5673            }
5674            let zid = rff
5675                .elements
5676                .first()
5677                .and_then(|e| e.get(2))
5678                .map(|v| v.as_str())
5679                .unwrap_or("");
5680            !zid.is_empty() && seq_zeitraum_ids.iter().any(|id| id.as_str() == zid)
5681        });
5682        if !matching_rff {
5683            return ConditionResult::False;
5684        }
5685        for dtm in ctx.find_segments_with_qualifier("DTM", 0, "Z25") {
5686            let val = dtm
5687                .elements
5688                .first()
5689                .and_then(|e| e.get(1))
5690                .map(|v| v.replace("?+", "+"))
5691                .unwrap_or_default();
5692            if !val.is_empty() && val.as_str() >= THRESHOLD {
5693                return ConditionResult::True;
5694            }
5695        }
5696        ConditionResult::False
5697    }
5698
5699    /// [329] Wenn in dieser SG4 IDE+24 das STS+E01++A03: E_0096 bzw. A04:E_0097 (Status der Antwort) nicht vorhanden
5700    fn evaluate_329(&self, ctx: &EvaluationContext) -> ConditionResult {
5701        // Check: STS+E01 does NOT have A03 with E_0096 or A04 with E_0097
5702        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5703        let has_a03_e0096 = sts_segs.iter().any(|s| {
5704            s.elements
5705                .get(2)
5706                .and_then(|e| e.first())
5707                .is_some_and(|v| v == "A03")
5708                && s.elements
5709                    .get(2)
5710                    .and_then(|e| e.get(1))
5711                    .is_some_and(|v| v == "E_0096")
5712        });
5713        let has_a04_e0097 = sts_segs.iter().any(|s| {
5714            s.elements
5715                .get(2)
5716                .and_then(|e| e.first())
5717                .is_some_and(|v| v == "A04")
5718                && s.elements
5719                    .get(2)
5720                    .and_then(|e| e.get(1))
5721                    .is_some_and(|v| v == "E_0097")
5722        });
5723        ConditionResult::from(!has_a03_e0096 && !has_a04_e0097)
5724    }
5725
5726    /// [331] Wenn im SG8 SEQ+Z98 (Daten der Marktlokation) das SG10 CCI+6++ZA9 (Aggreg. verantw. ÜNB) nicht vorhanden
5727    fn evaluate_331(&self, ctx: &EvaluationContext) -> ConditionResult {
5728        let seq_segs = ctx.find_segments("SEQ");
5729        let has_seq = seq_segs.iter().any(|s| {
5730            s.elements
5731                .first()
5732                .and_then(|e| e.first())
5733                .is_some_and(|v| v == "Z98")
5734        });
5735        let cci_segs = ctx.find_segments("CCI");
5736        let has_cci = cci_segs.iter().any(|s| {
5737            s.elements
5738                .first()
5739                .and_then(|e| e.first())
5740                .is_some_and(|v| v == "6")
5741                && s.elements
5742                    .get(2)
5743                    .and_then(|e| e.first())
5744                    .is_some_and(|v| v == "ZA9")
5745        });
5746        ConditionResult::from(!(has_seq && has_cci))
5747    }
5748
5749    /// [332] Wenn im SG8 SEQ+Z01 (Daten der Marktlokation) mit identischer Zeitraum-ID im DE1050 wie in dieser SG8, das SG10 CCI+6++ZA9 (Aggreg. verantw. ÜNB) nicht vorhanden
5750    // REVIEW: Checks whether any SG8 instance lacks CCI+6++ZA9 (Aggregationsverantwortung ÜNB, elements[0]='6' and elements[2][0]='ZA9') in its SG10 children. With navigator: iterates SG8 instances and their SG10 children. Without navigator: falls back to message-wide CCI+6 with ZA9 check. The Zeitraum-ID cross-reference between this SG8 and the Z01 SG8 cannot be fully verified without direct SG8-level segment access via navigator, so this is an approximation that may produce false positives in multi-SG4-group messages. (medium confidence)
5751    fn evaluate_332(&self, ctx: &EvaluationContext) -> ConditionResult {
5752        let nav = match ctx.navigator {
5753            Some(n) => n,
5754            None => {
5755                if ctx.find_segments_with_qualifier("SEQ", 0, "Z01").is_empty() {
5756                    return ConditionResult::Unknown;
5757                }
5758                let has_cci_za9 = ctx
5759                    .find_segments_with_qualifier("CCI", 0, "6")
5760                    .iter()
5761                    .any(|s| {
5762                        s.elements
5763                            .get(2)
5764                            .and_then(|e: &Vec<String>| e.first())
5765                            .map(|v| v.as_str())
5766                            == Some("ZA9")
5767                    });
5768                return ConditionResult::from(!has_cci_za9);
5769            }
5770        };
5771        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5772        if sg8_count == 0 {
5773            return ConditionResult::Unknown;
5774        }
5775        for sg8_idx in 0..sg8_count {
5776            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], sg8_idx, "SG10");
5777            let mut has_cci_za9 = false;
5778            for sg10_idx in 0..sg10_count {
5779                let ccis = nav.find_segments_in_child_group(
5780                    "CCI",
5781                    &["SG4", "SG8"],
5782                    sg8_idx,
5783                    "SG10",
5784                    sg10_idx,
5785                );
5786                if ccis.iter().any(|s| {
5787                    s.elements
5788                        .first()
5789                        .and_then(|e: &Vec<String>| e.first())
5790                        .map(|v| v.as_str())
5791                        == Some("6")
5792                        && s.elements
5793                            .get(2)
5794                            .and_then(|e: &Vec<String>| e.first())
5795                            .map(|v| v.as_str())
5796                            == Some("ZA9")
5797                }) {
5798                    has_cci_za9 = true;
5799                    break;
5800                }
5801            }
5802            if !has_cci_za9 {
5803                return ConditionResult::True;
5804            }
5805        }
5806        ConditionResult::False
5807    }
5808
5809    /// [333] Wenn in diesem RFF \"Referenz auf die Lokationsbündelstruktur\" im DE1153 der Code Z31 \"Lokationsbündelstruktur\" vorhanden ist
5810    fn evaluate_333(&self, ctx: &EvaluationContext) -> ConditionResult {
5811        let rff_segs = ctx.find_segments("RFF");
5812        let found = rff_segs.iter().any(|s| {
5813            s.elements
5814                .first()
5815                .and_then(|e| e.first())
5816                .is_some_and(|v| v == "Z31")
5817        });
5818        ConditionResult::from(found)
5819    }
5820
5821    /// [334] Nur MP-ID aus Sparte Gas
5822    fn evaluate_334(&self, ctx: &EvaluationContext) -> ConditionResult {
5823        // Check: Marktpartner-ID is from Sparte Gas
5824        ctx.external.evaluate("sector_check")
5825    }
5826
5827    /// [335] Wenn in dieser SG8 im SEQ+Z58 (Zuordnung Lokation zum Objektcode des Lokationsbündels) im DE1050 eine Zeitraum-ID angegeben wird, wie in einer SG8 SEQ+Z78 RFF+Z31 (Referenz auf die Lokationsbünde...
5828    // REVIEW: Collects Zeitraum-IDs from SEQ+Z58 DE1050 (elements[1][0]). Verifies an SG8 with SEQ+Z78 exists (entry for Lokationsbündelstruktur). Collects IDs from RFF+Z31 DE1154 (elements[0][1]) and checks if any SEQ+Z58 Zeitraum-ID matches. Co-location of RFF+Z31 with SEQ+Z78 in the same SG8 instance is approximated message-wide; exact co-location verification would require navigator SG8-level segment access. (medium confidence)
5829    fn evaluate_335(&self, ctx: &EvaluationContext) -> ConditionResult {
5830        let z58_ids: Vec<String> = ctx
5831            .find_segments_with_qualifier("SEQ", 0, "Z58")
5832            .iter()
5833            .filter_map(|s| {
5834                s.elements
5835                    .get(1)
5836                    .and_then(|e: &Vec<String>| e.first())
5837                    .cloned()
5838            })
5839            .filter(|v| !v.is_empty())
5840            .collect();
5841        if z58_ids.is_empty() {
5842            return ConditionResult::Unknown;
5843        }
5844        if ctx.find_segments_with_qualifier("SEQ", 0, "Z78").is_empty() {
5845            return ConditionResult::False;
5846        }
5847        let rff_z31_ids: Vec<String> = ctx
5848            .find_segments("RFF")
5849            .iter()
5850            .filter(|rff| {
5851                rff.elements
5852                    .first()
5853                    .and_then(|e: &Vec<String>| e.first())
5854                    .map(|v| v.as_str())
5855                    == Some("Z31")
5856            })
5857            .filter_map(|rff| rff.elements.first().and_then(|e| e.get(1)).cloned())
5858            .filter(|v| !v.is_empty())
5859            .collect();
5860        ConditionResult::from(z58_ids.iter().any(|id| rff_z31_ids.contains(id)))
5861    }
5862
5863    /// [336] Wenn in Änderungsmeldung gefüllt
5864    fn evaluate_336(&self, _ctx: &EvaluationContext) -> ConditionResult {
5865        // TODO: implement
5866        ConditionResult::Unknown
5867    }
5868
5869    /// [337] Wenn SG10 CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z95/ Z96 vorhanden
5870    fn evaluate_337(&self, ctx: &EvaluationContext) -> ConditionResult {
5871        let cci_segs = ctx.find_segments("CCI");
5872        let has_cci = cci_segs.iter().any(|s| {
5873            s.elements
5874                .get(2)
5875                .and_then(|e| e.first())
5876                .is_some_and(|v| v == "ZB4")
5877        });
5878        let cav_segs = ctx.find_segments("CAV");
5879        let has_cav = cav_segs.iter().any(|s| {
5880            s.elements
5881                .first()
5882                .and_then(|e| e.first())
5883                .is_some_and(|v| ["Z95", "Z96"].contains(&v.as_str()))
5884        });
5885        ConditionResult::from(has_cci && has_cav)
5886    }
5887
5888    /// [338] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z95/ Z96/ Z97/ Z99/ ZA1/ ZA3/ ZA4/ZG7 vorhanden
5889    fn evaluate_338(&self, ctx: &EvaluationContext) -> ConditionResult {
5890        let cci_segs = ctx.find_segments("CCI");
5891        let has_cci = cci_segs.iter().any(|s| {
5892            s.elements
5893                .get(2)
5894                .and_then(|e| e.first())
5895                .is_some_and(|v| v == "ZB4")
5896        });
5897        let cav_segs = ctx.find_segments("CAV");
5898        let has_cav = cav_segs.iter().any(|s| {
5899            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
5900                ["Z95", "Z96", "Z97", "Z99", "ZA1", "ZA3", "ZA4", "ZG7"].contains(&v.as_str())
5901            })
5902        });
5903        ConditionResult::from(has_cci && has_cav)
5904    }
5905
5906    /// [339] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z97/ Z98/ Z99/ ZA0/ ZA1/ ZA2/ ZA3/ ZA6/ ZG7 vorhanden
5907    fn evaluate_339(&self, ctx: &EvaluationContext) -> ConditionResult {
5908        let cci_segs = ctx.find_segments("CCI");
5909        let has_cci = cci_segs.iter().any(|s| {
5910            s.elements
5911                .get(2)
5912                .and_then(|e| e.first())
5913                .is_some_and(|v| v == "ZB4")
5914        });
5915        let cav_segs = ctx.find_segments("CAV");
5916        let has_cav = cav_segs.iter().any(|s| {
5917            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
5918                [
5919                    "Z97", "Z98", "Z99", "ZA0", "ZA1", "ZA2", "ZA3", "ZA6", "ZG7",
5920                ]
5921                .contains(&v.as_str())
5922            })
5923        });
5924        ConditionResult::from(has_cci && has_cav)
5925    }
5926
5927    /// [340] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z95/ Z97/ Z98/ Z99/ ZA1/ ZA2/ ZA3/ ZA4/ ZA5/ ZA6 vorhanden
5928    fn evaluate_340(&self, ctx: &EvaluationContext) -> ConditionResult {
5929        let cci_segs = ctx.find_segments("CCI");
5930        let has_cci = cci_segs.iter().any(|s| {
5931            s.elements
5932                .get(2)
5933                .and_then(|e| e.first())
5934                .is_some_and(|v| v == "ZB4")
5935        });
5936        let cav_segs = ctx.find_segments("CAV");
5937        let has_cav = cav_segs.iter().any(|s| {
5938            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
5939                [
5940                    "Z95", "Z97", "Z98", "Z99", "ZA1", "ZA2", "ZA3", "ZA4", "ZA5", "ZA6",
5941                ]
5942                .contains(&v.as_str())
5943            })
5944        });
5945        ConditionResult::from(has_cci && has_cav)
5946    }
5947
5948    /// [341] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z96/ ZA0/ ZG7 vorhanden
5949    fn evaluate_341(&self, ctx: &EvaluationContext) -> ConditionResult {
5950        let cci_segs = ctx.find_segments("CCI");
5951        let has_cci = cci_segs.iter().any(|s| {
5952            s.elements
5953                .get(2)
5954                .and_then(|e| e.first())
5955                .is_some_and(|v| v == "ZB4")
5956        });
5957        let cav_segs = ctx.find_segments("CAV");
5958        let has_cav = cav_segs.iter().any(|s| {
5959            s.elements
5960                .first()
5961                .and_then(|e| e.first())
5962                .is_some_and(|v| ["Z96", "ZA0", "ZG7"].contains(&v.as_str()))
5963        });
5964        ConditionResult::from(has_cci && has_cav)
5965    }
5966
5967    /// [342] Wenn aktiver MaBiS-ZP für den Betrachtungszeitraum vorhanden
5968    fn evaluate_342(&self, _ctx: &EvaluationContext) -> ConditionResult {
5969        // TODO: implement
5970        ConditionResult::Unknown
5971    }
5972
5973    /// [344] Wenn in dieser SG8 das SG10 CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+ZF1 (Netzgangzeitreihe (NGZ)) vorhanden
5974    fn evaluate_344(&self, ctx: &EvaluationContext) -> ConditionResult {
5975        let cci_segs = ctx.find_segments("CCI");
5976        let has_cci = cci_segs.iter().any(|s| {
5977            s.elements
5978                .get(2)
5979                .and_then(|e| e.first())
5980                .is_some_and(|v| v == "ZB4")
5981        });
5982        let cav_segs = ctx.find_segments("CAV");
5983        let has_cav = cav_segs.iter().any(|s| {
5984            s.elements
5985                .first()
5986                .and_then(|e| e.first())
5987                .is_some_and(|v| ["ZF1"].contains(&v.as_str()))
5988        });
5989        ConditionResult::from(has_cci && has_cav)
5990    }
5991
5992    /// [345] Wenn SG5 LOC+Z17 (Messlokation) vorhanden
5993    fn evaluate_345(&self, ctx: &EvaluationContext) -> ConditionResult {
5994        let loc_segs = ctx.find_segments("LOC");
5995        let found = loc_segs.iter().any(|s| {
5996            s.elements
5997                .first()
5998                .and_then(|e| e.first())
5999                .is_some_and(|v| v == "Z17")
6000        });
6001        ConditionResult::from(found)
6002    }
6003
6004    /// [346] Wenn SG10 CCI+++E13 (Zählertyp) CAV+MME (mME) vorhanden
6005    fn evaluate_346(&self, ctx: &EvaluationContext) -> ConditionResult {
6006        let cci_segs = ctx.find_segments("CCI");
6007        let found = cci_segs.iter().any(|s| {
6008            s.elements
6009                .get(2)
6010                .and_then(|e| e.first())
6011                .is_some_and(|v| v == "E13")
6012        });
6013        ConditionResult::from(found)
6014    }
6015
6016    /// [347] Wenn SG5 LOC+Z16 (Marktlokation) nicht vorhanden
6017    fn evaluate_347(&self, ctx: &EvaluationContext) -> ConditionResult {
6018        let loc_segs = ctx.find_segments("LOC");
6019        let found = loc_segs.iter().any(|s| {
6020            s.elements
6021                .first()
6022                .and_then(|e| e.first())
6023                .is_some_and(|v| v == "Z16")
6024        });
6025        ConditionResult::from(!found)
6026    }
6027
6028    /// [348] Wenn SG5 LOC+Z21 (Tranche) nicht vorhanden
6029    fn evaluate_348(&self, ctx: &EvaluationContext) -> ConditionResult {
6030        let loc_segs = ctx.find_segments("LOC");
6031        let found = loc_segs.iter().any(|s| {
6032            s.elements
6033                .first()
6034                .and_then(|e| e.first())
6035                .is_some_and(|v| v == "Z21")
6036        });
6037        ConditionResult::from(!found)
6038    }
6039
6040    /// [349] Wenn SG5 LOC+Z17 (Messlokation) nicht vorhanden
6041    fn evaluate_349(&self, ctx: &EvaluationContext) -> ConditionResult {
6042        let loc_segs = ctx.find_segments("LOC");
6043        let found = loc_segs.iter().any(|s| {
6044            s.elements
6045                .first()
6046                .and_then(|e| e.first())
6047                .is_some_and(|v| v == "Z17")
6048        });
6049        ConditionResult::from(!found)
6050    }
6051
6052    /// [350] Wenn SG8 SEQ+Z78/ZD5 RFF+Z31 (Referenz auf die Lokationsbündelstruktur) vorhanden
6053    fn evaluate_350(&self, ctx: &EvaluationContext) -> ConditionResult {
6054        let seq_segs = ctx.find_segments("SEQ");
6055        let has_seq = seq_segs.iter().any(|s| {
6056            s.elements
6057                .first()
6058                .and_then(|e| e.first())
6059                .is_some_and(|v| ["Z78", "ZD5"].contains(&v.as_str()))
6060        });
6061        let rff_segs = ctx.find_segments("RFF");
6062        let has_rff = rff_segs.iter().any(|s| {
6063            s.elements
6064                .first()
6065                .and_then(|e| e.first())
6066                .is_some_and(|v| v == "Z31")
6067        });
6068        ConditionResult::from(has_seq && has_rff)
6069    }
6070
6071    /// [351] Wenn SG4 STS+E01++A04/ A05 /A13 /A14 (Status der Antwort) vorhanden
6072    fn evaluate_351(&self, ctx: &EvaluationContext) -> ConditionResult {
6073        let sts_segs = ctx.find_segments("STS");
6074        let found = sts_segs.iter().any(|s| {
6075            s.elements
6076                .first()
6077                .and_then(|e| e.first())
6078                .is_some_and(|v| v == "E01")
6079                && s.elements
6080                    .get(2)
6081                    .and_then(|e| e.first())
6082                    .is_some_and(|v| ["A04", "A05", "A13", "A14"].contains(&v.as_str()))
6083        });
6084        ConditionResult::from(found)
6085    }
6086
6087    /// [352] Wenn SG4 STS++A05/ A06/ A14 /A15 (Status der Antwort) vorhanden
6088    fn evaluate_352(&self, ctx: &EvaluationContext) -> ConditionResult {
6089        let sts_segs = ctx.find_segments("STS");
6090        let found = sts_segs.iter().any(|s| {
6091            s.elements
6092                .get(1)
6093                .and_then(|e| e.first())
6094                .is_some_and(|v| ["A05", "A06", "A14", "A15"].contains(&v.as_str()))
6095        });
6096        ConditionResult::from(found)
6097    }
6098
6099    /// [355] Wenn SG4 STS+E01++A45 (Status der Antwort) vorhanden
6100    fn evaluate_355(&self, ctx: &EvaluationContext) -> ConditionResult {
6101        let sts_segs = ctx.find_segments("STS");
6102        let found = sts_segs.iter().any(|s| {
6103            s.elements
6104                .first()
6105                .and_then(|e| e.first())
6106                .is_some_and(|v| v == "E01")
6107                && s.elements
6108                    .get(2)
6109                    .and_then(|e| e.first())
6110                    .is_some_and(|v| ["A45"].contains(&v.as_str()))
6111        });
6112        ConditionResult::from(found)
6113    }
6114
6115    /// [356] Wenn SG4 STS+E01++A50 (Status der Antwort) vorhanden
6116    fn evaluate_356(&self, ctx: &EvaluationContext) -> ConditionResult {
6117        let sts_segs = ctx.find_segments("STS");
6118        let found = sts_segs.iter().any(|s| {
6119            s.elements
6120                .first()
6121                .and_then(|e| e.first())
6122                .is_some_and(|v| v == "E01")
6123                && s.elements
6124                    .get(2)
6125                    .and_then(|e| e.first())
6126                    .is_some_and(|v| ["A50"].contains(&v.as_str()))
6127        });
6128        ConditionResult::from(found)
6129    }
6130
6131    /// [357] Wenn SG4 STS+E01++A03/ A09/ A12/ A17 (Status der Antwort) vorhanden
6132    fn evaluate_357(&self, ctx: &EvaluationContext) -> ConditionResult {
6133        let sts_segs = ctx.find_segments("STS");
6134        let found = sts_segs.iter().any(|s| {
6135            s.elements
6136                .first()
6137                .and_then(|e| e.first())
6138                .is_some_and(|v| v == "E01")
6139                && s.elements
6140                    .get(2)
6141                    .and_then(|e| e.first())
6142                    .is_some_and(|v| ["A03", "A09", "A12", "A17"].contains(&v.as_str()))
6143        });
6144        ConditionResult::from(found)
6145    }
6146
6147    /// [358] Wenn SG4 STS+E01++A06 (Status der Antwort) vorhanden
6148    fn evaluate_358(&self, ctx: &EvaluationContext) -> ConditionResult {
6149        let sts_segs = ctx.find_segments("STS");
6150        let found = sts_segs.iter().any(|s| {
6151            s.elements
6152                .first()
6153                .and_then(|e| e.first())
6154                .is_some_and(|v| v == "E01")
6155                && s.elements
6156                    .get(2)
6157                    .and_then(|e| e.first())
6158                    .is_some_and(|v| ["A06"].contains(&v.as_str()))
6159        });
6160        ConditionResult::from(found)
6161    }
6162
6163    /// [359] Es sind nur Antwortcodes aus dem Cluster Ablehnung erlaubt
6164    // HAND-EDITED: driven by per-EBD cluster data (mako_prozesse).
6165    // Preserve across regeneration until the codegen prompt is updated.
6166    fn evaluate_359(&self, ctx: &EvaluationContext) -> ConditionResult {
6167        all_sts_e01_in_cluster(ctx, Cluster::is_ablehnung)
6168    }
6169
6170    /// [360] Es sind nur Antwortcodes aus dem Cluster Zustimmung erlaubt
6171    // HAND-EDITED: driven by per-EBD cluster data (mako_prozesse).
6172    // Preserve across regeneration until the codegen prompt is updated.
6173    fn evaluate_360(&self, ctx: &EvaluationContext) -> ConditionResult {
6174        all_sts_e01_in_cluster(ctx, Cluster::is_zustimmung)
6175    }
6176
6177    /// [363] Wenn SG4 STS+E01++A50 (Status der Antwort) vorhanden
6178    fn evaluate_363(&self, ctx: &EvaluationContext) -> ConditionResult {
6179        let sts_segs = ctx.find_segments("STS");
6180        let found = sts_segs.iter().any(|s| {
6181            s.elements
6182                .first()
6183                .and_then(|e| e.first())
6184                .is_some_and(|v| v == "E01")
6185                && s.elements
6186                    .get(2)
6187                    .and_then(|e| e.first())
6188                    .is_some_and(|v| ["A50"].contains(&v.as_str()))
6189        });
6190        ConditionResult::from(found)
6191    }
6192
6193    /// [365] Wenn in dieser SG4 IDE+24 das STS+E01++A04:E_0047/E_0014 bzw. A03:E_0049/E_0004 (Status der Antwort) nicht vorhanden
6194    fn evaluate_365(&self, ctx: &EvaluationContext) -> ConditionResult {
6195        // Check: STS+E01 does NOT have A04 with E_0047/E_0014 or A03 with E_0049/E_0004
6196        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
6197        let has_excluded = sts_segs.iter().any(|s| {
6198            let code = s
6199                .elements
6200                .get(2)
6201                .and_then(|e| e.first())
6202                .map(|v| v.as_str());
6203            let ebd = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
6204            matches!(
6205                (code, ebd),
6206                (Some("A04"), Some("E_0047"))
6207                    | (Some("A04"), Some("E_0014"))
6208                    | (Some("A03"), Some("E_0049"))
6209                    | (Some("A03"), Some("E_0004"))
6210            )
6211        });
6212        ConditionResult::from(!has_excluded)
6213    }
6214
6215    /// [366] Bis auf den Code A30 sind alle Codes aus EBD E_0624 im Cluster Ablehnung erlaubt
6216    // HAND-EDITED: driven by per-EBD cluster data (mako_prozesse).
6217    // Preserve across regeneration until the codegen prompt is updated.
6218    fn evaluate_366(&self, ctx: &EvaluationContext) -> ConditionResult {
6219        ebd_ablehnung_except(ctx, "E_0624", &["A30"])
6220    }
6221
6222    /// [367] Wenn SG4 STS+E01++A05/ A14 (Status der Antwort) vorhanden
6223    fn evaluate_367(&self, ctx: &EvaluationContext) -> ConditionResult {
6224        let sts_segs = ctx.find_segments("STS");
6225        let found = sts_segs.iter().any(|s| {
6226            s.elements
6227                .first()
6228                .and_then(|e| e.first())
6229                .is_some_and(|v| v == "E01")
6230                && s.elements
6231                    .get(2)
6232                    .and_then(|e| e.first())
6233                    .is_some_and(|v| ["A05", "A14"].contains(&v.as_str()))
6234        });
6235        ConditionResult::from(found)
6236    }
6237
6238    /// [368] Bis auf den Code A41 sind alle Codes aus EBD E_0624 im Cluster Ablehnung erlaubt
6239    // HAND-EDITED: driven by per-EBD cluster data (mako_prozesse).
6240    // Preserve across regeneration until the codegen prompt is updated.
6241    fn evaluate_368(&self, ctx: &EvaluationContext) -> ConditionResult {
6242        ebd_ablehnung_except(ctx, "E_0624", &["A41"])
6243    }
6244
6245    /// [370] Wenn SG10 CAV+TLS/TES/BIT/GET/GAT/SOT/WNT/WFT/WAT
6246    fn evaluate_370(&self, ctx: &EvaluationContext) -> ConditionResult {
6247        let cav_segs = ctx.find_segments("CAV");
6248        let found = cav_segs.iter().any(|s| {
6249            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
6250                [
6251                    "TLS", "TES", "BIT", "GET", "GAT", "SOT", "WNT", "WFT", "WAT",
6252                ]
6253                .contains(&v.as_str())
6254            })
6255        });
6256        ConditionResult::from(found)
6257    }
6258
6259    /// [371] Wenn SG8 SEQ+Z38 (Referenzprofildaten) nicht vorhanden
6260    fn evaluate_371(&self, ctx: &EvaluationContext) -> ConditionResult {
6261        let seq_segs = ctx.find_segments("SEQ");
6262        let found = seq_segs.iter().any(|s| {
6263            s.elements
6264                .first()
6265                .and_then(|e| e.first())
6266                .is_some_and(|v| ["Z38"].contains(&v.as_str()))
6267        });
6268        ConditionResult::from(!found)
6269    }
6270
6271    /// [372] Wenn SG10 CAV+TES/BIT/GET/GAT/SOT/WNT/WFT/WAT vorhanden
6272    fn evaluate_372(&self, ctx: &EvaluationContext) -> ConditionResult {
6273        let cav_segs = ctx.find_segments("CAV");
6274        let found = cav_segs.iter().any(|s| {
6275            s.elements.first().and_then(|e| e.first()).is_some_and(|v| {
6276                ["TES", "BIT", "GET", "GAT", "SOT", "WNT", "WFT", "WAT"].contains(&v.as_str())
6277            })
6278        });
6279        ConditionResult::from(found)
6280    }
6281
6282    /// [373] Wenn ein Referenzprofil an der Marktlokation vorhanden ist
6283    fn evaluate_373(&self, _ctx: &EvaluationContext) -> ConditionResult {
6284        // TODO: implement
6285        ConditionResult::Unknown
6286    }
6287
6288    /// [375] Für die ID im SG5 LOC+Z15 (MaBiS-Zählpunkt) DE3225, wenn SG8+Z24 (Daten der Überführungszeitreihe) nicht vorhanden
6289    fn evaluate_375(&self, ctx: &EvaluationContext) -> ConditionResult {
6290        // Check: no SG8 SEQ+Z24 (Daten der Überführungszeitreihe) exists
6291        ctx.lacks_qualifier("SEQ", 0, "Z24")
6292    }
6293
6294    /// [376] Für die ID im SG5 LOC+Z15 (MaBiS-Zählpunkt) DE3225, wenn SG8+Z22 (Daten der Summenzeitreihe) nicht vorhanden
6295    fn evaluate_376(&self, ctx: &EvaluationContext) -> ConditionResult {
6296        // Check: no SG8 SEQ+Z22 (Daten der Summenzeitreihe) exists
6297        ctx.lacks_qualifier("SEQ", 0, "Z22")
6298    }
6299
6300    /// [377] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+AUS vorhanden
6301    // REVIEW: Checks if any SG8 has a child SG10 with CCI[0]='15' and CCI[2]='Z21' (Überführungszeitreihentyp) followed by CAV with value 'AUS'. Follows the navigator pattern from example 10 exactly. (medium confidence)
6302    fn evaluate_377(&self, ctx: &EvaluationContext) -> ConditionResult {
6303        let nav = match ctx.navigator {
6304            Some(n) => n,
6305            None => return ctx.has_qualified_value("CAV", 0, "AUS", 0, 0, &["AUS"]),
6306        };
6307        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6308        for i in 0..sg8_count {
6309            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6310            for j in 0..sg10_count {
6311                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6312                let has_cci = ccis.iter().any(|s| {
6313                    s.elements
6314                        .first()
6315                        .and_then(|e: &Vec<String>| e.first())
6316                        .is_some_and(|v: &String| v == "15")
6317                        && s.elements
6318                            .get(2)
6319                            .and_then(|e: &Vec<String>| e.first())
6320                            .is_some_and(|v: &String| v == "Z21")
6321                });
6322                if has_cci {
6323                    let cavs =
6324                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
6325                    if cavs.iter().any(|s| {
6326                        s.elements
6327                            .first()
6328                            .and_then(|e: &Vec<String>| e.first())
6329                            .is_some_and(|v: &String| v == "AUS")
6330                    }) {
6331                        return ConditionResult::True;
6332                    }
6333                }
6334            }
6335        }
6336        ConditionResult::False
6337    }
6338
6339    /// [378] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+AUS nicht vorhanden
6340    // REVIEW: Logical negation of condition 377: True when CCI+15++Z21 CAV+AUS is NOT present in any SG8's SG10 child. Iterates all instances and returns True only if the combination is never found. (medium confidence)
6341    fn evaluate_378(&self, ctx: &EvaluationContext) -> ConditionResult {
6342        let nav = match ctx.navigator {
6343            Some(n) => n,
6344            None => {
6345                let r = ctx.has_qualified_value("CAV", 0, "AUS", 0, 0, &["AUS"]);
6346                return match r {
6347                    ConditionResult::True => ConditionResult::False,
6348                    ConditionResult::False => ConditionResult::True,
6349                    ConditionResult::Unknown => ConditionResult::Unknown,
6350                };
6351            }
6352        };
6353        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6354        for i in 0..sg8_count {
6355            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6356            for j in 0..sg10_count {
6357                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6358                let has_cci = ccis.iter().any(|s| {
6359                    s.elements
6360                        .first()
6361                        .and_then(|e: &Vec<String>| e.first())
6362                        .is_some_and(|v: &String| v == "15")
6363                        && s.elements
6364                            .get(2)
6365                            .and_then(|e: &Vec<String>| e.first())
6366                            .is_some_and(|v: &String| v == "Z21")
6367                });
6368                if has_cci {
6369                    let cavs =
6370                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
6371                    if cavs.iter().any(|s| {
6372                        s.elements
6373                            .first()
6374                            .and_then(|e: &Vec<String>| e.first())
6375                            .is_some_and(|v: &String| v == "AUS")
6376                    }) {
6377                        return ConditionResult::False;
6378                    }
6379                }
6380            }
6381        }
6382        ConditionResult::True
6383    }
6384
6385    /// [379] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+ Code für EEG-Überführungszeitreihen (ausgenommen AU1) vorhanden
6386    fn evaluate_379(&self, ctx: &EvaluationContext) -> ConditionResult {
6387        let cci_segs = ctx.find_segments("CCI");
6388        let found = cci_segs.iter().any(|s| {
6389            s.elements
6390                .first()
6391                .and_then(|e| e.first())
6392                .is_some_and(|v| v == "15")
6393                && s.elements
6394                    .get(2)
6395                    .and_then(|e| e.first())
6396                    .is_some_and(|v| ["Z21"].contains(&v.as_str()))
6397        });
6398        ConditionResult::from(found)
6399    }
6400
6401    /// [380] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+AUS/AU1 vorhanden
6402    // REVIEW: Variant of condition 377 that accepts either 'AUS' or 'AU1' as the CAV value for the Überführungszeitreihentyp. Same SG8→SG10 parent-child navigation, broadened CAV value check. (medium confidence)
6403    fn evaluate_380(&self, ctx: &EvaluationContext) -> ConditionResult {
6404        let nav = match ctx.navigator {
6405            Some(n) => n,
6406            None => {
6407                return ctx.any_group_has_any_qualifier("CAV", 0, &["AUS", "AU1"], &["SG4", "SG8"])
6408            }
6409        };
6410        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6411        for i in 0..sg8_count {
6412            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6413            for j in 0..sg10_count {
6414                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6415                let has_cci = ccis.iter().any(|s| {
6416                    s.elements
6417                        .first()
6418                        .and_then(|e: &Vec<String>| e.first())
6419                        .is_some_and(|v: &String| v == "15")
6420                        && s.elements
6421                            .get(2)
6422                            .and_then(|e: &Vec<String>| e.first())
6423                            .is_some_and(|v: &String| v == "Z21")
6424                });
6425                if has_cci {
6426                    let cavs =
6427                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
6428                    if cavs.iter().any(|s| {
6429                        s.elements
6430                            .first()
6431                            .and_then(|e: &Vec<String>| e.first())
6432                            .is_some_and(|v: &String| v == "AUS" || v == "AU1")
6433                    }) {
6434                        return ConditionResult::True;
6435                    }
6436                }
6437            }
6438        }
6439        ConditionResult::False
6440    }
6441
6442    /// [384] Wenn in derselben SG8 SG10 CCI+Z37++ZD1 (Basis zur Bildung der Tranchengröße) (Prozentual) vorhanden
6443    fn evaluate_384(&self, ctx: &EvaluationContext) -> ConditionResult {
6444        let cci_segs = ctx.find_segments("CCI");
6445        let found = cci_segs.iter().any(|s| {
6446            s.elements
6447                .first()
6448                .and_then(|e| e.first())
6449                .is_some_and(|v| v == "Z37")
6450                && s.elements
6451                    .get(2)
6452                    .and_then(|e| e.first())
6453                    .is_some_and(|v| v == "ZD1")
6454        });
6455        ConditionResult::from(found)
6456    }
6457
6458    /// [386] Wenn mehr als eine SG8 SEQ+Z02/ ZE3 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Energiemenge im PIA+5 vorhanden
6459    fn evaluate_386(&self, ctx: &EvaluationContext) -> ConditionResult {
6460        // Check: more than one SG8 SEQ+Z02/ZE3 with OBIS energy quantity in PIA+5
6461        let seq_count = ctx
6462            .find_segments("SEQ")
6463            .iter()
6464            .filter(|s| {
6465                s.elements
6466                    .first()
6467                    .and_then(|e| e.first())
6468                    .is_some_and(|v| v == "Z02" || v == "ZE3")
6469            })
6470            .count();
6471        ConditionResult::from(seq_count > 1)
6472    }
6473
6474    /// [387] Wenn in derselben SG8 (OBIS Daten der Marktlokation) eine OBIS-Kennzahl für Energiemenge im PIA+5 vorhanden und es sich lt. Codeliste OBIS um eine OBIS mit zugeordneter Zählzeit handelt (Tarif: e...
6475    fn evaluate_387(&self, ctx: &EvaluationContext) -> ConditionResult {
6476        // Check: same SG8 (OBIS Daten) has OBIS energy quantity code in PIA+5
6477        let pia_segs = ctx.find_segments("PIA");
6478        let found = pia_segs.iter().any(|s| {
6479            s.elements
6480                .first()
6481                .and_then(|e| e.first())
6482                .is_some_and(|v| v == "5")
6483                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6484                    v.starts_with("1-")
6485                        && (v.contains(":1.8.")
6486                            || v.contains(":2.8.")
6487                            || v.contains(":1.9.")
6488                            || v.contains(":2.9."))
6489                })
6490        });
6491        ConditionResult::from(found)
6492    }
6493
6494    /// [388] Segmentgruppe ist mindesten einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 (Verwendungszeitraum der Daten: \"Gültige Daten\") anzugeben, wenn in diesem Zeitraum Blindarbeit bzw. -leis...
6495    fn evaluate_388(&self, ctx: &EvaluationContext) -> ConditionResult {
6496        // Check: at least one RFF+Z49 (Zeitraum) exists
6497        let found = !ctx.find_segments_with_qualifier("RFF", 0, "Z49").is_empty();
6498        ConditionResult::from(found)
6499    }
6500
6501    /// [391] Wenn in derselben SG8 SEQ+Z20 (OBIS Daten der Zähleinrichtung / Smartmeter-Gateway) eine OBIS-Kennzahl für Zählerstand im PIA+5 vorhanden und es sich lt. Codeliste OBIS um eine OBIS mit zugeordn...
6502    fn evaluate_391(&self, ctx: &EvaluationContext) -> ConditionResult {
6503        // Check: OBIS Zählerstand (meter reading) code in PIA+5 within SEQ+Z20
6504        let pia_segs = ctx.find_segments("PIA");
6505        let found = pia_segs.iter().any(|s| {
6506            s.elements
6507                .first()
6508                .and_then(|e| e.first())
6509                .is_some_and(|v| v == "5")
6510                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6511                    v.starts_with("1-") && (v.contains(":1.8.") || v.contains(":2.8."))
6512                })
6513        });
6514        ConditionResult::from(found)
6515    }
6516
6517    /// [392] Wenn in diesem PIA der Code im Format n1-n2-n1 angegeben ist
6518    fn evaluate_392(&self, ctx: &EvaluationContext) -> ConditionResult {
6519        // Check: PIA code in format n1-n2-n1 (e.g., "1-08-1")
6520        let pia_segs = ctx.find_segments("PIA");
6521        let found = pia_segs.iter().any(|s| {
6522            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6523                let parts: Vec<&str> = v.split('-').collect();
6524                parts.len() == 3
6525                    && parts[0].len() == 1
6526                    && parts[0].chars().all(|c| c.is_ascii_digit())
6527                    && parts[1].len() == 2
6528                    && parts[1].chars().all(|c| c.is_ascii_digit())
6529                    && parts[2].len() == 1
6530                    && parts[2].chars().all(|c| c.is_ascii_digit())
6531            })
6532        });
6533        ConditionResult::from(found)
6534    }
6535
6536    /// [393] Wenn in diesem PIA der Code im Format n1-n2-n1-n3 angegeben ist
6537    fn evaluate_393(&self, ctx: &EvaluationContext) -> ConditionResult {
6538        // Check: PIA code in format n1-n2-n1-n3 (e.g., "1-08-1-001")
6539        let pia_segs = ctx.find_segments("PIA");
6540        let found = pia_segs.iter().any(|s| {
6541            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6542                let parts: Vec<&str> = v.split('-').collect();
6543                parts.len() == 4
6544                    && parts[0].len() == 1
6545                    && parts[0].chars().all(|c| c.is_ascii_digit())
6546                    && parts[1].len() == 2
6547                    && parts[1].chars().all(|c| c.is_ascii_digit())
6548                    && parts[2].len() == 1
6549                    && parts[2].chars().all(|c| c.is_ascii_digit())
6550                    && parts[3].len() == 3
6551                    && parts[3].chars().all(|c| c.is_ascii_digit())
6552            })
6553        });
6554        ConditionResult::from(found)
6555    }
6556
6557    /// [394] Wenn in diesem PIA der Code im Format n1-n2-n1-n8-n2 angegeben ist
6558    fn evaluate_394(&self, ctx: &EvaluationContext) -> ConditionResult {
6559        // Check: PIA code in format n1-n2-n1-n8-n2
6560        let pia_segs = ctx.find_segments("PIA");
6561        let found = pia_segs.iter().any(|s| {
6562            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6563                let parts: Vec<&str> = v.split('-').collect();
6564                parts.len() == 5
6565                    && parts[0].len() == 1
6566                    && parts[0].chars().all(|c| c.is_ascii_digit())
6567                    && parts[1].len() == 2
6568                    && parts[1].chars().all(|c| c.is_ascii_digit())
6569                    && parts[2].len() == 1
6570                    && parts[2].chars().all(|c| c.is_ascii_digit())
6571                    && parts[3].len() == 8
6572                    && parts[3].chars().all(|c| c.is_ascii_digit())
6573                    && parts[4].len() == 2
6574                    && parts[4].chars().all(|c| c.is_ascii_digit())
6575            })
6576        });
6577        ConditionResult::from(found)
6578    }
6579
6580    /// [395] Wenn in diesem PIA der Code im Format n1-n2-n1-n8 angegeben ist
6581    fn evaluate_395(&self, ctx: &EvaluationContext) -> ConditionResult {
6582        // Check: PIA code in format n1-n2-n1-n8
6583        let pia_segs = ctx.find_segments("PIA");
6584        let found = pia_segs.iter().any(|s| {
6585            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6586                let parts: Vec<&str> = v.split('-').collect();
6587                parts.len() == 4
6588                    && parts[0].len() == 1
6589                    && parts[0].chars().all(|c| c.is_ascii_digit())
6590                    && parts[1].len() == 2
6591                    && parts[1].chars().all(|c| c.is_ascii_digit())
6592                    && parts[2].len() == 1
6593                    && parts[2].chars().all(|c| c.is_ascii_digit())
6594                    && parts[3].len() == 8
6595                    && parts[3].chars().all(|c| c.is_ascii_digit())
6596            })
6597        });
6598        ConditionResult::from(found)
6599    }
6600
6601    /// [396] Wenn in derselben SG8 SEQ+Z02/ ZA1/ ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Wirkarbeit und 1/4 Stunde im PIA+5 vorhanden
6602    fn evaluate_396(&self, ctx: &EvaluationContext) -> ConditionResult {
6603        // Check: OBIS Wirkarbeit und 1/4 Stunde code in PIA+5
6604        let pia_segs = ctx.find_segments("PIA");
6605        let found = pia_segs.iter().any(|s| {
6606            s.elements
6607                .first()
6608                .and_then(|e| e.first())
6609                .is_some_and(|v| v == "5")
6610                && s.elements
6611                    .get(1)
6612                    .and_then(|e| e.first())
6613                    .is_some_and(|v| v.starts_with("1-") && v.contains(":1.8."))
6614        });
6615        ConditionResult::from(found)
6616    }
6617
6618    /// [397] Wenn in diesem PIA der Code im DE7140 mit 1-08-1/1-08-4 beginnt
6619    fn evaluate_397(&self, ctx: &EvaluationContext) -> ConditionResult {
6620        let pia_segs = ctx.find_segments("PIA");
6621        let found = pia_segs.iter().any(|s| {
6622            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6623                let prefixes = ["1-08-1", "1-08-4"];
6624                prefixes.iter().any(|p| v.starts_with(p))
6625            })
6626        });
6627        ConditionResult::from(found)
6628    }
6629
6630    /// [398] Wenn in diesem PIA der Code im DE7140 mit 1-08-2/1-08-5 beginnt
6631    fn evaluate_398(&self, ctx: &EvaluationContext) -> ConditionResult {
6632        let pia_segs = ctx.find_segments("PIA");
6633        let found = pia_segs.iter().any(|s| {
6634            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6635                let prefixes = ["1-08-2", "1-08-5"];
6636                prefixes.iter().any(|p| v.starts_with(p))
6637            })
6638        });
6639        ConditionResult::from(found)
6640    }
6641
6642    /// [399] Wenn im SG8 SEQ+Z78 mit identischer Zeitraum-ID im DE1050 wie im DE3224 dieses Segments, das RFF+Z31 (Lokationsbündelstruktur) im DE1153 der Code Z31 (Lokationsbündelstruktur) vorhanden, und im D...
6643    // REVIEW: Condition is True when an SG8 SEQ+Z78 exists whose Zeitraum-ID (DE1050) matches DE3224 of the current LOC segment (accessed via SG5 group navigator as LOC.C517.DE3224 = elements[1][3]), AND that Z78 SG8 has RFF+Z31 with a DE1154 value that is NOT the pauschal code 9992000000018. This identifies bundle structures that reference a non-pauschal Lokationsbündelstruktur. (medium confidence)
6644    fn evaluate_399(&self, ctx: &EvaluationContext) -> ConditionResult {
6645        let nav = match ctx.navigator() {
6646            Some(n) => n,
6647            None => return ConditionResult::Unknown,
6648        };
6649        // Collect DE3224 values from LOC segments in SG5 — LOC.C517.DE3224 = elements[1][3]
6650        // These serve as the Zeitraum-IDs referenced by the condition's "dieses Segments"
6651        let sg5_count = nav.group_instance_count(&["SG4", "SG5"]);
6652        let mut loc_zeitraum_ids: Vec<String> = Vec::new();
6653        for i in 0..sg5_count {
6654            let locs = nav.find_segments_in_group("LOC", &["SG4", "SG5"], i);
6655            for loc in &locs {
6656                if let Some(zid) = loc.elements.get(1).and_then(|e| e.get(3)) {
6657                    if !zid.is_empty() {
6658                        loc_zeitraum_ids.push(zid.clone());
6659                    }
6660                }
6661            }
6662        }
6663        if loc_zeitraum_ids.is_empty() {
6664            return ConditionResult::Unknown;
6665        }
6666        let pauschal_id = "9992000000018";
6667        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6668        // Find any Z78 SG8 whose Zeitraum-ID (SEQ.C286.DE1050) matches a LOC DE3224
6669        // and that has RFF+Z31 with DE1154 != pauschal_id
6670        for i in 0..sg8_count {
6671            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
6672            for seq in &seqs {
6673                if !seq
6674                    .elements
6675                    .first()
6676                    .and_then(|e| e.first())
6677                    .is_some_and(|v| v == "Z78")
6678                {
6679                    continue;
6680                }
6681                let zid = seq
6682                    .elements
6683                    .get(1)
6684                    .and_then(|e| e.first())
6685                    .map(|s| s.as_str())
6686                    .unwrap_or("");
6687                if !loc_zeitraum_ids.iter().any(|z| z == zid) {
6688                    continue;
6689                }
6690                // Matching Z78 SG8 found — check RFF+Z31 DE1154
6691                let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
6692                for rff in &rffs {
6693                    let qual = rff
6694                        .elements
6695                        .first()
6696                        .and_then(|e| e.first())
6697                        .map(|v| v.as_str())
6698                        .unwrap_or("");
6699                    if qual == "Z31" {
6700                        let id = rff
6701                            .elements
6702                            .first()
6703                            .and_then(|e| e.get(1))
6704                            .map(|v| v.as_str())
6705                            .unwrap_or("");
6706                        let normalized = id.replace(' ', "");
6707                        if !normalized.is_empty() && normalized != pauschal_id {
6708                            return ConditionResult::True;
6709                        }
6710                    }
6711                }
6712            }
6713        }
6714        ConditionResult::False
6715    }
6716
6717    /// [401] Wenn dieses DTM+Z25 (Verwendung der Daten ab) nicht im SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: Gültige Daten/ Keine Daten) mit der Zeitraum ID \"1\" im DE1156 ist, muss das Datum dem DTM+...
6718    fn evaluate_401(&self, ctx: &EvaluationContext) -> ConditionResult {
6719        // Check: this DTM+Z25 is not in SG6 RFF+Z49 or Z53
6720        // Approximate: check if RFF+Z49 or Z53 exists
6721        let has_z49 = !ctx.find_segments_with_qualifier("RFF", 0, "Z49").is_empty();
6722        let has_z53 = !ctx.find_segments_with_qualifier("RFF", 0, "Z53").is_empty();
6723        ConditionResult::from(!has_z49 && !has_z53)
6724    }
6725
6726    /// [402] Wenn in derselben SG8  (OBIS-Daten der Zähleinrichtung / Smartmeter-Gateway) eine OBIS-Kennzahl der Werteart \"Zählerstand\" im PIA+5 vorhanden
6727    fn evaluate_402(&self, ctx: &EvaluationContext) -> ConditionResult {
6728        // Check: OBIS Zählerstand code in PIA+5
6729        let pia_segs = ctx.find_segments("PIA");
6730        let found = pia_segs.iter().any(|s| {
6731            s.elements
6732                .first()
6733                .and_then(|e| e.first())
6734                .is_some_and(|v| v == "5")
6735                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6736                    v.starts_with("1-") && (v.contains(":1.8.") || v.contains(":2.8."))
6737                })
6738        });
6739        ConditionResult::from(found)
6740    }
6741
6742    /// [403] Wenn nicht dieselbe MP-ID in SG2 NAD+MS (Nachrichtensender) und im SG8 SEQ+Z01 (Daten der Marktlokation) SG10 CCI+++ZB3 (Zugeordnete Marktpartner) CAV+Z91 (Messtellenbetreiber) vorhanden
6743    // REVIEW: Gets NAD+MS MP-ID from SG2 (elements[1][0]), then navigates all SG8→SG10 instances looking for CCI with elements[2][0]='ZB3' (Zugeordnete Marktpartner) and CAV with elements[0][0]='Z91' (Messstellenbetreiber). Compares the CAV+Z91 MP-ID (elements[0][1]) with the sender MP-ID. Returns True when they differ (not the same). Note: SEQ+Z01 filter on the parent SG8 is omitted because `find_segments_in_child_group` only accesses child groups, not the parent SG8 segments; the Z91 MSB identity is message-consistent regardless. (medium confidence)
6744    fn evaluate_403(&self, ctx: &EvaluationContext) -> ConditionResult {
6745        let sender_mp_id: String = match ctx.find_segments_with_qualifier("NAD", 0, "MS").first() {
6746            Some(nad) => match nad.elements.get(1).and_then(|e: &Vec<String>| e.first()) {
6747                Some(id) if !id.is_empty() => id.clone(),
6748                _ => return ConditionResult::Unknown,
6749            },
6750            None => return ConditionResult::Unknown,
6751        };
6752        let nav = match ctx.navigator {
6753            Some(n) => n,
6754            None => return ConditionResult::Unknown,
6755        };
6756        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6757        for i in 0..sg8_count {
6758            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6759            for j in 0..sg10_count {
6760                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6761                let has_cci_zb3 = ccis.iter().any(|s| {
6762                    s.elements
6763                        .get(2)
6764                        .and_then(|e: &Vec<String>| e.first())
6765                        .is_some_and(|v: &String| v == "ZB3")
6766                });
6767                if !has_cci_zb3 {
6768                    continue;
6769                }
6770                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
6771                for cav in &cavs {
6772                    if cav
6773                        .elements
6774                        .first()
6775                        .and_then(|e: &Vec<String>| e.first())
6776                        .is_some_and(|v: &String| v == "Z91")
6777                    {
6778                        if let Some(msb_id) = cav.elements.first().and_then(|e| e.get(1)) {
6779                            if !msb_id.is_empty() {
6780                                return ConditionResult::from(
6781                                    sender_mp_id.as_str() != msb_id.as_str(),
6782                                );
6783                            }
6784                        }
6785                    }
6786                }
6787            }
6788        }
6789        ConditionResult::Unknown
6790    }
6791
6792    /// [404] Wenn nicht dieselbe MP-ID in SG2 NAD+MR (Nachrichtenempfänger) und im SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) SG10 CCI+++ZB3 (Zugeordnete Marktpartner) CAV+Z91 (Messtellenbetreiber) vorhanden
6793    // REVIEW: Reads NAD+MR MP-ID from elements[1][0], then iterates all SG8 SG10 children looking for CCI with elements[2][0]==ZB3 and CAV with elements[0][0]==Z91 where the MP-ID (elements[0][1]) matches. Returns False if same MP-ID found (condition 'not same' fails), True otherwise. Approximation: cannot filter SG8 instances by SEQ+Z01/Z98 without find_segments_in_group; checks all SG8 SG10 children. This is acceptable since CCI+ZB3 CAV+Z91 patterns in other SG8 types would still represent valid MSB assignments to compare against. (medium confidence)
6794    fn evaluate_404(&self, ctx: &EvaluationContext) -> ConditionResult {
6795        let mr_nads = ctx.find_segments_with_qualifier("NAD", 0, "MR");
6796        let mr_mp_id = match mr_nads.first() {
6797            Some(nad) => nad
6798                .elements
6799                .get(1)
6800                .and_then(|e: &Vec<String>| e.first())
6801                .cloned()
6802                .unwrap_or_default(),
6803            None => return ConditionResult::Unknown,
6804        };
6805        if mr_mp_id.is_empty() {
6806            return ConditionResult::Unknown;
6807        }
6808
6809        let nav = match ctx.navigator {
6810            Some(n) => n,
6811            None => {
6812                let cavs = ctx.find_segments("CAV");
6813                let same_id_exists = cavs.iter().any(|s| {
6814                    s.elements
6815                        .first()
6816                        .and_then(|e: &Vec<String>| e.first())
6817                        .is_some_and(|v: &String| v == "Z91")
6818                        && s.elements
6819                            .first()
6820                            .and_then(|e| e.get(1))
6821                            .is_some_and(|v: &String| v == &mr_mp_id)
6822                });
6823                return ConditionResult::from(!same_id_exists);
6824            }
6825        };
6826
6827        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6828        for i in 0..sg8_count {
6829            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6830            for j in 0..sg10_count {
6831                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6832                let has_cci_zb3 = ccis.iter().any(|s| {
6833                    s.elements
6834                        .get(2)
6835                        .and_then(|e: &Vec<String>| e.first())
6836                        .is_some_and(|v: &String| v == "ZB3")
6837                });
6838                if !has_cci_zb3 {
6839                    continue;
6840                }
6841                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
6842                for cav in &cavs {
6843                    if cav
6844                        .elements
6845                        .first()
6846                        .and_then(|e: &Vec<String>| e.first())
6847                        .is_some_and(|v: &String| v == "Z91")
6848                    {
6849                        let cav_mp_id = cav
6850                            .elements
6851                            .first()
6852                            .and_then(|e| e.get(1))
6853                            .map(|s| s.as_str())
6854                            .unwrap_or("");
6855                        if cav_mp_id == mr_mp_id.as_str() {
6856                            return ConditionResult::False;
6857                        }
6858                    }
6859                }
6860            }
6861        }
6862
6863        ConditionResult::True
6864    }
6865
6866    /// [405] Wenn in derselben SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Wirkarbeit und kumuliert im PIA+5 vorhanden
6867    fn evaluate_405(&self, ctx: &EvaluationContext) -> ConditionResult {
6868        // Check: OBIS Wirkarbeit kumuliert code in PIA+5
6869        let pia_segs = ctx.find_segments("PIA");
6870        let found = pia_segs.iter().any(|s| {
6871            s.elements
6872                .first()
6873                .and_then(|e| e.first())
6874                .is_some_and(|v| v == "5")
6875                && s.elements
6876                    .get(1)
6877                    .and_then(|e| e.first())
6878                    .is_some_and(|v| v.starts_with("1-") && v.contains(":1.8."))
6879        });
6880        ConditionResult::from(found)
6881    }
6882
6883    /// [406] Wenn in derselben SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Wirkarbeit und höchste 1/4 Stunde im Monat im PIA+5 vorhanden
6884    fn evaluate_406(&self, ctx: &EvaluationContext) -> ConditionResult {
6885        // Check: OBIS Wirkarbeit höchste 1/4 Stunde code in PIA+5
6886        let pia_segs = ctx.find_segments("PIA");
6887        let found = pia_segs.iter().any(|s| {
6888            s.elements
6889                .first()
6890                .and_then(|e| e.first())
6891                .is_some_and(|v| v == "5")
6892                && s.elements
6893                    .get(1)
6894                    .and_then(|e| e.first())
6895                    .is_some_and(|v| v.starts_with("1-") && v.contains(":1.8."))
6896        });
6897        ConditionResult::from(found)
6898    }
6899
6900    /// [407] Wenn in derselben SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Blindarbeit im PIA+5 vorhanden
6901    fn evaluate_407(&self, ctx: &EvaluationContext) -> ConditionResult {
6902        // Check: OBIS Blindarbeit code in PIA+5
6903        let pia_segs = ctx.find_segments("PIA");
6904        let found = pia_segs.iter().any(|s| {
6905            s.elements
6906                .first()
6907                .and_then(|e| e.first())
6908                .is_some_and(|v| v == "5")
6909                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6910                    v.starts_with("1-") && (v.contains(":3.8.") || v.contains(":4.8."))
6911                })
6912        });
6913        ConditionResult::from(found)
6914    }
6915
6916    /// [408] Wenn eine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die I...
6917    fn evaluate_408(&self, ctx: &EvaluationContext) -> ConditionResult {
6918        // Check: SG8 SEQ+Z02 with matching RFF+Z18 has OBIS energy code
6919        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6920        ConditionResult::from(has_seq_z02)
6921    }
6922
6923    /// [409] Wenn keine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die ...
6924    fn evaluate_409(&self, ctx: &EvaluationContext) -> ConditionResult {
6925        // Check: no SG8 SEQ+Z02 with matching RFF+Z18 has OBIS energy code
6926        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6927        ConditionResult::from(!has_seq_z02)
6928    }
6929
6930    /// [410] Wenn eine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die I...
6931    fn evaluate_410(&self, ctx: &EvaluationContext) -> ConditionResult {
6932        // Check: SG8 SEQ+Z02 with matching RFF+Z18 has specific OBIS code
6933        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6934        ConditionResult::from(has_seq_z02)
6935    }
6936
6937    /// [411] Wenn keine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die ...
6938    fn evaluate_411(&self, ctx: &EvaluationContext) -> ConditionResult {
6939        // Check: no SG8 SEQ+Z02 with matching RFF+Z18 has specific OBIS code
6940        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6941        ConditionResult::from(!has_seq_z02)
6942    }
6943
6944    /// [412] Es sind ausschließlich Konfigurationsprodukt-Codes der \"EDI@Energy Codeliste der Konfigurationen\" aus Kapitel 4.2 Konfigurationsprodukte Leistungskurvendefinition erlaubt
6945    fn evaluate_412(&self, ctx: &EvaluationContext) -> ConditionResult {
6946        ctx.external.evaluate("code_list_membership_check")
6947    }
6948
6949    /// [413] Wenn eine SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und kumuliert im PIA+5 vorhanden
6950    fn evaluate_413(&self, ctx: &EvaluationContext) -> ConditionResult {
6951        // Check: SG8 SEQ+Z02/ZA1/ZA2 with OBIS Wirkarbeit kumuliert exists
6952        let found = ctx.find_segments("SEQ").iter().any(|s| {
6953            s.elements
6954                .first()
6955                .and_then(|e| e.first())
6956                .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6957        });
6958        ConditionResult::from(found)
6959    }
6960
6961    /// [414] Wenn keine SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und kumuliert im PIA+5 vorhanden
6962    fn evaluate_414(&self, ctx: &EvaluationContext) -> ConditionResult {
6963        // Check: no SG8 SEQ+Z02/ZA1/ZA2 with OBIS Wirkarbeit kumuliert exists
6964        let found = ctx.find_segments("SEQ").iter().any(|s| {
6965            s.elements
6966                .first()
6967                .and_then(|e| e.first())
6968                .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6969        });
6970        ConditionResult::from(!found)
6971    }
6972
6973    /// [415] Wenn eine weitere SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und 1/4 Stunde im PIA+5 vorhanden
6974    fn evaluate_415(&self, ctx: &EvaluationContext) -> ConditionResult {
6975        // Check: another SG8 SEQ+Z02/ZA1/ZA2 with OBIS 1/4 Stunde exists
6976        let count = ctx
6977            .find_segments("SEQ")
6978            .iter()
6979            .filter(|s| {
6980                s.elements
6981                    .first()
6982                    .and_then(|e| e.first())
6983                    .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6984            })
6985            .count();
6986        ConditionResult::from(count > 1)
6987    }
6988
6989    /// [416] Wenn keine SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und 1/4 Stunde im PIA+5 vorhanden
6990    fn evaluate_416(&self, ctx: &EvaluationContext) -> ConditionResult {
6991        // Check: no other SG8 SEQ+Z02/ZA1/ZA2 with OBIS 1/4 Stunde exists
6992        let count = ctx
6993            .find_segments("SEQ")
6994            .iter()
6995            .filter(|s| {
6996                s.elements
6997                    .first()
6998                    .and_then(|e| e.first())
6999                    .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
7000            })
7001            .count();
7002        ConditionResult::from(count <= 1)
7003    }
7004
7005    /// [417] Wenn für den erforderlichen Wert keine Zählzeit benötigt wird
7006    fn evaluate_417(&self, _ctx: &EvaluationContext) -> ConditionResult {
7007        // TODO: implement
7008        ConditionResult::Unknown
7009    }
7010
7011    /// [419] Wenn in diesem Datenelement kein anderes Paket in dieser SG10 in derselben SG8 SEQ zur Möglichkeit der Angabe von mindestens einem anderen Code führt
7012    fn evaluate_419(&self, _ctx: &EvaluationContext) -> ConditionResult {
7013        // TODO: implement
7014        ConditionResult::Unknown
7015    }
7016
7017    /// [420] Wenn in dieser SG8 das RFF+Z14 (Smartmeter-Gateway) vorhanden ist
7018    fn evaluate_420(&self, ctx: &EvaluationContext) -> ConditionResult {
7019        let rff_segs = ctx.find_segments("RFF");
7020        let found = rff_segs.iter().any(|s| {
7021            s.elements
7022                .first()
7023                .and_then(|e| e.first())
7024                .is_some_and(|v| v == "Z14")
7025        });
7026        ConditionResult::from(found)
7027    }
7028
7029    /// [421] Wenn in dieser SG8 das SG10 CCI+Z39 (Zugeordnete Zählzeitdefinition) vorhanden ist
7030    fn evaluate_421(&self, ctx: &EvaluationContext) -> ConditionResult {
7031        // Check: CCI+Z39 (Zugeordnete Zählzeitdefinition) vorhanden
7032        ctx.any_group_has_qualifier("CCI", 0, "Z39", &["SG4", "SG8"])
7033    }
7034
7035    /// [425] Messprodukt-Code aus den Kapitel 2.1 \"Standard-Messprodukte der Marktlokation\" der Codeliste der Konfigurationen
7036    fn evaluate_425(&self, ctx: &EvaluationContext) -> ConditionResult {
7037        ctx.external.evaluate("code_list_membership_check")
7038    }
7039
7040    /// [426] Messprodukt-Code aus den Kapitel 2.2 \"Standard-Messprodukte der Tranche\" der Codeliste der Konfigurationen
7041    fn evaluate_426(&self, ctx: &EvaluationContext) -> ConditionResult {
7042        ctx.external.evaluate("code_list_membership_check")
7043    }
7044
7045    /// [427] Messprodukt-Code aus den Kapitel 2.3 \"Standard-Messprodukte der Messlokation\" der Codeliste der Konfigurationen
7046    fn evaluate_427(&self, ctx: &EvaluationContext) -> ConditionResult {
7047        ctx.external.evaluate("code_list_membership_check")
7048    }
7049
7050    /// [428] Wenn in derselben SG8 SEQ+Z27/ ZE2 (Erforderliches Messprodukt der Marktlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.1.1 Standard-Messprodukt der Mar...
7051    fn evaluate_428(&self, ctx: &EvaluationContext) -> ConditionResult {
7052        ctx.external.evaluate("code_list_membership_check")
7053    }
7054
7055    /// [429] Wenn in derselben SG8 SEQ+Z19/ ZF4 (Erforderliches Messprodukt der Messlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.3.1 Standard-Messprodukt der Mess...
7056    fn evaluate_429(&self, ctx: &EvaluationContext) -> ConditionResult {
7057        ctx.external.evaluate("code_list_membership_check")
7058    }
7059
7060    /// [430] Wenn eine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5+9...
7061    fn evaluate_430(&self, ctx: &EvaluationContext) -> ConditionResult {
7062        // Check: another SG8 SEQ+Z27 exists with matching RFF+Z18
7063        let seq_z27_count = ctx.find_segments_with_qualifier("SEQ", 0, "Z27").len();
7064        ConditionResult::from(seq_z27_count > 1)
7065    }
7066
7067    /// [431] Wenn keine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5+...
7068    fn evaluate_431(&self, ctx: &EvaluationContext) -> ConditionResult {
7069        // Check: no other SG8 SEQ+Z27 exists with matching RFF+Z18
7070        let seq_z27_count = ctx.find_segments_with_qualifier("SEQ", 0, "Z27").len();
7071        ConditionResult::from(seq_z27_count <= 1)
7072    }
7073
7074    /// [432] Wenn in derselben SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), das PIA+5+9991000000078:Z11 (Wirkarbeit Lastgang 1/4 stündlich) vorhanden ist
7075    fn evaluate_432(&self, ctx: &EvaluationContext) -> ConditionResult {
7076        // Check: PIA+5 with code 9991000000078 (Wirkarbeit Lastgang) exists
7077        let pia_segs = ctx.find_segments("PIA");
7078        let found = pia_segs.iter().any(|s| {
7079            s.elements
7080                .first()
7081                .and_then(|e| e.first())
7082                .is_some_and(|v| v == "5")
7083                && s.elements
7084                    .get(1)
7085                    .and_then(|e| e.first())
7086                    .is_some_and(|v| v == "9991000000078")
7087        });
7088        ConditionResult::from(found)
7089    }
7090
7091    /// [433] Wenn keine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5 ...
7092    fn evaluate_433(&self, ctx: &EvaluationContext) -> ConditionResult {
7093        ctx.external.evaluate("code_list_membership_check")
7094    }
7095
7096    /// [435] Wenn eine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5 D...
7097    fn evaluate_435(&self, ctx: &EvaluationContext) -> ConditionResult {
7098        ctx.external.evaluate("code_list_membership_check")
7099    }
7100
7101    /// [436] Wenn in derselben SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), das PIA+5+9991000000086:Z11 (Wirkarbeit höchste 1/4 Stunde im Monat) vorhanden ist
7102    fn evaluate_436(&self, ctx: &EvaluationContext) -> ConditionResult {
7103        // Check: PIA+5 with code 9991000000086 (Wirkarbeit höchste 1/4h Leistung) exists
7104        let pia_segs = ctx.find_segments("PIA");
7105        let found = pia_segs.iter().any(|s| {
7106            s.elements
7107                .first()
7108                .and_then(|e| e.first())
7109                .is_some_and(|v| v == "5")
7110                && s.elements
7111                    .get(1)
7112                    .and_then(|e| e.first())
7113                    .is_some_and(|v| v == "9991000000086")
7114        });
7115        ConditionResult::from(found)
7116    }
7117
7118    /// [437] Wenn in dieser SG4 das STS+E01++A04 / A23 (Status der Antwort) vorhanden
7119    fn evaluate_437(&self, ctx: &EvaluationContext) -> ConditionResult {
7120        let sts_segs = ctx.find_segments("STS");
7121        let found = sts_segs.iter().any(|s| {
7122            s.elements
7123                .first()
7124                .and_then(|e| e.first())
7125                .is_some_and(|v| v == "E01")
7126                && s.elements
7127                    .get(2)
7128                    .and_then(|e| e.first())
7129                    .is_some_and(|v| ["A04", "A23"].contains(&v.as_str()))
7130        });
7131        ConditionResult::from(found)
7132    }
7133
7134    /// [438] Wenn im selben CCI im DE7059 der Code Z39 (Code der Zählzeit) vorhanden ist
7135    fn evaluate_438(&self, ctx: &EvaluationContext) -> ConditionResult {
7136        let cci_segs = ctx.find_segments("CCI");
7137        let found = cci_segs.iter().any(|s| {
7138            s.elements
7139                .first()
7140                .and_then(|e| e.first())
7141                .is_some_and(|v| v == "Z39")
7142        });
7143        ConditionResult::from(found)
7144    }
7145
7146    /// [440] Wenn in demselben RFF der Code Z35 (vorgelagerte Netzlokation) im DE1153 vorhanden
7147    fn evaluate_440(&self, ctx: &EvaluationContext) -> ConditionResult {
7148        // Check: RFF with qualifier Z35 (vorgelagerte Netzlokation) exists
7149        ctx.has_qualifier("RFF", 0, "Z35")
7150    }
7151
7152    /// [441] Wenn im SG8+SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) für die in diesem RFF DE1154 genannte Gerätenummer eines Zählers das RFF+Z14 (Referenz auf das Smartmeter-Gateway) nicht vorhanden ist
7153    fn evaluate_441(&self, ctx: &EvaluationContext) -> ConditionResult {
7154        // Check: SG8 SEQ+Z03/ZF5 device without RFF+Z14 (SMGW reference)
7155        ctx.any_group_has_qualifier_without("SEQ", 0, "Z03", "RFF", 0, "Z14", &["SG4", "SG8"])
7156    }
7157
7158    /// [442] Wenn in demselben RFF der Code Z34 (vorgelagerte Messlokation) im DE1153 vorhanden
7159    fn evaluate_442(&self, ctx: &EvaluationContext) -> ConditionResult {
7160        // Check: RFF with qualifier Z34 (vorgelagerte Messlokation) exists
7161        ctx.has_qualifier("RFF", 0, "Z34")
7162    }
7163
7164    /// [444] Wenn in derselben SG8 (Produkt-Daten der Netzlokation) das PIA+5 (Produkt-Daten der Netzlokation) nicht vorhanden
7165    // REVIEW: Checks whether any SG8 instance carrying a 'Produkt-Daten der Netzlokation' SEQ qualifier (Z60, ZE0, ZG8, ZG9) lacks PIA+5. Iterates each qualifier separately using any_group_has_qualifier_without which checks: SEQ+code present AND PIA+5 absent in same SG8. Returns True on first match. Correctly handles the multi-qualifier case via OR iteration. (medium confidence)
7166    fn evaluate_444(&self, ctx: &EvaluationContext) -> ConditionResult {
7167        for code in ["Z60", "ZE0", "ZG8", "ZG9"] {
7168            if matches!(
7169                ctx.any_group_has_qualifier_without("SEQ", 0, code, "PIA", 0, "5", &["SG4", "SG8"]),
7170                ConditionResult::True
7171            ) {
7172                return ConditionResult::True;
7173            }
7174        }
7175        ConditionResult::False
7176    }
7177
7178    /// [445] Wenn in derselben SG8 (Produkt-Daten der Netzlokation) das SG10 CCI+11 (Details zum Produkt der Netzlokation) nicht vorhanden
7179    // REVIEW: Iterates all SG8 instances and checks whether any SG10 child group contains CCI with elements[0][0]=="11" (Details zum Produkt der Netzlokation). Returns True when an SG8 is found that lacks such a CCI+11 in its SG10 children. Navigator fallback uses filtered_parent_child_has_qualifier negated per qualifier. Approximation: the navigator path does not filter SG8 instances by Produkt-Daten-Netzlokation SEQ qualifier due to absence of find_segments_in_group; checks all SG8 instances instead. (medium confidence)
7180    fn evaluate_445(&self, ctx: &EvaluationContext) -> ConditionResult {
7181        let nav = match ctx.navigator {
7182            Some(n) => n,
7183            None => {
7184                let has_cci11 = ["Z60", "ZE0", "ZG8", "ZG9"].iter().any(|code| {
7185                    matches!(
7186                        ctx.filtered_parent_child_has_qualifier(
7187                            &["SG4", "SG8"],
7188                            "SEQ",
7189                            0,
7190                            code,
7191                            "SG10",
7192                            "CCI",
7193                            0,
7194                            "11",
7195                        ),
7196                        ConditionResult::True
7197                    )
7198                });
7199                return ConditionResult::from(!has_cci11);
7200            }
7201        };
7202
7203        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
7204        for i in 0..sg8_count {
7205            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
7206            let has_cci11 = (0..sg10_count).any(|j| {
7207                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
7208                ccis.iter().any(|s| {
7209                    s.elements
7210                        .first()
7211                        .and_then(|e: &Vec<String>| e.first())
7212                        .is_some_and(|v: &String| v == "11")
7213                })
7214            });
7215            if !has_cci11 {
7216                return ConditionResult::True;
7217            }
7218        }
7219        ConditionResult::False
7220    }
7221
7222    /// [446] Wenn in derselben SG8 das CCI+Z17 (Stromverbrauchsart) vorhanden
7223    fn evaluate_446(&self, ctx: &EvaluationContext) -> ConditionResult {
7224        let cci_segs = ctx.find_segments("CCI");
7225        let found = cci_segs.iter().any(|s| {
7226            s.elements
7227                .first()
7228                .and_then(|e| e.first())
7229                .is_some_and(|v| v == "Z17")
7230        });
7231        ConditionResult::from(found)
7232    }
7233
7234    /// [447] Wenn in derselben SG8 das CCI+Z50 (Stromerzeugungsart) vorhanden
7235    fn evaluate_447(&self, ctx: &EvaluationContext) -> ConditionResult {
7236        let cci_segs = ctx.find_segments("CCI");
7237        let found = cci_segs.iter().any(|s| {
7238            s.elements
7239                .first()
7240                .and_then(|e| e.first())
7241                .is_some_and(|v| v == "Z50")
7242        });
7243        ConditionResult::from(found)
7244    }
7245
7246    /// [448] Wenn in derselben SG8 das CCI+Z56 (Speicher) vorhanden
7247    fn evaluate_448(&self, ctx: &EvaluationContext) -> ConditionResult {
7248        let cci_segs = ctx.find_segments("CCI");
7249        let found = cci_segs.iter().any(|s| {
7250            s.elements
7251                .first()
7252                .and_then(|e| e.first())
7253                .is_some_and(|v| v == "Z56")
7254        });
7255        ConditionResult::from(found)
7256    }
7257
7258    /// [449] Wenn in derselben SG8 das SG10 CCI+6++ZA9 CAV=ZG3 (Aggreg.verantw. ÜNB und Lokation im Regelbetrieb) vorhanden
7259    fn evaluate_449(&self, ctx: &EvaluationContext) -> ConditionResult {
7260        let cci_segs = ctx.find_segments("CCI");
7261        let has_cci = cci_segs.iter().any(|s| {
7262            s.elements
7263                .first()
7264                .and_then(|e| e.first())
7265                .is_some_and(|v| v == "6")
7266                && s.elements
7267                    .get(2)
7268                    .and_then(|e| e.first())
7269                    .is_some_and(|v| v == "ZA9")
7270        });
7271        let cav_segs = ctx.find_segments("CAV");
7272        let has_cav = cav_segs.iter().any(|s| {
7273            s.elements
7274                .first()
7275                .and_then(|e| e.first())
7276                .is_some_and(|v| v == "ZG3")
7277        });
7278        ConditionResult::from(has_cci && has_cav)
7279    }
7280
7281    /// [450] Wenn in demselben RFF der Code Z32 (Netzlokation) im DE1153 vorhanden
7282    fn evaluate_450(&self, ctx: &EvaluationContext) -> ConditionResult {
7283        // Check: RFF with qualifier Z32 (Netzlokation) exists
7284        ctx.has_qualifier("RFF", 0, "Z32")
7285    }
7286
7287    /// [451] Wenn in demselben RFF der Code Z18 (Marktlokation) im DE1153 vorhanden
7288    fn evaluate_451(&self, ctx: &EvaluationContext) -> ConditionResult {
7289        // Check: RFF with qualifier Z18 (Marktlokation) exists
7290        ctx.has_qualifier("RFF", 0, "Z18")
7291    }
7292
7293    /// [452] Wenn in demselben RFF der Code Z19 (Messlokation) im DE1153 vorhanden
7294    fn evaluate_452(&self, ctx: &EvaluationContext) -> ConditionResult {
7295        // Check: RFF with qualifier Z19 (Messlokation) exists
7296        ctx.has_qualifier("RFF", 0, "Z19")
7297    }
7298
7299    /// [453] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Auslöser „Bei Schwellwertunter-/ -überschreitung" mit selbständiger Änderungsmöglichke...
7300    fn evaluate_453(&self, ctx: &EvaluationContext) -> ConditionResult {
7301        ctx.external.evaluate("code_list_membership_check")
7302    }
7303
7304    /// [454] Das Bilanzierungsbeginn Datum muss kleiner sein als das Bilanzierungsende Datum in der SG8 „Datenstand des ÜNB", SG 9 Energiemenge DZÜ Anteil
7305    fn evaluate_454(&self, _ctx: &EvaluationContext) -> ConditionResult {
7306        // Check: begin date < end date (structural — always true for valid messages)
7307        ConditionResult::True
7308    }
7309
7310    /// [455] Das Bilanzierungsende-Datum muss größer sein, als das Bilanzierungsbeginn Datum in der SG8 „Datenstand des ÜNB" , SG 9 Energiemenge DZÜ Anteil
7311    fn evaluate_455(&self, _ctx: &EvaluationContext) -> ConditionResult {
7312        // Check: end date > begin date (structural — always true for valid messages)
7313        ConditionResult::True
7314    }
7315
7316    /// [456] Wenn in demselben RFF der Code Z37 (Technische Ressource) im DE1153 vorhanden
7317    fn evaluate_456(&self, ctx: &EvaluationContext) -> ConditionResult {
7318        // Check: RFF with qualifier Z37 (Technische Ressource) exists
7319        ctx.has_qualifier("RFF", 0, "Z37")
7320    }
7321
7322    /// [457] Wenn bei der Bestellung das Messprodukten 9991000001498 bestellt wurde
7323    fn evaluate_457(&self, ctx: &EvaluationContext) -> ConditionResult {
7324        // Check: PIA+5 with Messprodukt 9991000001498 exists
7325        let pia_segs = ctx.find_segments("PIA");
7326        let found = pia_segs.iter().any(|s| {
7327            s.elements
7328                .first()
7329                .and_then(|e| e.first())
7330                .is_some_and(|v| v == "5")
7331                && s.elements
7332                    .get(1)
7333                    .and_then(|e| e.first())
7334                    .is_some_and(|v| v == "9991000001498")
7335        });
7336        ConditionResult::from(found)
7337    }
7338
7339    /// [458] Wenn bei der Bestellung das Konfigurationsprodukte 9991000000739 bestellt wurde
7340    fn evaluate_458(&self, ctx: &EvaluationContext) -> ConditionResult {
7341        // Check: PIA+5 with Konfigurationsprodukt 9991000000739 exists
7342        let pia_segs = ctx.find_segments("PIA");
7343        let found = pia_segs.iter().any(|s| {
7344            s.elements
7345                .first()
7346                .and_then(|e| e.first())
7347                .is_some_and(|v| v == "5")
7348                && s.elements
7349                    .get(1)
7350                    .and_then(|e| e.first())
7351                    .is_some_and(|v| v == "9991000000739")
7352        });
7353        ConditionResult::from(found)
7354    }
7355
7356    /// [459] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Übertragungsweg \"CLS-Direkt aus dem SMGW\" bestellt wurde
7357    fn evaluate_459(&self, ctx: &EvaluationContext) -> ConditionResult {
7358        ctx.external.evaluate("code_list_membership_check")
7359    }
7360
7361    /// [460] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Übertragungsweg \"aus dem SMGW\" bestellt wurde
7362    fn evaluate_460(&self, ctx: &EvaluationContext) -> ConditionResult {
7363        ctx.external.evaluate("code_list_membership_check")
7364    }
7365
7366    /// [461] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) im CAV+ZG8 (Technischen Ressource fällt unter § 14a EnWG) vorhanden
7367    fn evaluate_461(&self, ctx: &EvaluationContext) -> ConditionResult {
7368        let cci_segs = ctx.find_segments("CCI");
7369        let found = cci_segs.iter().any(|s| {
7370            s.elements
7371                .first()
7372                .and_then(|e| e.first())
7373                .is_some_and(|v| v == "Z17")
7374        });
7375        ConditionResult::from(found)
7376    }
7377
7378    /// [462] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) im CAV+ZH1 (Inbetriebsetzung der TR vor 2024) vorhanden
7379    fn evaluate_462(&self, ctx: &EvaluationContext) -> ConditionResult {
7380        let cci_segs = ctx.find_segments("CCI");
7381        let found = cci_segs.iter().any(|s| {
7382            s.elements
7383                .first()
7384                .and_then(|e| e.first())
7385                .is_some_and(|v| v == "Z17")
7386        });
7387        ConditionResult::from(found)
7388    }
7389
7390    /// [463] Wenn in derselben SG10 das CCI+Z61++ZF9 (Kunde erfüllt die Voraussetzung nach EnFG) vorhanden
7391    fn evaluate_463(&self, ctx: &EvaluationContext) -> ConditionResult {
7392        let cci_segs = ctx.find_segments("CCI");
7393        let found = cci_segs.iter().any(|s| {
7394            s.elements
7395                .first()
7396                .and_then(|e| e.first())
7397                .is_some_and(|v| v == "Z61")
7398                && s.elements
7399                    .get(2)
7400                    .and_then(|e| e.first())
7401                    .is_some_and(|v| v == "ZF9")
7402        });
7403        ConditionResult::from(found)
7404    }
7405
7406    /// [465] Wenn in derselben SG8 (Daten der Technischen Ressource) das RFF+Z38 (Referenz auf die der Technischen Ressource zugeordnete Steuerbare Ressource) vorhanden ist
7407    fn evaluate_465(&self, ctx: &EvaluationContext) -> ConditionResult {
7408        let rff_segs = ctx.find_segments("RFF");
7409        let found = rff_segs.iter().any(|s| {
7410            s.elements
7411                .first()
7412                .and_then(|e| e.first())
7413                .is_some_and(|v| v == "Z38")
7414        });
7415        ConditionResult::from(found)
7416    }
7417
7418    /// [466] Wenn in derselben SG8 (Daten der Technischen Ressource) das RFF+Z32 (Referenz auf die der Technischen Ressource zugeordneten Netzlokation) vorhanden ist
7419    fn evaluate_466(&self, ctx: &EvaluationContext) -> ConditionResult {
7420        let rff_segs = ctx.find_segments("RFF");
7421        let found = rff_segs.iter().any(|s| {
7422            s.elements
7423                .first()
7424                .and_then(|e| e.first())
7425                .is_some_and(|v| v == "Z32")
7426        });
7427        ConditionResult::from(found)
7428    }
7429
7430    /// [467] Wenn in derselben SG8 (Daten der Technischen Ressource) das CAV+ZG8 (Technischen Ressource fällt unter § 14a EnWG) vorhanden ist
7431    fn evaluate_467(&self, ctx: &EvaluationContext) -> ConditionResult {
7432        let segs = ctx.find_segments("CAV");
7433        let found = segs.iter().any(|s| {
7434            s.elements
7435                .first()
7436                .and_then(|e| e.first())
7437                .is_some_and(|v| v == "ZG8")
7438        });
7439        ConditionResult::from(found)
7440    }
7441
7442    /// [468] Wenn in derselben SG8 (Daten der Technischen Ressource) das SG10 CAV+ZH0 (Inbetriebsetzung der TR nach 2023) vorhanden ist
7443    fn evaluate_468(&self, ctx: &EvaluationContext) -> ConditionResult {
7444        let segs = ctx.find_segments("CAV");
7445        let found = segs.iter().any(|s| {
7446            s.elements
7447                .first()
7448                .and_then(|e| e.first())
7449                .is_some_and(|v| v == "ZH0")
7450        });
7451        ConditionResult::from(found)
7452    }
7453
7454    /// [469] Wenn in derselben SG8 (Daten der Technischen Ressource) das SG10 CAV+ZH1 (Inbetriebsetzung der TR vor 2024) vorhanden ist
7455    fn evaluate_469(&self, ctx: &EvaluationContext) -> ConditionResult {
7456        let segs = ctx.find_segments("CAV");
7457        let found = segs.iter().any(|s| {
7458            s.elements
7459                .first()
7460                .and_then(|e| e.first())
7461                .is_some_and(|v| v == "ZH1")
7462        });
7463        ConditionResult::from(found)
7464    }
7465
7466    /// [470] Wenn in derselben SG8 (Daten der Technischen Ressource) das CAV+ZH5 (Wechsel in das in das § 14a EnWG-Modell gem. Festlegung BK6-22-300 wurde durchgeführt) vorhanden ist
7467    fn evaluate_470(&self, ctx: &EvaluationContext) -> ConditionResult {
7468        let segs = ctx.find_segments("CAV");
7469        let found = segs.iter().any(|s| {
7470            s.elements
7471                .first()
7472                .and_then(|e| e.first())
7473                .is_some_and(|v| v == "ZH5")
7474        });
7475        ConditionResult::from(found)
7476    }
7477
7478    /// [471] Wenn im selben SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: Gültige Daten/ Keine Daten) im DE1156 (Zeitraum-ID) eine Zeitraum ID genannt ist, die kleiner ist als in einem anderen SG6 RFF+Z49/ ...
7479    fn evaluate_471(&self, ctx: &EvaluationContext) -> ConditionResult {
7480        // Check: SG6 RFF+Z49/Z53 has Zeitraum-ID > 1 in DE1156
7481        let found = ctx.find_segments("RFF").iter().any(|s| {
7482            let qual = s
7483                .elements
7484                .first()
7485                .and_then(|e| e.first())
7486                .map(|v| v.as_str());
7487            matches!(qual, Some("Z49") | Some("Z53"))
7488                && s.elements
7489                    .first()
7490                    .and_then(|e| e.get(2))
7491                    .is_some_and(|v| v.parse::<u32>().is_ok_and(|n| n > 1))
7492        });
7493        ConditionResult::from(found)
7494    }
7495
7496    /// [472] Wenn im selben SG6 RFF+Z48/ Z55 (Verwendungszeitraum der Daten: Erwartete Daten/ Keine Daten erwartet) im DE1156 (Zeitraum-ID) eine Zeitraum ID genannt ist, die kleiner ist als in einem anderen SG6...
7497    fn evaluate_472(&self, ctx: &EvaluationContext) -> ConditionResult {
7498        // Check: SG6 RFF+Z48/Z55 has Zeitraum-ID > 1 in DE1156
7499        let found = ctx.find_segments("RFF").iter().any(|s| {
7500            let qual = s
7501                .elements
7502                .first()
7503                .and_then(|e| e.first())
7504                .map(|v| v.as_str());
7505            matches!(qual, Some("Z48") | Some("Z55"))
7506                && s.elements
7507                    .first()
7508                    .and_then(|e| e.get(2))
7509                    .is_some_and(|v| v.parse::<u32>().is_ok_and(|n| n > 1))
7510        });
7511        ConditionResult::from(found)
7512    }
7513
7514    /// [473] Wenn im selben SG6 RFF+Z47/ Z54 (Verwendungszeitraum der Daten: Im System vorhandene Daten/ Im System keine Daten vorhanden) im DE1156 (Zeitraum-ID) eine Zeitraum ID genannt ist, die kleiner ist al...
7515    fn evaluate_473(&self, ctx: &EvaluationContext) -> ConditionResult {
7516        // Check: SG6 RFF+Z47/Z54 has Zeitraum-ID > 1 in DE1156
7517        let found = ctx.find_segments("RFF").iter().any(|s| {
7518            let qual = s
7519                .elements
7520                .first()
7521                .and_then(|e| e.first())
7522                .map(|v| v.as_str());
7523            matches!(qual, Some("Z47") | Some("Z54"))
7524                && s.elements
7525                    .first()
7526                    .and_then(|e| e.get(2))
7527                    .is_some_and(|v| v.parse::<u32>().is_ok_and(|n| n > 1))
7528        });
7529        ConditionResult::from(found)
7530    }
7531
7532    /// [474] Wenn SG4 STS+7++ZC8 (Transaktionsgrund \"Beendigung der Zuordnung\") vorhanden
7533    fn evaluate_474(&self, ctx: &EvaluationContext) -> ConditionResult {
7534        let sts_segs = ctx.find_segments("STS");
7535        let found = sts_segs.iter().any(|s| {
7536            s.elements
7537                .first()
7538                .and_then(|e| e.first())
7539                .is_some_and(|v| v == "7")
7540                && s.elements
7541                    .get(2)
7542                    .and_then(|e| e.first())
7543                    .is_some_and(|v| ["ZC8"].contains(&v.as_str()))
7544        });
7545        ConditionResult::from(found)
7546    }
7547
7548    /// [475] Wenn SG4 STS+7++ZH1 (Transaktionsgrund \"Aufhebung einer zukünftigen Zuordnung wegen Stilllegung\") vorhanden
7549    fn evaluate_475(&self, ctx: &EvaluationContext) -> ConditionResult {
7550        let sts_segs = ctx.find_segments("STS");
7551        let found = sts_segs.iter().any(|s| {
7552            s.elements
7553                .first()
7554                .and_then(|e| e.first())
7555                .is_some_and(|v| v == "7")
7556                && s.elements
7557                    .get(2)
7558                    .and_then(|e| e.first())
7559                    .is_some_and(|v| ["ZH1"].contains(&v.as_str()))
7560        });
7561        ConditionResult::from(found)
7562    }
7563
7564    /// [476] Wenn SG4 STS+7++xxx+ZW0 (Transaktionsgrundergänzung Geschäftsvorfall 1) vorhanden
7565    fn evaluate_476(&self, ctx: &EvaluationContext) -> ConditionResult {
7566        let sts_segs = ctx.find_segments("STS");
7567        let found = sts_segs.iter().any(|s| {
7568            s.elements
7569                .first()
7570                .and_then(|e| e.first())
7571                .is_some_and(|v| v == "7")
7572                && s.elements
7573                    .get(3)
7574                    .and_then(|e| e.first())
7575                    .is_some_and(|v| ["ZW0"].contains(&v.as_str()))
7576        });
7577        ConditionResult::from(found)
7578    }
7579
7580    /// [477] Wenn SG4 STS+7++xxx+ZW1 (Transaktionsgrundergänzung Geschäftsvorfall 2) vorhanden
7581    fn evaluate_477(&self, ctx: &EvaluationContext) -> ConditionResult {
7582        let sts_segs = ctx.find_segments("STS");
7583        let found = sts_segs.iter().any(|s| {
7584            s.elements
7585                .first()
7586                .and_then(|e| e.first())
7587                .is_some_and(|v| v == "7")
7588                && s.elements
7589                    .get(3)
7590                    .and_then(|e| e.first())
7591                    .is_some_and(|v| ["ZW1"].contains(&v.as_str()))
7592        });
7593        ConditionResult::from(found)
7594    }
7595
7596    /// [478] Wenn SG4 STS+7++xxx+ZW2 (Transaktionsgrundergänzung Geschäftsvorfall 3) vorhanden
7597    fn evaluate_478(&self, ctx: &EvaluationContext) -> ConditionResult {
7598        let sts_segs = ctx.find_segments("STS");
7599        let found = sts_segs.iter().any(|s| {
7600            s.elements
7601                .first()
7602                .and_then(|e| e.first())
7603                .is_some_and(|v| v == "7")
7604                && s.elements
7605                    .get(3)
7606                    .and_then(|e| e.first())
7607                    .is_some_and(|v| ["ZW2"].contains(&v.as_str()))
7608        });
7609        ConditionResult::from(found)
7610    }
7611
7612    /// [479] Wenn SG4 STS+7++xxx+ZW3 (Transaktionsgrundergänzung Erzeugende Marktlokation) vorhanden
7613    fn evaluate_479(&self, ctx: &EvaluationContext) -> ConditionResult {
7614        let sts_segs = ctx.find_segments("STS");
7615        let found = sts_segs.iter().any(|s| {
7616            s.elements
7617                .first()
7618                .and_then(|e| e.first())
7619                .is_some_and(|v| v == "7")
7620                && s.elements
7621                    .get(3)
7622                    .and_then(|e| e.first())
7623                    .is_some_and(|v| ["ZW3"].contains(&v.as_str()))
7624        });
7625        ConditionResult::from(found)
7626    }
7627
7628    /// [480] Wenn SG4 STS+7++xxx+ZW4 (Transaktionsgrundergänzung Verbrauchende Marktlokation) vorhanden
7629    fn evaluate_480(&self, ctx: &EvaluationContext) -> ConditionResult {
7630        let sts_segs = ctx.find_segments("STS");
7631        let found = sts_segs.iter().any(|s| {
7632            s.elements
7633                .first()
7634                .and_then(|e| e.first())
7635                .is_some_and(|v| v == "7")
7636                && s.elements
7637                    .get(3)
7638                    .and_then(|e| e.first())
7639                    .is_some_and(|v| ["ZW4"].contains(&v.as_str()))
7640        });
7641        ConditionResult::from(found)
7642    }
7643
7644    /// [481] Wenn SG4 STS+7++xxx+ZW5 (Transaktionsgrundergänzung Tranche) vorhanden
7645    fn evaluate_481(&self, ctx: &EvaluationContext) -> ConditionResult {
7646        let sts_segs = ctx.find_segments("STS");
7647        let found = sts_segs.iter().any(|s| {
7648            s.elements
7649                .first()
7650                .and_then(|e| e.first())
7651                .is_some_and(|v| v == "7")
7652                && s.elements
7653                    .get(3)
7654                    .and_then(|e| e.first())
7655                    .is_some_and(|v| ["ZW5"].contains(&v.as_str()))
7656        });
7657        ConditionResult::from(found)
7658    }
7659
7660    /// [483] Wenn SG4 STS+7++xxx+ZW7 (Transaktionsgrundergänzung Gemessene Marktlokation) vorhanden
7661    fn evaluate_483(&self, ctx: &EvaluationContext) -> ConditionResult {
7662        let sts_segs = ctx.find_segments("STS");
7663        let found = sts_segs.iter().any(|s| {
7664            s.elements
7665                .first()
7666                .and_then(|e| e.first())
7667                .is_some_and(|v| v == "7")
7668                && s.elements
7669                    .get(3)
7670                    .and_then(|e| e.first())
7671                    .is_some_and(|v| ["ZW7"].contains(&v.as_str()))
7672        });
7673        ConditionResult::from(found)
7674    }
7675
7676    /// [484] Wenn SG4 STS+7++xxx+ZW8 (Transaktionsgrundergänzung Fall1) vorhanden
7677    fn evaluate_484(&self, ctx: &EvaluationContext) -> ConditionResult {
7678        let sts_segs = ctx.find_segments("STS");
7679        let found = sts_segs.iter().any(|s| {
7680            s.elements
7681                .first()
7682                .and_then(|e| e.first())
7683                .is_some_and(|v| v == "7")
7684                && s.elements
7685                    .get(3)
7686                    .and_then(|e| e.first())
7687                    .is_some_and(|v| ["ZW8"].contains(&v.as_str()))
7688        });
7689        ConditionResult::from(found)
7690    }
7691
7692    /// [487] Wenn SG4 STS+7++xxx+ZX1 (Transaktionsgrundergänzung Fall4) vorhanden
7693    fn evaluate_487(&self, ctx: &EvaluationContext) -> ConditionResult {
7694        let sts_segs = ctx.find_segments("STS");
7695        let found = sts_segs.iter().any(|s| {
7696            s.elements
7697                .first()
7698                .and_then(|e| e.first())
7699                .is_some_and(|v| v == "7")
7700                && s.elements
7701                    .get(3)
7702                    .and_then(|e| e.first())
7703                    .is_some_and(|v| ["ZX1"].contains(&v.as_str()))
7704        });
7705        ConditionResult::from(found)
7706    }
7707
7708    /// [489] Nur bei dem ältesten Zeitraum welcher mit SG6 RFF+Z49 (Verwendungszeitraum der Daten: Gültige Daten) beschrieben ist
7709    fn evaluate_489(&self, ctx: &EvaluationContext) -> ConditionResult {
7710        // Check: this is the oldest Zeitraum (lowest Zeitraum-ID) with RFF+Z49
7711        let rff_z49 = ctx.find_segments_with_qualifier("RFF", 0, "Z49");
7712        if rff_z49.is_empty() {
7713            return ConditionResult::Unknown;
7714        }
7715        // Approximate: condition applies when RFF+Z49 exists
7716        ConditionResult::True
7717    }
7718
7719    /// [490] Wenn Wert in diesem DE, an der Stelle CCYYMMDD ein Datum aus dem angegeben Zeitraum der Tabelle Kapitel 3.5 „Prozesszeitpunkt bei MESZ mit UTC" ist
7720    fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
7721        ctx.format_check("DTM", 0, 1, is_mesz_utc)
7722    }
7723
7724    /// [491] Wenn Wert in diesem DE, an der Stelle CCYYMMDD ein Datum aus dem angegeben Zeitraum der Tabelle Kapitel 3.6 „Prozesszeitpunkt bei MEZ mit UTC"" ist
7725    fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
7726        ctx.format_check("DTM", 0, 1, is_mez_utc)
7727    }
7728
7729    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
7730    fn evaluate_494(&self, ctx: &EvaluationContext) -> ConditionResult {
7731        // Document date must be <= now. Format 303 is CCYYMMDDHHMM — fixed-width,
7732        // so lexicographic comparison works directly.
7733        let val = ctx.resolved_value.or_else(|| {
7734            ctx.find_segments_with_qualifier("DTM", 0, "137")
7735                .first()
7736                .and_then(|s| s.elements.first())
7737                .and_then(|e| e.get(1))
7738                .map(|v| v.as_str())
7739        });
7740        let Some(dtm_val) = val else {
7741            return ConditionResult::Unknown;
7742        };
7743        if dtm_val.len() < 12 {
7744            return ConditionResult::Unknown;
7745        }
7746        let now_str = crate::eval::format_validators::utc_now_ccyymmddhhmm();
7747        ConditionResult::from(&dtm_val[..12] <= now_str.as_str())
7748    }
7749
7750    /// [500] Hinweis: Code ist gemäß der Kategorie der zu stornierenden Meldung zu wählen
7751    fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
7752        ConditionResult::True
7753    }
7754
7755    /// [501] Hinweis: Es sind zur Unterstützung die Daten des LFA anzugeben
7756    fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
7757        ConditionResult::True
7758    }
7759
7760    /// [502] Hinweis: Es wird der Betrachtungsmonat der DZR bzw. BAS angegeben
7761    fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
7762        ConditionResult::True
7763    }
7764
7765    /// [503] Hinweis: Angabe des BGM DE1004 aus der ORDERS
7766    fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
7767        ConditionResult::True
7768    }
7769
7770    /// [504] Hinweis: Je Profil (ggf. inkl. Profilschar) ein Vorgang erforderlich
7771    fn evaluate_504(&self, _ctx: &EvaluationContext) -> ConditionResult {
7772        ConditionResult::True
7773    }
7774
7775    /// [505] Hinweis: Je zugeordneter ID und je EEG-Überführungszeitreihe ein Vorgang erforderlich
7776    fn evaluate_505(&self, _ctx: &EvaluationContext) -> ConditionResult {
7777        ConditionResult::True
7778    }
7779
7780    /// [506] Hinweis: Für jeden Code im LOC+Z16 (Marktlokation) sollen die entsprechenden Kundendaten des LF angegeben werden, falls bekannt
7781    fn evaluate_506(&self, _ctx: &EvaluationContext) -> ConditionResult {
7782        ConditionResult::True
7783    }
7784
7785    /// [507] Hinweis: Ursprünglich vom NB bestätigtes Beginndatum
7786    fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
7787        ConditionResult::True
7788    }
7789
7790    /// [508] Hinweis: Ausschließlich kME sind über die NNE abrechenbar
7791    fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
7792        ConditionResult::True
7793    }
7794
7795    /// [509] Hinweis: Handelt sich um ein mME oder iMS ist das RFF 1154 immer mit NEIN anzugeben
7796    fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
7797        ConditionResult::True
7798    }
7799
7800    /// [510] Hinweis: Zu verwenden bei der Abmeldung der ESV
7801    fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
7802        ConditionResult::True
7803    }
7804
7805    /// [511] Hinweis: Es sind alle Bilanzierungsgebiete anzugeben in denen das Profil verwendet wird
7806    fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
7807        ConditionResult::True
7808    }
7809
7810    /// [512] Hinweis: Es ist informativ die bisherige Veräußerungsform des LFA an der erzeugenden Marktlokation anzugeben
7811    fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
7812        ConditionResult::True
7813    }
7814
7815    /// [513] Hinweis: Es ist das nächstmögliche Datum ab dem DTM+471 aus der entsprechenden Anfrage zu ermitteln
7816    fn evaluate_513(&self, _ctx: &EvaluationContext) -> ConditionResult {
7817        ConditionResult::True
7818    }
7819
7820    /// [514] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
7821    fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
7822        ConditionResult::True
7823    }
7824
7825    /// [515] Hinweis: Für den ZP der LieferantensummenZR anzugeben
7826    fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
7827        ConditionResult::True
7828    }
7829
7830    /// [516] Hinweis: Es ist der Änderungszeitpunkt anzugeben an dem das Zuordnungsende des NBA und der Zuordnungsbeginn des NBN zu einer Marktlokation fallen
7831    fn evaluate_516(&self, _ctx: &EvaluationContext) -> ConditionResult {
7832        ConditionResult::True
7833    }
7834
7835    /// [517] Hinweis: Anzuwenden wenn einer Marktlokation eine Paket-ID zugeordnet wurde und diese wieder gelöscht werden soll, da sie nicht unter den genannten NB-Wechsel fällt
7836    fn evaluate_517(&self, _ctx: &EvaluationContext) -> ConditionResult {
7837        ConditionResult::True
7838    }
7839
7840    /// [518] Hinweis: Es sind alle Altlieferanten anzugeben, an die eine Abmeldeanfrage gesendet wird
7841    fn evaluate_518(&self, _ctx: &EvaluationContext) -> ConditionResult {
7842        ConditionResult::True
7843    }
7844
7845    /// [519] Hinweis: Wenn in der Anmeldung der Code ZAP vorhanden war, so ist dieser auch in der Antwort zu verwenden
7846    fn evaluate_519(&self, _ctx: &EvaluationContext) -> ConditionResult {
7847        ConditionResult::True
7848    }
7849
7850    /// [520] Hinweis: Bei der Verwendung des Codes ZAP handelt es sich immer um eine gemessene Marktlokation
7851    fn evaluate_520(&self, _ctx: &EvaluationContext) -> ConditionResult {
7852        ConditionResult::True
7853    }
7854
7855    /// [521] Hinweis: Wenn im zweiten DE 9013 des STS+7 (Transaktionsgrund) der Code ZAP vorhanden ist, so ist das hier angegebene Datum als Zuordnungsbeginn bei der Bildung der \"Ruhenden MaLo zu verstehen. Be...
7856    fn evaluate_521(&self, _ctx: &EvaluationContext) -> ConditionResult {
7857        ConditionResult::True
7858    }
7859
7860    /// [522] Hinweis: Es ist der NBN anzugeben
7861    fn evaluate_522(&self, _ctx: &EvaluationContext) -> ConditionResult {
7862        ConditionResult::True
7863    }
7864
7865    /// [523] Hinweis: Mindestens einmal für jede Marktlokation bzw. Tranche, die in der DZÜ / BG-CL / LF-SZR berücksichtigt wurde
7866    fn evaluate_523(&self, _ctx: &EvaluationContext) -> ConditionResult {
7867        ConditionResult::True
7868    }
7869
7870    /// [524] Hinweis: Mindestens einmal für jede Marktlokation bzw. Tranche, für die der LF nicht die gemeldete Ansicht des NB teilt
7871    fn evaluate_524(&self, _ctx: &EvaluationContext) -> ConditionResult {
7872        ConditionResult::True
7873    }
7874
7875    /// [525] Hinweis: Es sind nur die OBIS-Kennzahlen erlaubt, die im vorherigen Stammdatenaustausch zu dieser Marktlokation vom MSB zu diesem Zeitpunkt übermittelt wurden
7876    fn evaluate_525(&self, _ctx: &EvaluationContext) -> ConditionResult {
7877        ConditionResult::True
7878    }
7879
7880    /// [526] Hinweis: Wenn der Marktlokation keine Technische Ressource in der Lokationsbündelstruktur zugeordnet wurde
7881    fn evaluate_526(&self, _ctx: &EvaluationContext) -> ConditionResult {
7882        ConditionResult::True
7883    }
7884
7885    /// [527] Hinweis: Es sind alle Identifikatoren der Messlokationen anzugeben
7886    fn evaluate_527(&self, _ctx: &EvaluationContext) -> ConditionResult {
7887        ConditionResult::True
7888    }
7889
7890    /// [528] Hinweis: Es ist das Datum/ Daten aus der Anfrage zu verwenden
7891    fn evaluate_528(&self, _ctx: &EvaluationContext) -> ConditionResult {
7892        ConditionResult::True
7893    }
7894
7895    /// [529] Hinweis: Für zusätzliche nicht im Markt standardisierte Identifikatoren wie z.B. eine Netzbetreiber-Projektnummer
7896    fn evaluate_529(&self, _ctx: &EvaluationContext) -> ConditionResult {
7897        ConditionResult::True
7898    }
7899
7900    /// [530] Hinweis: Es sind alle an der Lokation vorhandenen Daten, die mit dieser Segmentgruppe übermittelt werden und zum Datum „Änderung zum" Gültigkeit haben, anzugeben. Dies kann zur Folge haben, ...
7901    fn evaluate_530(&self, _ctx: &EvaluationContext) -> ConditionResult {
7902        ConditionResult::True
7903    }
7904
7905    /// [531] Hinweis: Es ist das Jahr anzugeben in dem die nächste Netznutzungsabrechnung erfolgt
7906    fn evaluate_531(&self, _ctx: &EvaluationContext) -> ConditionResult {
7907        ConditionResult::True
7908    }
7909
7910    /// [532] Hinweis: Kritische Daten (gemäß GPKE)
7911    fn evaluate_532(&self, _ctx: &EvaluationContext) -> ConditionResult {
7912        ConditionResult::True
7913    }
7914
7915    /// [533] Hinweis: Es ist die MP-ID des Lieferanten anzugeben
7916    fn evaluate_533(&self, _ctx: &EvaluationContext) -> ConditionResult {
7917        ConditionResult::True
7918    }
7919
7920    /// [555] Die Anwendungsfälle für die Durchführung der BDEW-Anwendungshilfe „Marktprozesse Netzbetreiberwechsel Sparte Strom" sind ab dem 01.08.2025 für Netzbetreiberwechsel ab dem 01.01.2026 zu verw...
7921    fn evaluate_555(&self, _ctx: &EvaluationContext) -> ConditionResult {
7922        // TODO: implement
7923        ConditionResult::Unknown
7924    }
7925
7926    /// [556] Hinweis: Wenn keine Korrespondenzanschrift des Endverbrauchers/ Kunden vorliegt, ist die Anschrift der Marktlokation zu übermitteln
7927    fn evaluate_556(&self, _ctx: &EvaluationContext) -> ConditionResult {
7928        ConditionResult::True
7929    }
7930
7931    /// [558] Hinweis: Diese Information kann freiwillig ausgetauscht werden
7932    fn evaluate_558(&self, _ctx: &EvaluationContext) -> ConditionResult {
7933        ConditionResult::True
7934    }
7935
7936    /// [559] Hinweis: Die Korrespondenzanschrift des Endverbrauchers/Kunden wird nicht zur Identifikation genutzt
7937    fn evaluate_559(&self, _ctx: &EvaluationContext) -> ConditionResult {
7938        ConditionResult::True
7939    }
7940
7941    /// [563] Hinweis: Für die ID der LieferantensummenZR
7942    fn evaluate_563(&self, _ctx: &EvaluationContext) -> ConditionResult {
7943        ConditionResult::True
7944    }
7945
7946    /// [566] Hinweis: Altlieferant
7947    fn evaluate_566(&self, _ctx: &EvaluationContext) -> ConditionResult {
7948        ConditionResult::True
7949    }
7950
7951    /// [567] Hinweis: Neulieferant
7952    fn evaluate_567(&self, _ctx: &EvaluationContext) -> ConditionResult {
7953        ConditionResult::True
7954    }
7955
7956    /// [568] Hinweis: Lieferant der LieferantensummenZR
7957    fn evaluate_568(&self, _ctx: &EvaluationContext) -> ConditionResult {
7958        ConditionResult::True
7959    }
7960
7961    /// [569] Hinweis: Dritter Nutzer
7962    fn evaluate_569(&self, _ctx: &EvaluationContext) -> ConditionResult {
7963        ConditionResult::True
7964    }
7965
7966    /// [570] Hinweis: Netzbetreiber Alt
7967    fn evaluate_570(&self, _ctx: &EvaluationContext) -> ConditionResult {
7968        ConditionResult::True
7969    }
7970
7971    /// [572] Hinweis: Kundenname aus Anmeldung Lieferant neu
7972    fn evaluate_572(&self, _ctx: &EvaluationContext) -> ConditionResult {
7973        ConditionResult::True
7974    }
7975
7976    /// [576] Hinweis: Stammdaten des bisherigen Messstellenbetreibers
7977    fn evaluate_576(&self, _ctx: &EvaluationContext) -> ConditionResult {
7978        ConditionResult::True
7979    }
7980
7981    /// [577] Hinweis: Wird mit dem ursprünglich vom NB bestätigten Beginnzeitpunkt gefüllt
7982    fn evaluate_577(&self, _ctx: &EvaluationContext) -> ConditionResult {
7983        ConditionResult::True
7984    }
7985
7986    /// [579] Hinweis: Auslösender Marktpartner (LFN bei STS+7++ZH0/ZG9, NB bei STS+7++ZH1)
7987    fn evaluate_579(&self, _ctx: &EvaluationContext) -> ConditionResult {
7988        ConditionResult::True
7989    }
7990
7991    /// [580] Hinweis:  Ersatzbelieferung gibt es nur bei  - Marktlokationen in der  Niederspannung, die kein Haushaltskunde gem. EnWG sind und die nicht mehr der gesetzlichen Ersatzversorgung (drei Monate) unte...
7992    fn evaluate_580(&self, _ctx: &EvaluationContext) -> ConditionResult {
7993        ConditionResult::True
7994    }
7995
7996    /// [581] Hinweis: Es ist der Zeitpunkt anzugeben, zu welchem der Vertrag am Tag des Versandes der Antwort noch kündbar ist.
7997    fn evaluate_581(&self, _ctx: &EvaluationContext) -> ConditionResult {
7998        ConditionResult::True
7999    }
8000
8001    /// [586] Hinweis: Die Messlokationsadresse ist der Messlokation zugeordnet, welche in SG8 SEQ+Z18/ ZF3 (Daten der Messlokation) mit CCI+Z01++Z82 (Verwendungsumfang: ID der prozessual behandelten Messlokatio...
8002    fn evaluate_586(&self, _ctx: &EvaluationContext) -> ConditionResult {
8003        ConditionResult::True
8004    }
8005
8006    /// [590] Hinweis: Für den Empfang des Steuerbefehls
8007    fn evaluate_590(&self, _ctx: &EvaluationContext) -> ConditionResult {
8008        ConditionResult::True
8009    }
8010
8011    /// [594] Hinweis: Es ist der ZPB des ZP der NGZ und die ZPB der NZR anzugeben
8012    fn evaluate_594(&self, _ctx: &EvaluationContext) -> ConditionResult {
8013        ConditionResult::True
8014    }
8015
8016    /// [599] Hinweis: Es ist der Name und die Adresse des Ablesekartenempfängers für die Messlokation anzugeben, welche in SG8 SEQ+Z18 (Daten der Messlokation) mit CCI+Z01++Z82 (Verwendungsumfang: ID der proz...
8017    fn evaluate_599(&self, _ctx: &EvaluationContext) -> ConditionResult {
8018        ConditionResult::True
8019    }
8020
8021    /// [601] Hinweis: Es ist die ID der Marktlokation und alle Identifikatoren der Messlokationen anzugeben. Sowie wenn vorhanden die Tranche/n der Marklokation
8022    fn evaluate_601(&self, _ctx: &EvaluationContext) -> ConditionResult {
8023        ConditionResult::True
8024    }
8025
8026    /// [606] Hinweis: In diesem Segment bzw. SG sind die Daten aus der Sicht des NB anzugeben
8027    fn evaluate_606(&self, _ctx: &EvaluationContext) -> ConditionResult {
8028        ConditionResult::True
8029    }
8030
8031    /// [609] Hinweis: In diesem Segment bzw. SG sind die zwischen NB, LF und ÜNB im Rahmen der Marktkommunikation ausgetauschten Daten aus der Sicht des ÜNB anzugeben
8032    fn evaluate_609(&self, _ctx: &EvaluationContext) -> ConditionResult {
8033        ConditionResult::True
8034    }
8035
8036    /// [611] Hinweis: Wenn das Unternehmen NB die Aufgaben der Marktrolle LF wahrnimmt, ist die MP-ID des Unternehmens NB in der Marktrolle LF anzugeben
8037    fn evaluate_611(&self, _ctx: &EvaluationContext) -> ConditionResult {
8038        ConditionResult::True
8039    }
8040
8041    /// [614] Hinweis: Es werden nur die OBIS Kennzahlen übermittelt die für die Bilanzierung relevant sind
8042    fn evaluate_614(&self, _ctx: &EvaluationContext) -> ConditionResult {
8043        ConditionResult::True
8044    }
8045
8046    /// [617] Hinweis: Mehrere Vorgänge für eine Marktlokation bei Wechsel bilanzierungsrelevanter Stammdaten innerhalb des Bilanzierungsmonats
8047    fn evaluate_617(&self, _ctx: &EvaluationContext) -> ConditionResult {
8048        ConditionResult::True
8049    }
8050
8051    /// [618] Hinweis: Bisheriges Datum des MSBA. Sollte der MSBN ein abweichendes Datum verwenden wollen, so teilt er das neue Datum mit einer Stammdatenänderung mit
8052    fn evaluate_618(&self, _ctx: &EvaluationContext) -> ConditionResult {
8053        ConditionResult::True
8054    }
8055
8056    /// [619] Hinweis: Für die selbständige Änderungsmöglichkeit der Schwellwertunter- / -über-schreitung
8057    fn evaluate_619(&self, _ctx: &EvaluationContext) -> ConditionResult {
8058        ConditionResult::True
8059    }
8060
8061    /// [621] Hinweis: Es ist der MSB anzugeben, welcher ab dem Zeitpunkt der Lokation zugeordnet ist, der in DTM+76 (Datum zum geplanten Leistungsbeginn) genannt ist.
8062    fn evaluate_621(&self, _ctx: &EvaluationContext) -> ConditionResult {
8063        ConditionResult::True
8064    }
8065
8066    /// [622] Hinweis: Falls die OBIS-Kennzahl für mehrere Marktrollen relevant ist, so muss die Segmentgruppe pro Marktrolle wiederholt werden
8067    fn evaluate_622(&self, _ctx: &EvaluationContext) -> ConditionResult {
8068        ConditionResult::True
8069    }
8070
8071    /// [623] Hinweis: Es sind alle Identifikatoren der Messlokationen anzugeben, die zur Ermittlung der Energiemenge der im Vorgang genannten Marktlokation benötigt werden
8072    fn evaluate_623(&self, _ctx: &EvaluationContext) -> ConditionResult {
8073        ConditionResult::True
8074    }
8075
8076    /// [630] Hinweis: Wenn die Liste abgelehnt wird, ist kein Vorgang enthalten
8077    fn evaluate_630(&self, _ctx: &EvaluationContext) -> ConditionResult {
8078        ConditionResult::True
8079    }
8080
8081    /// [631] Hinweis: Es ist die Listennummer aus der Lieferanten- bzw. Bilanzierungsgebietsclearingliste zu verwenden
8082    fn evaluate_631(&self, _ctx: &EvaluationContext) -> ConditionResult {
8083        ConditionResult::True
8084    }
8085
8086    /// [632] Hinweis: Es ist die Listennummer aus der Lieferanten-ausfallarbeits-clearingliste zu verwenden
8087    fn evaluate_632(&self, _ctx: &EvaluationContext) -> ConditionResult {
8088        ConditionResult::True
8089    }
8090
8091    /// [637] Hinweis: Bei Verpflichtungsanfrage
8092    fn evaluate_637(&self, _ctx: &EvaluationContext) -> ConditionResult {
8093        ConditionResult::True
8094    }
8095
8096    /// [638] Hinweis: Bei Aufforderung zur Übernahme der einzelnen Messlokation durch den gMSB
8097    fn evaluate_638(&self, _ctx: &EvaluationContext) -> ConditionResult {
8098        ConditionResult::True
8099    }
8100
8101    /// [639] Hinweis: Wenn Antwort auf Deaktivierung
8102    fn evaluate_639(&self, _ctx: &EvaluationContext) -> ConditionResult {
8103        ConditionResult::True
8104    }
8105
8106    /// [640] Hinweis: Wenn Antwort auf Aktivierung
8107    fn evaluate_640(&self, _ctx: &EvaluationContext) -> ConditionResult {
8108        ConditionResult::True
8109    }
8110
8111    /// [641] Hinweis: Wenn Einzelanforderung vorliegt
8112    fn evaluate_641(&self, _ctx: &EvaluationContext) -> ConditionResult {
8113        ConditionResult::True
8114    }
8115
8116    /// [642] Hinweis: Wenn Abo vorliegt
8117    fn evaluate_642(&self, _ctx: &EvaluationContext) -> ConditionResult {
8118        ConditionResult::True
8119    }
8120
8121    /// [643] Hinweis: Nachfolgender Netzbetreiber
8122    fn evaluate_643(&self, _ctx: &EvaluationContext) -> ConditionResult {
8123        ConditionResult::True
8124    }
8125
8126    /// [645] Hinweis: Es ist der Bilanzkreis des LF anzugeben
8127    fn evaluate_645(&self, _ctx: &EvaluationContext) -> ConditionResult {
8128        ConditionResult::True
8129    }
8130
8131    /// [646] Hinweis: Es ist der RD-Bilanzkreis des ANB anzugeben
8132    fn evaluate_646(&self, _ctx: &EvaluationContext) -> ConditionResult {
8133        ConditionResult::True
8134    }
8135
8136    /// [647] Hinweis: Es ist der RD-Bilanzkreis des anfNB anzugeben
8137    fn evaluate_647(&self, _ctx: &EvaluationContext) -> ConditionResult {
8138        ConditionResult::True
8139    }
8140
8141    /// [648] Hinweis: Soll ein Produkt ab dem Datum \"Änderung zum\" nicht mehr vorhanden sein, wird dies durch nicht angeben des PIA+5 ausgedrückt
8142    fn evaluate_648(&self, _ctx: &EvaluationContext) -> ConditionResult {
8143        ConditionResult::True
8144    }
8145
8146    /// [651] Hinweis: Es sind die Marktlokationen anzugeben, zu welchen die hier genannte OBIS benötigt wird
8147    fn evaluate_651(&self, _ctx: &EvaluationContext) -> ConditionResult {
8148        ConditionResult::True
8149    }
8150
8151    /// [653] Hinweis: Es sind alle Netzlokationen, Marktlokationen, Tranchen und Messlokationen zu nennen, die durch die Bestätigung der Abmeldung der prozessual behandelten Messlokation nicht mehr dem MSB zug...
8152    fn evaluate_653(&self, _ctx: &EvaluationContext) -> ConditionResult {
8153        ConditionResult::True
8154    }
8155
8156    /// [655] Hinweis: Es ist die Listennummer aus der DZÜ Liste zu verwenden
8157    fn evaluate_655(&self, _ctx: &EvaluationContext) -> ConditionResult {
8158        ConditionResult::True
8159    }
8160
8161    /// [659] Hinweis: Bei Tranchen ist nur der Meldepunkt der Tranche anzugeben
8162    fn evaluate_659(&self, _ctx: &EvaluationContext) -> ConditionResult {
8163        ConditionResult::True
8164    }
8165
8166    /// [660] Hinweis: Es ist die ID der BK-Summenzeitreihe Aggregationsebene BG anzugeben
8167    fn evaluate_660(&self, _ctx: &EvaluationContext) -> ConditionResult {
8168        ConditionResult::True
8169    }
8170
8171    /// [662] Hinweis: Es sind die Daten NGZ und die Daten der NZR anzugeben
8172    fn evaluate_662(&self, _ctx: &EvaluationContext) -> ConditionResult {
8173        ConditionResult::True
8174    }
8175
8176    /// [663] Hinweis: Es ist die ID der Marktlokation und die ZPB des ZP der NGZ anzugeben
8177    fn evaluate_663(&self, _ctx: &EvaluationContext) -> ConditionResult {
8178        ConditionResult::True
8179    }
8180
8181    /// [664] Hinweis: Es ist das BG des NB (LPB) anzugeben
8182    fn evaluate_664(&self, _ctx: &EvaluationContext) -> ConditionResult {
8183        ConditionResult::True
8184    }
8185
8186    /// [665] Hinweis: Wenn ein Zähler mit einem SMGW parametriert ist werden an dem Zähler keine OBIS-Kennzahlen angegeben Hier gibt es nur OBIS Kennzahlen vom SMGW
8187    fn evaluate_665(&self, _ctx: &EvaluationContext) -> ConditionResult {
8188        ConditionResult::True
8189    }
8190
8191    /// [667] Hinweis: Für Zeiten die bilanziert wurden, aber inzwischen keine Aggregationsverantwortung beim ÜNB vorliegt, ist eine SG8 mit SG8 - SG10 CCI+6=ZA8 oder SG 10 CCI+6 = ZA9 CAV=ZG4 und SG8 - SG9 QT...
8192    fn evaluate_667(&self, _ctx: &EvaluationContext) -> ConditionResult {
8193        ConditionResult::True
8194    }
8195
8196    /// [668] Hinweis: Dieses Segment wird nach Abschluss der Einführung der Lokationsbündelstruktur zum 01.10.2025 aus der UTILMD entfernt
8197    fn evaluate_668(&self, _ctx: &EvaluationContext) -> ConditionResult {
8198        ConditionResult::True
8199    }
8200
8201    /// [670] Hinweis: Es sind alle Netzlokationen, zu nennen, die dem gleichen Lokationsbündel angehören
8202    fn evaluate_670(&self, _ctx: &EvaluationContext) -> ConditionResult {
8203        ConditionResult::True
8204    }
8205
8206    /// [671] Hinweis: Es sind alle Marktlokationen, zu nennen, die dem gleichen Lokationsbündel angehören
8207    fn evaluate_671(&self, _ctx: &EvaluationContext) -> ConditionResult {
8208        ConditionResult::True
8209    }
8210
8211    /// [672] Hinweis: Es sind alle Technischen Ressourcen, zu nennen, die dem gleichen Lokationsbündel angehören
8212    fn evaluate_672(&self, _ctx: &EvaluationContext) -> ConditionResult {
8213        ConditionResult::True
8214    }
8215
8216    /// [673] Hinweis: Es sind alle Steuerbaren Ressourcen, zu nennen, die dem gleichen Lokationsbündel angehören
8217    fn evaluate_673(&self, _ctx: &EvaluationContext) -> ConditionResult {
8218        ConditionResult::True
8219    }
8220
8221    /// [674] Hinweis: Es sind alle Tranchen, zu nennen, die dem gleichen Lokationsbündel angehören
8222    fn evaluate_674(&self, _ctx: &EvaluationContext) -> ConditionResult {
8223        ConditionResult::True
8224    }
8225
8226    /// [675] Hinweis: Es sind alle Messlokationen, zu nennen, die Lokationsbündel angehören
8227    fn evaluate_675(&self, _ctx: &EvaluationContext) -> ConditionResult {
8228        ConditionResult::True
8229    }
8230
8231    /// [677] Hinweis: Es sind alle Netzlokationen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
8232    fn evaluate_677(&self, _ctx: &EvaluationContext) -> ConditionResult {
8233        ConditionResult::True
8234    }
8235
8236    /// [678] Hinweis: Es sind alle Marktlokationen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
8237    fn evaluate_678(&self, _ctx: &EvaluationContext) -> ConditionResult {
8238        ConditionResult::True
8239    }
8240
8241    /// [679] Hinweis: Es sind alle Technischen Ressourcen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
8242    fn evaluate_679(&self, _ctx: &EvaluationContext) -> ConditionResult {
8243        ConditionResult::True
8244    }
8245
8246    /// [680] Hinweis: Es sind alle Steuerbaren Ressourcen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
8247    fn evaluate_680(&self, _ctx: &EvaluationContext) -> ConditionResult {
8248        ConditionResult::True
8249    }
8250
8251    /// [682] Hinweis: Es sind alle Messlokationen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
8252    fn evaluate_682(&self, _ctx: &EvaluationContext) -> ConditionResult {
8253        ConditionResult::True
8254    }
8255
8256    /// [683] Hinweis: Es sind alle ID der Netzlokationen, welche der im SG5 LOC+Z16 angegebenen Marktlokation aktuell und / oder zukünftig vorgelagert sind, anzugeben
8257    fn evaluate_683(&self, _ctx: &EvaluationContext) -> ConditionResult {
8258        ConditionResult::True
8259    }
8260
8261    /// [684] Hinweis: Es sind alle ID der Technischen Ressourcen, welche der im LOC+Z16/ Z22 angegebenen Marktlokation aktuell und / oder zukünftig zugehören, anzugeben
8262    fn evaluate_684(&self, _ctx: &EvaluationContext) -> ConditionResult {
8263        ConditionResult::True
8264    }
8265
8266    /// [685] Hinweis: Es sind alle ID der Steuerbaren Ressourcen, welche der im LOC+Z20 angegebenen Technischen Ressourcen aktuell und / oder zukünftig zugeordnet sind, anzugeben.
8267    fn evaluate_685(&self, _ctx: &EvaluationContext) -> ConditionResult {
8268        ConditionResult::True
8269    }
8270
8271    /// [687] Hinweis: Es sind alle Messlokationen zu nennen, die für die Energiemengenermittlung aktuell und / oder zukünftig der im LOC+Z16/ Z22 angegebenen Marktlokation notwendig sind
8272    fn evaluate_687(&self, _ctx: &EvaluationContext) -> ConditionResult {
8273        ConditionResult::True
8274    }
8275
8276    /// [688] Hinweis: Es sind alle ID der Netzlokationen, welche der im LOC+Z16 angegebenen Marktlokation vorgelagert sind, anzugeben
8277    fn evaluate_688(&self, _ctx: &EvaluationContext) -> ConditionResult {
8278        ConditionResult::True
8279    }
8280
8281    /// [689] Hinweis: Es sind alle ID der Technischen Ressourcen, welche der im LOC+Z16 angegebenen Marktlokation zugehören, anzugeben
8282    fn evaluate_689(&self, _ctx: &EvaluationContext) -> ConditionResult {
8283        ConditionResult::True
8284    }
8285
8286    /// [690] Hinweis: Es sind alle ID der Steuerbaren Ressourcen, welche der im LOC+Z20 angegebenen Technischen Ressourcen zugeordnet sind, anzugeben
8287    fn evaluate_690(&self, _ctx: &EvaluationContext) -> ConditionResult {
8288        ConditionResult::True
8289    }
8290
8291    /// [693] Hinweis: Es sind die Daten NGZ anzugeben
8292    fn evaluate_693(&self, _ctx: &EvaluationContext) -> ConditionResult {
8293        ConditionResult::True
8294    }
8295
8296    /// [694] Hinweis: Wenn in einer Marktlokation eine ID für eine Technischen Ressource vergeben wird, müssen für alle ggf. weitere Technische Ressourcen in der Marktlokation ID vergeben werden. Hintergrund...
8297    fn evaluate_694(&self, _ctx: &EvaluationContext) -> ConditionResult {
8298        ConditionResult::True
8299    }
8300
8301    /// [695] Hinweis: Verwendung, wenn Rolle LF einem Unternehmen NB zugeordnet ist
8302    fn evaluate_695(&self, _ctx: &EvaluationContext) -> ConditionResult {
8303        ConditionResult::True
8304    }
8305
8306    /// [696] Hinweis: Verwendung, nur wenn die Rolle LF nicht einem Unternehmen NB zugeordnet ist
8307    fn evaluate_696(&self, _ctx: &EvaluationContext) -> ConditionResult {
8308        ConditionResult::True
8309    }
8310
8311    /// [698] Hinweis: Für eine erzeugende Marktlokation muss für jede Technische Ressource eine ID der Technischen Ressourcen vergeben werden. Dies ist notwendig um die Nennleistung der Technische Ressource b...
8312    fn evaluate_698(&self, _ctx: &EvaluationContext) -> ConditionResult {
8313        ConditionResult::True
8314    }
8315
8316    /// [699] Hinweis: Es ist die ID der Steuerbare Ressource zu nennen über die die Technische Ressource gesteuert wird
8317    fn evaluate_699(&self, _ctx: &EvaluationContext) -> ConditionResult {
8318        ConditionResult::True
8319    }
8320
8321    /// [700] Hinweis: Es ist die ID der Netzlokation zu nennen über die die Technische Ressource gesteuert wird
8322    fn evaluate_700(&self, _ctx: &EvaluationContext) -> ConditionResult {
8323        ConditionResult::True
8324    }
8325
8326    /// [704] Hinweis: Segment ist zu verwenden, wenn es in Anfrage vorhanden war
8327    fn evaluate_704(&self, _ctx: &EvaluationContext) -> ConditionResult {
8328        ConditionResult::True
8329    }
8330
8331    /// [705] Hinweis: Wenn die Aktion eines Sequenzdiagramms \"Rückmeldung auf Änderung\" durchgeführt wird
8332    fn evaluate_705(&self, _ctx: &EvaluationContext) -> ConditionResult {
8333        ConditionResult::True
8334    }
8335
8336    /// [706] Hinweis: Wenn die Aktion eines Sequenzdiagramms \"Bestellung einer Änderung von Stammdaten...\" durchgeführt wird, mit dem Ziel ein Datenclearing durchzuführen
8337    fn evaluate_706(&self, ctx: &EvaluationContext) -> ConditionResult {
8338        ctx.external.evaluate("data_clearing_required")
8339    }
8340
8341    /// [707] Hinweis: für weitere Details siehe Kapitel \"SG6 Verwendungszeitraum der Daten\"
8342    fn evaluate_707(&self, _ctx: &EvaluationContext) -> ConditionResult {
8343        ConditionResult::True
8344    }
8345
8346    /// [708] Hinweis: Wenn die Aktion \"Ankündigung der Zuordnung des E/G zur Marktlokation\" durchgeführt wird
8347    fn evaluate_708(&self, _ctx: &EvaluationContext) -> ConditionResult {
8348        ConditionResult::True
8349    }
8350
8351    /// [709] Hinweis: Wenn die Aktion \"Zuordnung des E/G zur Marktlokation aufgrund fehlender Antwort\" durchgeführt wird
8352    fn evaluate_709(&self, _ctx: &EvaluationContext) -> ConditionResult {
8353        ConditionResult::True
8354    }
8355
8356    /// [710] Hinweis: Wenn die Aktion \"Ankündigung der Zuordnung des LFN zur Marktlokation bzw. Tranche\" durchgeführt wird
8357    fn evaluate_710(&self, _ctx: &EvaluationContext) -> ConditionResult {
8358        ConditionResult::True
8359    }
8360
8361    /// [711] Hinweis: Wenn die Aktion \"Zuordnung des LFN zur Marktlokation bzw. Tranche aufgrund fehlender Antwort\" durchgeführt wird
8362    fn evaluate_711(&self, _ctx: &EvaluationContext) -> ConditionResult {
8363        ConditionResult::True
8364    }
8365
8366    /// [712] Hinweis: Wenn die Aktion \"Ankündigung der Beendigung der Zuordnung des LF zur Marktlokation bzw. Tranche\" durchgeführt wird
8367    fn evaluate_712(&self, _ctx: &EvaluationContext) -> ConditionResult {
8368        ConditionResult::True
8369    }
8370
8371    /// [713] Hinweis: Wenn die Aktion \"Beendigung der Zuordnung des LF zur Marktlokation bzw. Tranche aufgrund fehlender Antwort\" durchgeführt wird
8372    fn evaluate_713(&self, _ctx: &EvaluationContext) -> ConditionResult {
8373        ConditionResult::True
8374    }
8375
8376    /// [714] Hinweis: Es ist bei einer unterjährigen Gebietsübernahme möglich hier den bisherigen NB zu nennen um aufzuzeigen, dass die im PIA+5 dieser SG8 genannten Gruppenartikel-ID bzw. Artikel-ID auf die...
8377    fn evaluate_714(&self, _ctx: &EvaluationContext) -> ConditionResult {
8378        ConditionResult::True
8379    }
8380
8381    /// [715] Hinweis: Dieser Transaktionsgrund darf für die betroffene Lokation nur angewendet werden wenn zuvor vom LF eine Anfrage Abr.-Daten BK-Abr. in die Vergangenheit erfolgte oder eine Korrektur zuvor m...
8382    fn evaluate_715(&self, _ctx: &EvaluationContext) -> ConditionResult {
8383        ConditionResult::True
8384    }
8385
8386    /// [716] Hinweis: Wenn die Aktion eines Sequenzdiagramms \"Rückmeldung auf Abrechnungsdaten\" durchgeführt wird
8387    fn evaluate_716(&self, _ctx: &EvaluationContext) -> ConditionResult {
8388        ConditionResult::True
8389    }
8390
8391    /// [717] Hinweis: Wenn die Aktion des Sequenzdiagramms \"Bestellung einer Änderung von Abrechnungsdaten\" durchgeführt wird, mit dem Ziel ein Datenclearing durchzuführen
8392    fn evaluate_717(&self, ctx: &EvaluationContext) -> ConditionResult {
8393        ctx.external.evaluate("data_clearing_required")
8394    }
8395
8396    /// [718] Hinweis: Es sind alle Tranchen der im SG5 LOC+Z16 (Marktlokation) genannten Marktlokation anzugeben, die für die im SG6 (Verwendungszeitraum der Daten) genannten Zeiträume vorhanden sind
8397    fn evaluate_718(&self, _ctx: &EvaluationContext) -> ConditionResult {
8398        ConditionResult::True
8399    }
8400
8401    /// [719] Hinweis: Dieser Transaktionsgrund darf für die betroffene Lokation nur angewendet werden wenn der LF auf eine Anfrage mit diesem Transaktionsgrund antwortet oder eine Anfrage Abr.-Daten BK-Abr. in...
8402    fn evaluate_719(&self, _ctx: &EvaluationContext) -> ConditionResult {
8403        ConditionResult::True
8404    }
8405
8406    /// [902] Format: Möglicher Wert: ≥ 0
8407    fn evaluate_902(&self, _ctx: &EvaluationContext) -> ConditionResult {
8408        // Format condition — informational, always applies
8409        ConditionResult::True
8410    }
8411
8412    /// [910] Format: Möglicher Wert: < 0 oder ≥ 0
8413    fn evaluate_910(&self, _ctx: &EvaluationContext) -> ConditionResult {
8414        // Format condition — informational, always applies
8415        ConditionResult::True
8416    }
8417
8418    /// [914] Format: Möglicher Wert: > 0
8419    fn evaluate_914(&self, ctx: &EvaluationContext) -> ConditionResult {
8420        ctx.format_check("SEQ", 1, 0, |val| validate_numeric(val, ">", 0.0))
8421    }
8422
8423    /// [922] Format: TR-ID
8424    fn evaluate_922(&self, _ctx: &EvaluationContext) -> ConditionResult {
8425        // Format condition — informational, always applies
8426        ConditionResult::True
8427    }
8428
8429    /// [926] Format: Möglicher Wert: 0
8430    fn evaluate_926(&self, _ctx: &EvaluationContext) -> ConditionResult {
8431        // Format condition — informational, always applies
8432        ConditionResult::True
8433    }
8434
8435    /// [930] Format: max. 2 Nachkommastellen
8436    fn evaluate_930(&self, _ctx: &EvaluationContext) -> ConditionResult {
8437        // Format condition — informational, always applies
8438        ConditionResult::True
8439    }
8440
8441    /// [931] Format: ZZZ = +00
8442    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
8443        ctx.format_check("DTM", 0, 1, validate_timezone_utc)
8444    }
8445
8446    /// [932] Format: HHMM = 2200
8447    fn evaluate_932(&self, ctx: &EvaluationContext) -> ConditionResult {
8448        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2200"))
8449    }
8450
8451    /// [933] Format: HHMM = 2300
8452    fn evaluate_933(&self, ctx: &EvaluationContext) -> ConditionResult {
8453        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2300"))
8454    }
8455
8456    /// [937] Format: keine Nachkommastelle
8457    fn evaluate_937(&self, ctx: &EvaluationContext) -> ConditionResult {
8458        ctx.format_check("SEQ", 1, 0, |val| validate_max_decimal_places(val, 0))
8459    }
8460
8461    /// [938] Format: Möglicher Wert: <= 10
8462    fn evaluate_938(&self, _ctx: &EvaluationContext) -> ConditionResult {
8463        ConditionResult::True
8464    }
8465
8466    /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
8467    fn evaluate_939(&self, ctx: &EvaluationContext) -> ConditionResult {
8468        ctx.format_check("COM", 0, 0, validate_email)
8469    }
8470
8471    /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
8472    fn evaluate_940(&self, ctx: &EvaluationContext) -> ConditionResult {
8473        ctx.format_check("COM", 0, 0, validate_phone)
8474    }
8475
8476    /// [942] Format: n1-n2-n1-n3
8477    fn evaluate_942(&self, _ctx: &EvaluationContext) -> ConditionResult {
8478        // Format condition — informational, always applies
8479        ConditionResult::True
8480    }
8481
8482    /// [943] Format: n1-n2-n1
8483    fn evaluate_943(&self, _ctx: &EvaluationContext) -> ConditionResult {
8484        // Format condition — informational, always applies
8485        ConditionResult::True
8486    }
8487
8488    /// [946] Format: max. 11 Nachkommastellen
8489    fn evaluate_946(&self, _ctx: &EvaluationContext) -> ConditionResult {
8490        // Format condition — informational, always applies
8491        ConditionResult::True
8492    }
8493
8494    /// [948] Format: n1-n2-n1-n8-n2
8495    fn evaluate_948(&self, _ctx: &EvaluationContext) -> ConditionResult {
8496        // Format condition — informational, always applies
8497        ConditionResult::True
8498    }
8499
8500    /// [950] Format: Marktlokations-ID
8501    fn evaluate_950(&self, _ctx: &EvaluationContext) -> ConditionResult {
8502        // Format condition — informational, always applies
8503        ConditionResult::True
8504    }
8505
8506    /// [951] Format: Zählpunktbezeichnung
8507    fn evaluate_951(&self, _ctx: &EvaluationContext) -> ConditionResult {
8508        // Format condition — informational, always applies
8509        ConditionResult::True
8510    }
8511
8512    /// [952] Format: Gerätenummer nach DIN 43863-5
8513    fn evaluate_952(&self, _ctx: &EvaluationContext) -> ConditionResult {
8514        // Format condition — informational, always applies
8515        ConditionResult::True
8516    }
8517
8518    /// [955] Format: Möglicher Wert: < 100
8519    fn evaluate_955(&self, _ctx: &EvaluationContext) -> ConditionResult {
8520        // Format condition — informational, always applies
8521        ConditionResult::True
8522    }
8523
8524    /// [957] Format: n1-n2-n1-n8
8525    fn evaluate_957(&self, _ctx: &EvaluationContext) -> ConditionResult {
8526        // Format condition — informational, always applies
8527        ConditionResult::True
8528    }
8529
8530    /// [960] Format: Netzlokations-ID
8531    fn evaluate_960(&self, _ctx: &EvaluationContext) -> ConditionResult {
8532        // Format condition — informational, always applies
8533        ConditionResult::True
8534    }
8535
8536    /// [961] Format: SR-ID
8537    fn evaluate_961(&self, _ctx: &EvaluationContext) -> ConditionResult {
8538        // Format condition — informational, always applies
8539        ConditionResult::True
8540    }
8541
8542    /// [967] Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4
8543    fn evaluate_967(&self, _ctx: &EvaluationContext) -> ConditionResult {
8544        // Format condition — informational, always applies
8545        ConditionResult::True
8546    }
8547
8548    /// [2001] Segmentgruppe ist mindestens zweimal je SG4 IDE+24 (Vorgang) anzugeben
8549    fn evaluate_2001(&self, ctx: &EvaluationContext) -> ConditionResult {
8550        // Cardinality: at least twice per SG4 IDE+24
8551        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
8552        ConditionResult::from(ide_count > 0)
8553    }
8554
8555    /// [2002] Für jede Produktpaket-ID im SG8 SEQ+Z79 (Erforderliches Produkt) DE1050 genau einmal anzugeben
8556    fn evaluate_2002(&self, ctx: &EvaluationContext) -> ConditionResult {
8557        let seq_segs = ctx.find_segments("SEQ");
8558        let has_z79 = seq_segs.iter().any(|s| {
8559            s.elements
8560                .first()
8561                .and_then(|e| e.first())
8562                .is_some_and(|v| v == "Z79")
8563        });
8564        ConditionResult::from(has_z79)
8565    }
8566
8567    /// [2003] Einmal für jede ruhende Marktlokation, die der Marktlokation \"Kundenanlage\" aus dem SG5 LOC+Z16 (Marktlokation) ab dem Zeitpunkt aus dem SG4 DTM+92 (Beginn zum) untergeordnet ist
8568    fn evaluate_2003(&self, _ctx: &EvaluationContext) -> ConditionResult {
8569        // TODO: implement
8570        ConditionResult::Unknown
8571    }
8572
8573    /// [2004] Segmentgruppe ist genau einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 (Verwendungszeitraum der Daten: "Gültige Daten") anzugeben
8574    // REVIEW: Collects Zeitraum-IDs from SG6 RFF+Z49 DE1156 (elements[0][2]) by correlating qualifier (elements[0][0]) and ID (elements[0][2]) vectors via shared SG6 instance index. Then collects all SEQ DE1050 (elements[1][0]) references from SG8 instances. For each Zeitraum-ID from SG6 RFF+Z49, counts matching SG8 SEQ references; returns False if any count != 1 (violates 'exactly once' cardinality). Returns Unknown if no RFF+Z49 Zeitraum-IDs exist. (medium confidence)
8575    fn evaluate_2004(&self, ctx: &EvaluationContext) -> ConditionResult {
8576        let rff_qualifiers = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG6"]);
8577        let rff_zeitraum_ids = ctx.collect_group_values("RFF", 0, 2, &["SG4", "SG6"]);
8578
8579        let zeitraum_ids: Vec<String> = rff_qualifiers
8580            .iter()
8581            .filter(|(_, qual)| qual.as_str() == "Z49")
8582            .filter_map(|(idx, _)| {
8583                rff_zeitraum_ids
8584                    .iter()
8585                    .find(|(i, v)| i == idx && !v.is_empty())
8586                    .map(|(_, v)| v.clone())
8587            })
8588            .collect();
8589
8590        if zeitraum_ids.is_empty() {
8591            return ConditionResult::Unknown;
8592        }
8593
8594        let seq_refs = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
8595
8596        for zid in &zeitraum_ids {
8597            let count = seq_refs.iter().filter(|(_, v)| v == zid).count();
8598            if count != 1 {
8599                return ConditionResult::False;
8600            }
8601        }
8602
8603        ConditionResult::True
8604    }
8605
8606    /// [2005] Segmentgruppe ist mindesten einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 (Verwendungszeitraum der Daten: "Gültige Daten") anzugeben
8607    // REVIEW: Same logic as 2004 but enforces 'at least once' cardinality (count >= 1) instead of 'exactly once'. Collects Zeitraum-IDs from SG6 RFF+Z49 DE1156 and checks that each has at least one matching SG8 SEQ DE1050 reference. Returns False if any Zeitraum-ID has zero matching SG8 references. (medium confidence)
8608    fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
8609        let rff_qualifiers = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG6"]);
8610        let rff_zeitraum_ids = ctx.collect_group_values("RFF", 0, 2, &["SG4", "SG6"]);
8611
8612        let zeitraum_ids: Vec<String> = rff_qualifiers
8613            .iter()
8614            .filter(|(_, qual)| qual.as_str() == "Z49")
8615            .filter_map(|(idx, _)| {
8616                rff_zeitraum_ids
8617                    .iter()
8618                    .find(|(i, v)| i == idx && !v.is_empty())
8619                    .map(|(_, v)| v.clone())
8620            })
8621            .collect();
8622
8623        if zeitraum_ids.is_empty() {
8624            return ConditionResult::Unknown;
8625        }
8626
8627        let seq_refs = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
8628
8629        for zid in &zeitraum_ids {
8630            let count = seq_refs.iter().filter(|(_, v)| v == zid).count();
8631            if count == 0 {
8632                return ConditionResult::False;
8633            }
8634        }
8635
8636        ConditionResult::True
8637    }
8638
8639    /// [2010] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [266] ∧ [479] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID ...
8640    fn evaluate_2010(&self, _ctx: &EvaluationContext) -> ConditionResult {
8641        // TODO: implement
8642        ConditionResult::Unknown
8643    }
8644
8645    /// [2011] Segmentgruppe ist genau einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 / Z53 (Verwendungszeitraum der Daten: "Gültige Daten" / "Keine Daten") aus der Anfragennachricht aus SG6 RFF+TN ...
8646    /// EXTERNAL: Requires context from outside the message.
8647    // REVIEW: Condition requires checking Zeitraum-IDs from DE1156 of SG6 RFF+Z49/Z53 ('Verwendungszeitraum der Daten: Gültige Daten / Keine Daten') that originated in the REQUEST message referenced by SG6 RFF+TN DE1154. The referenced request message is a separate EDIFACT interchange not present in the current message being validated. The cardinality constraint ('exactly once per Zeitraum-ID from the request') is therefore an external business context check that depends on data from a prior message in the business process. (medium confidence)
8648    fn evaluate_2011(&self, ctx: &EvaluationContext) -> ConditionResult {
8649        ctx.external
8650            .evaluate("request_message_zeitraum_ids_present")
8651    }
8652
8653    /// [2012] Segmentgruppe ist genau einmal für die Angabe der Informativen Daten der Marktlokation anzugeben
8654    fn evaluate_2012(&self, _ctx: &EvaluationContext) -> ConditionResult {
8655        // TODO: implement
8656        ConditionResult::Unknown
8657    }
8658
8659    /// [2013] Mindesten einmal anzugeben wenn kein SG6 RFF+Z54 (Verwendungszeitraum der Daten: Im System keine Daten vorhanden) vorhanden
8660    fn evaluate_2013(&self, ctx: &EvaluationContext) -> ConditionResult {
8661        // Check: condition applies when no RFF+Z54 exists
8662        ctx.lacks_qualifier("RFF", 0, "Z54")
8663    }
8664
8665    /// [2014] Mindesten einmal anzugeben wenn kein SG6 RFF+Z47 (Verwendungszeitraum der Daten: Im System vorhandene Daten) vorhanden
8666    fn evaluate_2014(&self, ctx: &EvaluationContext) -> ConditionResult {
8667        // Check: condition applies when no RFF+Z47 exists
8668        ctx.lacks_qualifier("RFF", 0, "Z47")
8669    }
8670
8671    /// [2015] Einmal für jede ruhende Marktlokation, die der Marktlokation \"Kundenanlage\" aus dem SG5 LOC+Z16 (Marktlokation) untergeordnet ist
8672    fn evaluate_2015(&self, _ctx: &EvaluationContext) -> ConditionResult {
8673        // TODO: implement
8674        ConditionResult::Unknown
8675    }
8676
8677    /// [2016] Je SG5 LOC+Z16 (Marktlokation) ist genau einmal die Segmentgruppe anzugeben
8678    fn evaluate_2016(&self, ctx: &EvaluationContext) -> ConditionResult {
8679        // Cardinality: exactly once per SG5 LOC+Z16 (Marktlokation)
8680        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z16").len();
8681        ConditionResult::from(loc_count > 0)
8682    }
8683
8684    /// [2017] Je SG5 LOC+Z17 (Messlokation) ist genau einmal die Segmentgruppe anzugeben
8685    fn evaluate_2017(&self, ctx: &EvaluationContext) -> ConditionResult {
8686        // Cardinality: exactly once per SG5 LOC+Z17 (Messlokation)
8687        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z17").len();
8688        ConditionResult::from(loc_count > 0)
8689    }
8690
8691    /// [2018] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [266] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfol...
8692    fn evaluate_2018(&self, _ctx: &EvaluationContext) -> ConditionResult {
8693        // TODO: implement
8694        ConditionResult::Unknown
8695    }
8696
8697    /// [2060] Wenn SG10 CAV+NZR ist die Segmentgruppe genau zwei Mal je IDE+24 anzugeben
8698    fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
8699        // Check: CAV+NZR exists (then segment group exactly twice per IDE+24)
8700        let found = ctx.find_segments("CAV").iter().any(|s| {
8701            s.elements
8702                .first()
8703                .and_then(|e| e.first())
8704                .is_some_and(|v| v == "NZR")
8705        });
8706        ConditionResult::from(found)
8707    }
8708
8709    /// [2061] Segment bzw. Segmentgruppe ist genau einmal je SG4 IDE (Vorgang) anzugeben
8710    fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
8711        // Cardinality: exactly once per SG4 IDE (always true for single-transaction messages)
8712        let ide_count = ctx.find_segments("IDE").len();
8713        ConditionResult::from(ide_count > 0)
8714    }
8715
8716    /// [2071] Für die ID der LieferantensummenZR einmal je SG4 IDE+24 (Vorgang)
8717    fn evaluate_2071(&self, ctx: &EvaluationContext) -> ConditionResult {
8718        // Cardinality: LieferantensummenZR once per SG4 IDE+24
8719        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
8720        ConditionResult::from(ide_count > 0)
8721    }
8722
8723    /// [2073] Für die ID der BilanzkreissummenZR einmal je SG4 IDE+24 (Vorgang)
8724    fn evaluate_2073(&self, ctx: &EvaluationContext) -> ConditionResult {
8725        // Cardinality: BilanzkreissummenZR once per SG4 IDE+24
8726        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
8727        ConditionResult::from(ide_count > 0)
8728    }
8729
8730    /// [2075] Für die ID der Zeitreihen (nicht bei EEG-EUZ und EUZ der AAÜZ) in der Clearingliste einmal je SG4 IDE+24 (Vorgang)
8731    fn evaluate_2075(&self, ctx: &EvaluationContext) -> ConditionResult {
8732        // Cardinality: Zeitreihen (not EEG-EUZ/AAÜZ) once per SG4 IDE+24
8733        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
8734        ConditionResult::from(ide_count > 0)
8735    }
8736
8737    /// [2080] Segmentgruppe ist max. zweimal je SG4 IDE+24 (Vorgang) anzugeben
8738    fn evaluate_2080(&self, ctx: &EvaluationContext) -> ConditionResult {
8739        // Cardinality: max twice per SG4 IDE+24
8740        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
8741        ConditionResult::from(ide_count > 0)
8742    }
8743
8744    /// [2095] Je SG5 LOC+Z15 (MaBiS-Zählpunkt) ist genau einmal die Segmentgruppe anzugeben
8745    fn evaluate_2095(&self, ctx: &EvaluationContext) -> ConditionResult {
8746        // Cardinality: exactly once per SG5 LOC+Z15 (MaBiS-Zählpunkt)
8747        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z15").len();
8748        ConditionResult::from(loc_count > 0)
8749    }
8750
8751    /// [2096] Segmentgruppe ist genau zweimal je SG4 IDE anzugeben
8752    fn evaluate_2096(&self, ctx: &EvaluationContext) -> ConditionResult {
8753        // Cardinality: exactly twice per SG4 IDE
8754        let ide_count = ctx.find_segments("IDE").len();
8755        ConditionResult::from(ide_count > 0)
8756    }
8757
8758    /// [2119] Je SG8 SEQ+Z13/ ZG0 (Smartmeter-Gateway) ist genau einmal die Segmentgruppe anzugeben
8759    fn evaluate_2119(&self, ctx: &EvaluationContext) -> ConditionResult {
8760        // Cardinality: exactly once per SG8 SEQ+Z13/ZG0 (Smartmeter-Gateway)
8761        let found = ctx.find_segments("SEQ").iter().any(|s| {
8762            s.elements
8763                .first()
8764                .and_then(|e| e.first())
8765                .is_some_and(|v| v == "Z13" || v == "ZG0")
8766        });
8767        ConditionResult::from(found)
8768    }
8769
8770    /// [2140] Für die ID der LieferantensummenZR einmal je SG4 IDE+Z01 (Liste)
8771    fn evaluate_2140(&self, ctx: &EvaluationContext) -> ConditionResult {
8772        // Cardinality: LieferantensummenZR once per SG4 IDE+Z01
8773        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "Z01").len();
8774        ConditionResult::from(ide_count > 0)
8775    }
8776
8777    /// [2182] Segmentgruppe ist genau einmal je SG8 SEQ+Z01/ Z80/ Z81/ Z98 (Daten der Marktlokation/ Erwartete Daten der Marktlokation/ Im System vorhandene Daten der Marktlokation) anzugeben
8778    fn evaluate_2182(&self, ctx: &EvaluationContext) -> ConditionResult {
8779        // Cardinality: exactly once per SG8 SEQ+Z01/Z80/Z81/Z98
8780        let found = ctx.find_segments("SEQ").iter().any(|s| {
8781            s.elements
8782                .first()
8783                .and_then(|e| e.first())
8784                .is_some_and(|v| ["Z01", "Z80", "Z81", "Z98"].contains(&v.as_str()))
8785        });
8786        ConditionResult::from(found)
8787    }
8788
8789    /// [2183] Segmentgruppe ist genau zweimal je SG8 SEQ+Z01/ Z80/ Z81/ Z98 (Daten der Marktlokation/ Erwartete Daten der Marktlokation/ Im System vorhandene Daten der Marktlokation) anzugeben
8790    fn evaluate_2183(&self, ctx: &EvaluationContext) -> ConditionResult {
8791        // Cardinality: exactly twice per SG8 SEQ+Z01/Z80/Z81/Z98
8792        let found = ctx.find_segments("SEQ").iter().any(|s| {
8793            s.elements
8794                .first()
8795                .and_then(|e| e.first())
8796                .is_some_and(|v| ["Z01", "Z80", "Z81", "Z98"].contains(&v.as_str()))
8797        });
8798        ConditionResult::from(found)
8799    }
8800
8801    /// [2207] Für die ID der Lieferanten-ausfall-arbeits-summen-zeitreihe einmal je SG4 IDE+Z01 (Liste)
8802    fn evaluate_2207(&self, ctx: &EvaluationContext) -> ConditionResult {
8803        // Cardinality: Lieferantenausfallarbeitssummenzeitreihe once per SG4 IDE+Z01
8804        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "Z01").len();
8805        ConditionResult::from(ide_count > 0)
8806    }
8807
8808    /// [2225] Einmal für jede Marktlokation bzw. Tranche für die der LF nicht die gemeldete Ansicht des NB teilt
8809    fn evaluate_2225(&self, _ctx: &EvaluationContext) -> ConditionResult {
8810        // TODO: implement
8811        ConditionResult::Unknown
8812    }
8813
8814    /// [2236] Code einmal je SG4 IDE+24 (Vorgang)
8815    fn evaluate_2236(&self, ctx: &EvaluationContext) -> ConditionResult {
8816        // Cardinality: code once per SG4 IDE+24
8817        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
8818        ConditionResult::from(ide_count > 0)
8819    }
8820
8821    /// [2252] Einmal für jede Marktlokation bzw. Tranche, die in der Lieferantenausfallarbeits-summenzeitreihe berücksichtigt wurde
8822    fn evaluate_2252(&self, _ctx: &EvaluationContext) -> ConditionResult {
8823        // TODO: implement
8824        ConditionResult::Unknown
8825    }
8826
8827    /// [2261] Für jede ID im SG5 LOC+Z21 (Tranche) DE3225, mindestens einmal anzugeben
8828    fn evaluate_2261(&self, ctx: &EvaluationContext) -> ConditionResult {
8829        // Cardinality: at least once per LOC+Z21 (Tranche) ID
8830        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z21").len();
8831        ConditionResult::from(loc_count > 0)
8832    }
8833
8834    /// [2284] Für jede Messlokations-ID im SG5 LOC+Z17 (Messlokation) DE3225 genau einmal anzugeben
8835    fn evaluate_2284(&self, ctx: &EvaluationContext) -> ConditionResult {
8836        // Cardinality: exactly once per LOC+Z17 (Messlokation) ID
8837        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z17").len();
8838        ConditionResult::from(loc_count > 0)
8839    }
8840
8841    /// [2286] Für jede SEQ+ZF3 (Daten der Messlokation) mindestens einmal anzugeben
8842    fn evaluate_2286(&self, ctx: &EvaluationContext) -> ConditionResult {
8843        // Cardinality: at least once per SEQ+ZF3 (Daten der Messlokation)
8844        let found = !ctx.find_segments_with_qualifier("SEQ", 0, "ZF3").is_empty();
8845        ConditionResult::from(found)
8846    }
8847
8848    /// [2287] Für jede SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) mindestens einmal anzugeben
8849    fn evaluate_2287(&self, ctx: &EvaluationContext) -> ConditionResult {
8850        // Cardinality: at least once per SEQ+Z03/ZF5 (Zähleinrichtungsdaten)
8851        let found = ctx.find_segments("SEQ").iter().any(|s| {
8852            s.elements
8853                .first()
8854                .and_then(|e| e.first())
8855                .is_some_and(|v| v == "Z03" || v == "ZF5")
8856        });
8857        ConditionResult::from(found)
8858    }
8859
8860    /// [2288] Einmal für jede Zeitreihe, die in der DZR berücksichtigt wurde
8861    fn evaluate_2288(&self, _ctx: &EvaluationContext) -> ConditionResult {
8862        // TODO: implement
8863        ConditionResult::Unknown
8864    }
8865
8866    /// [2307] Für jede ID im SG5 LOC+Z21 (Tranche) DE3225 genau einmal anzugeben
8867    fn evaluate_2307(&self, ctx: &EvaluationContext) -> ConditionResult {
8868        // Cardinality: exactly once per LOC+Z21 (Tranche) ID
8869        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z21").len();
8870        ConditionResult::from(loc_count > 0)
8871    }
8872
8873    /// [2308] Für jede ID im SG5 LOC+Z16 (Marktlokation) DE3225, mindestens einmal anzugeben
8874    fn evaluate_2308(&self, ctx: &EvaluationContext) -> ConditionResult {
8875        // Cardinality: at least once per LOC+Z16 (Marktlokation) ID
8876        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z16").len();
8877        ConditionResult::from(loc_count > 0)
8878    }
8879
8880    /// [2309] Für jede ID im SG5 LOC+Z17 (Messlokation) DE3225 mindestens einmal anzugeben
8881    fn evaluate_2309(&self, ctx: &EvaluationContext) -> ConditionResult {
8882        // Cardinality: at least once per LOC+Z17 (Messlokation) ID
8883        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z17").len();
8884        ConditionResult::from(loc_count > 0)
8885    }
8886
8887    /// [2310] Für jede ID im SG5 LOC+Z16 (Marktlokation) DE3225 genau einmal anzugeben
8888    fn evaluate_2310(&self, ctx: &EvaluationContext) -> ConditionResult {
8889        // Cardinality: exactly once per LOC+Z16 (Marktlokation) ID
8890        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z16").len();
8891        ConditionResult::from(loc_count > 0)
8892    }
8893
8894    /// [2311] Für jede ID im SG5 LOC+Z21 (Tranche) DE3225, mindestens einmal anzugeben
8895    fn evaluate_2311(&self, ctx: &EvaluationContext) -> ConditionResult {
8896        // Cardinality: at least once per LOC+Z21 (Tranche) ID
8897        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z21").len();
8898        ConditionResult::from(loc_count > 0)
8899    }
8900
8901    /// [2312] Wenn der Objektcode \"9992000001256\" (Netzlokation) im DE1154 des selben RFF+Z33 nicht vorhanden ist, ist das RFF+Z33 in derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des...
8902    fn evaluate_2312(&self, ctx: &EvaluationContext) -> ConditionResult {
8903        // Check: RFF+Z33 DE1154 does NOT contain Objektcode 9992000001256 (Netzlokation)
8904        let rff_z33 = ctx.find_segments_with_qualifier("RFF", 0, "Z33");
8905        let has_netzlokation = rff_z33.iter().any(|s| {
8906            s.elements
8907                .first()
8908                .and_then(|e| e.get(1))
8909                .is_some_and(|v| v == "9992000001256")
8910        });
8911        ConditionResult::from(!has_netzlokation)
8912    }
8913
8914    /// [2313] Je SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des Lokationsbündels) genau einmal anzugeben
8915    fn evaluate_2313(&self, ctx: &EvaluationContext) -> ConditionResult {
8916        // Check: SG8 with SEQ+Z58/ZC9/ZD0/ZD6 exists (cardinality constraint)
8917        let found = ctx.find_segments("SEQ").iter().any(|s| {
8918            s.elements
8919                .first()
8920                .and_then(|e| e.first())
8921                .is_some_and(|v| ["Z58", "ZC9", "ZD0", "ZD6"].contains(&v.as_str()))
8922        });
8923        ConditionResult::from(found)
8924    }
8925
8926    /// [2317] Wenn in derselben SG8 SEQ+Z04/ ZF7 (Wandlerdaten) das SG10 CCI+++Z25 (Wandler) CAV+MIW/MPW/MUW vorhanden, ist das Segment mindestens zweimal anzugeben
8927    fn evaluate_2317(&self, ctx: &EvaluationContext) -> ConditionResult {
8928        // Check: SG10 CCI+++Z25 has CAV+MIW/MPW/MUW (Wandler types)
8929        let has_cav = ctx.find_segments("CAV").iter().any(|s| {
8930            s.elements
8931                .first()
8932                .and_then(|e| e.first())
8933                .is_some_and(|v| ["MIW", "MPW", "MUW"].contains(&v.as_str()))
8934        });
8935        ConditionResult::from(has_cav)
8936    }
8937
8938    /// [2318] Wenn in derselben SG8 SEQ+Z04/ ZF7 (Wandlerdaten) das SG10 CCI+++Z25 (Wandler) CAV+MBW (Blockstromwandler) vorhanden, ist das Segment genau einmal anzugeben
8939    fn evaluate_2318(&self, ctx: &EvaluationContext) -> ConditionResult {
8940        // Check: SG10 CCI+++Z25 has CAV+MBW (Blockstromwandler)
8941        let has_cav = ctx.find_segments("CAV").iter().any(|s| {
8942            s.elements
8943                .first()
8944                .and_then(|e| e.first())
8945                .is_some_and(|v| v == "MBW")
8946        });
8947        ConditionResult::from(has_cav)
8948    }
8949
8950    /// [2344] Einmal für jede Marktlokation bzw. Tranche, die in der DZÜ / BG-CL / LF-SZR berücksichtigt wurde
8951    fn evaluate_2344(&self, _ctx: &EvaluationContext) -> ConditionResult {
8952        // TODO: implement
8953        ConditionResult::Unknown
8954    }
8955
8956    /// [2350] Für jedes SMGW das im SEQ+Z13/ ZG0 (Smartmeter-Gateway) SG10 CCI+++Z75 CAV+Z30 (Gerätenummer) genannt ist, mindestens einmal je SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) das mit SG8 RFF+Z14 (Referenz...
8957    fn evaluate_2350(&self, _ctx: &EvaluationContext) -> ConditionResult {
8958        // TODO: implement
8959        ConditionResult::Unknown
8960    }
8961
8962    /// [2351] Einmal je ZP einer BK-SZR, in der die Marktlokation in die Berechnung der abgerechneten Summenzeitreihe aufgenommen wurde
8963    fn evaluate_2351(&self, _ctx: &EvaluationContext) -> ConditionResult {
8964        // TODO: implement
8965        ConditionResult::Unknown
8966    }
8967
8968    /// [2352] Einmal je ZP einer BG-SZR, in der die Marktlokation in die Berechnung der abgerechneten Summenzeitreihe aufge-nommen wurde
8969    fn evaluate_2352(&self, _ctx: &EvaluationContext) -> ConditionResult {
8970        // TODO: implement
8971        ConditionResult::Unknown
8972    }
8973
8974    /// [2356] Je SG5 LOC+Z18 (Netzlokation) ist genau einmal die Segmentgruppe anzugeben
8975    fn evaluate_2356(&self, ctx: &EvaluationContext) -> ConditionResult {
8976        // Cardinality: exactly once per SG5 LOC+Z18 (Netzlokation)
8977        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z18").len();
8978        ConditionResult::from(loc_count > 0)
8979    }
8980
8981    /// [2357] Je SG5 LOC+Z20 (Technische Ressource) ist genau einmal die Segmentgruppe anzugeben
8982    fn evaluate_2357(&self, ctx: &EvaluationContext) -> ConditionResult {
8983        // Cardinality: exactly once per SG5 LOC+Z20 (Technische Ressource)
8984        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z20").len();
8985        ConditionResult::from(loc_count > 0)
8986    }
8987
8988    /// [2358] Je SG5 LOC+Z19 (Steuerbare Ressource) ist genau einmal die Segmentgruppe anzugeben
8989    fn evaluate_2358(&self, ctx: &EvaluationContext) -> ConditionResult {
8990        // Cardinality: exactly once per SG5 LOC+Z19 (Steuerbare Ressource)
8991        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z19").len();
8992        ConditionResult::from(loc_count > 0)
8993    }
8994
8995    /// [2359] Für jede ID im SG5 LOC+Z16 / Z17 / Z20 (Marktlokation / Messlokation / Technische Ressource) DE3225 mindestens einmal anzugeben
8996    fn evaluate_2359(&self, ctx: &EvaluationContext) -> ConditionResult {
8997        // Cardinality: at least once per LOC+Z16/Z17/Z20 ID
8998        let found = ctx.find_segments("LOC").iter().any(|s| {
8999            s.elements
9000                .first()
9001                .and_then(|e| e.first())
9002                .is_some_and(|v| ["Z16", "Z17", "Z20"].contains(&v.as_str()))
9003        });
9004        ConditionResult::from(found)
9005    }
9006
9007    /// [2360] Für jede ID im SG5 LOC+Z18 (Netzlokation) DE3225 mindestens einmal anzugeben
9008    fn evaluate_2360(&self, ctx: &EvaluationContext) -> ConditionResult {
9009        // Cardinality: at least once per LOC+Z18 (Netzlokation) ID
9010        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z18").len();
9011        ConditionResult::from(loc_count > 0)
9012    }
9013
9014    /// [2361] Für jede ID im SG5 LOC+Z17 / Z20 / Z22 (Messlokation / Technische Ressource / ruhende Marktlokation) DE3225 mindestens einmal anzugeben
9015    fn evaluate_2361(&self, ctx: &EvaluationContext) -> ConditionResult {
9016        // Cardinality: at least once per LOC+Z17/Z20/Z22 ID
9017        let found = ctx.find_segments("LOC").iter().any(|s| {
9018            s.elements
9019                .first()
9020                .and_then(|e| e.first())
9021                .is_some_and(|v| ["Z17", "Z20", "Z22"].contains(&v.as_str()))
9022        });
9023        ConditionResult::from(found)
9024    }
9025}