workflow vastopolis-outbreak-origin-and-transmission
  template: characterise (extract-symptom-features) ->
            loop(assess -> characterise (refine-lexicon)) ->
            define-unit (filter-illness-events) ->
            define-unit (daily-episodes) -> characterise (daily-profile) ->
            define-unit (cluster-days) -> contextualise (calendar) ->
            visualise -> abstract -> generate-knowledge ->
            loop(define-unit (derive-places) -> characterise ->
                 contextualise -> visualise -> assess) ->
            abstract (origin-candidates) -> assess (origin-uniqueness) ->
            define-unit (origin-candidates) ->
            characterise (downwind-alignment) ->
            loop(define-unit (lag-windows) -> characterise (cross-impact) ->
                 visualise -> assess) ->
            generate-knowledge (airborne-evidence) ->
            loop(characterise (social-mentions) -> assess) ->
            define-unit (social-network) -> visualise ->
            contextualise (map) -> visualise (water-overlay) ->
            abstract (waterborne-pattern) ->
            characterise (zone-incidence) ->
            loop(define-unit (zone-grouping) ->
                 characterise (growth-and-residuals) -> visualise ->
                 abstract (spread-and-p2p-pattern) ->
                 generate-knowledge (checklist) -> assess) ->
            generate-knowledge (final-report)
  description: "Visual analytics workflow for identifying the spatio-temporal
    origin of a flu-like outbreak in Vastopolis from geolocated microblogs,
    and for adjudicating among candidate transmission mechanisms (airborne,
    person-to-person, waterborne) using map, population, and wind data.
    Revised to externalise key clustering/grouping decisions as specifications
    with assess-driven refinement, to surface origin-candidate ambiguity
    explicitly, and to make hypothesis comparison across mechanisms iterative
    rather than a single linear pass."

# ============================================================================
# INPUT ARTIFACTS
# ============================================================================

artifact D_microblogs : entities
  origin: given
  internal structure: elementary
  embedment: {space, time}
  features:
    - id: text_content
      value structure: atomic
      value type: text
      description: "Raw message text"
  description: "Geolocated microblog messages posted from mobile devices
    over several days, each with timestamp, GPS coordinates, and text
    content"

artifact D_map_features : entities
  origin: given
  internal structure: elementary
  embedment: space
  features:
    - id: feature_type
      value structure: atomic
      value type: categorical
      description: "Category of map feature: highway, hospital, landmark,
        water body, water-service area"
  description: "Static geographic features of the Vastopolis metropolitan
    area, used as map context"

artifact D_zones : entities
  origin: given
  internal structure: region
  embedment: space
  features:
    - id: population
      value structure: atomic
      value type: numeric
      description: "Resident population of the zone"
  description: "13 city zones of Vastopolis with population statistics"

artifact D_weather : entities
  origin: given
  internal structure: elementary
  embedment: time
  features:
    - id: wind_speed
      value structure: atomic
      value type: numeric
      description: "Daily wind speed"
    - id: wind_direction
      value structure: atomic
      value type: {numeric, spatial}
      description: "Daily wind direction (bearing)"
  description: "Daily weather observations including wind speed and
    direction"

artifact D_calendar : entities
  origin: given
  internal structure: elementary
  embedment: time
  features:
    - id: date
      value structure: atomic
      value type: temporal
      description: "Calendar date"
  description: "Calendar days spanning the observation period, used as
    arrangement context"

artifact S_symptom_lexicon : specification
  origin: given
  representation form: "keyword lexicon"
  description: "Flu-related symptom terms and severity indicators (fever,
    cough, vomiting, hospital, death, etc.) used to seed text extraction"

# ============================================================================
# STAGE A: EXTRACT AND VALIDATE ILLNESS-REPORT EVENTS FROM TEXT
# (unchanged from previous stage)
# ============================================================================

transform T_extract_symptoms :
  intent: characterise
  manner: "extract (keyword/entity extraction of symptom and severity
    terms)"
  input: D_microblogs, S_symptom_lexicon
  output: F_symptom_features
  actor: machine
  description: "Extract symptom mentions, severity indicators
    (hospitalization, death), and embedded place references from message
    text"

artifact F_symptom_features : feature(D_microblogs)
  value structure: vector
  value type: {categorical, ordinal, text}
  description: "Per-message symptom type(s), severity level, and any
    embedded place mentions"

loop L_extraction_validation:
  purpose: "Validate and correct automatically extracted symptom/severity
    indicators against raw message text before trusting the derived event
    set"
  until: "Sampled false positive/negative rate in extracted indicators is
    acceptable to the analyst"
  body:

    transform T_assess_extraction :
      intent: assess
      manner: "sample and inspect raw text against extracted indicators"
      input: F_symptom_features, D_microblogs
      output: K_extraction_quality
      actor: human
      description: "Sample messages and check extracted symptom/severity
        labels against raw text for false positives and false negatives"

    artifact K_extraction_quality : knowledge(F_symptom_features)
      representation form: "quality judgment"
      description: "Judgment of whether extraction lexicon/rules yield an
        acceptable false positive/negative rate"

    if K_extraction_quality indicates refinement needed:
      then:
        transform T_refine_lexicon :
          intent: characterise
          manner: "refine extraction lexicon/rules"
          input: D_microblogs, S_symptom_lexicon, K_extraction_quality
          output: F_symptom_features_r, S_symptom_lexicon_r
          actor: human
          description: "Adjust keyword lexicon or extraction rules based on
            observed errors and re-extract"

        artifact F_symptom_features_r : feature(D_microblogs)
          value structure: vector
          value type: {categorical, ordinal, text}
          description: "Updated per-message symptom/severity/place-mention
            indicators"

        artifact S_symptom_lexicon_r : specification
          representation form: "keyword lexicon"
          description: "Revised symptom lexicon"

        assign:
          F_symptom_features := F_symptom_features_r
          S_symptom_lexicon := S_symptom_lexicon_r
      else:
        exit loop L_extraction_validation

end loop L_extraction_validation

transform T_define_illness_events :
  intent: define-unit
  manner: "filter messages with validated symptom/severity indicators"
  input: D_microblogs, F_symptom_features
  output: D_illness_events
  actor: hybrid
  description: "Retain only messages carrying validated illness-related
    indicators as geolocated, time-stamped illness-report events"

artifact D_illness_events : entities
  internal structure: elementary
  embedment: {space, time}
  features:
    - id: symptom_type
      value structure: atomic
      value type: categorical
      description: "Symptom type(s) mentioned"
    - id: severity
      value structure: atomic
      value type: ordinal
      description: "Severity level (mild vs. severe/hospitalization/death)"
    - id: raw_text
      value structure: atomic
      value type: text
      description: "Original message text retained for drill-down"
  description: "Geolocated, time-stamped illness-report events derived from
    validated microblog messages"

# ============================================================================
# STAGE B: TEMPORAL OVERVIEW - ONSET DETECTION
# (unchanged; deliberately left linear - see revision notes)
# ============================================================================

transform T_define_days :
  intent: define-unit
  manner: "time-partitioning into per-zone daily episodes"
  input: D_illness_events, D_zones
  output: D_days
  actor: machine
  description: "Aggregate illness events into hourly/6-hour bins and group
    into daily episodes per zone"

artifact D_days : entities
  internal structure: episode
  embedment: {set, time}
  features:
    - id: hourly_counts
      value structure: vector
      value type: numeric
      description: "Hourly (or 6-hour) event counts within the day, per
        zone"
  description: "Per-zone daily episodes of illness-event counts"

transform T_characterise_daily_profile :
  intent: characterise
  manner: "profile"
  input: D_days
  output: F_daily_profile
  actor: machine
  description: "Normalise hourly count vectors into comparable daily shape
    profiles"

artifact F_daily_profile : feature(D_days)
  value structure: vector
  value type: numeric
  representation form: "daily count profile"
  description: "Normalized daily profile shape used for baseline-deviation
    clustering"

transform T_cluster_days :
  intent: define-unit
  manner: "cluster-by-similarity of daily profile shape"
  input: D_days, F_daily_profile
  output: D_day_clusters, F_day_cluster_label
  actor: machine
  description: "Cluster days by profile shape so that days deviating from
    the pre-outbreak baseline pattern are separated out"

artifact D_day_clusters : entities
  internal structure: group/cluster
  embedment: set
  description: "Groups of days with similar profile shape (baseline vs.
    deviating clusters)"

artifact F_day_cluster_label : feature(D_days)
  value structure: atomic
  value type: categorical
  description: "Cluster membership label (baseline vs. deviating) for each
    day"

transform T_arrange_calendar :
  intent: contextualise
  manner: "calendar-based"
  input: D_days, D_calendar
  output: A_calendar
  actor: machine
  description: "Position each per-zone daily episode in its corresponding
    calendar cell"

artifact A_calendar : arrangement(D_days)
  context: D_calendar
  principle: "calendar(date, zone)"
  description: "Calendar-based arrangement of daily episodes per zone"

transform T_vis_calendar :
  intent: visualise
  manner: "coloured-marks"
  input: A_calendar, F_day_cluster_label
  output: V_calendar_clusters
  actor: machine
  description: "Calendar view showing cluster membership of each day, per
    zone"

artifact V_calendar_clusters : visualisation(A_calendar, F_day_cluster_label)
  layout: "calendar grid per zone"
  form: "coloured marks"
  encoding: "layout: from A_calendar; colour: from F_day_cluster_label"
  description: "Visual overview for spotting onset day(s) and
    earliest-deviating zones"

transform T_abstract_onset :
  intent: abstract
  manner: "perception-and-interpretation"
  input: V_calendar_clusters
  output: P_onset_pattern
  actor: human
  description: "Identify the earliest day(s) and zone(s) whose profile
    breaks from the baseline pattern"

artifact P_onset_pattern : pattern(D_days)
  representation form: "textual description"
  description: "Description of onset day(s) and earliest-deviating
    zone(s)"

transform T_knowledge_onset :
  intent: generate-knowledge
  manner: "formulate-statements"
  input: P_onset_pattern
  output: K_onset_candidates
  actor: human
  description: "Formulate candidate onset time window and earliest zone(s)
    as a soft working hypothesis, to be cross-checked against place-level
    evidence in Stage C"

artifact K_onset_candidates : knowledge(D_days)
  representation form: "statements"
  description: "Candidate onset time window and earliest-affected zone(s)"

# ============================================================================
# STAGE C: SIGNIFICANT-PLACE DERIVATION (REVISED)
# Recommendation 1 implemented here: clustering criteria externalised as a
# specification, with an assess-driven refinement loop.
# Recommendation 2 implemented here: explicit assessment of origin-candidate
# uniqueness/ambiguity after clustering has stabilised.
# ============================================================================

artifact S_place_clustering : specification
  origin: given
  representation form: "parameter settings"
  description: "Spatial and temporal distance thresholds (and minimum
    event count) used to derive candidate places from illness events via
    density-based clustering"

loop L_place_derivation:
  purpose: "Calibrate spatio-temporal clustering criteria so that derived
    place clusters are coherent, stable, and support reliable per-place
    incidence time series"
  until: "Place clusters are spatially/temporally coherent and their
    membership is stable under minor variation of the clustering
    thresholds"
  body:

    transform T_define_places :
      intent: define-unit
      manner: "derive-places (spatio-temporal density clustering)"
      input: D_illness_events, S_place_clustering
      output: D_places, F_place_membership
      actor: machine
      description: "Cluster illness events jointly by spatial and temporal
        proximity into candidate significant places, treating isolated
        events as noise"

    artifact D_places : entities
      internal structure: group/cluster
      embedment: space
      features:
        - id: place_extent
          value structure: atomic
          value type: spatial
          description: "Spatial hull/buffer delineating the place"
        - id: onset_time
          value structure: atomic
          value type: temporal
          description: "Earliest event time within the place cluster"
      description: "Candidate significant places derived from illness
        events under the current clustering specification"

    artifact F_place_membership : feature(D_illness_events)
      value structure: atomic
      value type: reference
      description: "Assignment of each illness event to a place cluster
        (or noise)"

    transform T_characterise_place_timeseries :
      intent: characterise
      manner: "aggregate"
      input: D_places, D_illness_events, F_place_membership
      output: F_place_timeseries
      actor: machine
      description: "Compute per-place time series of event counts"

    artifact F_place_timeseries : feature(D_places)
      value structure: vector
      value type: numeric
      representation form: "time series per place"
      description: "Event-count time series per candidate place"

    transform T_characterise_place_incidence :
      intent: characterise
      manner: "normalise by population"
      input: D_places, D_zones, F_place_timeseries
      output: F_place_incidence
      actor: machine
      description: "Normalise place-level event counts by zone population
        to obtain per-capita incidence"

    artifact F_place_incidence : feature(D_places)
      value structure: vector
      value type: numeric
      description: "Per-capita incidence time series per place"

    transform T_arrange_map_places :
      intent: contextualise
      manner: "map-based"
      input: D_places, D_map_features
      output: A_map_places
      actor: machine
      description: "Overlay candidate places on the map context"

    artifact A_map_places : arrangement(D_places)
      context: D_map_features
      principle: "geographic coordinates"
      description: "Spatial arrangement of candidate places relative to
        map features"

    transform T_vis_map_hotspots :
      intent: visualise
      manner: "coloured-marks"
      input: A_map_places, F_place_incidence, D_map_features
      output: V_map_hotspots
      actor: machine
      description: "Map view of candidate places sized/coloured by onset
        time and per-capita incidence, overlaid on landmarks and water
        bodies"

    artifact V_map_hotspots : visualisation(A_map_places, F_place_incidence,
        D_map_features)
      layout: "geographic map"
      form: "coloured marks with size/time encoding"
      encoding: "position: from A_map_places; colour/size: from
        F_place_incidence and onset_time; background: D_map_features"
      description: "Visual basis for judging cluster coherence and for
        later identifying candidate origin place(s)"

    transform T_assess_place_clusters :
      intent: assess
      manner: "evaluate clustering coherence and stability"
      input: V_map_hotspots, D_places, F_place_incidence
      output: K_place_quality
      actor: human
      description: "Judge whether place clusters are spatially/temporally
        coherent, interpretable, and stable under minor threshold changes;
        decide whether the clustering specification needs adjustment"

    artifact K_place_quality : knowledge(D_places)
      representation form: "quality judgment"
      description: "Judgment of clustering adequacy and stability"

    if K_place_quality indicates refinement needed:
      then:
        transform T_refine_place_clustering :
          intent: generate-knowledge
          manner: "adjust parameter settings"
          input: K_place_quality, S_place_clustering
          output: S_place_clustering_r
          actor: human
          description: "Adjust spatial/temporal distance thresholds based
            on observed over- or under-segmentation"

        artifact S_place_clustering_r : specification
          representation form: "parameter settings"
          description: "Revised place-clustering thresholds"

        assign:
          S_place_clustering := S_place_clustering_r
      else:
        exit loop L_place_derivation

end loop L_place_derivation

transform T_abstract_origin_candidates :
  intent: abstract
  manner: "perception-and-interpretation"
  input: V_map_hotspots
  output: P_origin_candidates
  actor: human
  description: "Identify the earliest and most severe place cluster(s) and
    note whether each coincides with a specific fixed feature (e.g.,
    reservoir, festival ground) versus diffuse residential spread; more
    than one candidate may be identified"

artifact P_origin_candidates : pattern(D_places)
  representation form: "textual description"
  description: "Candidate origin place(s), their co-location with map
    features, and earliest onset time"

transform T_assess_origin_uniqueness :
  intent: assess
  manner: "evaluate confidence and uniqueness of origin candidates"
  input: P_origin_candidates
  output: K_origin_confidence
  actor: human
  description: "Judge whether a single dominant earliest cluster stands out
    as the origin, or whether several competing candidates remain equally
    plausible; this judgment is not resolved by further threshold tuning,
    since it reflects genuine ambiguity in the data rather than a clustering
    artifact"

artifact K_origin_confidence : knowledge(P_origin_candidates)
  representation form: "quality judgment"
  description: "Assessment of whether the origin is uniquely identified or
    remains ambiguous among several candidates"

transform T_define_origin_candidates :
  intent: define-unit
  manner: "filter/select retained candidate origin places"
  input: D_places, P_origin_candidates, K_origin_confidence
  output: D_origin_candidates
  actor: human
  description: "Finalise the (possibly plural) set of candidate origin
    places to be carried forward into mechanism testing; if multiple
    candidates survive, later stages are applied to each retained
    candidate rather than forcing a single choice"

artifact D_origin_candidates : entities
  internal structure: elementary
  embedment: space
  features:
    - id: confidence_rank
      value structure: atomic
      value type: ordinal
      description: "Analyst-assigned confidence ranking among retained
        candidates"
  description: "Retained candidate origin place(s) carried forward into
    Stage E and Stage F waterborne testing"

# ============================================================================
# STAGE E: WIND-SPREAD CROSS-IMPACT ANALYSIS (AIRBORNE HYPOTHESIS)
# Adapted to operate relative to D_origin_candidates (possibly plural);
# otherwise structurally unchanged from previous revision.
# ============================================================================

transform T_characterise_downwind_alignment :
  intent: characterise
  manner: "compute directional alignment relative to wind"
  input: D_zones, D_weather, D_origin_candidates
  output: F_downwind_alignment
  actor: machine
  description: "For each zone, candidate origin, and day, compute how well
    the zone's bearing from the candidate origin matches that day's wind
    direction"

artifact F_downwind_alignment : feature(D_zones)
  value structure: matrix
  value type: numeric
  representation form: "daily alignment score per zone per candidate
    origin"
  description: "Downwind alignment score per zone relative to each
    retained candidate origin"

artifact S_lag_spec : specification
  origin: given
  representation form: "parameter settings"
  description: "Initial window length, lag range, and tolerance interval
    for cross-impact analysis between wind and incidence/alignment
    series"

loop L_wind_analysis:
  purpose: "Compute and calibrate the wind-incidence cross-impact pattern,
    for each retained candidate origin, to test the airborne transmission
    hypothesis"
  until: "Impact matrix is stable/interpretable enough to support a
    judgment on the airborne hypothesis for each candidate origin"
  body:

    transform T_define_lag_windows :
      intent: define-unit
      manner: "time-partitioning into sliding windows"
      input: D_weather, F_downwind_alignment, S_lag_spec
      output: D_windows
      actor: machine
      description: "Partition the wind series and each zone/candidate
        response series into sliding comparison windows over a range of
        plausible incubation lags"

    artifact D_windows : entities
      internal structure: episode
      embedment: time
      features:
        - id: lag
          value structure: atomic
          value type: numeric
          description: "Lag offset applied in this window"
      description: "Sliding time windows used to compare the wind series
        with each zone/candidate response series at varying lags"

    transform T_characterise_cross_impact :
      intent: characterise
      manner: "compute lagged association (tolerance-based)"
      input: D_windows, D_weather, F_downwind_alignment, S_lag_spec
      output: F_impact_matrix
      actor: machine
      description: "Compute a tolerance-based association measure between
        the wind base series and each zone's response series, per
        candidate origin, across the window/lag grid"

    artifact F_impact_matrix : feature(D_zones)
      value structure: matrix
      value type: numeric
      representation form: "time x lag impact matrix per candidate origin
        (Ikat-style)"
      description: "Per-zone, per-candidate matrix of association strength
        across time windows and lags"

    transform T_vis_impact :
      intent: visualise
      manner: "matrix-plot"
      input: F_impact_matrix
      output: V_wind_impact
      actor: machine
      description: "Ikat-style visualisation of the time x lag impact
        matrix for each zone/candidate combination"

    artifact V_wind_impact : visualisation(F_impact_matrix)
      layout: "time x lag grid, per zone and candidate origin"
      form: "matrix plot"
      encoding: "cell colour: from F_impact_matrix association strength"
      description: "Visual display for inspecting whether downwind zones
        show a consistent positive impact at a plausible lag"

    transform T_assess_impact :
      intent: assess
      manner: "evaluate stability and interpretability of impact pattern"
      input: V_wind_impact, D_weather, F_downwind_alignment
      output: K_impact_quality
      actor: human
      description: "Judge whether current window/lag/tolerance settings
        yield a stable, interpretable impact pattern"

    artifact K_impact_quality : knowledge(F_impact_matrix)
      representation form: "quality judgment"
      description: "Judgment of impact-matrix stability/interpretability"

    if K_impact_quality indicates refinement needed:
      then:
        transform T_refine_lag_spec :
          intent: generate-knowledge
          manner: "adjust parameter settings"
          input: K_impact_quality, S_lag_spec
          output: S_lag_spec_r
          actor: human
          description: "Adjust window length, lag range, or tolerance"

        artifact S_lag_spec_r : specification
          representation form: "parameter settings"
          description: "Revised window/lag/tolerance settings"

        assign:
          S_lag_spec := S_lag_spec_r
      else:
        exit loop L_wind_analysis

end loop L_wind_analysis

transform T_knowledge_airborne :
  intent: generate-knowledge
  manner: "formulate-statements"
  input: V_wind_impact, F_impact_matrix
  output: K_airborne_evidence
  actor: human
  description: "Formulate, per candidate origin, a statement on whether
    downwind zones show a consistent lagged impact from wind, supporting
    or refuting airborne transmission from that candidate"

artifact K_airborne_evidence : knowledge(F_impact_matrix, D_origin_candidates)
  representation form: "statements"
  description: "Evidence for or against airborne transmission, per
    candidate origin; computed once and treated as fixed evidence in the
    mechanism-comparison loop below"

# ============================================================================
# STAGE F PART 1: PERSON-TO-PERSON EVIDENCE (SOCIAL NETWORK)
# Recommendation 3 implemented here: extraction-validation loop added,
# mirroring Stage A.
# ============================================================================

artifact S_social_lexicon : specification
  origin: given
  representation form: "keyword/pattern lexicon"
  description: "Seed patterns for detecting social/co-location mentions
    (coworkers, family, shared venues, shared transit lines) in illness-
    event text"

loop L_social_extraction:
  purpose: "Validate and correct automatically extracted social/co-location
    mentions against raw message text before trusting the derived
    co-occurrence structure"
  until: "Sampled false positive/negative rate in extracted social
    mentions is acceptable to the analyst"
  body:

    transform T_characterise_social_mentions :
      intent: characterise
      manner: "extract (co-location/social mentions from text)"
      input: D_illness_events, S_social_lexicon
      output: F_social_mentions
      actor: hybrid
      description: "Extract mentions of shared social context from
        illness-event text"

    artifact F_social_mentions : feature(D_illness_events)
      value structure: list
      value type: {text, categorical}
      description: "Extracted social/co-location references per illness
        event"

    transform T_assess_social_extraction :
      intent: assess
      manner: "sample and inspect raw text against extracted mentions"
      input: F_social_mentions, D_illness_events
      output: K_social_quality
      actor: human
      description: "Sample events and check extracted social mentions
        against raw text for false positives/negatives (e.g., ambiguous
        pronoun references, unrelated group mentions)"

    artifact K_social_quality : knowledge(F_social_mentions)
      representation form: "quality judgment"
      description: "Judgment of whether extraction acceptably captures
        genuine social/co-location references"

    if K_social_quality indicates refinement needed:
      then:
        transform T_refine_social_lexicon :
          intent: characterise
          manner: "refine extraction lexicon/rules"
          input: D_illness_events, S_social_lexicon, K_social_quality
          output: F_social_mentions_r, S_social_lexicon_r
          actor: human
          description: "Adjust social-mention lexicon/rules based on
            observed errors and re-extract"

        artifact F_social_mentions_r : feature(D_illness_events)
          value structure: list
          value type: {text, categorical}
          description: "Updated social/co-location references"

        artifact S_social_lexicon_r : specification
          representation form: "keyword/pattern lexicon"
          description: "Revised social-mention lexicon"

        assign:
          F_social_mentions := F_social_mentions_r
          S_social_lexicon := S_social_lexicon_r
      else:
        exit loop L_social_extraction

end loop L_social_extraction

transform T_define_social_network :
  intent: define-unit
  manner: "derive relational structure from co-occurrence mentions"
  input: D_illness_events, F_social_mentions
  output: D_social_network
  actor: hybrid
  description: "Build a light co-occurrence network of people/places
    mentioned together across illness events"

artifact D_social_network : entities
  internal structure: formation
  features:
    - id: edge_weight
      value structure: atomic
      value type: numeric
      description: "Strength of co-occurrence link"
  description: "Co-occurrence network of persons/places mentioned together
    in illness reports"

transform T_vis_social_network :
  intent: visualise
  manner: "node-link-diagram"
  input: D_social_network
  output: V_social_network
  actor: machine
  description: "Node-link visualisation of the social/co-location
    co-occurrence network; computed once and reused as fixed evidence
    inside the mechanism-comparison loop below"

artifact V_social_network : visualisation(D_social_network)
  layout: "force-directed network layout"
  form: "node-link diagram"
  encoding: "edges: from D_social_network edge_weight"
  description: "Visualisation for inspecting chains of social/mobility
    contact among cases"

# ============================================================================
# STAGE F PART 2: WATERBORNE EVIDENCE
# Adapted to overlay the finalised D_origin_candidates rather than all
# places; otherwise unchanged in substance.
# ============================================================================

transform T_arrange_map_origin_candidates :
  intent: contextualise
  manner: "map-based"
  input: D_origin_candidates, D_map_features
  output: A_map_origin_candidates
  actor: machine
  description: "Position retained candidate origins on the map context,
    including the water-body and water-service-area layers"

artifact A_map_origin_candidates : arrangement(D_origin_candidates)
  context: D_map_features
  principle: "geographic coordinates"
  description: "Spatial arrangement of candidate origins relative to water
    bodies and service areas"

transform T_vis_water_overlay :
  intent: visualise
  manner: "map-based overlay"
  input: A_map_origin_candidates, D_map_features
  output: V_water_overlay
  actor: machine
  description: "Overlay candidate origin(s) directly on the water-body
    layer and any known water-service-area boundaries"

artifact V_water_overlay : visualisation(A_map_origin_candidates,
    D_map_features)
  layout: "geographic map"
  form: "coloured marks over water/service-area layer"
  encoding: "candidate-origin marks: from A_map_origin_candidates;
    background: water bodies/service areas from D_map_features"
  description: "Visual check of whether candidate origins are coincident
    with water sources or service-area boundaries"

transform T_abstract_waterborne_pattern :
  intent: abstract
  manner: "perception-and-interpretation"
  input: V_water_overlay, D_origin_candidates
  output: P_waterborne_pattern
  actor: human
  description: "Assess, per candidate origin, whether it coincides with a
    water source and whether the map suggests water-service-area alignment
    rather than road proximity or social chains; computed once and reused
    as fixed evidence in the mechanism-comparison loop below"

artifact P_waterborne_pattern : pattern(D_origin_candidates)
  representation form: "textual description"
  description: "Evidence for/against waterborne transmission, per
    candidate origin"

# ============================================================================
# STAGE D+F SYNTHESIS: ITERATIVE ZONE-GROUPING AND MECHANISM COMPARISON
# Substantially restructured (recommendations 4 and 5): the former linear
# Stage D (zone grouping/growth modelling) and the mechanism-comparison step
# of former Stage F are merged into a single loop that redefines the
# zone-grouping criterion when evidence is inconclusive, and that folds the
# conclusiveness check directly into the loop's own assess step rather than
# treating it as a separate downstream step.
# ============================================================================

transform T_characterise_zone_incidence :
  intent: characterise
  manner: "aggregate and normalise by population"
  input: D_zones, D_illness_events
  output: F_zone_incidence
  actor: machine
  description: "Compute per-capita incidence time series for each of the
    13 zones; computed once, independent of the grouping criterion used
    below"

artifact F_zone_incidence : feature(D_zones)
  value structure: vector
  value type: numeric
  representation form: "time series per zone"
  description: "Daily per-capita incidence time series per zone"

transform T_arrange_map_zones :
  intent: contextualise
  manner: "map-based"
  input: D_zones, D_map_features
  output: A_map_zones
  actor: machine
  description: "Position zones on the map context, including highways and
    water-service areas; positions are fixed regardless of grouping
    criterion, so this is computed once outside the loop"

artifact A_map_zones : arrangement(D_zones)
  context: D_map_features
  principle: "geographic coordinates"
  description: "Spatial arrangement of zones relative to map features"

artifact S_zone_grouping : specification
  origin: given
  representation form: "method choice"
  description: "Criterion currently used to group the 13 zones: initially
    'temporal-incidence-similarity'; alternatives to be tried if evidence
    remains inconclusive include 'water-service-area' and
    'mobility-network-proximity'"

loop L_hypothesis_testing:
  purpose: "Iteratively test whether the current zone-grouping criterion,
    combined with the fixed airborne and waterborne evidence lines,
    yields conclusive support for one transmission mechanism; if not,
    redefine the zone-grouping criterion and re-test"
  until: "The mechanism-comparison checklist is conclusive for a single
    dominant transmission mechanism, or all analytically motivated
    alternative grouping criteria have been tried without resolving the
    ambiguity"
  body:

    transform T_define_zone_groups :
      intent: define-unit
      manner: "cluster/group zones according to current criterion"
      input: D_zones, F_zone_incidence, D_map_features, S_zone_grouping
      output: D_zone_groups, F_zone_group_label
      actor: machine
      description: "Group the 13 zones according to the current criterion
        (temporal-incidence similarity, water-service area, or
        mobility-network proximity)"

    artifact D_zone_groups : entities
      internal structure: group/cluster
      embedment: space
      description: "Groups of zones under the current grouping criterion"

    artifact F_zone_group_label : feature(D_zones)
      value structure: atomic
      value type: categorical
      description: "Group label for each zone under the current criterion"

    transform T_vis_zone_groups :
      intent: visualise
      manner: "coloured-marks"
      input: A_map_zones, F_zone_group_label, D_map_features
      output: V_zone_groups_map
      actor: machine
      description: "Map view of zones coloured by current group, overlaid
        on the highway network, to check spatial contiguity vs. dispersion"

    artifact V_zone_groups_map : visualisation(A_map_zones,
        F_zone_group_label, D_map_features)
      layout: "geographic map"
      form: "coloured region marks"
      encoding: "position: from A_map_zones; colour: from
        F_zone_group_label; background: highway layer"
      description: "Visual check of zone-group spatial coherence relative
        to roads/water areas under the current criterion"

    transform T_build_growth_model :
      intent: build-model
      manner: "fit-growth-curve"
      input: F_zone_incidence, D_zone_groups
      output: M_growth
      actor: machine
      description: "Fit a growth curve to each zone group's representative
        incidence curve"

    artifact M_growth : model(F_zone_incidence, D_zone_groups)
      model type: "growth model"
      representation form: "exponential/logistic curve parameters per
        group"
      description: "Growth model of outbreak expansion per zone group
        under the current grouping criterion"

    transform T_characterise_residuals :
      intent: characterise
      manner: "compute-statistics (residuals)"
      input: F_zone_incidence, M_growth
      output: F_growth_residuals
      actor: machine
      description: "Compute residuals of observed incidence relative to
        the fitted group growth curve"

    artifact F_growth_residuals : feature(D_zones)
      value structure: vector
      value type: numeric
      description: "Residual time series per zone"

    transform T_vis_residuals :
      intent: visualise
      manner: "line-graph / coloured-marks on map"
      input: F_growth_residuals, A_map_zones
      output: V_residuals_map
      actor: machine
      description: "Highlight zones with large residuals relative to the
        current grouping's growth model"

    artifact V_residuals_map : visualisation(F_growth_residuals, A_map_zones)
      layout: "geographic map / aligned timelines"
      form: "coloured marks / line graph"
      encoding: "colour/line deviation: from F_growth_residuals; position:
        from A_map_zones"
      description: "Highlights zones deviating from the current grouping's
        dominant growth pattern"

    transform T_abstract_spread_pattern :
      intent: abstract
      manner: "perception-and-interpretation"
      input: V_zone_groups_map, V_residuals_map, D_map_features
      output: P_spread_pattern
      actor: human
      description: "Interpret whether the current zone grouping follows
        the highway/mobility network or the water-service-area layout,
        and whether it plausibly explains the observed growth pattern"

    artifact P_spread_pattern : pattern(D_zone_groups, F_growth_residuals)
      representation form: "textual description"
      description: "Description of spread geometry under the current
        grouping criterion"

    transform T_abstract_p2p_pattern :
      intent: abstract
      manner: "perception-and-interpretation"
      input: V_social_network, V_zone_groups_map
      output: P_p2p_pattern
      actor: human
      description: "Assess, against the current zone-groups map, whether
        cases chain along social/mobility links and whether spatial growth
        tracks the highway/transit network"

    artifact P_p2p_pattern : pattern(D_social_network, D_zone_groups)
      representation form: "textual description"
      description: "Evidence for/against person-to-person transmission
        under the current grouping criterion"

    transform T_knowledge_mechanism_checklist :
      intent: generate-knowledge
      manner: "formulate-statements (comparison checklist)"
      input: K_airborne_evidence, P_p2p_pattern, P_waterborne_pattern,
             P_spread_pattern
      output: K_mechanism_assessment
      actor: human
      description: "Compile a diagnostic checklist comparing the expected
        signature of each mechanism against observed evidence: the
        airborne and waterborne evidence lines are fixed across
        iterations, while the person-to-person and spread-pattern evidence
        reflect the current zone-grouping criterion"

    artifact K_mechanism_assessment : knowledge(K_airborne_evidence,
        P_p2p_pattern, P_waterborne_pattern, P_spread_pattern)
      representation form: "comparison checklist / statements"
      description: "Structured comparison of candidate transmission
        mechanisms against observed diagnostic signatures, under the
        current zone-grouping criterion"

    transform T_assess_conclusiveness :
      intent: assess
      manner: "evaluate decisiveness of mechanism comparison"
      input: K_mechanism_assessment
      output: K_conclusiveness
      actor: human
      description: "Judge whether the checklist evidence decisively favours
        one mechanism, or remains ambiguous (e.g., moderate support for two
        mechanisms simultaneously); if ambiguous, judge whether an
        untried grouping criterion could plausibly discriminate further"

    artifact K_conclusiveness : knowledge(K_mechanism_assessment)
      representation form: "quality judgment"
      description: "Judgment of whether the mechanism comparison is
        decisive, and if not, whether further grouping criteria remain
        worth testing"

    if K_conclusiveness indicates inconclusive and untried criteria remain:
      then:
        transform T_refine_zone_grouping :
          intent: generate-knowledge
          manner: "select alternative grouping criterion"
          input: K_conclusiveness, S_zone_grouping
          output: S_zone_grouping_r
          actor: human
          description: "Select the next untried grouping criterion (e.g.,
            switch from temporal-incidence similarity to water-service-area
            or mobility-network proximity) based on which evidence line
            remains ambiguous"

        artifact S_zone_grouping_r : specification
          representation form: "method choice"
          description: "Revised zone-grouping criterion"

        assign:
          S_zone_grouping := S_zone_grouping_r
      else:
        exit loop L_hypothesis_testing

end loop L_hypothesis_testing

# ============================================================================
# STAGE G: SYNTHESIS AND REPORTING
# ============================================================================

transform T_synthesise_report :
  intent: generate-knowledge
  manner: "write-summary"
  input: K_onset_candidates, P_origin_candidates, K_mechanism_assessment,
         K_conclusiveness
  output: K_final_report
  actor: human
  description: "Synthesise the probable origin place(s) and time window,
    the dominant spread pattern, the best-supported transmission mechanism
    (or the residual ambiguity, if evidence remained inconclusive after
    exhausting alternative grouping criteria), into an evidence-linked
    report for emergency management"

artifact K_final_report : knowledge(D_origin_candidates, D_zone_groups,
    K_mechanism_assessment)
  representation form: "statements / report"
  description: "Evidence-linked report on outbreak origin, spread pattern,
    and most probable transmission mechanism, to guide deployment of
    emergency management resources"