System Rules
Domain policies governing TennisAgent tool execution
Data Integrity Rules
Tools SHALL NOT generate, invent, or hallucinate sensor readings, session data, or match results not present in the database.
All timestamps are stored in UTC. Display conversions happen at presentation layer only.
Every data point must be traceable to its source sensor (AppleWatch, Zepp, Babolat, Garmin).
Query Processing Rules
Identical queries MUST produce identical results. No randomness in query resolution or tool execution.
Dates are normalized to YYYY-MM-DD format. Relative dates ("yesterday", "last week") are resolved at parse time.
Session IDs support device prefix matching. "watch_20251113" resolves to full Apple Watch session ID.
Queries without explicit date range default to last 52 weeks unless tool specifies otherwise.
Tool Execution Rules
Query tools are stateless. No tool call affects the outcome of any subsequent tool call (except explicit data mutations).
All tool parameters are validated before execution. Invalid session IDs, dates, or sensor types are rejected with error.
Step dependencies (e.g., $step_0_result.session_id) are resolved before tool execution using ExecutionContext.
Session summaries and sensor data are cached per-execution to avoid redundant database queries.
Sensor-Specific Rules
Default swing detection threshold is 10 rad/s rotation rate. Configurable per-tool call.
Sessions are considered "linked" if start times are within 5 minutes (configurable via tolerance_minutes).
Zepp sessions require minimum 10 swings to be considered valid for analysis (configurable via min_swings).
Babolat activity IDs follow format "MAC_ADDRESS_NUMBER" (e.g., "9C:68:5B:00:35:65_657").
Visualization Rules
Visualizations are saved to /tmp/tennis_viz by default unless output_dir is specified.
Zepp impact visualizations show 5-zone overlay by default (show_zones=True).
Scatter plots use jitter (default 0.03) to prevent point overlap on identical positions.
Error Handling Rules
Missing data returns structured error with context, not crashes. Query continues with available data.
When no results match, return explicit "not found" message with search criteria, not empty result.
On error during RUNNING state, transition to FAILED with error context preserved for debugging.