Critical bug fix from pytest failures:
**Problem:**
- execute_end_node() tried to use 'graph' variable without defining it
- UnboundLocalError at line 602: "if graph:"
- Caused 2 test failures in test_end_node_template.py
**Root Cause:**
- In Issue #5 fix, added graph lookup for node labels in AUTO mode
- But forgot to get graph from context first
- TEMPLATE mode already had: graph = context.get("graph")
**Fix:**
- Added: graph = context.get("graph") at start of AUTO mode block
- Same pattern as TEMPLATE mode
- graph is optional (None if not in context), so if-check is safe
**Tests:**
- test_auto_mode_concatenates_all_analyses - should pass now
- test_auto_mode_skips_skipped_nodes - should pass now
Files changed:
- backend/workflow_executor.py: Added graph = context.get("graph") line 596
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Introduced a new utility function to streamline the extraction of user-facing content from aggregated workflow results.
- Updated backend prompt handling to utilize the new function for improved clarity and maintainability.
- Adjusted frontend analysis component to leverage the utility for consistent content display across different workflow result formats.
These changes enhance the overall user experience by ensuring more reliable and readable output from workflow executions.
- Added support for handling aggregated results in workflow prompts, allowing for various data formats (string, object).
- Introduced a utility function to filter active prompts for both pipeline and workflow types in the analysis page.
- Updated content handling in the analysis component to accommodate new workflow data structures.
This improves the flexibility and usability of the prompt execution process in both backend and frontend components.
ISSUE: Inline templates referencing node outputs ({{ node_id.analysis_core }},
{{ node_id.signal_xyz }}) were not resolved - AI received empty data from
previous workflow stages.
ROOT CAUSE: load_prompt_template() only loaded system placeholders
(name, age, etc.) but not node execution results from context['node_results'].
FIX:
- Extract node outputs from context['node_results']
- Add as placeholders: node_id.analysis_core, node_id.signal_xyz, node_id.question_xyz
- Format matches PlaceholderPicker extraction logic
- Debug logging shows which node placeholders are added
TESTING:
- System placeholder test: ✅ SUCCESS (name, age, geschlecht resolved)
- Node output placeholders: Fixed (previously missing)
- User workflow: Join → Analysis → End now receives upstream data
Part 3: Inline Prompts - placeholder resolution completion
- Updated the `validate_csv_template` function to normalize both the column signature and field mappings for accurate comparison, preventing false warnings about mismatches.
- Enhanced warning messages to provide clearer guidance on the relationship between normalized signatures and raw field mappings.
- Added a new test to ensure that normalized signatures do not trigger false warnings when compared to raw mappings.
- Introduced a new endpoint for validating CSV templates without saving, allowing users to check field mappings and type conversions.
- Updated the `create_system_template` and `update_system_template` functions to include validation reports in responses.
- Enhanced error handling in CSV import processes by integrating `enrich_row_error` for more informative error messages.
- Improved the AdminCsvTemplateEditorPage to support format checking and display validation results, enhancing user experience.
- Incremented version numbers for `csv_import` and `admin_csv_templates` to reflect these updates.
- Increased precision for `kcal_active`, `kcal_resting`, `hr_avg`, and `hr_max` fields in the activity log schema.
- Added a new function `_activity_hr_bpm` to validate heart rate values during CSV import, ensuring they fall within plausible ranges.
- Updated the CSV parser to utilize the new heart rate validation function for improved data integrity.
- Enhanced the type converter to accommodate additional aliases for energy fields in CSV imports.
- Added a test to verify conversion of active energy from kJ to kcal, ensuring accurate data handling.
- Added SAVEPOINT management to the `_import_activity` function to improve error handling during CSV imports.
- Moved the training type resolution logic to occur within a transaction block, ensuring that errors can be rolled back without affecting the entire import process.
- Enhanced error logging to capture evaluation failures, providing better insights during CSV import operations.
- Modified `_resolve_training_type_for_activity` to accept a database cursor, improving efficiency and avoiding potential deadlocks during CSV imports.
- Introduced `get_training_type_for_activity_with_cursor` to handle training type resolution with an existing cursor, streamlining database interactions.
- Updated related calls in the activity import logic to utilize the new function, ensuring consistent behavior across the application.
- Introduced `diagnose_blood_pressure_row` and `diagnose_activity_row` functions to validate and analyze blood pressure and activity data from CSV imports.
- Updated the CSV import logic to handle combined datetime columns for blood pressure and activity, improving data integrity during import.
- Enhanced type conversion specifications to include `start_time` for blood pressure and activity, ensuring accurate data mapping.
- Added tests to validate the new diagnosis functions and their integration with existing import processes, ensuring robustness and reliability.
- Updated frontend messages to provide clearer guidance on blood pressure and activity data handling during CSV imports.
- Implemented a new endpoint for diagnosing CSV imports without writing to the database, allowing users to validate mappings and type conversions.
- Introduced the `diagnose_vitals_row` function to analyze vital metrics and provide detailed feedback on data validity.
- Enhanced the CSV import logic to include alias handling for vital fields, improving compatibility with different CSV formats.
- Updated the frontend to support the new diagnosis feature, including UI elements for displaying diagnosis results and error details.
- Added tests to ensure the correctness of the new diagnosis functionality and its integration with existing import processes.
- Updated migration scripts to ensure idempotent behavior for the source CHECK constraint, allowing for consistent application even if previous migrations were partially successful.
- Enhanced SQL logic to drop existing constraints safely and re-add them, ensuring compatibility with the universal CSV import.
- Clarified comments for better understanding of migration context and functionality.
- Updated the CSV import logic to include SAVEPOINT management, allowing for better error handling during the vitals baseline import process.
- Enhanced the SQL migration script to drop existing CHECK constraints related to the 'source' field, ensuring compatibility with the new universal CSV import.
- Incremented DB_SCHEMA_VERSION to "20260409c" to reflect these changes and improve the import process reliability.
- Incremented DB_SCHEMA_VERSION to "20260409b" to reflect changes related to the vitals_baseline.source CSV migration.
- Updated comments to clarify the migration context for better maintainability.
- Updated the aggregate_mapped_rows function to support multiple row policies, allowing for flexible handling of duplicate keys during CSV imports.
- Introduced deduplication of identical rows before aggregation, improving data integrity.
- Enhanced validation for multi_row_policy and dedupe_identical_rows in import_row_processing specifications.
- Updated the AdminCsvTemplateEditorPage to include options for multi-row policies and deduplication settings, improving user experience in template management.
- Added comprehensive tests to validate new aggregation behaviors and ensure correct error handling for multiple rows.
- Bumped version numbers for csv_import to 0.3.1 and admin_csv_templates to 0.2.0, reflecting recent enhancements.
- Added support for import_row_processing_default in the CSV modules endpoint, improving data handling capabilities.
- Introduced new row aggregation operations in the AdminCsvTemplateEditorPage, allowing for more flexible data processing options.
- Implemented parsing and validation for custom row processing configurations, enhancing user experience in template management.
- Updated the CSV import logic to support new row processing specifications for weight and vitals baseline, allowing for better data aggregation and validation.
- Implemented handling for multiple rows on the same day, enabling aggregation of values such as averages for vitals and last values for weight.
- Enhanced test coverage for the new import functionalities, ensuring correct behavior during data processing and validation.
- Refactored the module registry to include default import row processing options for better flexibility in handling CSV data.
- Updated the nutrition import logic to utilize a new row processing specification, improving data aggregation and validation.
- Refactored the template rendering process in the workflow executor to use Jinja2's Environment with ChainableUndefined for better handling of missing attributes.
- Added backward-compatible shortcuts for accessing decision signals in node contexts, enhancing flexibility in template usage.
- Introduced import row processing options in CSV templates, allowing for more customizable data handling during imports.
- Updated the test execution command in the CI workflow to run all tests excluding slow ones, improving efficiency.
- Enhanced the AdminCsvTemplateEditorPage to support custom equivalence for unit conversions, allowing for more flexible data handling.
- Added markers in pytest configuration for categorizing tests, facilitating better test management.
- Adjusted the extract_value_raw function to return failure for unavailable values in strict mode.
- Expanded the circumference detection logic in infer_unit_strict to include additional terms for better accuracy in unit inference.
- Updated the source_unit_choices_for_field function to include a custom option for user-defined conversion factors, improving flexibility in unit conversions.
- Modified the AdminCsvTemplateEditorPage to support custom conversion factors, allowing users to input specific scaling factors for their data.
- Added tests to ensure the custom option is correctly included in the source unit choices and functions as expected in the template editor.
- Changed source unit representation from "kJ" to "kj" for consistency across CSV templates and migrations.
- Updated CI workflow to enhance testing conditions, ensuring tests run in the correct environment based on deployment context.
- Improved job steps for backend testing and syntax checking by utilizing deployed application directories, streamlining the CI process.
- Added workflow_run triggers for "Deploy Development" and "Deploy Production" to ensure tests run only after successful deployments.
- Updated Python version in CI from 3.12 to 3.11 for better compatibility with the Debian 12 ARM64 runner.
- Enhanced job conditions to skip tests on failed workflow runs.
- Improved frontend build process by updating Node.js setup and ensuring correct directory navigation.
- Refined CSV parsing logic to handle custom and unknown source units, enhancing conversion flexibility.
- Added new tests for custom source unit handling in CSV conversions, ensuring accurate processing.
- Updated the CSV import architecture to clarify the distinction between import and data layer responsibilities, as outlined in the new section of ARCHITECTURE.md.
- Enhanced the build_row_after_mapping function to include module-specific context for improved data processing.
- Introduced source unit options in the admin CSV template editor to facilitate user-defined conversions, improving flexibility in handling various data formats.
- Added new tests to validate the handling of source units and ensure accurate conversions during CSV imports.
- Updated module definitions to include unit specifications for nutritional and activity data fields, enhancing data integrity.
- Integrated date parsing improvements using dateutil for better handling of various date formats in sleep data.
- Added total sleep hours to the nights dictionary for comprehensive sleep analysis.
- Updated the import logic to handle cases where sleep duration is zero, providing appropriate warnings.
- Enhanced the CSV import interface to detect Apple sleep CSV format and provide user feedback on template selection.
- Improved the admin CSV template editor to accommodate new sleep import requirements and clarify usage instructions.
- Added support for new CSV import modules: sleep and vitals_baseline, expanding the import capabilities.
- Implemented backend logic for handling CSV imports related to sleep and vitals baseline, including error handling and data processing.
- Updated frontend components to include new modules in the CSV import interface, improving user experience.
- Introduced unit tests for the new import functionalities to ensure reliability and correctness.
- Enhanced existing CSV analysis features to accommodate the new modules, ensuring consistent behavior across the application.
- Added new functions for calculating header signature recall and ranking metrics, improving the analysis of CSV templates.
- Updated existing CSV analysis endpoints to utilize the new ranking metrics, enhancing the accuracy of template matching.
- Refactored related code to replace Jaccard score calculations with the new metrics, providing a more comprehensive evaluation of CSV structure.
- Improved documentation for new functions to clarify their purpose and usage in the context of CSV template analysis.
- Added a new endpoint for analyzing uploaded CSV files, providing suggestions for field mappings and type conversions.
- Implemented validation for required field targets to ensure all mandatory fields are mapped correctly.
- Enhanced the admin CSV templates interface with new routes and navigation options in the frontend.
- Updated API utility functions to support the new CSV analysis functionality.
- Improved error handling for CSV uploads, including file size and row count checks.
- Added a new function to strip header keys of unwanted characters, improving CSV import consistency.
- Updated CSV row iteration to utilize the new header normalization function, ensuring cleaner data processing.
- Enhanced date parsing capabilities to support flexible formats, accommodating various date representations in CSV files.
- Introduced additional tests to validate the new header normalization and date parsing functionalities.
- Bumped version of csv_import to 0.3.0, reflecting new analysis capabilities.
- Modified analyze_csv endpoint to allow optional module filtering, improving flexibility in template selection.
- Enhanced the import process to support both system and user-defined templates, ensuring backward compatibility.
- Updated frontend to streamline mapping choices and improve user experience during CSV analysis and import.
- Added detailed error handling and user feedback for import operations.
- Updated version for csv_import to 0.2.0, reflecting new features.
- Implemented a new POST endpoint for universal CSV import, supporting nutrition, weight, and blood pressure modules.
- Added CSV parsing function to yield rows as dictionaries for easier data handling.
- Enhanced error handling and logging for import operations.
- Introduced tests for the new CSV parsing functionality to ensure reliability.
- Changed feature ID from 'csv_import' to 'data_import' in the features table.
- Updated foreign key references in tier_limits, user_feature_restrictions, user_feature_usage, and widget_feature_requirements.
- Removed the old 'csv_import' feature entry after ensuring all references are updated.
- Simplified the migration process by using an INSERT with ON CONFLICT for the new feature entry.
- Added permissions for editing and deleting CSV field mappings.
- Created type converter for CSV cells to handle various data types.
- Implemented database migrations for CSV field mappings and import logs.
- Seeded initial system templates for nutrition and activity data imports.
- Developed admin endpoints for managing system CSV templates.
- Introduced user endpoints for CSV import analysis and mapping retrieval.
- Added tests for core CSV parser functionalities, including delimiter detection and value conversion.
ROOT ARCHITECTURAL CHANGE:
Multiple questions with same type are now supported!
Problem:
- question_augmenter used q.type as LLM key
- If two questions had type="unsicherheit":
- LLM saw duplicate keys: "- unsicherheit: [ja/nein]"
- Could only answer one
- Signals were ambiguous
Solution:
- Use question.id as LLM key (unique by design)
- Keep type for normalization logic
- Map id → type internally
Backend question_augmenter.py:
- format_question_list() now uses q.id as key
- Format: "- **q21**: [ja/nein] # Question text"
- Question text as comment for LLM context
Backend workflow_executor.py:
- Removed type→id mapping (no longer needed)
- decision_signals now keyed by id (from LLM)
- Build id→type catalog for normalization
- NormalizedSignal.question_type stores id (not type!)
- End Node template: signal_{id} directly available
Flow:
1. Questions sent to LLM: "- q21: [ja/nein] # Ist Protein unsicher?"
2. LLM answers: "- q21: nein"
3. Normalization: id→type lookup for spectrum/rules
4. Template: {{ node_4.signal_q21 }} = "nein"
Example (TWO unsicherheit questions):
Questions:
- q21: type=unsicherheit, question="Ist Protein unsicher?"
- q22: type=unsicherheit, question="Ist Energie unsicher?"
LLM Prompt:
```
## Entscheidungsfragen
- **q21**: [ja/nein] # Ist Protein unsicher?
- **q22**: [ja/nein] # Ist Energie unsicher?
```
LLM Response:
```
- q21: nein
- q22: ja
```
Template:
```
{{ node_4.signal_q21 }} → "nein"
{{ node_4.signal_q22 }} → "ja"
```
BREAKING CHANGE:
- Old workflows with decision_signals keyed by type will break
- Need to re-execute workflows after update
Issue: Cannot have multiple questions with same type
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - ARCHITECTURAL FIX
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root Cause:
- Previous index-based mapping assumed signals come in same order as questions
- But LLM response order can differ from question configuration order
- Led to signal values being assigned to wrong question IDs
Old Logic (BUGGY):
1. Build question_type → [list of IDs]
2. Track index per type
3. Get Nth ID from list
→ Assumes LLM answers in question definition order ❌
New Logic (CORRECT):
1. Build question_type → question_id (direct mapping)
2. For each signal: lookup type → get ID
→ Order-independent ✅
Backend workflow_executor.py:
- Removed index tracking (type_counts)
- Direct lookup: question_type_to_id[signal.question_type]
- Added ERROR log if duplicate question types found
- Added INFO log for each mapped signal (debugging)
Important:
- Each question MUST have a UNIQUE type
- If two questions share same type: ERROR logged
- System designed for unique types (LLM can't answer duplicates)
Example Debug Output:
```
Mapped signal: protein_ausreichend → signal_q21 = 'nein'
Mapped signal: kohlenhydrate_strategie → signal_q1775... = 'von Proteinen'
```
Issue: Signal values assigned to wrong question IDs
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Signal Mapping Fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three major improvements for workflow templates:
1. **Normalized Signal Placeholders:**
- Signals now available as {{ node_4.signal_kalorienbilanz }}
- Uses normalized_value (not raw decision_signals)
- Enables structured decision-based outputs
2. **Question Text Placeholders:**
- Question texts available as {{ node_4.question_kalorienbilanz }}
- Extracted from workflow graph (question_augmentations)
- Allows displaying questions alongside answers
3. **Clean End Node Output:**
- End Node output no longer duplicated with "## node_4" headers
- aggregate_results() detects End Nodes via graph.nodes
- Only shows final template-rendered output
- Backward compatible: Falls back to combined_analysis if no End Node
Backend workflow_executor.py:
- execute_end_node(): Added normalized signals to template context
- execute_end_node(): Added question texts to template context
- execute_workflow(): Added graph to context for End Node access
- aggregate_results(): Signature change to accept graph
- aggregate_results(): Detects End Nodes and uses only their output
Frontend WorkflowResultViewer.jsx:
- Now uses aggregated.analysis_core (primary output)
- Removed fallback to combined_analysis (was showing duplicates)
Example Template:
```jinja2
**Frage:** {{ node_4.question_kalorienbilanz }}
**Antwort:** {{ node_4.signal_kalorienbilanz }}
---
{{ node_4.analysis_core }}
```
Issue: Signal placeholders empty, question texts unavailable, duplicate output
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root Cause:
- Frontend serialized as "questions"
- Backend expected "question_augmentations"
- Analysis Nodes WITH questions configured sent empty array to backend
- Questions were never added to LLM prompt
Frontend workflowSerializer.js:
- Serialization: questions → question_augmentations (Backend field name)
- Deserialization: question_augmentations → questions (Frontend data object)
- Backward compatible: Falls back to "questions" for old workflows
Backend workflow_executor.py:
- Removed incorrect load_prompt_questions() function (was a misunderstanding)
- Back to original logic: Only use node.question_augmentations
- Simplified normalization logging
Impact:
- Analysis Node questions are now correctly sent to backend
- Questions augment the base prompt as intended
- LLM receives structured questions
- Decision signals are generated and accessible as placeholders
Example:
- Node configures question with id="q21"
- Signal becomes accessible as {{ node_2.signal_q21 }}
- Can be used in Logic Nodes and End Node templates
Issue: Workflow questions not sent to LLM (field name mismatch)
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Critical Fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend workflow_executor.py:
- New function: load_prompt_questions() loads questions from base prompt
- execute_node() now implements Hybrid Model correctly:
* IF node has question_augmentations → use those (override)
* ELSE load questions from referenced base prompt (fallback)
- Normalization now uses `questions` variable (not node.question_augmentations)
- This fixes base prompts having questions that were ignored in workflows
Root Cause:
- Phase 1 Hybrid Model was incomplete
- Node-specific questions worked, but base prompt questions were ignored
- augment_prompt_with_questions() was only called when node.question_augmentations existed
Impact:
- Analysis Nodes WITHOUT custom questions now use base prompt questions
- LLM receives proper question augmentation
- Decision signals are generated and normalized correctly
Issue: Workflow questions not sent to LLM
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Critical Fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend workflow_executor.py:
- load_prompt_template() now uses modern resolve_placeholders() from prompt_executor
- Calls get_placeholder_example_values() to populate ALL registered placeholders
- Passes catalog for |d modifier support
- Fixes issue where basis prompts had empty/null placeholder values in workflows
Backend placeholder_resolver.py:
- get_placeholder_catalog() now includes ALL placeholders from PLACEHOLDER_MAP
- Uncategorized placeholders added to "Sonstiges" category
- Fixes discrepancy: 111 total placeholders but only ~30 shown in picker
Root Cause:
- Workflow used old resolve_placeholders() (only PLACEHOLDER_MAP, no variables)
- Isolated execution used modern resolve_placeholders() (full variables dict)
- Catalog excluded non-registry placeholders from PLACEHOLDER_MAP
Impact:
- All placeholders now resolve correctly in workflow execution
- PlaceholderPicker shows all 111+ placeholders (not just registry ones)
Version: 0.9p (workflow module)
Part 3: End Node Template Engine - Bug Fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- Moved /placeholders endpoint BEFORE /{prompt_id} catch-all
- Prevents "placeholders" being parsed as UUID parameter
- Fixes 500 Internal Server Error preventing placeholder loading
Frontend:
- PlaceholderPicker can now load ~120+ system placeholders
Root Cause:
- FastAPI matches routes in order
- Generic /{prompt_id} was catching /placeholders first
- psycopg2 error: invalid input syntax for type uuid: "placeholders"
Version: 0.9p (workflow module)
Part 3: End Node Template Engine
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>