# IETF Draft Analyzer — Architectural Assessment **Date:** 2026-03-09 **Scope:** Core source code analysis (src/, tests/) **Project Size:** ~7.6 MB, 19,662 lines of Python --- ## 1. File Sizes and Complexity ### God Files (largest, highest complexity risk) | File | LOC | Severity | Issue | |------|-----|----------|-------| | `webui/data.py` | 4,360 | HIGH | Service/data access layer doing too much | | `cli.py` | 3,438 | MEDIUM | 96 functions, 40+ Click commands, hard to navigate | | `reports.py` | 2,739 | MEDIUM | Single Reporter class with many report generation methods | | `db.py` | 1,690 | MEDIUM | 100+ methods, schema + CRUD + business logic mixed | ### Healthy Modules (< 500 LOC, focused) - `models.py` (104 LOC) — Domain models only - `config.py` (108 LOC) — Configuration with env overrides - `embeddings.py` (205 LOC) — Ollama embedding wrapper - `authors.py` (137 LOC) — Author network fetching - `fetcher.py` (204 LOC) — Datatracker API client --- ## 2. Module Boundaries: Core vs. Web ### Clean Separation ✓ - **Core layer (`src/ietf_analyzer/`):** Self-contained, no Flask dependencies - **Web layer (`src/webui/`):** Depends on core, not vice-versa - **No circular imports detected** ### Problem: webui/data.py Violates Single Responsibility **What it does:** 1. Wraps `Database` (4,360 lines!) 2. Implements domain logic (clustering, readiness scoring, similarity graphs) 3. Prepares data for JSON/Jinja2 serialization 4. Defines TypedDicts for response shapes 5. Calls `sklearn` for TSNE/hierarchical clustering 6. Builds visualization data (radar, histogram, network graphs) **Risk:** Tests only `test_web_data.py` — hard to regression-test domain logic when mixed with presentation layer. --- ## 3. Flask Structure (`app.py`) ### Routes Count - **72 functions** (includes helpers) - **~40+ @app.route()** handlers - **No blueprints** — monolithic Flask app ### Route Categories 1. **Overview pages** (5) — `/`, `/landscape`, `/timeline`, `/idea-clusters`, `/ratings` 2. **Detail pages** (6) — `/drafts`, `/drafts/`, `/gaps`, `/gaps/`, etc. 3. **Feature pages** (8) — `/search`, `/ask`, `/compare`, `/monitor`, `/admin/analytics`, etc. 4. **API endpoints** (20+) — `/api/drafts`, `/api/stats`, `/api/search`, `/api/ask`, etc. 5. **Helpers** (5+) — auth, rate limiting, CSV export, DB context ### Issues | Issue | Effort | Impact | |-------|--------|--------| | **No blueprint organization** — Mix of concerns (pages, APIs, admin) in one file | SMALL | Makes navigation hard | | **Tight coupling to data.py** — 50 imports from data.py | SMALL | Hard to refactor data layer | | **Mixed JSON/HTML rendering** — Some routes render both based on Accept header | SMALL | Should be separate APIs | | **Admin functions inline** — `/admin/analytics` uses `@admin_required` decorator | SMALL | Should be separate blueprint | **Recommendation:** Split into 4 blueprints: - `blueprints/pages.py` — HTML pages - `blueprints/api.py` — JSON endpoints - `blueprints/admin.py` — Admin routes - `blueprints/helpers.py` — Shared utilities --- ## 4. Database Layer (`db.py`) ### Structure: Single `Database` Class **100+ methods** doing: 1. **Schema definition** — `SCHEMA` constant, `ensure_tables()` 2. **CRUD operations** — `add_draft()`, `update_draft()`, `get_draft()`, `delete_draft()` 3. **Bulk operations** — `add_drafts()`, `update_ratings()` 4. **Complex queries** — `get_drafts_by_category()`, `search_fts()`, `most_cited()`, `co_authors()` 5. **Business logic** — Rating aggregations, clustering, similarity ranking 6. **Cache management** — `llm_cache` table operations 7. **Stats** — `count_drafts()`, `count_by_source()`, aggregations ### Issues | Issue | Evidence | Refactor Effort | |-------|----------|-----------------| | **Mixed concerns** | Methods scattered: schema, CRUD, queries, business logic | LARGE | | **No transaction support** | `add_draft()` does 3+ INSERT statements without explicit tx | MEDIUM | | **Hard to unit test** | Database class touches 8+ tables; need fixtures for each | MEDIUM | | **Tight coupling to models** | Direct `Author`, `Draft`, `Rating` dataclass deps | SMALL | | **No query builders** | Raw SQL in 20+ methods (injection risk if not careful) | MEDIUM | ### Refactoring Path (4-step) ```python # Current: db.Database (100 methods) # # Refactored: # - db.Schema — @dataclass fixtures, schema def (10 methods) # - db.Repository — CRUD base class (15 methods) # - db.DraftRepository, AuthorRepository, etc. — domain-specific CRUD # - db.Queries — Complex queries as static methods or separate class # - db.Cache — LLM cache operations (10 methods) ``` **Effort:** LARGE (4+ hours) **Benefit:** Testability, reusability, transaction support, easier migrations --- ## 5. Pipeline Architecture (`pipeline/`) ### Structure: Modular design ✓ - `context.py` — ContextBuilder (domain logic for draft generation) - `generator.py` — DraftGenerator (Claude-based content generation) - `family.py` — Family/relationships logic - `formatter.py` — Output formatting - `quality.py` — Quality checks - `prompts.py` — System prompts - `PROMPTS` constant — Shared across modules ### Assessment ✓ **Good separation** — Each module has a single responsibility ✓ **Testable** — Pure functions + dependency injection via Config/Database ✓ **Extensible** — Can add new stages without touching existing code **No refactoring needed** for pipeline itself. --- ## 6. Sources Architecture (`sources/`) ### Structure: Plugin pattern ✓ - `base.py` — `SourceDocument` dataclass, `SourceFetcher` protocol - `ietf.py`, `w3c.py`, `etsi.py`, `itu.py`, `iso.py`, `nist.py` — Concrete fetchers ### Assessment ✓ **Excellent separation** — Base protocol + concrete implementations ✓ **Testable** — Mock fetchers easy to create ✓ **Extensible** — New source = new file, no changes to orchestrator **No refactoring needed**. --- ## 7. Config Management (`config.py`) ### Structure - Single `Config` dataclass (40 fields) - `load()` class method with env var override support - `save()` method to persist to JSON - Validation in `_validate()` ### Assessment ✓ **Clean** — Single responsibility ✓ **Testable** — No I/O except file read/write ✓ **Env support** — `_ENV_OVERRIDES` dict maps env vars **Minor issue:** Could use structured logging of which env vars override config (currently silent). **No refactoring needed** unless config grows beyond 50 fields. --- ## 8. CLI Structure (`cli.py`) ### Count: 96 functions **Command groups:** - `fetch` — Datatracker + multi-source fetching - `classify` — Ollama-based pre-filtering - `list`, `search`, `show`, `annotate` — Draft browsing - `analyze` — Claude analysis (rate, ideas, gaps) - `ask`, `compare` — Interactive queries - `embed`, `embed-ideas` — Ollama embeddings - `similar`, `clusters` — Embedding-based search - `report` (group) → `overview`, `landscape`, `digest`, `timeline`, etc. - `monitor` — Background pipeline automation - `pipeline`, `pipeline-status`, `pipeline-auto-heal` — Orchestration - `observatory` — Multi-source dashboard - `readiness` — Release readiness analysis - `export` — Generate drafts from gaps - `web` — Flask app launcher ### Issues | Issue | Severity | Solution | |-------|----------|----------| | **96 functions in one file** | MEDIUM | Hard to navigate, should split into subcommands or files | | **Long help text inline** | LOW | Could use .help-txt files for docstrings | | **Late imports** | LOW | Some imports inside `@pass_cfg_db` functions to save startup time (OK pattern) | | **Global console object** | LOW | OK for Click, allows colorized output | ### Recommended Split (5 files) ```python # cli.py (main entry, 200 lines) # └─ cli/fetching.py (fetch, classify) — 400 lines # └─ cli/analysis.py (analyze, ask, compare) — 600 lines # └─ cli/reporting.py (report *, export, observatory) — 800 lines # └─ cli/admin.py (monitor, pipeline, web) — 400 lines ``` **Effort:** SMALL (1 hour) **Benefit:** Easier to navigate, faster to find commands, clearer testing boundaries. --- ## 9. Circular Dependencies ### Check Results **✓ No circular imports detected** - `cli.py` → `db`, `config`, `models` ✓ - `app.py` → `webui.data`, `webui.auth`, `ietf_analyzer.*` ✓ - `webui.data` → `ietf_analyzer.db`, `ietf_analyzer.config` ✓ - `db.py` → `models`, `config` ✓ --- ## 10. Test Structure **Test files:** 8 modules covering: - `test_db.py` — Database operations - `test_analyzer.py` — Claude analysis - `test_search.py` — Similarity + FTS - `test_web_data.py` — Data layer for web - `test_models.py` — Domain models - `test_obsidian_export.py` — Export **Coverage gaps:** - No tests for `cli.py` (big commands, hard to test without mocking db) - No tests for `app.py` routes (would need Flask test client + fixtures) - No tests for pipeline modules (context, generator, family) - No tests for sources (would need HTTP mocks) **Effort to add 30% CLI coverage:** MEDIUM (2-3 hours) --- ## Summary: Refactoring Roadmap | Priority | Module | Issue | Effort | Benefit | |----------|--------|-------|--------|---------| | **HIGH** | `webui/data.py` | 4,360 LOC, mixed concerns (CRUD + domain logic + presentation) | LARGE | Separates presentation from domain, enables better testing | | **MEDIUM** | `db.py` | 100 methods, mixed schema/CRUD/logic | LARGE | Testability, transaction support, query builders | | **MEDIUM** | `cli.py` | 96 functions, hard to navigate | SMALL | Better organization, easier to find commands | | **MEDIUM** | `app.py` | 40+ routes, no blueprints | SMALL | Clearer structure, easier to refactor | | **LOW** | Config | 40 fields, working well | NONE | Monitor for growth beyond 50 fields | | **LOW** | Pipeline/Sources | Well-structured, testable | NONE | No changes needed | --- ## Recommendations (Priority Order) ### 1. **Extract webui/data.py → presentation + domain** (4 hours) ``` webui/ ├── data.py (current 4,360 → 1,000) — Only JSON serialization └── services/ ├── drafts.py (200) — Draft filtering/sorting logic ├── analytics.py (400) — Dashboard stats + visualizations ├── search.py (300) — Search + clustering └── readiness.py (200) — Readiness scoring ``` **Cost:** 4 hours **Benefit:** Can reuse analytics for CLI reports, easier to test ### 2. **Refactor db.py → Repository pattern** (4 hours) ``` db/ ├── __init__.py (exports Database facade) ├── schema.py (100) — Schema definition ├── repository.py (200) — Base CRUD class ├── drafts.py (300) — DraftRepository (get, add, update, delete drafts) ├── ratings.py (200) — RatingRepository ├── authors.py (150) — AuthorRepository ├── queries.py (400) — Complex queries (search, similarity, aggregations) └── cache.py (150) — LLM cache operations ``` **Cost:** 4 hours **Benefit:** 80% reduction in method count per class, transaction support, testability ### 3. **Split cli.py into subcommand groups** (1 hour) ``` cli/ ├── __init__.py (main entry, ~200 lines) ├── fetching.py (fetch, classify) ├── analysis.py (analyze, ask, compare) ├── reporting.py (report *, export, observatory) └── admin.py (monitor, pipeline, web) ``` **Cost:** 1 hour **Benefit:** Easier to navigate, clearer boundaries, faster to find commands ### 4. **Convert Flask app to blueprints** (1.5 hours) ``` webui/ ├── app.py (core Flask setup, ~100 lines) └── blueprints/ ├── pages.py (HTML routes: /, /drafts, /landscape, etc.) ├── api.py (JSON endpoints: /api/*) ├── admin.py (/admin/*) └── helpers.py (rate limiting, auth, CSV export) ``` **Cost:** 1.5 hours **Benefit:** Clearer separation of concerns, easier to add/remove features ### 5. **Add CLI tests** (3 hours) - Mock database for each command - Test success paths + error cases - Quick smoke tests for all 15+ major commands **Cost:** 3 hours **Benefit:** Catch regressions early, safe refactoring --- ## Current State Assessment | Dimension | Score | Notes | |-----------|-------|-------| | **Modularity** | 7/10 | Good separation of concerns; core vs. web clean; webui/data.py is the weak point | | **Testability** | 6/10 | DB layer hard to unit test; pipeline/sources good; no CLI tests | | **Maintainability** | 6/10 | Many large files; well-documented; consistent patterns throughout | | **Extensibility** | 8/10 | Plugin pattern for sources; easy to add new reports; CLI is open-ended | | **Performance** | 8/10 | Caching, FTS5, lazy imports in CLI; no N+1 queries detected | **Overall:** 7/10 — **Production-ready but showing signs of technical debt accumulation.** The project is well-organized at a high level but needs refactoring of large monolithic files to stay maintainable as it grows. The webui/data.py and db.py files should be prioritized first.