feat: clean up architecture and add test suite - #1
Open
Anty0 wants to merge 1 commit into
Open
Conversation
Bug fixes:
- Fix CodeBlockHtmlNormalizer to return content between fences (was
returning only the opening fence) and pass through unterminated fences
- Replace fragile str.format prompt/error substitution with collision-safe
str.replace / string.Template; reject the doubled {{weather_json}} token
- Use timedelta.total_seconds() for the progressive-update throttle
- Make timestamps tz-aware in the configured scheduler tz; force one
refresh on legacy/unparseable stored timestamps instead of crashing
Architecture:
- New neutral visualization/ package: Visualization value object (single
from_raw assembly point), VisualizationStatus enum, HtmlNormalizer
- Move normalization to generation time; ConnectionManager no longer
normalizes and strips the tz offset only at the wire boundary
- Replace module-global state with create_app(settings, provider_factory)
wiring components onto app.state; keep module-level app for aiweather:app
- Extract RefreshService (fetch/archive/state/broadcast/generate,
needs_refresh, load_initial_state); WeatherScheduler now owns triggers
- StateService is a pure passive holder
- Minimal provider factory (one instance per name, skips unknown with a
warning); bounded non-fatal availability probe; new /ready endpoint,
/health stays a cheap liveness check
- CWD-independent asset paths via aiweather/paths.py
- Modernize typing to py3.14 builtins; remove dead code
Testing:
- Add a pytest suite (79 tests) covering normalizer, config, archive,
state, refresh, AIManager, provider factory, weather client, websocket,
scheduler, and wired-app integration; add a CI test job
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
{{weather_json}}token); throttle usestotal_seconds(); timestamps are tz-aware and legacy/unparseable stored timestamps force one refresh instead of crashing startup.visualization/package:Visualizationvalue object with a singlefrom_rawassembly point,VisualizationStatusenum, and the movedHtmlNormalizer— a dependency leaf shared byai/,state/,websocket/,scheduler/.AIManagernormalizes every progressive frame;ConnectionManagerno longer normalizes and strips the tz offset only at the wire boundary.create_app(*, settings, provider_factory)wiring components ontoapp.state; module-levelapp = create_app()keepsaiweather:appworking.RefreshServiceextracted: owns fetch → archive → state → broadcast → generate,needs_refresh, andload_initial_state;WeatherSchedulernow only owns APScheduler triggers.StateServiceis a pure passive holder./readyendpoint while/healthstays a cheap liveness check.aiweather/paths.py); py3.14 builtin typing throughout; dead code removed;AGENTS.mdandconfig.example.yamlupdated.Accepted behavior changes
scheduler.timezone(documented inconfig.example.yaml)./readyendpoint;/healthpayload unchanged.Follow-up (not in this PR)
current_visualizations+visualization_statusinto a singledict[str, ModelSlot]so visualization and status update atomically.