diff --git a/pipeline/diagrams/future_possible_activity.svg b/pipeline/diagrams/future_possible_activity.svg
new file mode 100644
index 0000000..7676296
--- /dev/null
+++ b/pipeline/diagrams/future_possible_activity.svg
@@ -0,0 +1 @@
+The Biergarten Data Pipeline — Activity Diagram The Biergarten Data Pipeline — Activity Diagram ParseArguments(argc, argv) spdlog::error yes Invalid args? no Init CurlGlobalState & LlamaBackendState Build DI injector JsonLoader::LoadLocations("locations.json") JsonLoader::LoadBeerStyles("beer-styles.json") NEW : Beer styles do not need location context. Wikipedia summaries for the entire palette are fetched and cached globally at startup. EnrichmentService::PreWarmBeerStyleCache(beer_styles) Opens SQLite connection. Begins a single transaction covering all five fixture types. Initialize SqliteExportService BiergartenPipelineOrchestrator::Run() COMMIT covers all five fixture types. Finalize SqliteExportService spdlog::info "Pipeline complete in X ms" RunUserPhase(sampled_locations) Create BoundedChannels (user_llm_ch, user_exp_ch) Loop: Send Locations → user_llm_ch Close user_llm_ch Join LLM Worker, SQLite Worker RunBreweryAndBeerPhase(sampled_locations) Create BoundedChannels (loc_ch, llm_ch, exp_ch) Loop: Send Locations → loc_ch Close loc_ch Join Enrichment Workers Close llm_ch Both brewery_pool_ and beer_pool_ are now completely populated. Join LLM Worker, SQLite Worker RunCheckinPhase() ICheckinDistributionStrategy:: AssignActivityWeights(user_pool_) CheckinsForUser(user, brewery_pool_.size()) TimestampFor(user, index) Select brewery from brewery_pool_ GenerateCheckin(user, brewery, timestamp) via DataGenerator ProcessCheckin(checkin) → sqlite3_int64 Append → checkin_pool_ remaining For each checkin index? done remaining For each GeneratedUser in user_pool_? done RunRatingPhase() Match brewery_id → select beer from beer_pool_ (same brewery_id) Beer exists for brewery? yes no GenerateRating(user, beer, checkin_id) via DataGenerator ProcessRating(rating) Skip — brewery has no beers remaining For each GeneratedCheckin in checkin_pool_? done Receive Location GenerateUser(location) via DataGenerator Send GeneratedUser → user_exp_ch yes user_llm_ch has items? no Close user_exp_ch Receive EnrichedCity GenerateBrewery(location, context) via DataGenerator IBeerSelectionStrategy::SelectStyles( brewery, beer_style_palette_) Guaranteed cache hit from startup. GetStyleContextFromCache(style) GenerateBeer(brewery, style_context) via DataGenerator Attach GeneratedBeer to Brewery bundle remaining For each selected BeerStyle? done The next generation of a brewery is entirely dependent on the current brewery and its beers completing. Send BreweryWithBeers Bundle → exp_ch yes llm_ch has items? no Close exp_ch Receive GeneratedUser ProcessUser(user) → sqlite3_int64 Append → user_pool_ yes user_exp_ch has items? no Receive BreweryWithBeers Bundle ProcessBrewery(brewery) → brewery_id Append → brewery_pool_ Set beer.brewery_id = brewery_id ProcessBeer(beer) → sqlite3_int64 Append → beer_pool_ remaining For each beer in bundle? done yes exp_ch has items? no Receive Location GetLocationContext(location, BreweryContextStrategy) Send EnrichedCity → llm_ch yes loc_ch has items? no Main Orchestrator LLM Worker SQLite Worker Enrichment Workers (xN)
\ No newline at end of file
diff --git a/pipeline/diagrams/future_possible_architecture.svg b/pipeline/diagrams/future_possible_architecture.svg
new file mode 100644
index 0000000..bf052f3
--- /dev/null
+++ b/pipeline/diagrams/future_possible_architecture.svg
@@ -0,0 +1 @@
+The Biergarten Data Pipeline — Architecture The Biergarten Data Pipeline — Architecture Domain: Value Objects & Contracts Domain Policy Infrastructure: Enrichment Infrastructure: Generation Infrastructure: Pipeline Channel Infrastructure: Export Orchestration Location city : std::string state_province : std::string iso3166_2 : std::string country : std::string iso3166_1 : std::string local_languages : std::vector<std::string> latitude : double longitude : double LocationContext text : std::string completeness : Completeness char_count : size_t «enum» Completeness Full Partial Absent EnrichedCity location : Location context : LocationContext BeerStyle name : std::string description : std::string min_abv : float max_abv : float min_ibu : int max_ibu : int Loaded once at startup from beer-styles.json via JsonLoader. Passed as std::span<const BeerStyle> to IBeerSelectionStrategy. Generator receives the selected style as a parameter — it never reads the palette directly. BreweryResult name_en : std::string description_en : std::string name_local : std::string description_local : std::string BeerResult name_en : std::string description_en : std::string name_local : std::string description_local : std::string style : std::string abv : float ibu : int UserResult username : std::string bio : std::string activity_weight : float activity_weight assigned by ICheckinDistributionStrategy after the full user pool is committed. Drives J-curve checkin volume per user. CheckinResult checked_in_at : std::string note : std::string RatingResult score : float note : std::string GeneratedBrewery brewery_id : sqlite3_int64 location : Location brewery : BreweryResult context_completeness : LocationContext::Completeness generated_at : std::string GeneratedBeer beer_id : sqlite3_int64 brewery_id : sqlite3_int64 location : Location beer : BeerResult generated_at : std::string GeneratedUser user_id : sqlite3_int64 location : Location user : UserResult generated_at : std::string user_id populated after SQLite insert. Live FK carried in pool for checkin and rating references. GeneratedCheckin checkin_id : sqlite3_int64 user_id : sqlite3_int64 brewery_id : sqlite3_int64 checkin : CheckinResult generated_at : std::string GeneratedRating user_id : sqlite3_int64 beer_id : sqlite3_int64 checkin_id : sqlite3_int64 rating : RatingResult generated_at : std::string «interface» IContextStrategy QueriesFor(loc : const Location&) : std::vector<std::string> MaxContextChars() : size_t BreweryContextStrategy QueriesFor(loc : const Location&) : std::vector<std::string> MaxContextChars() : size_t BeerContextStrategy QueriesFor(loc : const Location&) : std::vector<std::string> MaxContextChars() : size_t «interface» ISamplingStrategy Sample(locations : const std::vector<Location>&) : std::vector<Location> UniformSamplingStrategy sample_size_ : size_t Sample(locations : const std::vector<Location>&) : std::vector<Location> «interface» IBeerSelectionStrategy SelectStyles(brewery : const GeneratedBrewery&, palette : std::span<const BeerStyle>) : std::vector<BeerStyle> Decides how many beers a brewery gets and which styles are selected. Count distribution and style deduplication logic live here, not in the orchestrator or generator. RandomBeerSelectionStrategy rng_ : std::mt19937 min_beers_ : size_t max_beers_ : size_t SelectStyles(brewery : const GeneratedBrewery&, palette : std::span<const BeerStyle>) : std::vector<BeerStyle> Draws a random count in [min, max]. Samples without replacement from palette to avoid duplicate styles per brewery. «interface» ICheckinDistributionStrategy AssignActivityWeights(users : std::vector<GeneratedUser>&) : void CheckinsForUser(user : const GeneratedUser&, brewery_count : size_t) : size_t TimestampFor(user : const GeneratedUser&, index : size_t) : std::string Owns all statistical policy: J-curve weight assignment, bursty weekend timestamps, per-user checkin volume. JCurveCheckinStrategy rng_ : std::mt19937 AssignActivityWeights(users : std::vector<GeneratedUser>&) : void CheckinsForUser(user : const GeneratedUser&, brewery_count : size_t) : size_t TimestampFor(user : const GeneratedUser&, index : size_t) : std::string «interface» IEnrichmentService GetLocationContext(loc : const Location&, strategy : const IContextStrategy&) : LocationContext WikipediaService client_ : std::unique_ptr<WebClient> extract_cache_ : std::unordered_map<std::string, std::string> GetLocationContext(loc : const Location&, strategy : const IContextStrategy&) : LocationContext FetchExtract(query : std::string_view) : std::string extract_cache_ keyed by query string. Beer pass gets near-100% cache hits since locations were already fetched during the brewery pass. «interface» WebClient Get(url : const std::string&) : std::string UrlEncode(value : const std::string&) : std::string CURLWebClient Get(url : const std::string&) : std::string UrlEncode(value : const std::string&) : std::string «interface» DataGenerator GenerateBrewery(location : const Location&, context : const LocationContext&) : BreweryResult GenerateBeer(brewery_id : sqlite3_int64, location : const Location&, context : const LocationContext&, style : const BeerStyle&) : BeerResult GenerateUser(location : const Location&) : UserResult GenerateCheckin(user : const GeneratedUser&, brewery : const GeneratedBrewery&, timestamp : const std::string&) : CheckinResult GenerateRating(user : const GeneratedUser&, beer : const GeneratedBeer&, checkin_id : sqlite3_int64) : RatingResult GenerateBeer receives BeerStyle as a parameter. Style selection and count decisions live in IBeerSelectionStrategy, not here. MockGenerator GenerateBrewery(...) : BreweryResult GenerateBeer(...) : BeerResult GenerateUser(...) : UserResult GenerateCheckin(...) : CheckinResult GenerateRating(...) : RatingResult DeterministicHash(location : const Location&) : size_t LlamaGenerator model_ : ModelHandle context_ : ContextHandle prompt_formatter_ : std::unique_ptr<IPromptFormatter> config_ : LlamaConfig rng_ : std::mt19937 GenerateBrewery(...) : BreweryResult GenerateBeer(...) : BeerResult GenerateUser(...) : UserResult GenerateCheckin(...) : CheckinResult GenerateRating(...) : RatingResult Load(config : const LlamaConfig&) : void Infer(system_prompt, user_prompt, max_tokens, grammar) : std::string ValidateModelArchitecture() : void «interface» IPromptFormatter Format(system_prompt : std::string_view, user_prompt : std::string_view) : std::string ExpectedArchitecture() : std::string_view Gemma4JinjaPromptFormatter Format(...) : std::string ExpectedArchitecture() : std::string_view LlamaConfig model_path : std::string temperature : float top_p : float top_k : uint32_t n_ctx : uint32_t seed : int BoundedChannel T queue_ : std::queue<T> mutex_ : std::mutex not_full_ : std::condition_variable not_empty_ : std::condition_variable capacity_ : size_t closed_ : bool Send(item : T) : void Receive() : std::optional<T> Close() : void Used for user, brewery, and checkin/rating phases. Beer phase uses a simple sequential loop — enrichment is all cache hits, no fan-out needed. «interface» IExportService Initialize() : void ProcessBrewery(brewery : const GeneratedBrewery&) : sqlite3_int64 ProcessBeer(beer : const GeneratedBeer&) : sqlite3_int64 ProcessUser(user : const GeneratedUser&) : sqlite3_int64 ProcessCheckin(checkin : const GeneratedCheckin&) : sqlite3_int64 ProcessRating(rating : const GeneratedRating&) : void Finalize() : void SqliteExportService date_time_provider_ : std::unique_ptr<IDateTimeProvider> db_handle_ : SqliteDatabaseHandle insert_location_stmt_ : SqliteStatementHandle insert_brewery_stmt_ : SqliteStatementHandle insert_beer_stmt_ : SqliteStatementHandle insert_user_stmt_ : SqliteStatementHandle insert_checkin_stmt_ : SqliteStatementHandle insert_rating_stmt_ : SqliteStatementHandle transaction_open_ : bool location_cache_ : std::unordered_map<std::string, sqlite3_int64> brewery_cache_ : std::unordered_map<std::string, sqlite3_int64> Initialize() : void ProcessBrewery(brewery : const GeneratedBrewery&) : sqlite3_int64 ProcessBeer(beer : const GeneratedBeer&) : sqlite3_int64 ProcessUser(user : const GeneratedUser&) : sqlite3_int64 ProcessCheckin(checkin : const GeneratedCheckin&) : sqlite3_int64 ProcessRating(rating : const GeneratedRating&) : void Finalize() : void InitializeSchema() : void PrepareStatements() : void RollbackAndCloseNoThrow() : void FinalizeStatements() : void brewery_cache_ restored. Keyed by location string for location deduplication, and by brewery identity for beer FK resolution without re-querying. «interface» IDateTimeProvider GetUtcTimestamp() : std::string SystemDateTimeProvider GetUtcTimestamp() : std::string BiergartenPipelineOrchestrator enrichment_service_ : std::unique_ptr<IEnrichmentService> generator_ : std::unique_ptr<DataGenerator> exporter_ : std::unique_ptr<IExportService> brewery_context_strategy_ : std::unique_ptr<IContextStrategy> beer_context_strategy_ : std::unique_ptr<IContextStrategy> sampling_strategy_ : std::unique_ptr<ISamplingStrategy> beer_selection_strategy_ : std::unique_ptr<IBeerSelectionStrategy> checkin_strategy_ : std::unique_ptr<ICheckinDistributionStrategy> beer_style_palette_ : std::vector<BeerStyle> user_pool_ : std::vector<GeneratedUser> brewery_pool_ : std::vector<GeneratedBrewery> beer_pool_ : std::vector<GeneratedBeer> checkin_pool_ : std::vector<GeneratedCheckin> Run() : bool RunUserPhase(locations : const std::vector<Location>&) : void RunBreweryPhase(locations : const std::vector<Location>&) : void RunBeerPhase() : void RunCheckinPhase() : void RunRatingPhase() : void beer_style_palette_ loaded once at startup from beer-styles.json. Passed as std::span<const BeerStyle> to IBeerSelectionStrategy per brewery. RunBeerPhase() is a sequential loop — no channels, no fan-out. Enrichment is cache hits; LLM is the only cost. JsonLoader LoadLocations(filepath : const std::filesystem::path&) : std::vector<Location> LoadBeerStyles(filepath : const std::filesystem::path&) : std::vector<BeerStyle> LoadBeerStyles() added. Reads beer-styles.json once at startup into the palette held by the orchestrator. owns owns owns owns owns owns uses implements implements implements implements implements implements owns uses (parameter) implements implements implements owns constructed with implements implements owns implements contains contains contains contains contains contains contains contains contains contains
\ No newline at end of file