VAST · Claude Sonnet 5 · C6+

Vastopolis outbreak investigation — C6+ · self-critique

C6+

Raw session log. Continues c6; gap-analysis of the atwl translation.

12 turns (6 user · 6 assistant) json raw log

1 Researcher

You have received a document titled Workflow Library: Titles and Summaries. This document contains natural-language summaries of 53 visual analytics workflows drawn from the published research literature. Each summary describes the analytical goal, the workflow structure, and the methodological approach of a specific published workflow. The summaries were extracted from a public workflow library curated by our research group.

Please read the summaries carefully before we proceed. In the next message I will describe a specific visual analytics design task. Your job will be to design an analytical workflow that addresses the task, drawing on the workflows in the library where relevant. The library is a resource — you may consult it to identify workflow structures, analytical strategies, or methodological approaches that could inform your recommendation for the target task. You are not obliged to use the library workflows, and you may combine elements from multiple workflows, adapt them, or design new steps as the task requires.

Please describe your recommended workflow in natural language, in sufficient detail that a research analyst could use it as a design template. Where you draw on specific library workflows, please cite them by name so the analyst can trace the sources of your recommendation.

Before we proceed, could you briefly confirm that you have absorbed the library, and let me know if you have any questions before the task is described? Please reply in English only.

2 Model

I have carefully read through the Workflow Library, which contains 53 workflow summaries spanning a wide range of visual analytics domains, including:

  • Temporal/sequential data: calendar-based clustering, event sequence simplification, event thread analysis, cross-impact detection in time series, IVESA event sequences
  • Spatial/movement data: mobility graphs, movement track analysis, progressive trajectory clustering
  • Network/graph analysis: dynamic network snapshots, NodeTrix, state transition graphs, RelEx overlay networks
  • Model understanding & ML interpretability: EventAction recommendation, exploratory model analysis, binary classifier diagnostics, RfX ensemble exploration, TensorFlow dataflow graphs, What-If Tool, explAIner, RuleSense, compound potency models, VBridge healthcare explanations
  • Cohort/subgroup analysis: COQUITO, Coral, Kokiri, single-cell omics cohort comparison
  • Clustering & dimensionality reduction workflows: SOMFlow, progressive high-dimensional analysis, knowledge-incorporated embeddings, EnsembleLens
  • Domain-specific design studies: DPVis (disease progression), IRVINE (acoustic diagnostics), StratomeX (cancer genomics), Tuner (segmentation parameters), ParaGlide (simulation parameter spaces), Hybrid Visual Steering (engineering simulations), QVis (spatiotemporal ensembles)
  • Eye-tracking & multimodal analysis: ISeeCube, Space-Time gaze analytics, Active Gaze Labeling, Image-Based Projection Labeling, Multimodal Collaborative Design
  • Text/investigative/sensemaking: Jigsaw, SensePath, topic modeling (UTOPIAN), Visual Movie Analytics, LFPeers temporal peer comparison
  • Regression/statistical modeling: Partition-based regression, spatio-temporal modelling, feature engineering for behavior recognition

I have absorbed the analytical goals, workflow structures, and methodological logic of each entry, including the key visual encodings, iterative loops, and citation details needed to trace design decisions back to specific sources.

I'm ready for the design task. I have no questions at this stage — please go ahead and describe the target task, and I will draw on relevant workflows from this library to construct a detailed recommended workflow.

3 Researcher

A public health team in Vastopolis, a metropolitan area of about two million residents, has observed a sharp increase in flu-like illnesses over the past few days, with several deaths believed to be associated with the current outbreak. The team wants to understand where the outbreak started and how the infection is being transmitted (person-to-person, airborne, waterborne, or something else) so that emergency management resources can be deployed appropriately.

The available data consists of: geolocated microblog messages posted from mobile devices over a period of several days, each with a timestamp, GPS coordinates, and text content; a map of the metropolitan area showing highways, hospitals, landmarks, and water bodies; population statistics for 13 city zones; and daily weather observations including wind speed and direction.

The analyst will need to inspect intermediate results visually and use domain knowledge to interpret patterns and make judgements at each stage.

Design an analytical workflow for this problem.

4 Model

I'm setting up a framework to analyze the Vastopolis outbreak using the microblog data, city geography, population zones, and weather patterns to trace where the outbreak started and how it spread through the population.

I'm drawing on several visualization and analysis techniques from the literature: Jigsaw for extracting entities and symptoms from the microblog text, movement clustering methods to identify significant locations where people congregated, temporal pattern visualization to track when cases appeared, and spatio-temporal modeling to understand how the infection propagated across zones. Some approaches like disease progression visualization and event sequence analysis could help me stage how the infection evolved over time.

The core workflow is filtering geolocated microblogs for flu-related content, then geocoding and timestamping them to build a spatio-temporal dataset. From there I'd apply density clustering to pinpoint outbreak origins, analyze temporal case counts to determine when and where it started, overlay geographic features like water bodies and highways to test transmission routes, and incorporate wind data to evaluate whether airborne spread explains the observed patterns. Then I'd validate the extracted entities through manual sampling to ensure the classifier is catching the right signals. For the temporal analysis, I'm aggregating message counts across the city and by zone to spot when the outbreak begins, using a calendar view to identify the sharp uptick in activity and clustering similar days to pinpoint the anomaly onset.

For the spatial component, I'm treating each geolocated flu message as an event and applying density-based clustering to find spatial hotspots and their timing, which helps identify the likely origin versus later spread zones. I'll also normalize incidence rates by population across the 13 zones to account for differences in baseline activity.

In Stage 4, I'm overlaying the hotspot locations and spread direction against contextual map features—highways for mobility-driven transmission, water bodies for potential contamination sources, landmarks like hospitals that might indicate reporting bias or point-source events—and then comparing the spatial spread pattern of new cases against wind direction and speed data to test whether airborne transmission aligns with the observed spread. cases concentrated in zones sharing that water source rather than spreading diffusively. For case linking, I'd extract social mentions from microblogs—coworkers, shared locations, family connections—to map person-to-person transmission chains and validate whether clusters align with social networks or workplaces. Then I'd iterate through spatial clusters, temporal curves, wind patterns, and text evidence together to test which transmission hypothesis best fits the data.

The system should coordinate multiple linked views: a map showing heatmaps, hotspot clusters, wind vectors, water bodies, and highways; a timeline tracking case counts colored by cluster; a text panel for reading actual microblog content; and a correlation view checking wind lag against spread timing. I'd also examine severity mentions and death locations—early severe cases near the true source would narrow down the origin point given the incubation period.

Now I'm structuring this as a design template that references established visualization workflows: entity extraction and symptom parsing from raw data with human feedback, temporal aggregation using hourly bins across the outbreak window with burst detection metrics, and spatial hotspot identification to pinpoint significant locations.

For the spatio-temporal component, I'm drawing on frameworks that group zones by similar temporal patterns and model their growth curves, then examining lagged correlations between wind conditions and disease spread using cross-impact detection methods.

Then I'd extract person-to-person relationships from text data, overlay everything onto a map with contextual features like highways and hospitals, and iterate through the analysis with human feedback to refine hypotheses and build the final narrative.

Now I'm structuring the full answer as a linear pipeline with distinct stages, each tied to specific analytical workflows so someone can actually follow and reproduce the approach. I'll frame it around three core questions—when and where it started, how it spread spatially over time, and what the transmission mechanism was—then walk through stages A through G with the appropriate visual encodings, interactions, and decision points where an analyst needs to make judgments.

Recommended Analytical Workflow: Vastopolis Outbreak — Origin and Transmission Mechanism

The task decomposes into three linked analytical questions that should be addressed in sequence but revisited iteratively:

  1. When and where did the outbreak begin? (spatio-temporal origin detection)
  2. How did it spread? (diffusion pattern in space and time)
  3. What is the likely transmission mechanism — person-to-person, airborne, waterborne, or other — inferred from how the spread pattern relates to human mobility infrastructure, water bodies, and wind?

Because microblog text is unstructured, population data is tabular, and weather is a bivariate time series, the workflow combines text-mining/entity-extraction logic (from Jigsaw), event-to-place extraction (from "From Movement Tracks through Events to Places", Andrienko et al. 2011), spatio-temporal grouping and modelling (from "A Visual Analytics Framework for Spatio-Temporal Analysis and Modelling," Andrienko & Andrienko 2013), calendar/temporal-cluster reasoning (from van Wijk & van Selow's Cluster and Calendar-Based Visualization), and lagged cross-series analysis (from "Detecting Stable Cross-Impact Patterns in Bivariate Time Series," Andrienko et al. 2026) to test the wind/airborne hypothesis specifically.


Stage A — Extract candidate illness events from microblog text

Goal: turn raw geolocated text into a structured set of "illness-report events," each with a location, timestamp, and semantic content.

  • Build a lexicon of flu-related symptom terms (fever, cough, vomiting, headache, chills, "sick," "dying," "hospital," "ER," etc.) and apply keyword/entity extraction to every message, analogous to Jigsaw's entity extraction step where persons, locations, organizations, and dates are pulled from text. Here the extracted "entities" are symptom mentions, severity indicators (e.g., mentions of death or hospitalization), and place/landmark references embedded in the text (which may be more precise than the GPS tag, e.g., "at the lake festival").
  • As in Jigsaw, treat extraction as imperfect: the analyst samples and corrects false positives/negatives (e.g., "flu-like" sarcasm, unrelated "sick of my job" posts) before trusting the derived event set. This mirrors Jigsaw's entity-correction loop and the human-in-the-loop feature-validation step from "Feature Engineering for Behaviour Pattern Recognition" (Andrienko et al. 2024), where engineered indicators are checked visually against representative examples before being trusted for further analysis.
  • Tag each retained message with a severity level (mild symptom mention vs. severe/death mention), since severity will later help disambiguate early point-source cases from general community spread.
  • Output: a table of geolocated, time-stamped "illness events," each with symptom type(s), severity, and raw text (kept for later drill-down reading).

Stage B — Temporal overview: detect onset and growth pattern

Goal: establish when the sharp increase began and whether it has a single abrupt onset (point-source signature) or a gradual ramp (person-to-person diffusion signature).

  • Aggregate illness-event counts into hourly (or 6-hour) bins, city-wide and per zone, producing a short multivariate time series (13 zones × time).
  • Use a timeline/heatmap overview in the spirit of IVESA: sort zones by onset time, event density, or burst intensity; visually inspect for gaps, sudden bursts, and regularity versus irregularity of report accumulation.
  • Where the data spans enough days to show daily rhythm (e.g., normal daytime microblogging vs. night silence), apply the van Wijk Cluster-and-Calendar logic: split the series into daily profiles, cluster days by shape (using a normalized or offset-corrected distance so that the outbreak's abnormal shape stands out from the "normal" pre-outbreak baseline), and display cluster membership per day. This immediately flags the specific day(s) that break from the baseline pattern — the operational start of the outbreak — without requiring the analyst to predefine a threshold.
  • Judgment point: identify the earliest zone(s) whose case curve deviates from baseline. These are candidates for the spatial origin, to be confirmed in Stage C.

Stage C — Spatial hotspot / significant-place extraction

Goal: convert scattered illness events into a small number of interpretable "significant places," and identify which one is earliest (candidate origin).

This stage directly follows the workflow in "From Movement Tracks through Events to Places" (Andrienko et al. 2011), substituting illness-report events for the paper's m-events:

  • Apply density-based clustering (DBSCAN-like) to the illness events in space and time jointly, using a distance function that combines spatial proximity and temporal proximity (and optionally symptom similarity), so that events close in space but far apart in time are not merged, and events in different unrelated locations are not merged. Isolated events are treated as noise.
  • Build spatial buffers/hulls around each event cluster to delineate candidate "outbreak places" (e.g., a park, a water treatment plant vicinity, a stadium, a hospital catchment).
  • For each place, compute a small time series of event counts, enabling a "when did this place become active" comparison across places — mirroring the paper's aggregation of events by place into time series.
  • Cross-reference the earliest, most severe cluster(s) with the city map's landmark layer (hospitals, water bodies, event venues) to see whether the earliest cluster coincides with a specific fixed feature (e.g., a reservoir, a festival ground) — a signature consistent with a point-source (waterborne or common-exposure) event, as opposed to diffuse residential spread consistent with person-to-person transmission.
  • Normalize event counts per place/zone by the 13-zone population statistics, producing incidence-per-capita rather than raw counts, since a raw count of reports may simply reflect population density or Twitter usage density rather than true attack rate.

Stage D — Spatio-temporal grouping and growth modelling across zones

Goal: determine whether the 13 zones behave as one expanding front (diffusion) or as several independently-seeded clusters (multiple point sources / common exposure).

Following the Spatio-temporal Analysis and Modelling framework (Andrienko & Andrienko, 2013):

  • Treat each zone's per-capita incidence time series as one spatial time series. Cluster zones by similarity of temporal profile (e.g., k-means or hierarchical clustering on normalized incidence curves), using a linked time-graph + map display so the analyst can check whether temporally similar zones are also spatially adjacent (supporting contiguous diffusion, e.g., along highways) or spatially disconnected (supporting a shared non-contact cause, e.g., a common water source or wind-borne plume).
  • Fit a simple growth model (e.g., exponential/logistic onset curve) to each group's representative curve and inspect residuals over time and space, as in the source workflow, to detect zones that deviate from the dominant growth pattern — these deviating zones are candidates for a distinct secondary source or a differently-timed exposure (e.g., a downwind zone affected only after a wind-driven delay).
  • Overlay zone clusters on the map together with the highway network: if the incidence-similar/temporally-lagged zones are strung along major highways or transit corridors, this favors person-to-person/mobility-driven spread; if they are unrelated to the road network but spatially coincide with a shared water body or its service area, this favors waterborne transmission; if they align with a downwind sector regardless of road connectivity or population contact, this favors airborne spread.

Stage E — Wind–spread cross-impact analysis (testing the airborne hypothesis specifically)

Goal: rigorously test whether the direction and timing of spread is statistically consistent with wind advection from the candidate origin, using a lagged-correlation approach rather than eyeballing alone.

This stage directly adapts "Detecting Stable Cross-Impact Patterns in Bivariate Time Series" (Andrienko et al., 2026):

  • Define the base series as the daily wind vector (speed and direction) at/near the candidate origin place identified in Stage C.
  • Define the response series as a directional exposure measure per zone: e.g., the daily per-capita incidence in each of the other 12 zones, or better, a projected "downwind alignment score" per zone (how well the zone's bearing from the origin matches the day's wind direction).
  • Slide a time window across the base series and compare it with time-shifted windows of each zone's response series over a range of plausible incubation lags (using a tolerance-based association measure such as the paper's tolerance-Kendall's-tau, which is robust to noisy daily fluctuations).
  • Visualize the resulting time×lag impact matrix with an Ikat-style plot for each zone (or for an aggregated "downwind vs upwind" comparison), and calibrate window length, lag range, and tolerance interactively while cross-checking against the actual wind and incidence series behind any cell.
  • Interpretation: if downwind zones show a consistent positive impact at a lag plausible for airborne incubation/dispersal, and upwind/crosswind zones do not, this is strong evidence for airborne transmission from the identified origin. If no stable directional lag pattern emerges (spread is equally likely upwind, downwind, and cross-wind, or tracks population/road proximity instead), airborne transmission from a single point source is less supported, and the analyst should weight person-to-person or waterborne explanations more heavily.

Stage F — Person-to-person and waterborne hypothesis checks

Goal: directly test the two remaining mechanisms using complementary evidence, since Stage E only tests the wind/airborne hypothesis.

  • Person-to-person check: using the corrected illness-event set from Stage A, extract social/co-location mentions from the text (e.g., "my coworker," "my whole family," shared venues, shared bus/train lines) — the same entity/relation-extraction logic as Jigsaw, here applied to build a light co-occurrence network of people/places mentioned together. If cases chain along social/mobility links (school, workplace, transit routes) and the spatial growth in Stage D tracks the highway/transit network rather than a single fixed landmark, this supports person-to-person spread following normal human contact and commuting patterns.
  • Waterborne check: overlay the earliest and largest clusters from Stage C directly on the map's water-body layer and any known water-distribution/service-area boundaries for the 13 zones (if available via the population/zone metadata). A waterborne signature would show: (a) an origin cluster physically coincident with a water source (reservoir, treatment plant, river) rather than a crowded public venue; (b) case distribution matching the water utility's service zones rather than geographic proximity or road adjacency; (c) no dependence on wind direction (ruling out Stage E's airborne signature) and no dependence on social/mobility chains (ruling out Stage F's person-to-person signature).
  • Because these are complementary, mutually-exclusive-leaning hypotheses, structure this stage as a comparison table/checklist: for each candidate mechanism, list the diagnostic spatial/temporal/contextual signature expected, and whether the data satisfies it — supporting transparent, auditable reasoning rather than a single black-box conclusion.

Stage G — Synthesis, drill-down, and reporting

Goal: consolidate findings into a defensible narrative the public-health team can act on.

  • Maintain a coordinated multi-view dashboard throughout: (1) a map view showing hotspot clusters, water bodies, highways, hospitals, and wind vectors per day; (2) a timeline/calendar view showing zone-level incidence and cluster membership over time; (3) a text drill-down panel to re-read raw microblog content behind any cluster or spike (essential domain-knowledge check, as emphasized throughout Jigsaw's Document View and the raw-record drill-downs in DPVis and Kokiri); (4) the Ikat-style wind-impact panel from Stage E; (5) a zone table with population-normalized rates.
  • Use an iterative "propose → visualize → validate against raw text/map → refine" loop, consistent with the general pattern seen across the library (e.g., explAIner's understand–diagnose–refine cycle and SOMFlow's provenance-tracked iterative refinement): each hypothesis about origin or mechanism should be checked against raw messages and map context before being accepted, and parameter choices (clustering distance, lag window, tolerance) should be logged so the reasoning is reproducible.
  • Deliverable: a short evidence-linked report identifying (a) the most probable origin place and time window, (b) the dominant spread pattern (contiguous/road-following vs. wind-directional vs. water-service-area-bound), and (c) the best-supported transmission mechanism with the specific visual/statistical evidence (Stage C cluster map, Stage D growth/residual plots, Stage E Ikat wind-lag plot, Stage F checklist) cited for each claim, so emergency-management resources can be targeted (e.g., quarantine/contact-tracing near roads, water-supply intervention, or air-quality/evacuation measures) accordingly.
5 Researcher

Make a list of papers from which you have taken relevant approaches.

6 Model

Here is the list of papers/workflows from the Workflow Library that I drew on for the Vastopolis outbreak-analysis design, with a note on what specific approach or logic was taken from each:

Papers Cited in the Recommended Workflow

  1. Jigsaw: Supporting Investigative Analysis through Interactive Visualization J. Stasko, C. Görg, and Z. Liu. Information Visualization, 7(2), 118–132, 2008. doi: 10.1057/palgrave.ivs.9500180 Used for: entity/keyword extraction from microblog text (Stage A), human correction of extraction errors, and the raw-text drill-down/document-verification logic (Stage G); also informed the co-occurrence/relation-extraction approach for testing person-to-person transmission (Stage F).

  2. From Movement Tracks through Events to Places: Extracting and Characterizing Significant Places from Mobility Data G. Andrienko, N. Andrienko, C. Hurter, S. Rinzivillo, and S. Wrobel. IEEE VAST, 2011. doi: 10.1109/VAST.2011.6102454 Used for: the core event-to-place extraction logic in Stage C — converting geolocated illness-report "events" into density-clustered "significant places" using combined spatio-temporal distance functions, then aggregating events into per-place time series.

  3. Cluster and Calendar Based Visualization of Time Series Data J. J. van Wijk and E. R. van Selow. IEEE InfoVis '99, 1999. doi: 10.1109/INFVIS.1999.801851 Used for: the daily-profile clustering and baseline-deviation detection approach in Stage B, applied to detect the onset day(s) that break from the "normal" pre-outbreak pattern.

  4. A Visual Analytics Framework for Spatio-Temporal Analysis and Modelling N. Andrienko and G. Andrienko. Data Mining and Knowledge Discovery, 27(1), 55–83, 2013. doi: 10.1007/s10618-012-0285-7 Used for: the zone-grouping, representative-curve modelling, and residual-inspection logic in Stage D — clustering the 13 zones by temporal incidence similarity and checking spatial coherence against the map.

  5. Detecting Stable Cross-Impact Patterns in Bivariate Time Series G. Andrienko, N. Andrienko, M. Akila, B. Kathirgamanathan, and M. Ponce-de-Leon. IEEE TVCG, 32(7), 5996–6013, 2026. doi: 10.1109/TVCG.2026.3676810 Used for: the lagged cross-impact/Ikat-plot methodology in Stage E, adapted to test whether wind direction/timing at the candidate origin is followed by consistent downwind incidence increases (airborne hypothesis testing).

  6. Human-in-the-Loop: Visual Analytics for Building Models Recognizing Behavioral Patterns in Time Series (Feature Engineering for Behaviour Pattern Recognition) N. Andrienko, G. Andrienko, A. Artikis, P. Mantenoglou, and S. Rinzivillo. IEEE Computer Graphics and Applications, 44(3), 14–29, 2024. doi: 10.1109/MCG.2024.3379851 Used for: the human-in-the-loop validation principle applied in Stage A — visually checking extracted symptom/severity indicators against representative examples before trusting them for further analysis.

7 Researcher

You have designed a visual analytics workflow for a specific task, expressing it in natural language. In this second stage, I am now uploading the ATWL specification and one example workflow expressed in ATWL. Your task is to produce an ATWL representation of the workflow you designed in the previous stage.

This is not a mechanical translation. Please express your workflow in the ATWL vocabulary using its artifact types, transform intents, actor designations, loop constructs, and specification artifacts in the way that most faithfully captures the analytical process you described in your natural-language recommendation. Where your natural-language description implied structure that is naturally expressed as an ATWL construct (for example, an iterative refinement step that is naturally expressed as a loop with an assess transform and a specification artifact), please make this structure explicit in the ATWL representation.

At the same time, please be honest about what your original recommendation supports. If a phase of your workflow was described only as a linear sequence of steps without explicit iteration, without human-machine actor distinctions, or without specifications being updated, please do not fabricate these elements to make the ATWL representation appear more sophisticated. The goal is to represent, in ATWL, the workflow you actually designed, not a hypothetically enhanced version of it.

After you produce the ATWL representation, please briefly note any structural elements you added that were implicit in your original recommendation. This helps me understand the difference between what your original design communicated explicitly and what your ATWL representation makes explicit. If some structural elements in the ATWL are new additions rather than translations of what was already there, please say so.

Please read the ATWL specification and the example carefully before proceeding. Do you have any questions about the language or the syntax before you produce the ATWL representation?

8 Model

I'm working through how to represent my Vastopolis workflow using ATWL constructs, starting with mapping the input artifacts. I need to clarify the structure of the microblogs data—specifically how entities and their embedment properties relate to the messages and their geolocation information.

For the map features, I'm thinking of this as a separate artifact containing static geographic entities like highways, hospitals, landmarks, and water bodies, each with spatial embedment and categorical type features. I'm also defining the zones artifact as regional entities with population statistics, and starting to work through the weather data structure.

Now I'm moving into Stage A of the analysis pipeline, which focuses on extracting candidate illness events from the microblog text. I'm designing a transformation that uses keyword and entity extraction to pull symptom and severity indicators from the text, drawing on a symptom lexicon. The key insight here is treating this extraction as inherently imperfect—like in Jigsaw—so I'm building in a human-in-loop validation step where an analyst can sample and correct false positives and negatives before the derived event set gets trusted. Once the lexicon is refined, I exit the validation loop and move on to filtering the microblogs to identify actual illness events—keeping only those messages that contain the validated symptom and severity indicators, with both human review and automated filtering working together to create the final dataset of illness-related posts.

Now I'm structuring these illness events with temporal and spatial embeddings, storing features like symptom type, severity level, and the raw text for reference, then moving into the temporal analysis phase where I'll aggregate the events into time bins organized by zone and time period to detect patterns and onset timing. Now I'm adding the hourly profile as a feature on each day, then clustering those days by the similarity of their profile shapes to create day clusters with categorical labels. Finally, I'm arranging these clustered days within a calendar structure for temporal context. ern as a textual description of the onset day(s) and deviating zones. From this pattern, I'm formulating candidate statements about the earliest zones and onset time windows that deviate from baseline. Then moving into Stage C, I'm defining spatial hotspots by applying spatio-temporal density clustering to the illness events to extract significant places. I'm normalizing the event counts by population to get per-capita incidence rates, then mapping these place clusters onto geographic features like landmarks and water bodies, and finally visualizing the resulting hotspots on an interactive map.

From the visualization, I'm identifying candidate origin locations by examining where the earliest and most severe clusters coincide with fixed geographic features like reservoirs or festival grounds. Now I'm moving into zone-level analysis to compute per-capita incidence rates across different geographic zones and model how the outbreak spreads over time. Now I'm mapping the zone groups onto the geographic features like highways, then fitting growth curves to the incidence data for each zone group to capture exponential or logistic patterns. After that, I'm computing the residuals between the observed incidence and the model predictions to see where the growth model deviates from reality, and visualizing those residuals.

Next, I'm interpreting the spatial patterns by looking at whether zones with similar temporal dynamics are clustered together along highways (suggesting diffusion) or scattered apart (suggesting shared exposure), flagging any zones that don't fit the pattern. Then I'm moving into analyzing how wind patterns might explain spread across zones, starting with establishing baseline wind data at the origin point and measuring how zone incidence responds to it.

I'm computing a directional alignment score for each zone that captures how well it aligns with the prevailing wind direction from the suspected origin, then partitioning the time series into sliding windows to compare the base wind signal against zone incidence responses across different time lags. F_impact_matrix gets visualized as a wind impact plot, then I'm setting up a calibration loop that iteratively refines the window length, lag range, and tolerance parameters until the impact matrix reveals a stable, interpretable directional lag pattern that either supports or contradicts the airborne hypothesis. Inside this loop, I'm assessing the impact patterns to guide the calibration process. Now I'm formulating statements about airborne transmission evidence based on the downwind lag patterns observed in the impact matrix. Moving into Stage F, I need to extract social contact mentions from the illness event data to check person-to-person transmission, then define the entities and relationships for a co-occurrence network.

I'm visualizing this social network as a node-link diagram to identify whether cases cluster along social and mobility connections that align with highway or transit routes. The waterborne hypothesis check is coming next.

Now I'm overlaying water bodies and service zones on the map to examine potential waterborne transmission patterns, then comparing all three hypotheses—airborne, person-to-person, and waterborne—against the evidence to identify which mechanisms best explain the outbreak. I'm deciding whether to represent the coordinated dashboard as a separate visualization or just note that the views work together, and I'm treating the general iterative loop of proposing, visualizing, and refining as an underlying principle rather than a distinct artifact since I've already modeled specific validation loops. Now I'm ready to sketch out the template structure, starting with how the stages connect—extraction and filtering in stage A, then moving into daily episode definition and clustering.

Continuing through the remaining stages: places are derived and contextualized with visualization and abstraction, zones get clustered with residual analysis and model building, windows capture cross-impacts through iterative visualization and assessment, the social network gets visualized with a water overlay for additional context, and finally the report synthesizes everything. I'm framing this as a template using intents where characterization feeds into assessment loops that cycle back to refine the characterization. Writing template structure... Continuing through the remaining analysis steps—wind alignment and lag windows to assess cross-impacts, then social media mentions and network analysis, water overlay visualization, and finally the mechanism checklist and report generation. Now I'm ready to write out the full ATWL body systematically with all artifacts and transforms, making sure the entity definitions align with the spec.

Defining the microblogs artifact with elementary structure, space-time embedment, and text content as the key feature. Then the map features artifact capturing static geographic elements like highways and landmarks. Moving into the zones artifact next... I'm defining a symptom lexicon with flu-related terms and severity indicators, then setting up a text extraction transform that pulls symptom mentions and severity signals from the microblogs using this lexicon to generate symptom features.

The extracted features capture symptom types, severity levels, and place references for each message, and I'm establishing a validation loop where a human samples and inspects the extracted indicators against the raw text to assess extraction quality until the false positive and negative rates reach an acceptable threshold. After refining the lexicon based on the validation results, I update the extracted features and lexicon artifacts, then either loop back to re-extract with the improved rules or exit the validation loop if quality is acceptable. Next, I'm moving into defining illness events as a higher-level unit from the extracted symptom indicators. Now I'm defining the time-partitioning stage to aggregate these illness events into hourly or 6-hour bins grouped by zone and day, creating daily episode records with vector counts and temporal metadata.

Next, I'm characterizing each daily episode by normalizing its hourly count patterns into comparable profile shapes that can be used for clustering and baseline deviation analysis.

Then I'm setting up a clustering transform that groups days together based on the similarity of their daily profile shapes...

Defining cluster artifacts... Defining the calendar visualization that marks each day's cluster membership to highlight baseline versus deviating patterns, then moving into the abstraction layer for detecting onset days. Now I'm defining a machine-driven clustering stage that groups illness events by spatial and temporal proximity to identify candidate outbreak locations, filtering out isolated cases as noise, and tracking which events belong to each place cluster. Defining the place-level time series feature and then normalizing event counts by population to get per-capita incidence rates for each place, which I'll then arrange on a map for visualization. Continuing the visualization description with the map hotspots showing candidate places encoded by color and size based on incidence and timing, overlaid on geographic features. Then I'm moving to the abstraction phase where a human interprets these visual patterns to identify the most likely origin location(s).

Now I'm shifting to Stage D, where I need to compute per-capita incidence rates for each of the 13 zones by normalizing the illness events against population data, creating a time series for each zone.

Then I'm clustering these zones based on how similar their temporal incidence patterns are, grouping them together and assigning categorical labels to identify which zones share comparable outbreak trajectories.

Next, I'm positioning these zones on a map context that includes the highway network, using geographic coordinates to show their spatial relationships. Finally, I'm creating a visualization that colors the zones according to their similarity groups on this map, incorporating the underlying map features to provide geographic context. Now I'm fitting exponential or logistic growth curves to each temporal group's incidence pattern to model how the outbreak expanded within each zone cluster. Then I'll compute the residuals between observed and fitted values to identify zones that deviate from their group's typical growth trajectory.

I'm creating a visualization that overlays these residuals on a geographic map or aligned timeline view, highlighting zones with unusually large deviations that might indicate a separate infection source or delayed exposure pattern.

Now I need to interpret the overall spread pattern by examining whether the zone groupings align with transportation networks and mobility corridors—suggesting person-to-person transmission—or if they're spatially scattered in ways that point toward a shared environmental exposure, while flagging any anomalous zones as potential secondary sources.

Moving into the next phase, I'm computing how well each zone's directional bearing from the suspected origin aligns with the prevailing wind direction on each day, creating a feature that captures this downwind alignment for every zone.

Now I need to establish the lag specification parameters—the initial window size, range of possible lags, and tolerance thresholds—that will guide the cross-impact analysis between wind patterns and the zone response series. Then I'm partitioning both the weather data and each zone's incidence and alignment series into sliding windows across different plausible incubation lags to enable comparison.

Next I'm computing a tolerance-based association measure like tolerance-Kendall's-tau across this window and lag grid to quantify how strongly wind conditions in one zone predict response patterns in downwind zones, producing a matrix indexed by zones with numeric values representing the lagged associations.

Then I'm setting up a calibration loop where I iteratively adjust the window length, lag range, and tolerance parameters until the resulting impact matrix reveals a stable directional lag pattern—or confirms there isn't one—that's interpretable enough to test the airborne hypothesis. Within that loop, I'm visualizing the impact matrix as an ikat-style plot to inspect the time-lag patterns across zones. ield a stable, interpretable impact pattern by cross-checking any anomalies against the actual wind and incidence data. This judgment then feeds into a refinement loop where I adjust the window length, lag range, or tolerance parameters if needed to improve the matrix quality.

I'm realizing the loop structure needs adjustment—the cross-impact computation should happen inside the calibration loop itself, not just once at the start, so that each iteration recalculates the impact matrix with the updated lag specifications. I need to compute the downwind alignment once before the loop since it doesn't depend on the lag spec, then set up the main loop to recompute the windows and impact matrix each iteration based on the evolving spec. The loop continues until the impact matrix stabilizes enough to evaluate the airborne transmission hypothesis. The refinement loop continues iteratively until the impact quality assessment indicates no further changes are needed, at which point we exit and move toward generating knowledge statements about airborne evidence using the final impact visualization and matrix.

Now I'm defining a transformation to extract social context mentions from the illness events data, identifying shared locations, social connections, and transportation patterns that might indicate person-to-person transmission routes.

Then I'm building a co-occurrence network from these social mentions, where nodes represent people and places, and edge weights capture how frequently they appear together across different illness events.

Now I'm creating a force-directed visualization of this network so we can see the contact chains and mobility patterns among cases at a glance.

Abstracting person-to-person patterns... I'm creating a map visualization that overlays the hotspot clusters directly onto water bodies and service-area boundaries to check whether cases cluster around water sources. Then I need to interpret this visual pattern to identify whether waterborne transmission explains the distribution. Defining the mechanism assessment checklist... Checking that all declared artifacts are used before reference, verifying feature value types like categorical and ordinal are valid, and confirming the mixed-type vector structure for symptom features works within the spec. Now I'm aligning the template with the actual transform sequence, using loop notation consistently for the extraction and wind analysis loops while avoiding unnecessary nesting. Writing the ATWL template... Checking that F_impact_matrix's type declaration aligns with its structure as a time-by-lag matrix per zone, which matches the pairwise similarity matrix pattern. P_spread_pattern is referenced later in Stage F, and it's properly declared earlier as an output from the abstract transform in Stage D. Now I need to verify whether V_wind_impact, which is declared inside the loop body, remains accessible to K_airborne_evidence after the loop completes.

Looking at the example, artifacts defined within loop iterations like D_clusters and V_clusters are referenced later at Step 4 outside the loop, using their final state from the last iteration. This confirms that the pattern of consuming loop-body artifacts after the loop ends is valid in ATWL, which means my design using V_wind_impact and F_impact_matrix after L_wind_analysis follows the same established style.

Now I'm verifying the remaining pieces: K_impact_quality stays confined to the loop, S_lag_spec follows the reassignment pattern where it's given initially then only modified inside the loop if refinement is needed. With those confirmed, I'm ready to finalize the workflow template string that sequences the transforms in order, starting with extracting symptom features, looping through assessment and lexicon refinement, then moving through the unit definitions, characterizations, and visualizations.

Continuing with the full template: after the initial symptom processing and daily profiling, the workflow branches into geographic analysis—deriving places, computing timeseries and per-capita incidence, mapping and visualizing—then clustering zones and modeling growth patterns with residual analysis. It then examines downwind alignment through a loop of lag windows and cross-impact assessment, followed by social network analysis and water overlay visualization. I've got everything I need from the spec and attachments, so I'll proceed directly to producing the ATWL representation along with notes on the structural elements that became explicit in this formalization.

I've read the ATWL specification and the example workflow carefully. No questions — I'll proceed directly to the ATWL representation of the Vastopolis workflow.

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 ->
            define-unit (derive-places) -> characterise (place-timeseries) ->
            characterise (per-capita-incidence) -> contextualise (map) ->
            visualise -> abstract ->
            characterise (zone-incidence) -> define-unit (cluster-zones) ->
            contextualise (map) -> visualise -> build-model (growth) ->
            characterise (residuals) -> visualise -> abstract ->
            characterise (downwind-alignment) ->
            loop(define-unit (lag-windows) -> characterise (cross-impact) ->
                 visualise -> assess) ->
            generate-knowledge ->
            characterise (social-mentions) -> define-unit (social-network) ->
            visualise -> abstract ->
            visualise (water-overlay) -> abstract ->
            generate-knowledge (mechanism-checklist) ->
            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."

# ============================================================================
# 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"
  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
# ============================================================================

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 (e.g., sarcastic
        'sick of...') 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 symptom vs.
        severe/hospitalization/death mention)"
    - 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
# ============================================================================

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 (baseline vs.
    deviating) 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 (day -> calendar cell); 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 outbreak onset time window and
    earliest zone(s) as working hypothesis for spatial origin"

artifact K_onset_candidates : knowledge(D_days)
  representation form: "statements"
  description: "Candidate onset time window and earliest-affected zone(s),
    to be confirmed against place-level evidence"

# ============================================================================
# STAGE C: SPATIAL HOTSPOT / SIGNIFICANT-PLACE EXTRACTION
# ============================================================================

transform T_define_places :
  intent: define-unit
  manner: "derive-places (spatio-temporal density clustering)"
  input: D_illness_events
  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 (spatio-temporal event
    clusters) derived from illness events"

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 (highways,
    hospitals, landmarks, water bodies)"

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 identification of the earliest and most severe
    place cluster(s) and their co-location with fixed landmarks"

transform T_abstract_origin_candidate :
  intent: abstract
  manner: "perception-and-interpretation"
  input: V_map_hotspots
  output: P_origin_candidate
  actor: human
  description: "Identify candidate origin place(s) and note whether they
    coincide with a specific fixed feature (e.g., reservoir, festival
    ground) versus diffuse residential spread"

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

# ============================================================================
# STAGE D: SPATIO-TEMPORAL GROUPING AND GROWTH MODELLING ACROSS ZONES
# ============================================================================

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"

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_cluster_zones :
  intent: define-unit
  manner: "cluster-by-similarity of incidence profile"
  input: D_zones, F_zone_incidence
  output: D_zone_groups, F_zone_group_label
  actor: machine
  description: "Group the 13 zones by similarity of their temporal
    incidence profile"

artifact D_zone_groups : entities
  internal structure: group/cluster
  embedment: space
  description: "Groups of zones with similar temporal incidence profiles"

artifact F_zone_group_label : feature(D_zones)
  value structure: atomic
  value type: categorical
  description: "Temporal-similarity group label for each 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 the highway
    network"

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

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 temporal-similarity group,
    overlaid on the highway network, to check spatial contiguity versus
    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 from D_map_features"
  description: "Visual check of whether temporally similar zones are
    spatially contiguous/highway-aligned or spatially disconnected"

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 an exponential/logistic 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: "Simple growth model of outbreak onset/expansion per zone
    group"

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, to flag zones deviating from the dominant
    pattern"

artifact F_growth_residuals : feature(D_zones)
  value structure: vector
  value type: numeric
  description: "Residual time series per zone relative to fitted growth
    model"

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: "Map and/or timeline view highlighting zones with large
    residuals (candidates for a distinct secondary source or delayed
    exposure)"

artifact V_residuals_map : visualisation(F_growth_residuals, A_map_zones)
  layout: "geographic map / aligned timelines"
  form: "coloured marks / line graph"
  encoding: "colour or line deviation: from F_growth_residuals; position:
    from A_map_zones"
  description: "Highlights zones whose incidence deviates from the
    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 zone grouping follows the
    highway/mobility network (favouring person-to-person spread) or is
    spatially disconnected (favouring a shared, non-contact exposure);
    flag deviating zones as candidate secondary sources"

artifact P_spread_pattern : pattern(D_zone_groups, F_growth_residuals)
  representation form: "textual description"
  description: "Description of the dominant spread geometry
    (contiguous/highway-aligned vs. disconnected) and any deviating zones"

# ============================================================================
# STAGE E: WIND-SPREAD CROSS-IMPACT ANALYSIS (AIRBORNE HYPOTHESIS)
# ============================================================================

transform T_characterise_downwind_alignment :
  intent: characterise
  manner: "compute directional alignment relative to wind"
  input: D_zones, D_weather, P_origin_candidate
  output: F_downwind_alignment
  actor: machine
  description: "For each zone 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: vector
  value type: numeric
  description: "Daily downwind alignment score per zone relative to the
    candidate origin place"

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
    to test the airborne transmission hypothesis"
  until: "Impact matrix is stable/interpretable enough to support a
    judgment on the airborne hypothesis"
  body:

    transform T_define_lag_windows :
      intent: define-unit
      manner: "time-partitioning into sliding windows"
      input: D_weather, F_zone_incidence, S_lag_spec
      output: D_windows
      actor: machine
      description: "Partition the wind series and each zone's 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 when comparing base and
            response series in this window"
      description: "Sliding time windows used to compare the wind (base)
        series with each zone's response series at varying lags"

    transform T_characterise_cross_impact :
      intent: characterise
      manner: "compute lagged association (tolerance-based)"
      input: D_windows, D_weather, F_zone_incidence, F_downwind_alignment,
             S_lag_spec
      output: F_impact_matrix
      actor: machine
      description: "Compute a tolerance-based association measure (e.g.,
        tolerance-Kendall's-tau) between the wind base series and each
        zone's response series 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 (Ikat-style)"
      description: "Per-zone 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 (or aggregated downwind vs. upwind
        comparison)"

    artifact V_wind_impact : visualisation(F_impact_matrix)
      layout: "time x lag grid, per zone"
      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_zone_incidence
      output: K_impact_quality
      actor: human
      description: "Judge whether the current window/lag/tolerance
        settings yield a stable, interpretable impact pattern,
        cross-checking suspicious cells against the underlying wind and
        incidence series"

    artifact K_impact_quality : knowledge(F_impact_matrix)
      representation form: "quality judgment"
      description: "Judgment of whether the impact matrix is
        stable/interpretable or requires recalibration of parameters"

    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
            based on assessment"

        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 a statement on whether downwind zones show a
    consistent lagged impact from wind at the candidate origin, supporting
    or refuting airborne transmission"

artifact K_airborne_evidence : knowledge(F_impact_matrix)
  representation form: "statements"
  description: "Evidence for or against airborne transmission based on
    stable directional wind-lag association"

# ============================================================================
# STAGE F: PERSON-TO-PERSON AND WATERBORNE HYPOTHESIS CHECKS
# ============================================================================

transform T_characterise_social_mentions :
  intent: characterise
  manner: "extract (co-location/social mentions from text)"
  input: D_illness_events
  output: F_social_mentions
  actor: hybrid
  description: "Extract mentions of shared social context (coworkers,
    family, shared venues, shared transit lines) 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_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 (single relational structure)"

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"

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"

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 whether cases chain along social/mobility links and
    whether spatial growth tracks the highway/transit network rather than
    a single fixed landmark"

artifact P_p2p_pattern : pattern(D_social_network, D_zone_groups)
  representation form: "textual description"
  description: "Description of evidence for/against person-to-person
    transmission via social and mobility chains"

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

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

transform T_abstract_waterborne_pattern :
  intent: abstract
  manner: "perception-and-interpretation"
  input: V_water_overlay, P_origin_candidate
  output: P_waterborne_pattern
  actor: human
  description: "Assess whether the origin/hotspot clusters coincide with a
    water source and whether case distribution matches water-service areas
    rather than road proximity or social chains"

artifact P_waterborne_pattern : pattern(D_places)
  representation form: "textual description"
  description: "Description of evidence for/against waterborne
    transmission"

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
    spatial/temporal/contextual signature of each transmission mechanism
    (airborne, person-to-person, waterborne) against the observed
    evidence"

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"

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

transform T_synthesise_report :
  intent: generate-knowledge
  manner: "write-summary"
  input: K_onset_candidates, P_origin_candidate, K_mechanism_assessment
  output: K_final_report
  actor: human
  description: "Synthesise the probable origin place and time window, the
    dominant spread pattern, and the best-supported transmission mechanism
    into an evidence-linked report for emergency management"

artifact K_final_report : knowledge(D_places, D_zone_groups,
    F_impact_matrix)
  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"

Notes on structural elements made explicit (vs. added)

Faithful translations (structure already implied in the natural-language design): - The two iterative "sample → correct → re-extract" and "calibrate → inspect → adjust" processes (Stage A text validation; Stage E wind-lag calibration) were explicitly described as iterative in prose, so representing them as loop constructs with assess transforms and if/exit branches is a direct translation, not an addition. - The hybrid actor designation for text/relation extraction (Stage A illness-event filtering, Stage F social-mention extraction, Stage F social-network construction) reflects the explicitly stated human-correction-of-machine-extraction pattern from the original description (modeled on Jigsaw). - The human actor for all abstract and generate-knowledge steps, and machine for clustering/aggregation/model-fitting steps, follows directly from the natural-language emphasis on "the analyst inspects... and interprets" versus automated computation.

Elements I made explicit that were only loosely implied, and should be flagged as added structure: 1. The general "propose → visualize → validate → refine" loop mentioned once in Stage G as a cross-cutting principle was not modeled as a single overarching loop wrapping the whole workflow. I only formalized the two places where iteration was concretely described (Stages A and E). Stages B, C, D, and F are represented as linear sequences of transforms, even though in practice an analyst might revisit them — I did not fabricate additional loops there because the original text did not describe explicit refinement cycles for those stages. 2. Splitting Stage E's S_lag_spec refinement and recomputation into a single loop (windows → cross-impact → visualise → assess → refine-spec) is a specific ATWL-loop realization of a process the natural-language description stated more loosely ("calibrate...interactively"). The precise loop body (recomputing D_windows and F_impact_matrix each iteration) is my interpretation of what "calibration" must mechanically involve, following the pattern of the example's L_feature_refinement loop; the original prose did not spell out this exact recomputation structure. 3. The F_place_membership and F_downwind_alignment intermediate feature artifacts, and the explicit separation of characterise transforms for place-timeseries vs. per-capita-incidence, are finer-grained decompositions than the natural-language prose, which described these as a single conceptual step ("compute a time series... normalize by population"). I split them to fit ATWL's one-intent-per-transform convention. 4. The Stage F comparison-checklist artifact (K_mechanism_assessment) was described in prose as a "structure this stage as a comparison table/checklist" — I formalized this as a distinct generate-knowledge transform/artifact, which is a reasonably direct translation but does add a discrete artifact boundary not explicitly named in the original text. 5. I did not add any build-model steps beyond the growth-curve fit in Stage D (e.g., no additional classifier or simulation model), since the original design did not call for one elsewhere.

No actor distinctions, loops, or specification-refinement structures were invented wholesale where the original description gave a purely linear account — where I judged the prose to be linear (Stages B, C, D, F), I kept the ATWL representation linear as well.

9 Researcher

Thank you. As a separate reflection: now that you have expressed this workflow in ATWL and worked through its structural elements, are there aspects of the workflow that thinking in ATWL terms suggests could be improved? For example, are there phases where the ATWL framing revealed missing structural elements (unnamed loops without specifications, ambiguous actor roles, implicit criteria that should be externalised as specifications) that would strengthen the workflow if added?

Please describe any such improvements separately as recommended modifications, not as changes to the ATWL representation you just produced. If ATWL thinking has not revealed anything worth modifying, please say so.

10 Model

Looking at the ATWL representation, I'm noticing that Stage C's place derivation relies on fixed clustering parameters without any feedback loop or reassessment mechanism. The workflow defines places using a static derive-places approach, but there's no way to validate or adjust those spatial and temporal distance thresholds based on the results.

This same issue appears throughout: Stage D's zone clustering and Stage B's day clustering both lack explicit specification artifacts or assessment steps to verify their clustering choices. Even more critically, the origin candidate identification in Stage E is a human abstraction step with no downstream validation—yet the entire Stage E analysis depends on getting that origin right, so an assess step there would catch errors before they propagate further.

I'm also noticing an asymmetry in how validation is handled across stages. Stage A explicitly validates its lexicon-based symptom extraction, but the social mention extraction in Stage C uses the same error-prone free text approach without an equivalent validation loop. And then there's the mechanism assessment at the end—it pulls together four different knowledge sources but has no conflict-resolution mechanism if they give contradictory signals.

Beyond that, I'm seeing a pattern where critical parameters like DBSCAN thresholds, clustering settings, and growth model choices are buried in the transform descriptions rather than externalized as explicit specification artifacts. The wind-lag loop is the only one with a proper specification artifact, which creates an inconsistency—these parameter choices are just as consequential for the analysis (DBSCAN settings directly determine which origin candidate gets identified), so they should probably have the same level of explicit specification and assessment loops as the lag parameters do.

I'm also noticing the origin candidate flows straight into Stage E's alignment computation without any robustness checking—adding a sensitivity analysis loop around candidate origins could make the causal claims stronger. More fundamentally, the whole pipeline might need a top-level hypothesis testing loop wrapping stages D through F, since real epidemiological investigations iterate between stages when evidence doesn't fit (discovering in Stage F that waterborne transmission fits better might send you back to Stage C to re-examine clusters near water bodies, or back to Stage D to regroup zones by water service area instead of just temporal similarity). by water-service area instead) would surface the pattern more effectively. So I need to consolidate these insights into a concrete set of modifications that prioritize impact: the key recommendation is to externalize all the clustering and threshold parameters as explicit specification artifacts across Stages B through D — day clustering, place derivation DBSCAN settings, and zone clustering — and add the same assess-and-loop validation structure to each one. Right now only symptom extraction and wind-lag calibration have that iterative treatment, but the other three clustering operations are equally sensitive to parameter choices and equally consequential for downstream results, yet they're being treated as one-shot transformations.

Beyond that, I should add a validation checkpoint after origin candidate identification in Stage C before it gets used as the anchor for Stage E's wind-alignment test, since a bad origin candidate would torpedo the entire airborne hypothesis. And I want to apply the same extraction-validation loop pattern to Stage F's social-mention extraction that's already working well for symptom lexicon extraction in Stage A — social and co-location mentions are just as prone to false positives and negatives, but currently they skip straight from extraction into network building without any correction cycle. There's also a potential higher-level hypothesis loop across Stages D through F worth exploring, since the three mechanism hypotheses are interdependent. These refinements feel like they'd strengthen the framework significantly. I should write this up as a concise reflection without altering the ATWL itself, as requested.

Reflecting on the ATWL representation, several genuine gaps became visible that were not apparent in the natural-language description. These are presented as recommended modifications to the workflow design, not as changes to the ATWL text already produced.

1. Asymmetric treatment of clustering/threshold decisions

Comparing the workflow against the example HITL template, I notice that only two of my clustering-type operations — symptom-lexicon extraction (Stage A) and wind-lag calibration (Stage E) — are wrapped in an explicit loop with an assess step and a specification artifact. Three other operations that are structurally identical in kind — day-profile clustering (Stage B), spatio-temporal place derivation (Stage C, DBSCAN-style), and zone-grouping by incidence similarity (Stage D) — were modeled as single-shot define-unit transforms with no externalized parameters and no adequacy check.

This is inconsistent, and the inconsistency matters analytically: the DBSCAN distance/time thresholds used to derive candidate "places" in Stage C directly determine what counts as the origin cluster, which is arguably the single most consequential decision in the whole workflow (everything in Stages E and F is anchored to it). Yet as originally designed, this choice is made once, silently, by an algorithm, with no visual check of cluster stability across parameter settings.

Recommendation: Externalize the clustering criteria in Stages B, C, and D as specification artifacts (e.g., S_place_clustering, S_zone_grouping, S_day_clustering), and wrap each corresponding define-unit transform in a loop with an assess step, following exactly the pattern already used for symptom-lexicon refinement. The analyst should be able to see, e.g., how sensitive the "earliest place" identification is to the DBSCAN radius before committing to it as the anchor for the wind analysis.

2. Unchecked dependency of Stage E on Stage C's origin candidate

P_origin_candidate is produced by a single human abstract step in Stage C and then flows directly into F_downwind_alignment in Stage E without any intervening assess. If the candidate origin is wrong or contested (e.g., two clusters are similarly early), the entire airborne-hypothesis test built on top of it inherits that uncertainty invisibly.

Recommendation: Add an explicit assess transform after T_abstract_origin_candidate that evaluates the confidence/uniqueness of the candidate origin (e.g., "is there a single dominant earliest cluster, or several competing candidates?") and produces a knowledge artifact documenting this. If multiple candidates are viable, Stage E should ideally be repeated per candidate rather than committing to one silently — this was not part of my original design and represents a real limitation.

3. Missing validation loop for social-mention extraction (Stage F)

Stage A's symptom extraction is explicitly validated against raw text through an iterative loop, because free-text extraction is acknowledged as error-prone. Stage F's extraction of social/co-location mentions (T_characterise_social_mentions) is exactly the same kind of operation — arguably more error-prone, since "my coworker" or "we were all at the same place" is harder to disambiguate than symptom keywords — yet it was designed as a single-pass transform with no correction step.

Recommendation: Apply the same extraction-validation loop pattern from Stage A to the social-mention extraction, before building the co-occurrence network. This is a straightforward transfer of an already-justified design decision to a structurally identical step that was, in the original design, treated more casually.

4. Stages D–F are three parallel one-shot hypothesis tests, not a cross-informing loop

Perhaps the most substantive gap: airborne (Stage E), person-to-person (Stage F), and waterborne (Stage F) mechanisms are each tested via an independent linear path, all feeding into a single final generate-knowledge checklist. There is no mechanism by which a finding in one branch (e.g., strong waterborne evidence) prompts re-examination of an earlier stage — for instance, re-deriving the zone groups in Stage D using water-service-area boundaries as the grouping criterion, rather than purely temporal-incidence similarity, to see whether that alternative unit definition fits the data even better.

As designed, the workflow is only as good as its first-choice unit definitions (temporal-similarity zone clusters, DBSCAN-derived places). In a real investigation, evidence from one hypothesis branch should be able to motivate redefining analysis units in an earlier stage and re-running the comparison — this is the kind of "progressive multi-phase analysis" pattern illustrated in the ATWL template guidelines (loop(define-unit → assess) → loop(define-unit → assess) → ...), which I did not employ here.

Recommendation: Consider restructuring Stages D–F as a higher-level loop: derive units → test against all three hypotheses → assess whether evidence is conclusive → if not, redefine units (e.g., re-cluster by water-service area, or re-cluster by mobility-network proximity) → re-test. This would make hypothesis comparison genuinely iterative rather than three independent linear passes.

5. No consistency check before final synthesis

K_mechanism_assessment (the comparison checklist) is produced directly by a generate-knowledge transform that consumes potentially conflicting evidence (e.g., moderate airborne support and moderate waterborne support simultaneously) without an intervening assess step to flag contradiction or insufficient discriminating power. As designed, ambiguity would be smoothed over silently by the human analyst inside a single synthesis step, rather than being surfaced as an explicit evaluative artifact that could, per point 4, trigger a return to earlier stages.

Recommendation: Insert an assess transform between the three hypothesis-branch outputs and the final checklist, producing an explicit evaluative knowledge artifact ("evidence is conclusive for X" / "evidence is ambiguous between X and Y") — this would make explicit whether the final report rests on decisive or merely suggestive evidence, which is an important distinction to communicate to emergency management decision-makers.


Summary: ATWL thinking did not reveal that the overall three-question decomposition (origin / spread / mechanism) is unsound, but it did reveal that I applied rigor (specifications, loops, assess steps) unevenly — concentrating it on the two stages I happened to describe as "calibration" in prose (Stages A and E) while leaving structurally identical clustering and extraction decisions in Stages B, C, D, and F under-specified and unchecked, and it revealed that the three-hypothesis comparison (Stages D–F) is architecturally linear when the underlying analytical logic (iteratively testing and refining hypotheses against alternative unit definitions) would be better served by an explicit cross-informing loop.

11 Researcher

Thank you. Now please implement the modifications you just recommended, producing a revised ATWL representation of the workflow.

Treat this as a genuine revision, not an exercise in maximising apparent structural sophistication: implement each recommended modification only if, on reflection, you still judge it a real improvement to the analytical workflow, not simply because it would add a loop, specification, or actor distinction. If implementing a change would not actually strengthen the workflow (for example, because the added structure wouldn't reflect a decision an analyst would really need to revisit), say so and leave that part as it was, explaining why.

You are not restricted to additive changes. If implementing a recommendation well requires restructuring an existing phase (splitting, merging, or re-sequencing transforms) rather than only adding to it, do so — but note explicitly where you departed from a purely additive patch.

After producing the revised representation, summarise what changed relative to the previous stage: which recommended modifications were implemented as described, which were implemented differently than originally suggested (and why), and which were not implemented and why not.

12 Model

I'm working through the five recommendations to decide which ones to implement and how to apply them. The first one stands out as a genuine improvement—externalizing the clustering criteria in stages B, C, and D as specifications with loops. Stage C in particular seems worth prioritizing since place derivation has the most impact downstream.

For Stage B (day clustering), I'm reconsidering whether the added loop machinery is worth it. It's a fairly standard step with clear criteria, so while consistency matters, it might not be as critical as Stage C. I'll implement the full loop-and-spec treatment for Stage C since it's the most consequential, and add a lighter specification approach for Stage D since it also feeds into pattern interpretation. I'm deciding against adding a full validation loop to Stage B since the day-clustering output serves mainly as a soft hypothesis that Stage C's place-based evidence will independently confirm or reject anyway—the downstream stages don't have a hard dependency on exact cluster boundaries. Instead, I'll implement the full loop with specifications for Stage C (place derivation, most consequential) and Stage D, leaving Stage B as a single-pass overview step to avoid adding rigor where there's no real decision point to revisit.

But now I'm reconsidering Stage D's zone-grouping refinement—recommendation 4 is already proposing a higher-level loop that restructures Stages D through F to test hypotheses and redefine units based on spread-pattern interpretation, so duplicating a separate refinement loop in Stage D would be redundant. I should fold that zone-grouping refinement into the broader recommendation-4 loop instead of having two overlapping loops for the same task.

For recommendation 4 itself, I'm designing a hypothesis-testing loop that cycles through candidate transmission mechanisms against different zone groupings, redefining analysis units when evidence is inconclusive—the loop continues until one mechanism shows decisive evidence or no more informative unit redefinitions emerge. Each iteration defines zones under the current grouping criterion, characterizes the growth model and residuals, visualizes the results, and then branches into three parallel hypothesis tests for different transmission pathways. if I can simplify by keeping the wind-lag loop sequential instead of nesting it, which would be cleaner for the template notation and easier to follow overall. If conclusive evidence emerges, I exit the loop; otherwise, I refine the grouping criterion and iterate. The wind analysis calibration loop stays independent and doesn't need to rerun unless the origin candidate changes, since airborne transmission patterns depend on per-zone incidence and wind patterns rather than how zones are grouped.

Actually, I'm realizing Stage E might be entirely independent of the zone-grouping redefinition in Stage D. The person-to-person and waterborne evaluations don't rely on zone groups either—they depend on the social network built from illness events and place clusters from Stage C. But zone-grouping does feed into the growth model, residuals, and spread pattern interpretation, which then influences the mechanism checklist by favoring person-to-person transmission if spatial clustering aligns with highway networks.

So the redefinition loop's real target is D_zone_groups, and possibly D_places if evidence suggests reclustering by water-service-area. But I already have a separate foundational loop for place refinement in Stage C focused on extraction quality, not hypothesis-driven redefinition. Adding place redefinition to the hypothesis loop would complicate things, so I'm keeping the focus on zone-grouping for now.

The key is to make recommendation 4's redefinition specifically about the S_zone_grouping specification—whether to group zones by temporal similarity, water-service-area, or mobility-network proximity. This keeps the outer loop's redefinable target confined to zone-grouping alone, avoiding the need to reopen Stage C's place clustering, which already has its own extraction-quality loop.

Now I'm laying out the concrete workflow structure, starting with Stage A and adding the extraction loop for social mentions as part of recommendation 3.

I'm considering whether to move Stage F's social-mention extraction earlier into Stage A's boundaries since they're structurally identical text extraction and validation tasks, but the original design already treats it as a separate Stage F step, so I'll keep it there and just apply the same loop pattern for consistency.

For Stage B, I'm keeping it linear as originally designed, though I'll note in the summary why recommendation 1 wasn't fully implemented there. Recommendation 1 mentioned Stages B, C, and D, but I'm implementing it fully for C and folding D into the new structure.

Stage C makes sense as its own dedicated loop since place derivation is foundational—it feeds into both Stage E's wind alignment and Stage F's waterborne overlay, so stabilizing it through its own assess-and-refine cycle before the downstream hypothesis testing begins is the right approach. The loop will handle place clustering specifications with distance and time thresholds, then cycle through deriving places, characterizing the timeseries, and characterizing incidence patterns.

The assess step will evaluate both cluster stability under current parameters and whether a single dominant earliest cluster emerges as the origin candidate or if multiple competing candidates remain—this elegantly folds in recommendation 2 about confidence and uniqueness without duplicating structure. If the assessment shows inadequate results, I'll refine the clustering parameters and loop back; otherwise, I exit with a stable place derivation.

If multiple origin candidates persist across reasonable parameter settings and can't be resolved through retuning, the loop exits honestly with a knowledge artifact documenting all candidates rather than forcing a single choice—this surfaces ambiguity as recommendation 2 suggests. Then downstream in Stage E, I'd characterize the wind cross-impact analysis per candidate origin, though I need to think through how to represent this in ATWL without overcomplicating the workflow.

The approach I'm settling on: D_origin_candidates becomes a set of entities (each with confidence/rank features), and F_downwind_alignment applies per candidate origin—either as a feature across zones and candidates, or noted in the description that the transform runs for each retained candidate. This keeps things tractable without full combinatorial branching, and each candidate gets its own impact matrix from the wind-loop.

For recommendation 3, I'll add a social-mentions extraction-validation loop in Stage F that mirrors the pattern from Stage A. For recommendations 4 and 5 together, I need to restructure Stage D's zone-grouping as an outer loop, integrate hypothesis branches (E by reference, F for person-to-person and waterborne pathways), run comparison and assessment to check conclusiveness, then conditionally redefine the zone-grouping criterion based on that assessment.

Stage E's wind-analysis loop is computed once per candidate origin before entering the outer hypothesis loop, since it doesn't depend on how zones are later grouped—the per-zone incidence and wind alignment are independent of the zone-grouping criterion. This means I can carry K_airborne_evidence through the outer loop's checklist without recomputing it each iteration, which keeps the complexity down.

Stage F, though, is different: the person-to-person pattern assessment explicitly compares the social network against the zone-grouping visualization to check whether spatial growth aligns with the highway/transit network. Since this interpretation depends on the current zone-grouping map, P_p2p_pattern needs to be re-evaluated each time S_zone_grouping changes in the outer loop.

The waterborne evidence, by contrast, only depends on origin clusters versus water bodies—it's independent of the zone-grouping criterion—so P_waterborne_pattern can be computed once and reused as fixed evidence throughout.

This means each outer loop iteration only needs to recompute the zone-grouping definition, the growth-model characterization, the map visualization, the spread pattern interpretation, and consequently the person-to-person pattern that references it.

Before entering the loop, I'll compute the airborne evidence and waterborne pattern as stable inputs that feed into the checklist each time. Then the loop itself iteratively tests different zone-grouping criteria against the social and spatial evidence, comparing them against candidate transmission mechanisms until the evidence becomes conclusive.

The loop continues until either a single dominant transmission mechanism is confirmed or there are no more alternative grouping criteria to test. Inside the loop, I cluster zones according to the current grouping criterion to get the zone groups and their labels, then map the zones spatially. Since the zone positions on the map don't change—only the coloring based on the grouping criterion changes—I can move the map arrangement outside the loop and keep just the visualization step inside, which updates based on the new labels.

Then I build the growth model, analyze residuals, and extract the spread pattern. For the social network analysis, the network extraction itself is independent of zone grouping since it comes from illness-event text mentions, but interpreting the network pattern requires comparing it against the current zone grouping visualization. So I extract and validate the social network once before the loop, then only redo the pattern interpretation inside the loop where it needs the updated zone grouping.

Next I generate a mechanism assessment by comparing the fixed airborne evidence and waterborne pattern against the current peer-to-peer and spread patterns. I assess how conclusive the evidence is, and if it's still inconclusive with alternative grouping criteria available, I refine the zone grouping strategy—maybe switching to water-service-area or mobility-network criteria—and loop back. Otherwise I exit and finalize the mechanism assessment.

Now I'm reconsidering whether the zone grouping should be a given specification that gets updated through generate-knowledge transforms. The refinement step itself should be a generate-knowledge transform since it's formulating a methodological decision about the grouping criterion. So I'll model it as an assess transform that produces conclusiveness knowledge, then conditionally trigger a generate-knowledge transform to refine the grouping criterion based on that conclusiveness evaluation. Looking at the example workflow more carefully, I see the pattern doesn't use explicit specification artifacts at all—instead, the assess step's conditional branches directly into a refine transform that reapplies the same domain operation (like characterise or build-model) but conditioned on the quality knowledge, producing a refined artifact rather than a separate spec. So for the zone grouping refinement, I should follow this same approach: have assess output the quality knowledge, then directly refine the grouping via a characterise step that takes that knowledge as input and outputs the improved grouping artifact. I'll stick with the explicit specification pattern I've already established with S_lag_spec for consistency across the loops, using the same refinement style where the human actor adjusts parameters and outputs a refined specification. Now I need to reconsider Stage B's day-clustering recommendation and decide whether to implement it, and then figure out what Stage C should actually calibrate—just the distance and time thresholds, or something broader.

For Stage C's loop, I'm thinking the assess step should evaluate both clustering coherence and whether there's a single dominant origin candidate or multiple competing ones. If clustering is inadequate, I refine the thresholds and loop again. But if clustering looks good but multiple candidates keep competing, I should exit the loop and carry forward all of them as D_origin_candidates rather than forcing an artificial single choice—the loop's termination condition is really about clustering adequacy, not about collapsing to one candidate. Defining the place derivation loop structure... The origin confidence assessment distinguishes between a single dominant candidate and multiple competing ones, then I'm defining the origin candidates as retained entities that could be plural. This directly addresses the recommendation without conflating it with the place-clustering loop. Now Stage E needs to adapt so that the downwind alignment feature is computed per candidate origin rather than treating origin as singular.

To keep this tractable without overcomplicating the workflow language, I'll handle multiple candidates through description—noting that if several are retained, the transform and downstream wind loop repeat once per candidate, with each producing its own airborne evidence artifact that feeds into per-candidate mechanism assessments. This keeps the analytical intent clear while avoiding combinatorial branching that the language doesn't natively support.

Now I'm folding in recommendation 3 by implementing the social-mention extraction validation loop to mirror Stage A's structure.

For the outer loop combining recommendations 4 and 5, I need to decide what gets computed once versus what repeats per iteration. The person-to-person pattern and waterborne pattern should stay outside—they're independent of zone grouping and computed upfront. But I'm still working through whether the person-to-person interpretation step needs to live inside the loop, since while the network itself is stable, the abstract pattern interpretation might shift depending on the zone context being evaluated.

Now I'm laying out the full template structure as a sequence: starting with symptom extraction, then looping through assessment and lexicon refinement, followed by filtering illness events into daily episodes, profiling those episodes, clustering days, adding calendar context, and finally visualizing, abstracting, and generating knowledge.

Continuing with spatial analysis—deriving places through a loop that characterizes, contextualizes, and visualizes them, then assessing origin candidates for uniqueness and characterizing downwind alignment. Then another loop for lag windows to examine cross-impacts, followed by airborne evidence generation. Social analysis comes next with a loop refining lexicon through mentions and assessment, building the social network, overlaying water data, and abstracting waterborne patterns.

Defining unit structures... I'm clarifying that the wind-analysis loop isn't actually nested at the template level—it's sequential like the others, which keeps things clean. Now I'm ready to write out the full ATWL template, being careful with syntax and reusing unchanged sections from before. Stage A stays the same with the extraction and validation loop feeding into illness events, and Stage B remains linear through daily episodes, profiling, clustering, and knowledge generation to produce onset candidates.

For Stage C, I'm revising it to include the place-derivation loop with clustering specs and assessment, then a post-loop uniqueness check that produces the origin candidates. Stage D gets merged into an outer hypothesis loop combined with what was Stage F, but I need to think through the zone-incidence characterization—it should happen once since it's foundational, while the S_zone_grouping specification determines how zones cluster based on whether we're using incidence similarity, water-service areas, or mobility-network proximity as the grouping criterion.

The key insight is that T_define_zone_groups can take different inputs depending on which criterion is active: temporal-similarity uses F_zone_incidence, water-service-area uses D_map_features, and mobility-network uses highway/transit structure. The transform's behavior is governed by S_zone_grouping to select the right method, which is exactly how specifications should control transform behavior.

Now I'm finalizing the input list for D_zone_groups: D_zones, F_zone_incidence, D_map_features, and S_zone_grouping. Since zone grouping changes each iteration, I need to recompute the growth model inside the outer loop, and that means V_residuals_map stays inside too since it depends on the current grouping. P_spread_pattern and T_abstract_p2p_pattern also need to stay in the loop—they both interpret the current zone grouping and residuals against the map features and social network respectively.

For each iteration, I'm outputting P_p2p_pattern, then running T_knowledge_mechanism_checklist to combine the fixed airborne and waterborne evidence with the current spread and p2p patterns to generate K_mechanism_assessment. After that, T_assess_conclusiveness evaluates whether the evidence is decisive for one mechanism or still ambiguous, producing K_conclusiveness. If the assessment isn't conclusive and untried criteria remain, the loop continues.

After exiting the loop, the final synthesis stage takes the accumulated evidence and produces K_final_report. I'm realizing though that if there are multiple origin candidates, I'd need to compute K_airborne_evidence and P_waterborne_pattern separately for each one, which makes the checklist and overall logic significantly more complex for a text-based framework.

I'll handle this pragmatically by noting in the description that Stages E and later are repeated per candidate if multiple remain, with Stage G comparing across all candidate-specific reports. Rather than explicitly branching the ATWL structure for each candidate, I'll represent D_origin_candidates as an entities artifact with multiple members that the downstream transforms implicitly operate over, similar to how D_zones with its 13 members is handled uniformly without explicit per-zone branching.

This approach treats D_origin_candidates like any other entities collection—transforms like F_downwind_alignment and V_water_overlay naturally process all members without needing explicit loop constructs, which fits ATWL semantics cleanly. The alignment score would then capture alignment per candidate-zone pair rather than against a single origin. I'll keep this manageable by modeling the candidate origins as entities with a confidence ranking feature, then adjusting the downwind alignment feature to have a matrix value structure representing zones by candidate origins. The water impact variable follows the same pattern, staying concise without exhaustively rewriting every downstream artifact's dimensionality.

For the visualization overlay, I'm shifting from using all map places to specifically overlaying the refined candidate origins on the water layer, so I'll create a new arrangement of just those candidates within the map features context. This makes the overlay more precise and aligned with the refined analysis.

Now I'm laying out the full document structure: keeping stages A and B largely intact, substantially revising C, adapting E's wind loop to work with the candidate origins, revising F to include an extraction loop for social mentions while updating the waterborne overlay, and restructuring the D and F hypothesis synthesis into an outer loop before the final stage G. For the actor designations, I'm deciding whether T_assess_place_clusters should be human or hybrid—leaning toward keeping it human for now since the judgment of coherence and stability across the raw map data benefits from human interpretation.

I'm maintaining consistency across all assessment transforms by assigning them to human actors, matching the pattern established earlier with T_assess_extraction and T_assess_impact. Then I'm mapping out the remaining transforms: T_refine_place_clustering as a generate-knowledge step producing the refined clustering state, T_abstract_origin_candidates as an abstract-perception step, T_assess_origin_uniqueness as another human assessment, and T_define_origin_candidates as either hybrid or human depending on how much filtering logic needs to be automated versus judged.

For the Stage F extraction loop, I'm mirroring Stage A's structure: starting with T_assess_social_extraction as a human assessment step that produces quality metrics, then adding a refine step if needed to update the social lexicon, just like how Stage A refined the symptom extraction lexicon.

I need to define S_social_lexicon as a specification artifact seeded from the initial given lexicon. For the outer hypothesis loop L_hypothesis_testing, I'm using S_zone_grouping as the specification with temporal-incidence-similarity as the initial criterion. The termination condition is when either the mechanism-comparison checklist shows conclusive evidence for a single dominant transmission mechanism, or we've exhausted all analytically motivated zone-grouping alternatives—temporal-similarity, water-service-area, and mobility-network-proximity—without resolving the ambiguity.

I should compute K_airborne_evidence and P_waterborne_pattern before entering the outer loop, placing them in their own subsections so they're available as fixed reference inputs throughout the iterations. For Stage G synthesis, I'll capture the final mechanism assessment either through a designated K_mechanism_assessment_final artifact or by referencing the last bound value from the loop using an assignment pattern similar to the spec's example. iteration's data, so they don't need pre-loop initialization like F_synoptic does since they're not carried forward as refined inputs to the next iteration. Now I'm ready to write out the full ATWL, reusing the previous structure but updating Stages C, D, and F with the loop logic we've established, then summarizing how each of the five recommendations was addressed. I need to set up consistent artifact IDs for the inputs and work through the naming scheme carefully. Set onset pattern and knowledge candidates. Stage C involves clustering places based on spatio-temporal distance thresholds, then iterating through defining places from illness events, characterizing their timeseries and incidence patterns, visualizing hotspots on a map, and assessing cluster quality before refining as needed.

Once clustering is finalized, I abstract origin candidates from the hotspot visualizations, assess how confident I am in distinguishing between them, and define the candidate entities with confidence rankings. Stage E will then map these origin candidates.

For spatial analysis, I characterize how wind patterns align with each zone relative to each candidate origin, building a matrix that captures this relationship. The wind analysis loop processes this per-zone-per-candidate structure, generating airborne evidence across the full impact matrix.

Moving into the social dimension, I'm extracting social media signals using a given lexicon...

Extracting social mentions from illness events and refining the lexicon iteratively until quality thresholds are met, then defining and visualizing the resulting social network. For the waterborne pathway, I'm mapping the candidate origins against geographic features to establish their spatial arrangement.

Now I'm restructuring the outer loop to separate the zone-level computations that only need to run once—calculating per-capita incidence and positioning zones on the map—from the hypothesis testing loop that will iterate through different grouping schemes.

Within each iteration, I'm defining zone groups based on the current grouping criterion, then visualizing them on the map, building a growth model from the incidence data and groups, examining the residuals to see how well the model fits, and mapping those residuals spatially to identify patterns.

Then I'm abstracting the spread pattern from the zone group visualization and residual map, extracting the person-to-person transmission pattern from the social network and zone groups, and running a knowledge mechanism checklist that compares airborne, waterborne, and direct transmission evidence against the observed patterns to assess which mechanism best explains the outbreak.

If the assessment is inconclusive and there are still untried grouping strategies, I refine the zone grouping and loop back to test the next criterion.

Once I've exhausted the assessment options or reached a conclusive result, I synthesize everything into a final report combining the onset candidates, origin candidates, transmission mechanism assessment, and conclusiveness determination.

Now I'm sketching out a template that captures the core workflow: starting with symptom characterization, iteratively refining the lexicon through assessment cycles, then defining illness units by filtering events and daily episodes, characterizing the daily profile, and clustering cases.

Continuing through the template... I'm specifying the internal structure for origin candidates—each one represents a place with spatial embedment and carries confidence ranking plus temporal onset information. For the transformation that defines these candidates, the human analyst filters from available places using the origin pattern to finalize which clusters move forward, taking confidence data as input to produce the candidate set. I should verify whether we need both the abstract pattern and the derived artifact entities, which aligns with keeping pattern and concrete data separate. Now I'm finalizing the input/output specifications for the origin assessment and definition steps, then compiling the complete document with a summary section that maps each of the five recommendations to how it's been implemented or addressed. Recommendation 2 is implemented through the post-place-loop assessment that generates origin confidence and candidate origins, though the downstream handling of multiple candidates uses entity collection semantics rather than explicit branching. Recommendations 4 and 5 are implemented via restructuring—merging the zone-grouping and hypothesis stages into a single outer loop, which substantially reorganizes the flow but achieves the intended effect.

Revised ATWL Representation

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"

Summary of Changes Relative to the Previous Stage

Implemented as described:

  1. Recommendation 3 (social-mention extraction-validation loop) — implemented directly, mirroring Stage A's L_extraction_validation structure with L_social_extraction. On reflection this remained a clear improvement: nothing about the original justification changed on further inspection.

  2. Recommendation 1, for Stage C only — the place-derivation clustering criterion is now externalised as S_place_clustering, wrapped in L_place_derivation with an assess step and conditional refinement. I confirmed this is a real improvement: place derivation anchors both the airborne test (Stage E) and the waterborne test (Stage F), so its parameter sensitivity genuinely warrants explicit calibration.

  3. Recommendation 2 (origin-candidate uniqueness) — implemented via T_abstract_origin_candidates → T_assess_origin_uniqueness → T_define_origin_candidates, producing a possibly-plural D_origin_candidates. I kept this separate from the L_place_derivation loop's own assess step, since the two are different concerns (clustering stability vs. genuine origin ambiguity) — conflating them would have obscured that ambiguity here is a legitimate finding, not a parameter-tuning failure.

Implemented, but differently than originally proposed:

  1. Recommendation 1, for Stage D — rather than giving Stage D its own standalone loop(define-unit → assess) for zone-grouping (as literally proposed), I folded it into the larger restructuring required by Recommendation 4, since the two recommendations targeted the same underlying artifact (D_zone_groups) for the same underlying reason (its grouping criterion is a genuine, revisitable analytic decision). Implementing them separately would have produced two overlapping loops governing the same artifact.

  2. Recommendation 4 (cross-informing loop across Stages D–F) — implemented as L_hypothesis_testing, but restructured rather than purely additive: Stage D's growth-modelling and Stage F's mechanism-checklist step are now merged into one loop body, with S_zone_grouping as the parameter that can be revised (switching among temporal-similarity, water-service-area, or mobility-network criteria). I deliberately kept the airborne evidence (K_airborne_evidence) and waterborne evidence (P_waterborne_pattern) computed once, outside the loop, since on reflection neither depends on the zone-grouping criterion — recomputing them each iteration would have been redundant structure added only for uniformity, which the instructions asked me to avoid.

  3. Recommendation 5 (consistency check before final synthesis) — implemented as T_assess_conclusiveness, but merged directly into the same loop as the exit condition, rather than as an isolated one-shot step between the three hypothesis branches and the final checklist. This was a deliberate deviation from the original suggestion: once Recommendation 4 restructured the checklist into an iterative loop, the natural place for a decisiveness check is exactly the loop's own until-condition assessment. Adding a second, separate consistency check afterward would have been redundant.

Not implemented:

  1. Recommendation 1, for Stage B — I did not add a specification/loop around the day-clustering step. On reflection, this remains the right call: K_onset_candidates is explicitly treated downstream only as a soft, non-binding hypothesis, cross-checked independently by the place-derivation evidence in Stage C. Since no downstream transform depends critically on getting the day-clustering boundaries exactly right, adding calibration machinery here would increase apparent structure without corresponding to a decision the analyst would actually need to revisit.