You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
7.8 KiB
Markdown

# Software Architect Audit Report (March 27, 2026)
## Clarification Questions
1. Should a new theme be creatable with empty categories/topic (draft mode), or must it be valid at creation?
2. Should `GET /themes/{id}/schedule` return `404` when absent, or `200` with `null`?
3. Which defaults are canonical for themes: DB/spec (`max_items_per_category=4`, `summary_length=3`) or UI/handler (`5`, `2`)?
## Assumptions
- Documentation in `docs/` is the intended target behavior.
- This is architecture-focused (entry points, service boundaries, major modules), not a line-by-line audit of all files.
## Prioritized Findings
### P0
- Theme creation contract is internally inconsistent and likely broken in practice.
- Evidence: UI creates empty topic/categories in `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/ThemeManager.tsx:144`, while backend rejects empty topic/categories in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/models/theme.rs:43` and enforces validation in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/themes.rs:45`.
- Why it matters: blocks core onboarding flow.
- Direction: align API contract + UI create flow (draft-support or valid seeded defaults).
### P1
- Schedule API contract drift across spec, backend, tests, and frontend typing.
- Evidence: spec says `ScheduleResponse` or 404 in `/Users/oabrivard/Projects/rust/ai_synth/docs/technical_specs.md:420`; backend returns `200 null` in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/schedules.rs:40`; tests expect `200 null` in `/Users/oabrivard/Projects/rust/ai_synth/backend/tests/api_schedules_test.rs:77`; frontend assumes non-null in `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/components/settings/SettingsSchedule.tsx:48`.
- Why it matters: runtime fragility and contract confusion.
- Direction: choose one contract and align all layers.
- Theme defaults are inconsistent with DB/spec.
- Evidence: DB migration defaults 4/3 in `/Users/oabrivard/Projects/rust/ai_synth/backend/migrations/20260326000028_create_themes_and_migrate.sql:8`; handler uses 5/2 in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/themes.rs:56`; UI uses 5/2 in `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/ThemeManager.tsx:51`.
- Why it matters: non-deterministic behavior and drift.
- Direction: establish a single source of truth for defaults.
- Reliability gap: job-store TTL cleanup exists but is not scheduled at runtime.
- Evidence: cleanup function exists in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/services/job_store.rs:153`; startup schedules other tasks but not job-store cleanup in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/main.rs:66`; docs expect periodic cleanup in `/Users/oabrivard/Projects/rust/ai_synth/docs/technical_specs.md:778`.
- Why it matters: stale in-memory entries and lock leakage risk over time.
- Direction: add periodic `job_store.cleanup_expired()` task.
- Scheduled generation path does not enforce 15-minute timeout used by manual generation.
- Evidence: manual timeout in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/handlers/generation.rs:89`; scheduler calls pipeline directly in `/Users/oabrivard/Projects/rust/ai_synth/backend/src/services/scheduler.rs:57`; requirement states 15-minute cap in `/Users/oabrivard/Projects/rust/ai_synth/docs/requirements.md:30`.
- Why it matters: scheduled runs can overrun and block throughput.
- Direction: apply same timeout semantics to scheduled execution.
### P2
- Core pipeline and key pages are too large.
- Evidence: `/Users/oabrivard/Projects/rust/ai_synth/backend/src/services/synthesis.rs`, `/Users/oabrivard/Projects/rust/ai_synth/backend/src/services/scraper.rs`, `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/ThemeManager.tsx`, `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/Settings.tsx`.
- Why it matters: weaker SRP, higher cognitive load, slower onboarding/review/testing.
- Direction: split by bounded responsibilities (phase modules/services/hooks/components).
- Frontend architectural consistency drift (API and data-loading patterns).
- Evidence: direct `fetch` in `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/pages/GenerateSynthesis.tsx:241` despite centralized client in `/Users/oabrivard/Projects/rust/ai_synth/frontend/src/api/client.ts:25`; guideline preference for `createResource` in `/Users/oabrivard/Projects/rust/ai_synth/docs/dev_guidelines.md:174`.
- Direction: enforce API client boundary and consistent data-loading patterns.
## SOLID Scorecard
| Dimension | Score (/5) | Notes |
|---|---:|---|
| Single Responsibility | 2 | Several large multi-responsibility modules. |
| Open/Closed | 4 | LLM provider abstraction/factory is extensible. |
| Liskov Substitution | 4 | Provider implementations conform to trait contract cleanly. |
| Interface Segregation | 3 | Mostly good boundaries with a few broad surfaces. |
| Dependency Inversion | 3 | Good trait usage for LLM, pipeline still tightly coupled in places. |
| Overall maintainability | 3 | Good foundations, but contract drift + module size are bottlenecks. |
## Refactoring Plan
1. Phase 0: Contract decisions (0.5-1 day, low risk).
- Decide canonical behavior for theme creation, schedule GET semantics, and defaults.
2. Phase 1: Correctness alignment (1-2 days, medium risk).
- Align backend/frontend/tests with chosen contracts.
3. Phase 2: Reliability hardening (1 day, low-medium risk).
- Add job-store cleanup scheduling and timeout parity in scheduler.
4. Phase 3: Backend decomposition (3-5 days, medium risk).
- Split synthesis pipeline into phase modules with explicit contexts.
5. Phase 4: Frontend decomposition (3-5 days, medium risk).
- Split large pages into composables/components and remove direct page-level fetch.
6. Phase 5: Drift prevention (1-2 days, low risk).
- Add conformance tests/checks for contracts/defaults and PR architecture checklist.
## Architecture/SOLID Scorecard
| Dimension | Score (/5) | Notes |
|---|---:|---|
| Layering clarity | 3 | Clear module boundaries, but some runtime orchestration gaps.
| SRP | 2 | Multiple "god files" in backend and frontend.
| OCP | 4 | LLM provider abstraction/factory is cleanly extensible.
| DIP | 3 | Core synthesis is trait-based for LLM, but still tightly coupled to DB/functions.
| Testability | 3 | Strong unit/integration coverage in backend; scheduler/e2e gaps remain.
| Spec alignment | 2 | Multiple contract/default mismatches.
## Refactoring Plan (Architecture-Level)
### Phase 1 (1-2 days) — Contract and reliability fixes
- Align theme creation contract (UI + model validation + tests).
- Align schedule GET semantics across docs/handler/tests/frontend types.
- Add periodic `job_store.cleanup_expired()` background task.
- Apply 15-minute timeout to scheduled generation path.
### Phase 2 (3-5 days) — Backend decomposition
- Split `services/synthesis.rs` into submodules:
- `init.rs` (load settings/theme/provider)
- `phase1_personalized.rs`
- `phase2_fallback.rs`
- `finalize.rs`
- `tracing.rs`
- Introduce explicit pipeline context structs to reduce argument fanout.
### Phase 3 (3-5 days) — Frontend decomposition
- Extract page-level logic from `ThemeManager` and `Settings` into composables/hooks:
- `useThemeEditor`, `useSourcesManager`, `useScheduleConfig`, `useSettingsForm`
- Normalize API usage through `api/client.ts` only.
### Phase 4 (2-3 days) — Conformance hardening
- Add spec-conformance tests for defaults, schedule contract, and theme creation.
- Add architecture fitness checks (lint/custom tests) for forbidden contract drifts.
## Quick Wins (< 1 day)
1. Add scheduled timeout wrapper in `scheduler.rs`.
2. Add job-store periodic cleanup task in `main.rs`.
3. Fix `ThemeManager` create payload to pass valid initial `theme` and categories.
4. Unify schedule GET typing with actual backend behavior.