diff --git a/README.md b/README.md index 5bc3713..3f99fe1 100644 --- a/README.md +++ b/README.md @@ -356,11 +356,11 @@ Run once per `(field, disease)` job by `pipeline/job.py::run_job`: | Rule | Predicates | |---|---| | `observation` true on `as_of` or the past 5 days | `systemicity` in `{systemic, mixed}` and `eradicant_action = 1` | + | `INCUBAZPRIMARIA` / `INCUBAZPRIMARIA_` today or in the past 5 days | `systemicity` in `{systemic, mixed}` and `curative_action = 1` and `eradicant_action = 0` | | `FASE2` anywhere and no `FASE5` anywhere | `systemicity == contact` and `preventive_action = 1` and `curative_action = 0` and `eradicant_action = 0` | | `FASE5` both past/today and future | `systemicity == mixed` and `preventive_action = 1` and `curative_action = 1` and `eradicant_action = 0` | | `FASE5` in the future only | same predicates as the `FASE2`-only rule | | `FASE5` today or in the past only | `systemicity` in `{contact, mixed}` and `preventive_action = 1` and `curative_action = 0` and `eradicant_action = 0` | - | `INCUBAZPRIMARIA` / `INCUBAZPRIMARIA_` today or in the past 5 days | `systemicity` in `{systemic, mixed}` and `curative_action = 1` and `eradicant_action = 0` | | none of the above | no FASE-specific cut; organic/crop/disease gates only | 9. **Vector search** — Weaviate `near_text` on `ProductProfile`, filtered server-side to the allowlisted `product_id`s diff --git a/pipeline/stages/disease.py b/pipeline/stages/disease.py index 2fd7c9b..9e548bf 100644 --- a/pipeline/stages/disease.py +++ b/pipeline/stages/disease.py @@ -220,11 +220,11 @@ def select_prefilter_rule( match wins: 1. `observation` True on as_of or any of the past 5 days -> "observation" - 2. FASE2 anywhere in the window AND no FASE5 anywhere -> "fase2_only" - 3. FASE5 present both past/today AND future -> "fase5_both" - 4. FASE5 present in the future only -> "fase5_future" - 5. FASE5 present today or in the past only -> "fase5_past" - 6. INCUBAZPRIMARIA today or in the past 5 days -> "incubazprimaria" + 2. INCUBAZPRIMARIA today or in the past 5 days -> "incubazprimaria" + 3. FASE2 anywhere in the window AND no FASE5 anywhere -> "fase2_only" + 4. FASE5 present both past/today AND future -> "fase5_both" + 5. FASE5 present in the future only -> "fase5_future" + 6. FASE5 present today or in the past only -> "fase5_past" 7. otherwise -> None None means the product prefilter applies only the crop / disease / @@ -236,6 +236,9 @@ def select_prefilter_rule( if any(observation_by_day.get(d, False) for d in past_today): return "observation" + if any(_is_incubazprimaria(forecasts_by_day.get(d)) for d in past_today): + return "incubazprimaria" + fase2_anywhere = any(v == "FASE2" for v in forecasts_by_day.values()) fase5_anywhere = any(v == "FASE5" for v in forecasts_by_day.values()) @@ -252,7 +255,4 @@ def select_prefilter_rule( if fase5_past_today: return "fase5_past" - if any(_is_incubazprimaria(forecasts_by_day.get(d)) for d in past_today): - return "incubazprimaria" - return None diff --git a/pipeline/stages/products.py b/pipeline/stages/products.py index 2d02914..1dfb028 100644 --- a/pipeline/stages/products.py +++ b/pipeline/stages/products.py @@ -138,6 +138,8 @@ def prefilter_products( prefilter rule (see pipeline.stages.disease.select_prefilter_rule). observation -> systemicity in {systemic, mixed} AND eradicant_action = 1 + incubazprimaria -> systemicity in {systemic, mixed} AND curative_action = 1 + AND eradicant_action = 0 fase2_only -> systemicity == contact AND preventive_action = 1 AND curative_action = 0 AND eradicant_action = 0 fase5_both -> systemicity == mixed AND preventive_action = 1 @@ -145,8 +147,6 @@ def prefilter_products( fase5_future -> same predicates as fase2_only fase5_past -> systemicity in {contact, mixed} AND preventive_action = 1 AND curative_action = 0 AND eradicant_action = 0 - incubazprimaria -> systemicity in {systemic, mixed} AND curative_action = 1 - AND eradicant_action = 0 None -> no FASE-specific cut; crop/disease/organic gates only """ candidates: list[ProductCandidate] = [] @@ -162,6 +162,13 @@ def prefilter_products( continue if not row.eradicant_action: continue + elif rule == "incubazprimaria": + if systemicity not in {"systemic", "mixed"}: + continue + if not row.curative_action: + continue + if row.eradicant_action: + continue elif rule in ("fase2_only", "fase5_future"): if systemicity != "contact": continue @@ -189,13 +196,6 @@ def prefilter_products( continue if row.eradicant_action: continue - elif rule == "incubazprimaria": - if systemicity not in {"systemic", "mixed"}: - continue - if not row.curative_action: - continue - if row.eradicant_action: - continue # rule is None: no FASE-specific cut, only the gates above apply. candidates.append(row.as_candidate())