From 8670aed9adb6f5a1677a4406fcc669aa2ea5d6f3 Mon Sep 17 00:00:00 2001 From: Alexandre Teixeira Date: Tue, 28 Jul 2026 07:59:37 +0100 Subject: [PATCH] docs: classify architecture inventory and refresh guidance --- discovery/README.md | 2 +- discovery/architecture-runtime-inventory.md | 331 +++++++++++++ docs/ARCHITECTURE.md | 87 ++++ docs/STYLE.md | 72 +++ docs/pr-blocker-audit.md | 4 +- specs/architecture-runtime-inventory.md | 443 ++---------------- tests/LAYOUT_INVENTORY.md | 300 +++++------- tests/OVERSIZED_TEST_SPLIT_PLAN.md | 325 +++++++------ .../tools/build_oversized_test_split_plan.py | 8 +- 9 files changed, 832 insertions(+), 740 deletions(-) create mode 100644 discovery/architecture-runtime-inventory.md create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/STYLE.md diff --git a/discovery/README.md b/discovery/README.md index f4c205837..234726851 100644 --- a/discovery/README.md +++ b/discovery/README.md @@ -31,4 +31,4 @@ Compact, code-grounded discovery maps of cross-cutting systems in the checked-in 4. When no owning specification exists, retain the verified finding here and record missing documentation ownership as a follow-up; otherwise retain unresolved context here and correct stale wording. > [!NOTE] -> This package intentionally contains no generator, validator, maturity scale, feature database, or parallel work tracker. The [architecture runtime inventory](../specs/architecture-runtime-inventory.md) remains useful structural context, but is an explicitly draft snapshot. +> This package intentionally contains no generator, validator, maturity scale, feature database, or parallel work tracker. The [architecture runtime inventory](./architecture-runtime-inventory.md) preserves dated structural metrics, investigation context, and historical planning as an explicitly non-canonical snapshot. diff --git a/discovery/architecture-runtime-inventory.md b/discovery/architecture-runtime-inventory.md new file mode 100644 index 000000000..22a56d9bf --- /dev/null +++ b/discovery/architecture-runtime-inventory.md @@ -0,0 +1,331 @@ +# Architecture runtime inventory + +> [!WARNING] +> This document is a dated structural snapshot, not a canonical runtime specification. +> Counts, paths, and implementation details may drift as the repository changes. +> Verify implementation-sensitive claims against the current code and tests. + +- **Branch:** `discovery` +- **Commit:** `c762efe1c97a` +- **Generated:** `2026-07-28T05:38:14+01:00` +- **Historical context:** readability and refactor planning in [#4071](https://github.com/odysseus-dev/odysseus/issues/4071) and [#4082](https://github.com/odysseus-dev/odysseus/issues/4082) + +## Disposition + +> [!NOTE] +> Reviewed for documentation classification. Stable runtime structure and +> subsystem ownership have been transferred to the proposed canonical +> destination, [`docs/ARCHITECTURE.md`](../docs/ARCHITECTURE.md), for +> maintainer review. +> +> This document retains dated metrics, rankings, investigation context, +> refactor-sensitive observations, and historical planning. Those contents are +> non-canonical and belong under `discovery/`. + +| Content | Authority and destination | +|---|---| +| Stable runtime structure | Proposed canonical destination: `docs/ARCHITECTURE.md` | +| Stable subsystem boundaries | Proposed canonical destination: `docs/ARCHITECTURE.md` | +| Frontend module organization | `static/js/MODULE_SUMMARY.md` | +| Counts, line totals, and rankings | This non-canonical inventory | +| Investigation context and open questions | `discovery/` | +| Refactor options and prioritization | Issues, Plane, or non-canonical discovery material | + +The transfer preserves the stable facts without promoting generated metrics or +historical prioritization into canonical documentation. + +## Purpose + +This inventory provides a reviewable map of the current repository structure, +large runtime modules, major subsystem boundaries, and refactor-sensitive areas. + +It does not: + +- define accepted subsystem behaviour; +- certify runtime correctness; +- prescribe a committed refactor sequence; +- replace focused specifications, tests, or source review. + +For cross-cutting implementation evidence, see the [discovery maps](./README.md). + +## Top-level runtime structure + +| Area | Role | +|---|---| +| `app.py` | FastAPI application composition and entry point | +| `launcher.py` | Application launch support | +| `setup.py` | Native setup workflow | +| `core/` | Authentication, middleware, persistence, sessions, and platform primitives | +| `routes/` | HTTP and API route handlers | +| `src/` | Application services, orchestration, tools, providers, and runtime helpers | +| `services/` | Domain-oriented service packages | +| `mcp_servers/` | Built-in MCP server implementations | +| `scripts/` | CLI tools, diagnostics, maintenance, and migration helpers | +| `static/` | No-build browser frontend and bundled assets | +| `tests/` | Automated test suite and supporting test infrastructure | + +## Directory snapshot + +| Directory | Tracked files | Tracked Python files | Direct subdirectories | +|---|---:|---:|---| +| `src/` | 143 | 143 | `agent_tools/`, `model_capability_readers/`, `search/`, `tools/` | +| `routes/` | 73 | 73 | `admin_wipe/`, `cleanup/`, `compare/`, `contacts/`, `gallery/`, `history/`, `memory/`, `note/`, `research/` | +| `core/` | 11 | 11 | None | +| `services/` | 42 | 40 | `docs/`, `faces/`, `hwfit/`, `memory/`, `research/`, `search/`, `shell/`, `stt/`, `tts/`, `youtube/` | +| `mcp_servers/` | 5 | 5 | None | +| `scripts/` | 44 | 17 | `_completion/`, `_lib/`, `demo_email/` | +| `static/js/` | 154 | 0 | `calendar/`, `color/`, `compare/`, `editor/`, `emailLibrary/`, `markdown/`, `model/`, `research/`, `util/` | +| `tests/` | 768 | 758 | `cli/`, `helpers/`, `streaming/`, `tools/` | + +> [!NOTE] +> Counts in this table use `git ls-files`, so generated caches, virtual +> environments, and other untracked local files are excluded. + +## Largest backend modules + +Large files are review signals, not proof that a module should be split. +Coupling, ownership, import compatibility, tests, and runtime authority matter more +than line count alone. + +| Rank | File | Lines | Classes | Top-level functions | Review signal | +|---:|---|---:|---:|---:|---| +| 1 | `routes/email_routes.py` | 6032 | 1 | 58 | High | +| 2 | `src/agent_loop.py` | 5248 | 0 | 63 | High | +| 3 | `routes/cookbook_routes.py` | 4545 | 0 | 16 | High | +| 4 | `mcp_servers/email_server.py` | 2920 | 0 | 77 | High | +| 5 | `src/llm_core.py` | 2895 | 3 | 85 | High | +| 6 | `src/builtin_actions.py` | 2845 | 2 | 27 | High | +| 7 | `routes/model_routes.py` | 2743 | 0 | 65 | High | +| 8 | `src/task_scheduler.py` | 2627 | 1 | 8 | Medium | +| 9 | `core/database.py` | 2562 | 28 | 67 | High | +| 10 | `routes/gallery/gallery_routes.py` | 2325 | 0 | 16 | Medium | +| 11 | `routes/chat_routes.py` | 2063 | 0 | 18 | Medium | +| 12 | `routes/shell_routes.py` | 1971 | 1 | 21 | Medium | +| 13 | `src/visual_report.py` | 1933 | 0 | 11 | Medium | +| 14 | `routes/email_helpers.py` | 1888 | 3 | 48 | Medium | +| 15 | `routes/document_routes.py` | 1810 | 0 | 5 | Medium | +| 16 | `src/tools/cookbook.py` | 1705 | 0 | 34 | Medium | +| 17 | `routes/calendar_routes.py` | 1667 | 2 | 19 | Medium | +| 18 | `routes/skills_routes.py` | 1662 | 3 | 19 | Medium | +| 19 | `src/tool_schemas.py` | 1595 | 0 | 3 | Medium | +| 20 | `routes/email_pollers.py` | 1551 | 0 | 23 | Medium | + +The largest current backend concentrations include: + +- email routing and helper logic; +- agent-loop orchestration; +- Cookbook lifecycle and serving logic; +- provider and model routing; +- task scheduling; +- shared database models and persistence helpers. + +These areas require focused ownership and compatibility analysis before structural +changes are attempted. + +## Largest frontend modules + +| Rank | File | Lines | +|---:|---|---:| +| 1 | `static/style.css` | 41132 | +| 2 | `static/js/document.js` | 11200 | +| 3 | `static/js/emailLibrary.js` | 8505 | +| 4 | `static/js/slashCommands.js` | 6520 | +| 5 | `static/js/chat.js` | 6001 | +| 6 | `static/js/settings.js` | 5819 | +| 7 | `static/js/notes.js` | 5365 | +| 8 | `static/app.js` | 4681 | +| 9 | `static/js/cookbookRunning.js` | 4433 | +| 10 | `static/js/galleryEditor.js` | 4386 | +| 11 | `static/js/cookbookServe.js` | 4305 | +| 12 | `static/js/calendar.js` | 3722 | +| 13 | `static/js/cookbook.js` | 3677 | +| 14 | `static/js/sessions.js` | 3665 | +| 15 | `static/js/documentLibrary.js` | 3422 | +| 16 | `static/js/tasks.js` | 3187 | +| 17 | `static/js/admin.js` | 3144 | +| 18 | `static/js/gallery.js` | 2958 | +| 19 | `static/js/cookbook-hwfit.js` | 2826 | +| 20 | `static/js/chatRenderer.js` | 2808 | + +The browser frontend remains a no-build ES-module application. Its current source +tree is authoritative; the maintained structural summary is available in +[`static/js/MODULE_SUMMARY.md`](../static/js/MODULE_SUMMARY.md). + +CSS modularization remains tracked separately in +[#2617](https://github.com/odysseus-dev/odysseus/issues/2617). + +## Major subsystem boundaries + +| Subsystem | Primary implementation locations | +|---|---| +| Application startup | `app.py`, `src/app_initializer.py`, `core/` | +| Authentication and sessions | `core/auth.py`, `core/middleware.py`, `core/session_manager.py`, `routes/auth_routes.py` | +| Chat and streaming | `routes/chat_routes.py`, `routes/chat_helpers.py`, `src/chat_handler.py`, `src/chat_processor.py`, `src/llm_core.py` | +| Agents and tools | `src/agent_loop.py`, `src/tool_execution.py`, `src/agent_tools/`, `src/tools/`, `src/tool_policy.py`, `src/tool_security.py` | +| Models and providers | `routes/model_routes.py`, `src/model_discovery.py`, `src/model_capabilities.py`, `src/endpoint_resolver.py`, `src/llm_core.py` | +| Cookbook and hardware fit | `routes/cookbook_routes.py`, `routes/cookbook_helpers.py`, `src/cookbook_serve_lifecycle.py`, `services/hwfit/` | +| Search and research | `routes/search_routes.py`, `services/search/`, `routes/research/`, `services/research/`, `src/deep_research.py` | +| Documents and retrieval | `routes/document_routes.py`, `src/document_processor.py`, `src/personal_docs.py`, `src/rag_manager.py`, `src/pdf_runtime.py` | +| Memory and skills | `routes/memory/`, `services/memory/`, `routes/skills_routes.py` | +| Email | `routes/email_routes.py`, `routes/email_helpers.py`, `routes/email_pollers.py`, `mcp_servers/email_server.py` | +| Calendar, contacts, notes, and tasks | `routes/calendar_routes.py`, `routes/contacts/`, `routes/note/`, `routes/task_routes.py`, `src/task_scheduler.py` | +| Media and speech | `routes/gallery/`, `routes/stt_routes.py`, `routes/tts_routes.py`, `services/stt/`, `services/tts/` | +| Persistence and operations | `core/database.py`, `src/runtime_paths.py`, `src/bg_jobs.py`, `routes/backup_routes.py`, `routes/cleanup/` | + +For a broader evidence map, see +[`system-map.md`](./system-map.md). + +## Refactor-sensitive areas + +### Shared persistence + +`core/database.py` is a central dependency containing models and shared persistence +helpers. Changes can affect routes, services, background work, tests, migrations, +and import compatibility. + +A split should not begin from file size alone. It requires: + +- an importer inventory; +- model and helper ownership decisions; +- migration compatibility checks; +- stable re-export or migration strategy; +- focused and full-suite validation. + +### Agent orchestration + +`src/agent_loop.py` coordinates model interaction, tool selection, policy decisions, +multi-round execution, and background behaviour. Extraction work must preserve tool +event semantics, policy enforcement, cancellation, and test patch points. + +Historical agent-loop modularization discussion is tracked in +[#3266](https://github.com/odysseus-dev/odysseus/issues/3266). + +### Tool implementation boundaries + +Tool implementation is no longer represented by one proposed future package alone. +Current responsibilities are distributed across: + +- `src/tool_execution.py`; +- `src/tool_schemas.py`; +- `src/tool_index.py`; +- `src/tool_policy.py`; +- `src/tool_security.py`; +- `src/agent_tools/`; +- `src/tools/`; +- remaining compatibility surfaces such as `src/tool_implementations.py`. + +Historical tool modularization work is tracked in +[#3629](https://github.com/odysseus-dev/odysseus/issues/3629). + +### Route ownership + +`routes/` now contains both flat modules and domain packages. Existing package +boundaries should be extended only through focused changes. Broad mechanical route +movement would affect registration, imports, tests, monkeypatch targets, and +compatibility paths. + +### Frontend concentration + +The no-build frontend contains several large JavaScript modules and one central CSS +file. Refactors should preserve module load order, global compatibility exports, +DOM contracts, deep-link handling, and browser behaviour. + +## Non-implemented architecture options + +> [!NOTE] +> The paths below are historical or possible design directions. They do not describe +> the current repository and are not approved implementation plans. + +Earlier planning discussed: + +- renaming `app.py` to `main.py`; +- moving agent orchestration into a new `src/agent/` package; +- introducing broad `src/domain/`, `src/infra/`, `src/api/`, or `src/pkg/` layers; +- moving all routes into domain subpackages; +- splitting database models into a new infrastructure hierarchy. + +These options should be reconsidered against the current tree rather than copied +forward as assumed targets. + +## Refactor guardrails + +- Keep structural changes behaviour-preserving. +- Change one ownership boundary at a time. +- Do not mix file movement with unrelated feature work. +- Preserve existing import and monkeypatch paths where compatibility is required. +- Identify focused tests before modifying high-authority modules. +- Validate startup, imports, and affected runtime paths. +- Avoid repository-wide package reorganizations without maintainer agreement. +- Treat generated metrics as snapshots, not architectural decisions. + +## Reproduce the snapshot + +Run these commands from the repository root. + +```bash +# Tracked directory totals +for dir in src routes core services mcp_servers scripts static/js tests; do + files="$(git ls-files "$dir" | wc -l)" + python_files="$(git ls-files "$dir" '*.py' | wc -l)" + + printf '%-14s tracked=%-5s python=%-5s\n' \ + "$dir" \ + "$files" \ + "$python_files" +done + +# Largest tracked backend files +git ls-files \ + 'app.py' \ + 'launcher.py' \ + 'setup.py' \ + 'core/*.py' \ + 'core/**/*.py' \ + 'routes/*.py' \ + 'routes/**/*.py' \ + 'services/*.py' \ + 'services/**/*.py' \ + 'src/*.py' \ + 'src/**/*.py' \ + 'mcp_servers/*.py' \ + 'scripts/*.py' \ + 'scripts/**/*.py' | +xargs wc -l | +sort -nr | +head -31 + +# Largest tracked frontend source files +git ls-files \ + 'static/*.js' \ + 'static/*.css' \ + 'static/*.html' \ + 'static/**/*.js' \ + 'static/**/*.css' \ + 'static/**/*.html' | +grep -vE '\.min\.js$' | +xargs wc -l | +sort -nr | +head -31 +``` + +## Validation for architecture changes + +Use the smallest relevant checks first, then expand according to risk: + +```bash +python3 -m compileall -q app.py core routes services src +venv/bin/python -m pytest tests/.py -q +venv/bin/python -m pytest -q +``` + +Startup, browser, Docker, and integration checks may also be required depending on +the affected boundary. + +## Related documentation + +- [Documentation style](../docs/STYLE.md) +- [Discovery maps](../discovery/README.md) +- [Current system map](../discovery/system-map.md) +- [Safety boundaries](../discovery/safety-boundaries.md) +- [Frontend module summary](../static/js/MODULE_SUMMARY.md) +- [Testing standard](../tests/TESTING_STANDARD.md) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 000000000..d00077d7e --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,87 @@ +# Architecture + +> [!NOTE] +> This document is the proposed canonical destination for stable high-level +> architecture facts. It remains subject to maintainer review. Source code, +> tests, and configuration remain authoritative for implementation-sensitive +> behaviour. + +## Purpose + +This document identifies the stable runtime boundaries and primary ownership +locations used to navigate and extend Odysseus. + +It intentionally excludes generated metrics, file-size rankings, refactor +priorities, unresolved investigation findings, and proposed package layouts. + +## Runtime structure + +| Area | Responsibility | +|---|---| +| `app.py` | FastAPI application composition and primary application entry point | +| `launcher.py` | Application launch support | +| `setup.py` | Native setup workflow | +| `core/` | Authentication, middleware, persistence, sessions, and platform primitives | +| `routes/` | HTTP and API route handlers | +| `src/` | Application orchestration, tools, providers, and runtime helpers | +| `services/` | Domain-oriented service implementations | +| `mcp_servers/` | Built-in MCP server implementations | +| `scripts/` | CLI tools, diagnostics, maintenance, and migration helpers | +| `static/` | No-build browser frontend and bundled assets | +| `tests/` | Automated tests and supporting test infrastructure | + +## Subsystem boundaries + +| Subsystem | Primary implementation locations | +|---|---| +| Application startup | `app.py`, `src/app_initializer.py`, `core/` | +| Authentication and sessions | `core/auth.py`, `core/middleware.py`, `core/session_manager.py`, `routes/auth_routes.py` | +| Chat and streaming | `routes/chat_routes.py`, `routes/chat_helpers.py`, `src/chat_handler.py`, `src/chat_processor.py`, `src/llm_core.py` | +| Agents and tools | `src/agent_loop.py`, `src/tool_execution.py`, `src/agent_tools/`, `src/tools/`, `src/tool_policy.py`, `src/tool_security.py` | +| Models and providers | `routes/model_routes.py`, `src/model_discovery.py`, `src/model_capabilities.py`, `src/endpoint_resolver.py`, `src/llm_core.py` | +| Cookbook and hardware fit | `routes/cookbook_routes.py`, `routes/cookbook_helpers.py`, `src/cookbook_serve_lifecycle.py`, `services/hwfit/` | +| Search and research | `routes/search_routes.py`, `services/search/`, `routes/research/`, `services/research/`, `src/deep_research.py` | +| Documents and retrieval | `routes/document_routes.py`, `src/document_processor.py`, `src/personal_docs.py`, `src/rag_manager.py`, `src/pdf_runtime.py` | +| Memory and skills | `routes/memory/`, `services/memory/`, `routes/skills_routes.py` | +| Email | `routes/email_routes.py`, `routes/email_helpers.py`, `routes/email_pollers.py`, `mcp_servers/email_server.py` | +| Calendar, contacts, notes, and tasks | `routes/calendar_routes.py`, `routes/contacts/`, `routes/note/`, `routes/task_routes.py`, `src/task_scheduler.py` | +| Media and speech | `routes/gallery/`, `routes/stt_routes.py`, `routes/tts_routes.py`, `services/stt/`, `services/tts/` | +| Persistence and operations | `core/database.py`, `src/runtime_paths.py`, `src/bg_jobs.py`, `routes/backup_routes.py`, `routes/cleanup/` | + +## Architectural constraints + +- Preserve established import and compatibility paths unless a focused change + explicitly migrates them. +- Keep HTTP concerns in route modules and reusable domain behaviour in runtime + or service modules. +- Treat shared persistence, agent orchestration, tool execution, and application + startup as high-authority boundaries. +- Change one ownership boundary at a time. +- Do not mix structural movement with unrelated feature behaviour. +- Validate affected imports, startup paths, compatibility surfaces, and tests. + +## Frontend + +The browser frontend is a no-build ES-module application under `static/`. + +Its maintained module-level structure is documented in +[`static/js/MODULE_SUMMARY.md`](../static/js/MODULE_SUMMARY.md). + +## Investigation and snapshots + +Non-canonical investigation material is maintained under [`discovery/`](../discovery/). + +The following documents may contain dated observations, metrics, unresolved +questions, or historical planning and must not be treated as specifications: + +- [`discovery/system-map.md`](../discovery/system-map.md) +- [`discovery/architecture-runtime-inventory.md`](../discovery/architecture-runtime-inventory.md) + +## Documentation authority + +- Code, tests, and configuration define implemented behaviour. +- Mature specifications define accepted subsystem behaviour where they exist. +- Following maintainer acceptance, this document will define the high-level + architecture map. +- Discovery documents preserve evidence and uncertainty but remain + non-canonical. diff --git a/docs/STYLE.md b/docs/STYLE.md new file mode 100644 index 000000000..23ea6d2c5 --- /dev/null +++ b/docs/STYLE.md @@ -0,0 +1,72 @@ +# Documentation style + +This guide defines the shared structure and writing conventions for Odysseus documentation. + +## Principles + +- Write for a clear audience and purpose. +- State whether a document is canonical, informational, a snapshot, or planning material. +- Prefer current behaviour over historical explanation. +- Link to source files, tests, issues, or other documentation when useful. +- Separate verified behaviour from assumptions, open questions, and future work. +- Keep headings descriptive and consistent. +- Use Markdown callouts where status or risk must be visible. +- Do not use emojis. + +## Document status + +Use a status callout near the top when the document is not normal canonical guidance. + +### Canonical documentation + +> [!IMPORTANT] +> This document describes accepted current behaviour. Verify implementation-sensitive details against the current code and tests. + +### Discovery material + +> [!NOTE] +> This is non-canonical discovery material. It records code-grounded observations and open questions. + +### Snapshot or inventory + +> [!WARNING] +> This document is a dated snapshot. Counts, paths, and implementation details may drift as the codebase changes. + +### Planning material + +> [!NOTE] +> This document records planning context. It does not define current runtime behaviour or guarantee future implementation. + +## Recommended structure + +Use the following sections where relevant: + +1. Title +2. Purpose or status callout +3. Scope +4. Current behaviour or guidance +5. Safety, limitations, or known gaps +6. Validation or evidence +7. Related documentation + +Not every document needs every section. + +## Writing style + +- Use concise sentences. +- Prefer direct language. +- Avoid jokes, filler, and informal warnings. +- Avoid repeating the same guidance across several files. +- Link to the owning document instead of duplicating large sections. +- Use lists for procedures, requirements, and comparisons. +- Use tables only when they improve scanning. +- Use fenced code blocks with an appropriate language identifier. +- Use relative repository links for internal files. + +## Authority + +The current code, tests, and configuration are the source of truth for implemented behaviour. + +Canonical documentation describes accepted behaviour and supported workflows. + +Discovery, inventory, and planning documents must identify themselves explicitly and must not silently become behavioural specifications. diff --git a/docs/pr-blocker-audit.md b/docs/pr-blocker-audit.md index b56f28cb3..75d94bc87 100644 --- a/docs/pr-blocker-audit.md +++ b/docs/pr-blocker-audit.md @@ -181,8 +181,8 @@ Dirty, blocked, conflicting, and unknown merge states are shown as risk/caution ## Validation ```bash -python3 -m py_compile scripts/pr_blocker_audit.py tests/test_pr_blocker_audit.py -python3 -m pytest tests/test_pr_blocker_audit.py -q +venv/bin/python -m py_compile scripts/pr_blocker_audit.py tests/test_pr_blocker_audit.py +venv/bin/python -m pytest tests/test_pr_blocker_audit.py -q python3 scripts/pr_blocker_audit.py --help git diff --check ``` diff --git a/specs/architecture-runtime-inventory.md b/specs/architecture-runtime-inventory.md index 5c8e4bc21..4ec156b15 100644 --- a/specs/architecture-runtime-inventory.md +++ b/specs/architecture-runtime-inventory.md @@ -1,412 +1,31 @@ -# Architecture Runtime Inventory - -> **Purpose**: Phase 0 planning baseline for codebase readability improvements (#4071). -> **Parent issue**: [#4082](https://github.com/odysseus-dev/odysseus/issues/4082) -> **Last updated**: dev@b58af42 | 2026-06-16 -> **Status**: Draft — to be reviewed before follow-up slices open. -> **Snapshot basis**: Importer / file / import-line counts are refreshed to `dev@b58af42` (2026-06-16) and are recomputable via the commands in §3.4. **Line counts** in §2.1 / §2.2 are a snapshot from an earlier baseline and drift as `dev` moves — recompute any of them with `wc -l `. This inventory tracks structure and risk, not live metrics. - -This document maps the current runtime module structure, identifies high-risk boundaries, and recommends safe first refactor slices. It does **not** move files, change imports, or alter runtime behavior. - ---- - -## 1. Current Structure Overview - -### 1.1 Top-Level Layout - -``` -odysseus/ -├── app.py # FastAPI app entrypoint (1,145 lines) -├── conf/ # Configuration (config.py, settings.py, settings_scrub.py) -├── src/ # 95 flat .py files + 2 subdirectories -│ ├── agent_tools/ # Tool helpers: document, filesystem, subprocess, web -│ └── search/ # Search subsystem -├── routes/ # 54 flat .py files — HTTP route handlers -├── core/ # 10 files — database models, auth, middleware, session -├── mcp_servers/ # 5 files — MCP server implementations -├── scripts/ # CLI tools and one-shot scripts -├── static/ # Frontend HTML/CSS/JS -├── tests/ # 583 test files (~54,800 lines) -└── services/ # (exists as needed) -``` - -### 1.2 Directory Flatness Metric - -| Directory | Flat `.py` Files | Subdirectories | Concern | -|-----------|-----------------|----------------|---------| -| `src/` | **95** | 2 (`agent_tools/`, `search/`) | No domain grouping; 95 files in one directory | -| `routes/` | **54** | 0 | All route handlers in one flat directory | -| `core/` | 10 | 0 | Manageable, but `database.py` is oversized | - ---- - -## 2. Largest Runtime Modules - -### 2.1 Python Backend - -| Rank | File | Lines | Classes | Functions | Risk | -|------|------|-------|---------|-----------|------| -| 1 | `src/tool_implementations.py` | **4,032** | 0 | ~48 | **HIGH** | -| 2 | `routes/email_routes.py` | **3,245** | — | — | **MEDIUM** | -| 3 | `routes/cookbook_routes.py` | **2,969** | — | — | **MEDIUM** | -| 4 | `src/agent_loop.py` | **2,961** | 0 | ~24 | **HIGH** | -| 5 | `src/task_scheduler.py` | **2,330** | — | 5 | MEDIUM | -| 6 | `routes/model_routes.py` | **2,266** | — | — | MEDIUM | -| 7 | `core/database.py` | **2,265** | 28 | ~59 helpers | **HIGH** | -| 8 | `src/builtin_actions.py` | **2,262** | 2 | ~24 | MEDIUM | -| 9 | `src/llm_core.py` | **2,164** | — | — | MEDIUM | -| 10 | `mcp_servers/email_server.py` | 2,197 | — | — | LOW (separate process) | -| 11 | `src/visual_report.py` | 1,918 | — | — | LOW | -| 12 | `routes/gallery_routes.py` | 1,896 | — | — | LOW | -| 13 | `src/ai_interaction.py` | 1,846 | — | — | MEDIUM | -| 14 | `routes/document_routes.py` | 1,717 | — | — | LOW | -| 15 | `routes/skills_routes.py` | 1,648 | — | — | LOW | - -**Heuristic**: Files > 2,000 lines with 20+ public symbols and many importers are the highest-risk splits. Files 1,000–2,000 lines are medium-risk if tightly coupled. - -### 2.2 Frontend - -| File | Lines | Concern | -|------|-------|---------| -| `static/style.css` | **36,653** | Entire app CSS in one file (tracked separately in #2617) | -| `static/js/document.js` | **9,776** | Single JS file for document functionality | -| `static/js/slashCommands.js` | 6,498 | | -| `static/js/settings.js` | 5,266 | | -| `static/js/emailLibrary.js` | 5,217 | | -| `static/js/notes.js` | 5,124 | | -| `static/js/chat.js` | 4,985 | | -| `static/app.js` | 4,090 | | - -**Note**: Frontend modularization is tracked separately in #2617 (CSS) and is not the focus of this Phase 0 inventory. Frontend is listed here for completeness but follow-up slices should target Python backend boundaries first. - ---- - -## 3. Import Dependency Graph - -### 3.1 Who Depends on `core/database.py` - -**102 files** import from `core.database` — this is the most depended-upon module: - -- All route handlers (`routes/*.py`) -- Most `src/*.py` files -- `core/session_manager.py`, `core/auth.py` -- Multiple test files - -**Implication**: Any split of `core/database.py` is the highest-risk refactor. It should be tackled **last**, never first. - -### 3.2 Who Depends on `src/tool_implementations.py` - -**17 files** import from `src.tool_implementations`: -- `src/agent_loop.py`, `src/builtin_actions.py`, `src/tool_index.py` -- `src/task_scheduler.py`, `src/tool_policy.py` -- Various tests - -### 3.3 Who Depends on `src/agent_loop.py` - -**22 files** import from `src.agent_loop`: - -- `src/tool_policy.py`, `src/teacher_escalation.py`, `src/bg_monitor.py` -- `src/task_scheduler.py` -- Multiple test files - -### 3.4 Cross-Layer Import Violations - -**`src/` importing from `routes/`** (backwards dependency — domain logic depending on HTTP layer): - -``` -src/tool_implementations.py ──→ routes/calendar_routes.py -src/tool_implementations.py ──→ routes/cookbook_helpers.py -src/tool_implementations.py ──→ routes/email_helpers.py -src/tool_implementations.py ──→ routes/email_pollers.py -src/tool_implementations.py ──→ routes/email_routes.py -src/tool_implementations.py ──→ routes/model_routes.py -src/tool_implementations.py ──→ routes/note_routes.py -src/tool_implementations.py ──→ routes/prefs_routes.py -``` - -> These are **runtime imports** (inside function bodies, not at module top), which mitigates circular import risk but indicates fuzzy layer boundaries. Function-level inline imports from the HTTP layer into business logic are a code smell. - -**Import counts (top-level)**: -| Direction | Count | Notes | -|-----------|-------|-------| -| `routes/` → `src/` | **374** | Expected: HTTP handlers call domain logic | -| `routes/` → `core/` | **126** | Expected: handlers access DB models | -| `src/` → `routes/` | **31** | **Unexpected**: domain logic reaching into HTTP layer (direct grep of import lines referencing `routes/`) | -| `src/` → `core/` | **106** | Acceptable but could be reduced with a data-access layer | - -> **How the metrics in this document are computed** — recompute against current `dev` before treating any count as authoritative (the tree drifts; these numbers are a snapshot, not a live value): -> - `src/` flat `.py` files: `find src -maxdepth 1 -name '*.py' | wc -l` -> - `tests/` test files: `find tests -name 'test_*.py' | wc -l` -> - `core.database` importers: `grep -rlE '(from|import) +core\.database' --include='*.py' . | grep -v core/database.py | wc -l` -> - `src.agent_loop` importers: `grep -rlE '(from|import) +src\.agent_loop' --include='*.py' . | grep -v src/agent_loop.py | wc -l` -> - Cross-layer import lines: `grep -rhE '(from|import) +' --include='*.py' / | wc -l` (e.g. `(from|import) +routes` over `src/`) - ---- - -## 4. Route Ownership Map - -Routes can be grouped into logical feature domains. Current flat structure obscures these boundaries: - -| Domain | Route Files | Total Lines | Review Complexity | -|--------|-------------|-------------|-------------------| -| **Email** | `email_routes.py`, `email_helpers.py`, `email_pollers.py` | 5,936 | HIGH — most complex domain | -| **Chat / Agent** | `chat_routes.py`, `chat_helpers.py`, `shell_routes.py`, `codex_routes.py`, `skills_routes.py` | 6,365 | HIGH — core interaction surface | -| **Cookbook** | `cookbook_routes.py`, `cookbook_helpers.py`, `cookbook_output.py` | 4,110 | MEDIUM | -| **Model / LLM** | `model_routes.py`, `assistant_routes.py`, `copilot_routes.py` | 2,764 | MEDIUM | -| **Calendar / Contacts** | `calendar_routes.py`, `contacts_routes.py` | 2,336 | MEDIUM | -| **Documents** | `document_routes.py`, `document_helpers.py` | 1,954 | LOW | -| **Auth** | `auth_routes.py`, `api_token_routes.py`, `device_flow.py` | 1,171 | LOW | -| **Tasks** | `task_routes.py` (standalone) | 1,157 | LOW | -| **Session** | `session_routes.py` (standalone) | 1,287 | LOW | -| **Gallery** | `gallery_routes.py`, `gallery_helpers.py` | 1,896 | LOW | -| **Memory** | `memory_routes.py` | — | LOW | -| **Research** | `research_routes.py` | — | LOW | -| **MCP** | `mcp_routes.py` | — | LOW | -| **Notes** | `note_routes.py` | — | LOW | -| **Other** | `prefs_routes.py`, `upload_routes.py`, `vault_routes.py`, `webhook_routes.py`, `workspace_routes.py`, `search_routes.py`, `history_routes.py`, `hwfit_routes.py`, `preset_routes.py`, `signature_routes.py`, `backup_routes.py`, `cleanup_routes.py`, `diagnostics_routes.py`, `embedding_routes.py`, `emoji_routes.py`, `font_routes.py`, `stt_routes.py`, `tts_routes.py`, `compare_routes.py`, `personal_routes.py`, `editor_draft_routes.py`, `admin_wipe_routes.py`, `chatgpt_subscription_routes.py` | 2,000+ | LOW individual, HIGH cumulative | - ---- - -## 5. Tool Registry & Implementation Boundaries - -### 5.1 Current Tool Architecture - -| Component | File | Lines | Role | -|-----------|------|-------|------| -| Tool schemas | `src/tool_schemas.py` | 1,392 | JSON Schema tool definitions (Duck-TypedDict) | -| Tool index | `src/tool_index.py` | 542 | RAG-based tool retrieval from ChromaDB | -| Tool implementations | `src/tool_implementations.py` | 4,032 | 33 `do_*` functions — all tool execution logic | -| Tool security | `src/tool_security.py` | — | Owner-scoped tool blocking | -| Tool policy | `src/tool_policy.py` | — | Guide-only directive, plan-mode disabled tools | -| Tool utils | `src/tool_utils.py` | — | Shared tool helpers | - -### 5.2 Tool Implementation Categories - -The 33 `do_*` functions in `tool_implementations.py` fall into natural domain groups — the basis for slice 1's split in §6.2: - -| Category | `do_*` functions | Count | -|----------|------------------|-------| -| **System / config** | `do_manage_skills`, `do_manage_tasks`, `do_manage_endpoints`, `do_manage_mcp`, `do_manage_webhooks`, `do_manage_tokens`, `do_manage_settings`, `do_api_call`, `do_app_api` | 9 | -| **Cookbook / model serving** | `do_download_model`, `do_serve_model`, `do_list_served_models`, `do_stop_served_model`, `do_tail_serve_output`, `do_list_downloads`, `do_cancel_download`, `do_search_hf_models`, `do_adopt_served_model`, `do_list_cookbook_servers`, `do_list_serve_presets`, `do_serve_preset`, `do_list_cached_models` | 13 | -| **Notes** | `do_manage_notes` | 1 | -| **Calendar** | `do_manage_calendar` | 1 | -| **Search** | `do_search_chats` | 1 | -| **Research** | `do_manage_research`, `do_trigger_research` | 2 | -| **Contacts** | `do_resolve_contact`, `do_manage_contact` | 2 | -| **Vault** | `do_vault_search`, `do_vault_get`, `do_vault_unlock` | 3 | -| **Image** | `do_edit_image` | 1 | -| | **Total** | **33** | - -> Low-level tools (filesystem, subprocess, web fetch, document parsing) live in `src/agent_tools/`, **not** in `tool_implementations.py` — out of scope for this split. - ---- - -## 6. Risk Assessment & Candidate Slice Ranking - -> **Candidate proposals, not a committed plan.** The rankings, package shapes (e.g. `src/pkg/`, `src/domain/`, `src/infra/`, `src/api/`), split ordering, and route-grouping strategy below are **options for maintainer discussion**. Per #4082/#4071, slice ownership and order are settled by maintainers before any follow-up PR. §1–§3 above are the factual current-state inventory. - -### 6.1 Risk Scale - -| Level | Criteria | -|-------|----------| -| **LOW** | File has ≤3 importers AND ≤500 lines, OR is a pure refactor with clear boundaries | -| **MEDIUM** | File has 4–15 importers OR 500–1,500 lines | -| **HIGH** | File has 16+ importers OR >2,000 lines, OR has cross-layer import violations | - -### 6.2 Ranked Split Candidates - -| Priority | Target | Risk | Rationale | -|----------|--------|------|-----------| -| **1** | `src/tool_implementations.py` → `src/tools/*.py` | **MEDIUM** | 4,032 lines → ~10 files by tool category. Already has natural boundaries. 17 importers, tracked in #3629. Use `__init__.py` shim to keep existing imports working. | -| **2** | `routes/` → domain subdirectories (one domain per PR) | **MEDIUM** | 54 flat files. Done **one domain at a time** (e.g. a standalone PR for the email domain, then chat, …), not a broad reorganization — route modules carry helper imports, registration assumptions, and test import paths. | -| **3** | `src/agent_loop.py` → `src/agent/loop.py` + submodules | **MEDIUM-HIGH** | 2,961 lines, 24 functions. Can extract prompt building, classification, verification, and runaway detection. Tracked in #3266. | -| **4** | `src/` → `src/pkg/`, `src/domain/`, `src/infra/`, `src/api/` | **MEDIUM** | Structural reorganization. Split flat `src/` into layered packages. Must come after routes and tools are stable. | -| **5** | `routes/email_*.py` consolidation | **LOW** | Already grouped by filename prefix. Low-risk cleanup within the email domain. | -| **6** | `core/database.py` → `src/infra/database/models/*.py` | **HIGH** | 28 classes, 102 importers. Highest-risk split. Must be **last** in any sequence. Requires careful import shim strategy. | -| **7** | Frontend CSS modularization | **MEDIUM** | 36,653 lines. Tracked in #2617. Separate timeline from backend work. | -| **8** | Frontend JS modularization | **MEDIUM** | 9,776 lines in `document.js`. Introduce ES modules at minimum. | - -### 6.3 Candidate First 3 Behavior-Preserving Slices - -**Slice 1: Split `tool_implementations.py`** (Lowest-risk high-impact) - -- Create `src/tools/` package with one file per tool category -- Add `src/tools/__init__.py` re-exporting all symbols with current names -- Update 17 importers to use new paths (can be deferred via shim) -- Validation: `python -m pytest tests/ -x -q` + manual smoke test of tool execution -- Reference: #3629 - -**Slice 2: Group `routes/` by domain** (one domain per PR, not a broad sweep) - -Route modules carry helper imports, router registration assumptions, and test import paths, so this must be done **one domain at a time** rather than as a single reorganization PR. Example sequence (each its own PR): - -- PR 2a: move the **email** domain (`email_routes.py`, `email_helpers.py`, `email_pollers.py`) → `routes/email/` + shim -- PR 2b: move the **chat/agent** domain → `routes/chat/` + shim -- PR 2c: move the **cookbook** domain → `routes/cookbook/` + shim -- …and so on per domain from §4 - -Each PR: add `__init__.py` re-exporting old names, update `app.py` router imports, validation `python app.py` starts clean. **No behavior change** — pure file reorganization. - -**Slice 3: Extract `agent_loop.py` submodules** (Improve reviewability) - -- Move prompt assembly → `src/agent/prompt.py` -- Move request classification → `src/agent/classifier.py` -- Move sub-agent verification → `src/agent/verifier.py` -- Move runaway detection → `src/agent/runaway.py` -- Move context management → `src/agent/context.py` -- Keep `src/agent/loop.py` as the main orchestration module -- Validation: `python -m pytest tests/test_agent_loop.py tests/test_loop_breaker_runaway.py -v` - ---- - -## 7. Safety Guardrails for Follow-Up Work - -Per maintainer guidance in #4082 and #4071: - -- [ ] **One domain/slice per PR** — never mix multiple reorganizations -- [ ] **No behavior changes** mixed with file moves — pure reorganization only -- [ ] **Keep compatibility shims** — `__init__.py` re-exports for all existing import paths -- [ ] **Add or identify focused tests** before risky splits -- [ ] **Do not start with `core/database.py`** or broad route movement unless this inventory shows a safe boundary -- [ ] **Prefer small, reviewable slices** over large restructures -- [ ] **No packaging/runtime/tooling migration** mixed into file moves -- [ ] **No frontend framework migration** inside this stabilization lane -- [ ] **Validate with `python -m compileall`** — every PR must pass CI checks -- [ ] **Validate with `pytest`** — run the full test suite before opening each PR - ---- - -## 8. Validation Commands - -Each follow-up PR should be verifiable with these commands before submission: - -```bash -# Syntax check — must pass with zero errors -python -m compileall src/ routes/ core/ conf/ - -# Full test suite — must match baseline pass rate -python -m pytest tests/ -x -q - -# Import shim verification — existing import paths must still work -python -c "from src.tool_implementations import do_search_chats; print('OK')" - -# App startup smoke test (if backend touched) -timeout 5 python app.py 2>&1 | head -5 || true -``` - ---- - -## 9. Open Questions - -1. Is `#2538` (specs ground truth) the canonical behavior map baseline, and should this inventory be kept in sync with those specs once merged? -2. Should route grouping follow the domain map proposed here, or is there a different taxonomy preferred by maintainers? -3. For the `tool_implementations.py` split (#3629), is the tool categorization in §5.2 acceptable, or should it follow a different grouping? -4. Should compatibility shims (`__init__.py`) be temporary (removed in a follow-up wave) or permanent? -5. Should an ADR (Architecture Decision Record) document be started to track decisions made during this process? - ---- - -## 10. Future Direction (NOT current state) - -The following are **future refactor targets** (candidate directions **pending maintainer agreement**, not committed), recorded here so this inventory does not imply they exist today. None of them are present in the current `dev` tree: - -- `main.py` — proposed rename of the `app.py` entrypoint. Today the app boots via `app.py`. -- `src/agent/` — proposed package to hold `agent_loop.py` submodules (prompt/classifier/verifier/runaway/context). Today `agent_loop.py` is a single flat file in `src/`. -- `src/infra/`, `src/domain/`, `src/pkg/`, `src/api/` — proposed layered reorganization of the flat `src/` directory (slice 4 in §6). - -These become real only when the corresponding slices land. - ---- - -## Appendix A: File Listing - -### `src/` (95 files — 61 shown; run `ls src/*.py` for the full list) - -``` -agent_loop.py tool_implementations.py tool_schemas.py -tool_index.py tool_security.py tool_policy.py -tool_utils.py builtin_actions.py task_scheduler.py -llm_core.py model_context.py model_discovery.py -session_search.py context_budget.py context_compactor.py -ai_interaction.py action_intents.py agent_runs.py -app_helpers.py app_initializer.py config.py -database.py memory.py memory_provider.py -secret_storage.py prompt_security.py url_security.py -url_safety.py rate_limiter.py cleanup_service.py -readiness.py service_health.py exceptions.py -request_models.py assistant_log.py bg_monitor.py -builtin_mcp.py chat_helpers.py chroma_client.py -document_processor.py embedding_lanes.py deep_research.py -research_handler.py research_utils.py personal_docs.py -rag_manager.py rag_singleton.py topic_analyzer.py -visual_report.py youtube_handler.py pdf_forms.py -pdf_form_doc.py pdf_runtime.py caldav_writeback.py -email_thread_parser.py text_helpers.py user_time.py -teacher_escalation.py cookbook_serve_lifecycle.py -chatgpt_subscription.py mcp_manager.py -``` - -### `routes/` (54 files) - -``` -__init__.py _validators.py -auth_routes.py api_token_routes.py device_flow.py -chat_routes.py chat_helpers.py shell_routes.py -codex_routes.py skills_routes.py -email_routes.py email_helpers.py email_pollers.py -cookbook_routes.py cookbook_helpers.py cookbook_output.py -model_routes.py assistant_routes.py copilot_routes.py -calendar_routes.py contacts_routes.py -document_routes.py document_helpers.py -gallery_routes.py gallery_helpers.py -task_routes.py session_routes.py -note_routes.py memory_routes.py research_routes.py -mcp_routes.py search_routes.py history_routes.py -webhook_routes.py workspace_routes.py upload_routes.py -vault_routes.py prefs_routes.py preset_routes.py -signature_routes.py personal_routes.py hwfit_routes.py -backup_routes.py cleanup_routes.py diagnostics_routes.py -embedding_routes.py emoji_routes.py font_routes.py -stt_routes.py tts_routes.py compare_routes.py -editor_draft_routes.py chatgpt_subscription_routes.py admin_wipe_routes.py -``` - -### `core/` (10 files) - -``` -__init__.py constants.py database.py models.py -auth.py middleware.py session_manager.py exceptions.py -atomic_io.py platform_compat.py -``` - ---- - -## Appendix B: Key Import Relationships - -``` -core/database.py ←── 102 importers (routes/*, src/*, core/*, tests/*) - ↑ - ├── routes/auth_routes.py - ├── routes/email_routes.py - ├── src/builtin_actions.py - ├── src/task_scheduler.py - ├── src/tool_implementations.py (inline) - └── ...97 more - -src/tool_implementations.py ←── 17 importers - ↑ - ├── src/agent_loop.py - ├── src/builtin_actions.py - ├── src/tool_index.py - ├── src/task_scheduler.py - ├── src/tool_policy.py - └── ...12 more (mostly tests) - -src/agent_loop.py ←── 22 importers - ↑ - ├── src/tool_policy.py - ├── src/teacher_escalation.py - ├── src/bg_monitor.py - ├── src/task_scheduler.py - └── 18 more (incl. tests) -``` +# Architecture runtime inventory disposition + +> [!NOTE] +> The dated architecture runtime inventory has been classified and transferred +> to [`discovery/architecture-runtime-inventory.md`](../discovery/architecture-runtime-inventory.md) +> after verification of its stable facts. +> +> Stable runtime structure and subsystem boundaries were transferred to the +> proposed canonical destination, +> [`docs/ARCHITECTURE.md`](../docs/ARCHITECTURE.md), for maintainer review. + +## Classification + +| Content | Disposition | +|---|---| +| Stable runtime structure | Proposed canonical architecture document | +| Stable subsystem boundaries | Proposed canonical architecture document | +| Frontend module organization | `static/js/MODULE_SUMMARY.md` | +| Counts, rankings, and generated metrics | Non-canonical discovery inventory | +| Investigation context and unresolved questions | Non-canonical discovery material | +| Refactor options and prioritization | Issues, Plane, or discovery material | + +No dated metrics, prioritization, or investigation findings remain in this +specification path. + +## Review status + +- Findings and scope have been validated. +- Transfer verification has completed. +- The final canonical status of `docs/ARCHITECTURE.md` requires maintainer review. +- No implementation behaviour, test taxonomy, or runtime files were changed. diff --git a/tests/LAYOUT_INVENTORY.md b/tests/LAYOUT_INVENTORY.md index 34c719774..4a14961be 100644 --- a/tests/LAYOUT_INVENTORY.md +++ b/tests/LAYOUT_INVENTORY.md @@ -1,202 +1,152 @@ -# Test Layout Inventory +# Test layout inventory + +> [!NOTE] +> This document is a completed implementation snapshot for the first low-risk +> test-directory reorganization. It does not propose additional file moves and +> is not the canonical definition of the current test taxonomy. + +- **Original inventory:** #3712 +- **Parent tracker:** #2523 +- **Implemented by:** #3842 +- **Status:** completed historical snapshot ## Purpose -Inventory for the first low-risk split of the flat `tests/` directory -(issue #3712, parent #2523). This document only records *what* should move -first and *why*; it moves nothing. The actual move is a separate, mechanical -PR that relocates the listed files verbatim and changes no test content. +This document preserves the reasoning, scope, and validation contract for the +first mechanical reorganization of the formerly flat `tests/` directory. -The target layout and category definitions come from -[`TESTING_STANDARD.md`](./TESTING_STANDARD.md); the collection-time markers -come from [`_taxonomy.py`](./_taxonomy.py), which classifies by **filename -tokens only** (paths are ignored, except the `tests/helpers/` rule). A file -keeps its `area_*`/`sub_*` markers when moved into a subdirectory, and -`conftest.py` discovers marker names recursively (`rglob`), so a move does not -disturb marker registration or focused selection. +The original change moved 28 tests classified as `area_cli` into `tests/cli/` +without changing their assertions, helpers, taxonomy, or runtime behaviour. -## Current low-risk candidate groups +Current testing guidance and classification rules are maintained in: -Groups whose tests need no route/app setup and no real DB/session setup: +- [`README.md`](./README.md) +- [`TESTING_STANDARD.md`](./TESTING_STANDARD.md) +- [`_taxonomy.py`](./_taxonomy.py) -1. **CLI / script tests** (`area_cli`, 28 files) - load `scripts/` entry - points via `tests.helpers.cli_loader.load_script`; DB access is stubbed - with `tests.helpers.db_stubs` (`SessionLocal` is a plain stub attribute). - No `TestClient`, no FastAPI app import, no SQLite files. -2. **Helper self-tests** (`area_helpers`) - e.g. `test_helpers_import_state.py`, - `test_db_stubs_helper.py`. Safe but tiny (two files), and they test the - shared helpers from the #3685 audit (merged) that the rest of the suite - depends on; little payoff as a first slice. -3. **Pure unit / parsing tests** (`area_unit`) - `*_nonstring.py`, - `*_nondict.py`, parsing tests. Large and heterogeneous; some touch - provider/session modules, so the boundary is less crisp. -4. **Static checks** - e.g. `test_readme_ascii_fenced.py`, - `test_docs_no_orphan_images.py`. Safe but tiny and `uncategorized` in the - taxonomy, so a move buys little and matches no existing marker. +The current repository and test suite remain authoritative when this snapshot +and the implementation differ. -Not candidates for the first move (per #3712 guidance): security/owner-scope -tests, route/API tests, DB/session-heavy tests, auth/session concurrency -tests, and the taxonomy/runner infrastructure tests that changed recently -(#3491, #3556, #3659, #3711). +## Why CLI tests were selected -## Recommended first move +The CLI and script tests were selected as the first low-risk group because they +formed a narrow, mechanically identifiable boundary: -**CLI / script tests → `tests/cli/`** +- script entry points were loaded through shared CLI helpers; +- database access used controlled stubs rather than persistent sessions; +- the tests did not require FastAPI application or route setup; +- the tests did not require a real database; +- taxonomy classification could be derived consistently from filenames; +- absolute helper imports remained valid after relocation. -Why this group over the alternatives: +This reduced the risk relative to route, security, session, provider, and +heterogeneous unit-test groups. -- Lowest coupling: every file imports only the script under test (via - `cli_loader`) plus `tests.helpers` stubs - no app, no routes, no real DB. -- Crisp, machine-checkable boundary: the set is exactly the files classified - `area_cli` by `_taxonomy.py`, so before/after selection counts can be - compared mechanically. -- Already the planned target dir for this category in `TESTING_STANDARD.md` - (`tests/cli/`). -- Absolute imports (`from tests.helpers...`) and unique basenames mean no - import-order or module-name collisions after the move. -- Lower risk than helper self-tests (tiny group, little payoff), unit tests - (fuzzy boundary), or anything security/route/session-shaped. +## Completed implementation -## Files included in the first move +Repository history records the implementation as: -The 28 files classified `area_cli` (verified against `_taxonomy.py`): +- `83af3ca test: move area_cli tests into cli directory (#3842)` -Note: this inventory was refreshed against current `dev` after `tests/test_research_cli_status.py` was added to the `area_cli` set. +The following 28 files were included in that completed move: -- `tests/test_calendar_cli_name.py` -- `tests/test_contacts_cli_rows.py` -- `tests/test_cookbook_cli_state.py` -- `tests/test_docs_cli_content_length.py` -- `tests/test_gallery_cli_album_count.py` -- `tests/test_gallery_cli_preview.py` -- `tests/test_logs_cli_resolve_nonstring.py` -- `tests/test_mail_cli_read_empty_fetch.py` -- `tests/test_mail_cli_recipients.py` -- `tests/test_mcp_cli_env_serialize.py` -- `tests/test_mcp_cli_json.py` -- `tests/test_memory_cli_rows.py` -- `tests/test_notes_cli_items.py` -- `tests/test_personal_cli_rows.py` -- `tests/test_preset_cli_invalid_entries.py` -- `tests/test_preset_cli_set_corrupt_entry.py` -- `tests/test_preset_cli_store.py` -- `tests/test_research_cli_preview.py` -- `tests/test_research_cli_status_filter.py` -- `tests/test_research_cli_status.py` -- `tests/test_research_cli_store.py` -- `tests/test_sessions_cli.py` -- `tests/test_signature_cli_export.py` -- `tests/test_skills_cli_preview.py` -- `tests/test_skills_cli_rows.py` -- `tests/test_tasks_cli_preview.py` -- `tests/test_theme_cli_store.py` -- `tests/test_webhook_cli_mask.py` +- `tests/cli/test_calendar_cli_name.py` +- `tests/cli/test_contacts_cli_rows.py` +- `tests/cli/test_cookbook_cli_state.py` +- `tests/cli/test_docs_cli_content_length.py` +- `tests/cli/test_gallery_cli_album_count.py` +- `tests/cli/test_gallery_cli_preview.py` +- `tests/cli/test_logs_cli_resolve_nonstring.py` +- `tests/cli/test_mail_cli_read_empty_fetch.py` +- `tests/cli/test_mail_cli_recipients.py` +- `tests/cli/test_mcp_cli_env_serialize.py` +- `tests/cli/test_mcp_cli_json.py` +- `tests/cli/test_memory_cli_rows.py` +- `tests/cli/test_notes_cli_items.py` +- `tests/cli/test_personal_cli_rows.py` +- `tests/cli/test_preset_cli_invalid_entries.py` +- `tests/cli/test_preset_cli_set_corrupt_entry.py` +- `tests/cli/test_preset_cli_store.py` +- `tests/cli/test_research_cli_preview.py` +- `tests/cli/test_research_cli_status.py` +- `tests/cli/test_research_cli_status_filter.py` +- `tests/cli/test_research_cli_store.py` +- `tests/cli/test_sessions_cli.py` +- `tests/cli/test_signature_cli_export.py` +- `tests/cli/test_skills_cli_preview.py` +- `tests/cli/test_skills_cli_rows.py` +- `tests/cli/test_tasks_cli_preview.py` +- `tests/cli/test_theme_cli_store.py` +- `tests/cli/test_webhook_cli_mask.py` -## Files intentionally excluded +## Original exclusions -- `tests/test_backup_cli_security.py` - classifies as `area_security` - (security outranks cli in the taxonomy); moving it into `tests/cli/` would - make the directory disagree with its marker. It belongs with the security - group in a later phase. -- `tests/test_run_focus.py`, `tests/test_taxonomy.py` - taxonomy/runner - infrastructure tests, recently changed (#3556, #3659); they also pin - flat-layout paths (e.g. `tests/test_auth_config_lock_concurrency.py` in - `test_run_focus.py`), so they stay put. -- Script-like but `uncategorized` files - `test_pr_blocker_audit.py`, - `test_update_database_script.py`, `test_windows_update_script.py`, - `test_setup_admin_user.py`, `test_amd_gpu_check_args.py`, `test_hwfit_*.py`. - They exercise `scripts/` too, but moving them would make `tests/cli/` - diverge from the `area_cli` marker set. Reclassify or move them in a later, - separate slice. -- Everything else (security, routes, services, unit, js, helpers) - out of - scope for the first move by design. +The original inventory deliberately excluded: -## How this was verified +- `tests/test_backup_cli_security.py`, because its security classification + outranked the CLI token in its filename; +- taxonomy and focused-runner infrastructure, including + `tests/test_taxonomy.py` and `tests/test_run_focus.py`; +- script-oriented tests not classified as `area_cli`; +- route, service, security, session, JavaScript, helper, and broad unit-test + groups. -Read-only checks, run from the repo root on this branch. Note the real API is -`classify_test_path` (there is no `classify_test_file`). +These exclusions kept the implementation mechanical and prevented it from +mixing taxonomy changes, assertion changes, helper extraction, or unrelated +test-suite restructuring. + +## Current repository observation + +The current taxonomy classifies 30 files as `area_cli`: + +| Location | Files | +|---|---:| +| `tests/cli/` | 28 | +| Flat `tests/` directory | 2 | + +The two currently classified CLI tests outside `tests/cli/` are: + +- `tests/test_calendar_cli_overlap.py` +- `tests/test_memory_cli_add_nondict.py` + +These files were not part of the original 28-file implementation. + +Their presence is recorded solely to keep this snapshot accurate. This +documentation update does not recommend moving them, changing their taxonomy, +or opening implementation work. Any future test-layout change requires separate +maintainer agreement, scope, and validation. + +## Validation contract preserved by the original move + +The completed implementation was designed to preserve: + +- identical `area_cli` selection before and after relocation; +- successful direct execution of the relocated tests; +- successful whole-suite collection; +- unchanged taxonomy and focused-runner behaviour; +- no stale references to the former flat paths; +- no production-code changes. + +Relevant current verification commands include: ```bash -# Compute the area_cli set and confirm test_backup_cli_security.py is -# area_security. Expected: 28 files, then "security". -./venv/bin/python - <<'PY' -from pathlib import Path -from tests._taxonomy import classify_test_path - -cli = [p for p in sorted(Path("tests").glob("test_*.py")) - if classify_test_path(p).area == "cli"] -print(len(cli)) -for p in cli: - print(p) -print(classify_test_path("tests/test_backup_cli_security.py").area) -PY - -# Coupling check across the CLI files. Expected: the only hits are -# "SessionLocal" as stub attribute names passed to tests.helpers.db_stubs; -# no TestClient, FastAPI, create_app, sqlite, or dependency_overrides. -rg -n "TestClient|FastAPI|create_app|SessionLocal|sqlite|dependency_overrides" \ - tests/test_*cli*.py tests/test_sessions_cli.py - -# Hard-coded flat paths to the exact CLI files outside tests/. Expected: no matches. -./venv/bin/python - <<'PY2' > /tmp/area_cli_paths.txt -from pathlib import Path -from tests._taxonomy import classify_test_path - -for path in sorted(Path("tests").glob("test_*.py")): - if classify_test_path(path).area == "cli": - print(path) -PY2 - -rg -n -F -f /tmp/area_cli_paths.txt .github scripts docs \ - tests/README.md tests/TESTING_STANDARD.md pyproject.toml 2>/dev/null || true +venv/bin/python tests/run_focus.py --dry-run --area cli +venv/bin/python -m pytest -m area_cli -q +venv/bin/python -m pytest tests/cli/ -q +venv/bin/python -m pytest tests/test_taxonomy.py tests/test_run_focus.py -q +venv/bin/python -m pytest --collect-only -q ``` -Also checked by reading the code: `tests/conftest.py` registers sub-markers -from a recursive `rglob` scan, and `tests/_taxonomy.py` classifies by filename -tokens only (plus the `tests/helpers/` directory rule), so the markers of the -28 files do not change when they move into `tests/cli/`. - -## Validation for the future move PR - -Run with the project venv (`./venv/bin/python`); system `python3` may miss -pinned deps. Before the move, record the baseline; after, compare: - -```bash -# Selection must match the 28 files before and after the move. -./venv/bin/python tests/run_focus.py --dry-run --area cli -./venv/bin/python -m pytest -m area_cli -q - -# Moved files pass when targeted directly. -./venv/bin/python -m pytest tests/cli/ -q - -# Whole-suite collection still succeeds (catches import/path breakage). -./venv/bin/python -m pytest --collect-only -q - -# Taxonomy/runner infrastructure is unaffected. -./venv/bin/python -m pytest tests/test_taxonomy.py tests/test_run_focus.py -q - -# No stale flat-path references to the moved files. Expected: no matches -# outside tests/cli/ itself. -./venv/bin/python - <<'PY2' > /tmp/area_cli_paths.txt -from pathlib import Path -from tests._taxonomy import classify_test_path - -for path in sorted(Path("tests").glob("test_*.py")): - if classify_test_path(path).area == "cli": - print(path) -PY2 - -rg -n -F -f /tmp/area_cli_paths.txt .github scripts docs \ - tests/README.md tests/TESTING_STANDARD.md pyproject.toml 2>/dev/null || true -``` - -Pass criteria: identical test counts for `-m area_cli` before/after, zero -collection errors, and no changes outside the moved files. +These commands describe validation coverage. This snapshot does not claim that +they were executed as part of the present documentation update. ## Non-goals -- No file moves, renames, or deletions in this PR. -- No changes to `conftest.py`, `_taxonomy.py`, `run_focus.py`, helpers, - markers, CI workflows, or production code. -- No recommendation to split the whole suite at once; later groups get their - own inventory-then-move slices. +This document does not: + +- propose moving or renaming tests; +- redefine taxonomy classifications; +- change test behaviour or assertions; +- prescribe the next test-suite refactor; +- replace the testing standard; +- create implementation work from the two current residual files. diff --git a/tests/OVERSIZED_TEST_SPLIT_PLAN.md b/tests/OVERSIZED_TEST_SPLIT_PLAN.md index 4f81080a4..481424e58 100644 --- a/tests/OVERSIZED_TEST_SPLIT_PLAN.md +++ b/tests/OVERSIZED_TEST_SPLIT_PLAN.md @@ -1,5 +1,9 @@ # Oversized Test File Split Plan +> [!NOTE] +> This is generated planning material based on the current test tree. +> It does not define runtime behaviour or approve any test-file split. + ## Purpose This document plans future oversized test-file splits using current repo data. @@ -26,8 +30,8 @@ Future split PRs must still inspect each file manually before editing. ## Current summary -- test files scanned: 583 -- collected pytest items counted: 3586 +- test files scanned: 746 +- collected pytest items counted: 4764 - large-file threshold: 300 lines - large-collected threshold: 20 collected items @@ -35,123 +39,123 @@ Area distribution: | Value | Files | |---|---:| -| cli | 28 | +| cli | 30 | | helpers | 1 | -| js | 39 | -| routes | 23 | -| security | 77 | -| services | 144 | -| uncategorized | 234 | -| unit | 37 | +| js | 49 | +| routes | 35 | +| security | 88 | +| services | 197 | +| uncategorized | 306 | +| unit | 40 | Sub-area distribution: | Value | Files | |---|---:| -| api | 6 | +| api | 8 | | atomic | 3 | -| auth | 9 | -| calendar | 10 | -| cli | 28 | -| confinement | 7 | -| cookbook | 13 | -| document | 11 | -| email | 12 | -| embedding | 3 | -| gallery | 5 | +| auth | 11 | +| calendar | 12 | +| cli | 30 | +| confinement | 8 | +| cookbook | 20 | +| document | 13 | +| email | 23 | +| embedding | 6 | +| gallery | 6 | | history | 3 | -| js | 39 | -| llm | 16 | -| mcp | 8 | -| memory | 15 | +| js | 49 | +| llm | 21 | +| mcp | 12 | +| memory | 17 | | nondict | 7 | -| nonstring | 22 | -| owner | 14 | -| owner_scope | 23 | -| parse | 4 | -| provider | 6 | -| research | 16 | +| nonstring | 23 | +| owner | 15 | +| owner_scope | 27 | +| parse | 5 | +| provider | 16 | +| research | 17 | | route | 6 | -| routes | 9 | -| scheduler | 3 | +| routes | 19 | +| scheduler | 4 | | scope | 5 | | security | 9 | -| session | 16 | -| ssrf | 3 | -| webhook | 3 | +| session | 18 | +| ssrf | 6 | +| webhook | 4 | | xss | 5 | -Values below 2 files: 244 values covering 244 files. +Values below 2 files: 318 values covering 318 files. ## Top files by collected pytest items | File | Lines | Collected tests | Test defs | Test classes | Area | Sub-area | Signals | |---|---:|---:|---:|---:|---|---|---| -| `tests/test_model_routes.py` | 1778 | 139 | 116 | 10 | routes | routes | route/api, db/session, import-state, async/threading | -| `tests/test_security_regressions.py` | 1224 | 92 | 68 | 0 | security | security | route/api, db/session, import-state, security, filesystem, async/threading, ui/static | -| `tests/test_provider_classification.py` | 188 | 67 | 21 | 4 | services | provider | - | -| `tests/test_cookbook_helpers.py` | 912 | 65 | 65 | 0 | services | cookbook | route/api, filesystem, subprocess/script, async/threading, ui/static | -| `tests/test_shell_routes.py` | 481 | 63 | 48 | 8 | routes | routes | route/api, import-state, filesystem | +| `tests/test_model_routes.py` | 2099 | 163 | 134 | 10 | routes | routes | route/api, db/session, import-state, async/threading | +| `tests/test_security_regressions.py` | 1515 | 98 | 74 | 0 | security | security | route/api, db/session, import-state, security, filesystem, async/threading, ui/static | +| `tests/test_cookbook_helpers.py` | 958 | 69 | 69 | 0 | services | cookbook | route/api, filesystem, subprocess/script, async/threading, ui/static | +| `tests/test_shell_routes.py` | 538 | 69 | 53 | 9 | routes | routes | route/api, import-state, filesystem | +| `tests/test_endpoint_probing.py` | 497 | 61 | 36 | 7 | uncategorized | endpoint_probing | route/api, db/session, import-state | | `tests/test_pr_blocker_audit.py` | 964 | 58 | 58 | 0 | uncategorized | pr_blocker_audit | import-state, security, filesystem | -| `tests/test_provider_endpoints.py` | 241 | 58 | 18 | 1 | services | provider | subprocess/script | -| `tests/test_agent_loop.py` | 469 | 52 | 52 | 5 | uncategorized | agent_loop | db/session, import-state | -| `tests/test_service_health.py` | 472 | 47 | 42 | 0 | uncategorized | service_health | async/threading | -| `tests/test_run_focus.py` | 399 | 47 | 44 | 0 | uncategorized | run_focus | security, filesystem, subprocess/script, ui/static | -| `tests/test_llm_core_temperature.py` | 196 | 41 | 17 | 0 | services | llm | - | -| `tests/test_endpoint_probing.py` | 411 | 34 | 30 | 6 | uncategorized | endpoint_probing | route/api, db/session, import-state | +| `tests/test_research_routes_path_confinement.py` | 565 | 58 | 26 | 0 | security | confinement | route/api, security, filesystem, async/threading | +| `tests/test_run_focus.py` | 492 | 55 | 52 | 0 | uncategorized | run_focus | security, filesystem, subprocess/script, ui/static | +| `tests/test_agent_loop.py` | 500 | 54 | 54 | 5 | uncategorized | agent_loop | db/session, import-state | +| `tests/test_manage_mcp_command_allowlist.py` | 168 | 45 | 10 | 0 | services | mcp | db/session, subprocess/script, async/threading, ui/static | +| `tests/test_provider_classification.py` | 115 | 42 | 9 | 2 | services | provider | - | +| `tests/test_review_regressions.py` | 1429 | 41 | 41 | 0 | uncategorized | review_regressions | route/api, db/session, import-state, filesystem, async/threading | +| `tests/test_chat_helpers.py` | 582 | 37 | 24 | 0 | uncategorized | chat_helpers | route/api, filesystem, async/threading | +| `tests/test_model_context.py` | 314 | 36 | 34 | 4 | uncategorized | model_context | db/session, import-state | +| `tests/test_email_oauth.py` | 798 | 34 | 29 | 0 | services | email | route/api, db/session, security, async/threading | | `tests/test_llm_core_anthropic_temp_omit.py` | 94 | 32 | 6 | 0 | services | llm | db/session | -| `tests/test_chat_helpers.py` | 264 | 31 | 18 | 0 | uncategorized | chat_helpers | route/api | -| `tests/test_provider_detection.py` | 148 | 31 | 31 | 5 | services | provider | - | -| `tests/test_model_context.py` | 251 | 30 | 30 | 4 | uncategorized | model_context | db/session, import-state | -| `tests/test_endpoint_resolver.py` | 148 | 30 | 30 | 6 | uncategorized | endpoint_resolver | - | -| `tests/test_embedding_lanes.py` | 1104 | 29 | 29 | 0 | services | embedding | filesystem | +| `tests/test_redos_verdict_continuation.py` | 80 | 30 | 5 | 0 | uncategorized | redos_verdict_continuation | route/api | | `tests/test_upload_limits_centralized.py` | 110 | 29 | 5 | 0 | uncategorized | upload_limits_centralized | import-state, filesystem | -| `tests/test_email_oauth.py` | 580 | 28 | 25 | 0 | services | email | route/api, db/session, security, async/threading | -| `tests/test_review_regressions.py` | 930 | 26 | 26 | 0 | uncategorized | review_regressions | route/api, db/session, import-state, filesystem, async/threading | -| `tests/test_rename_user_owner_sync.py` | 686 | 26 | 26 | 0 | security | owner | route/api, db/session, import-state, filesystem, async/threading | +| `tests/test_cookbook_docker_access.py` | 339 | 28 | 13 | 0 | services | cookbook | route/api, filesystem, async/threading | +| `tests/test_rename_user_owner_sync.py` | 740 | 27 | 27 | 0 | security | owner | route/api, db/session, import-state, filesystem, async/threading | +| `tests/test_taxonomy.py` | 151 | 27 | 17 | 0 | uncategorized | taxonomy | security, ui/static | +| `tests/test_endpoint_resolver_urls.py` | 95 | 27 | 23 | 3 | uncategorized | endpoint_resolver_urls | - | | `tests/test_helpers_import_state.py` | 426 | 26 | 26 | 0 | helpers | helpers | route/api, db/session, import-state | -| `tests/test_taxonomy.py` | 145 | 26 | 16 | 0 | uncategorized | taxonomy | security, ui/static | -| `tests/test_tool_path_confinement.py` | 282 | 24 | 24 | 0 | security | confinement | import-state, filesystem, async/threading | -| `tests/test_copilot.py` | 170 | 23 | 16 | 0 | uncategorized | copilot | - | -| `tests/test_research_utils.py` | 97 | 23 | 23 | 2 | services | research | - | -| `tests/test_api_chat_security.py` | 401 | 22 | 8 | 0 | security | security | route/api, db/session, import-state, filesystem, async/threading | -| `tests/test_tool_support_heuristic.py` | 166 | 22 | 22 | 3 | uncategorized | tool_support_heuristic | - | -| `tests/test_platform_compat.py` | 318 | 21 | 21 | 0 | uncategorized | platform_compat | import-state, filesystem, subprocess/script | +| `tests/test_workspace_confine.py` | 527 | 25 | 25 | 0 | uncategorized | workspace_confine | route/api, filesystem, subprocess/script, async/threading | +| `tests/test_chat_route_tool_policy.py` | 344 | 25 | 23 | 0 | routes | route | filesystem, ui/static | +| `tests/test_tool_path_confinement.py` | 303 | 25 | 25 | 0 | security | confinement | import-state, filesystem, async/threading | +| `tests/test_copilot.py` | 182 | 25 | 18 | 0 | uncategorized | copilot | - | +| `tests/test_llm_core_temperature_reasoning.py` | 133 | 25 | 9 | 0 | services | llm | - | +| `tests/test_provider_endpoints_url_building.py` | 86 | 25 | 3 | 0 | services | provider | - | +| `tests/test_bg_job_tools.py` | 174 | 23 | 16 | 0 | uncategorized | bg_job_tools | filesystem, async/threading | ## Top files by physical line count | File | Lines | Collected tests | Test defs | Test classes | Area | Sub-area | Signals | |---|---:|---:|---:|---:|---|---|---| -| `tests/test_model_routes.py` | 1778 | 139 | 116 | 10 | routes | routes | route/api, db/session, import-state, async/threading | -| `tests/test_security_regressions.py` | 1224 | 92 | 68 | 0 | security | security | route/api, db/session, import-state, security, filesystem, async/threading, ui/static | -| `tests/test_embedding_lanes.py` | 1104 | 29 | 29 | 0 | services | embedding | filesystem | +| `tests/test_model_routes.py` | 2099 | 163 | 134 | 10 | routes | routes | route/api, db/session, import-state, async/threading | +| `tests/test_security_regressions.py` | 1515 | 98 | 74 | 0 | security | security | route/api, db/session, import-state, security, filesystem, async/threading, ui/static | +| `tests/test_review_regressions.py` | 1429 | 41 | 41 | 0 | uncategorized | review_regressions | route/api, db/session, import-state, filesystem, async/threading | | `tests/test_pr_blocker_audit.py` | 964 | 58 | 58 | 0 | uncategorized | pr_blocker_audit | import-state, security, filesystem | -| `tests/test_review_regressions.py` | 930 | 26 | 26 | 0 | uncategorized | review_regressions | route/api, db/session, import-state, filesystem, async/threading | -| `tests/test_cookbook_helpers.py` | 912 | 65 | 65 | 0 | services | cookbook | route/api, filesystem, subprocess/script, async/threading, ui/static | -| `tests/test_rename_user_owner_sync.py` | 686 | 26 | 26 | 0 | security | owner | route/api, db/session, import-state, filesystem, async/threading | -| `tests/test_email_oauth.py` | 580 | 28 | 25 | 0 | services | email | route/api, db/session, security, async/threading | +| `tests/test_cookbook_helpers.py` | 958 | 69 | 69 | 0 | services | cookbook | route/api, filesystem, subprocess/script, async/threading, ui/static | +| `tests/test_upload_handler_cleanup.py` | 831 | 13 | 13 | 0 | uncategorized | upload_handler_cleanup | route/api, db/session, filesystem, async/threading | +| `tests/test_email_oauth.py` | 798 | 34 | 29 | 0 | services | email | route/api, db/session, security, async/threading | +| `tests/test_rename_user_owner_sync.py` | 740 | 27 | 27 | 0 | security | owner | route/api, db/session, import-state, filesystem, async/threading | +| `tests/test_email_owner_scope.py` | 656 | 13 | 13 | 0 | security | owner_scope | route/api, db/session, filesystem, async/threading | +| `tests/test_model_capability_readers.py` | 646 | 20 | 20 | 0 | uncategorized | model_capability_readers | - | +| `tests/test_chat_helpers.py` | 582 | 37 | 24 | 0 | uncategorized | chat_helpers | route/api, filesystem, async/threading | | `tests/test_api_token_routes.py` | 578 | 17 | 17 | 0 | routes | api_routes | route/api, db/session, import-state, async/threading | -| `tests/test_shell_routes.py` | 481 | 63 | 48 | 8 | routes | routes | route/api, import-state, filesystem | -| `tests/test_email_owner_scope.py` | 474 | 9 | 9 | 0 | security | owner_scope | route/api, db/session, filesystem, async/threading | -| `tests/test_service_health.py` | 472 | 47 | 42 | 0 | uncategorized | service_health | async/threading | -| `tests/test_agent_loop.py` | 469 | 52 | 52 | 5 | uncategorized | agent_loop | db/session, import-state | +| `tests/test_research_routes_path_confinement.py` | 565 | 58 | 26 | 0 | security | confinement | route/api, security, filesystem, async/threading | +| `tests/test_shell_routes.py` | 538 | 69 | 53 | 9 | routes | routes | route/api, import-state, filesystem | +| `tests/test_workspace_confine.py` | 527 | 25 | 25 | 0 | uncategorized | workspace_confine | route/api, filesystem, subprocess/script, async/threading | +| `tests/test_agent_loop.py` | 500 | 54 | 54 | 5 | uncategorized | agent_loop | db/session, import-state | +| `tests/test_endpoint_probing.py` | 497 | 61 | 36 | 7 | uncategorized | endpoint_probing | route/api, db/session, import-state | +| `tests/test_run_focus.py` | 492 | 55 | 52 | 0 | uncategorized | run_focus | security, filesystem, subprocess/script, ui/static | +| `tests/test_tool_policy.py` | 475 | 18 | 18 | 0 | uncategorized | tool_policy | import-state, async/threading | | `tests/test_kv_cache_invalidation_2927.py` | 463 | 8 | 8 | 0 | uncategorized | kv_cache_invalidation_2927 | route/api, db/session, import-state, async/threading | +| `tests/test_email_test_connection_oauth.py` | 436 | 9 | 7 | 0 | services | email | route/api, db/session, async/threading | | `tests/test_helpers_import_state.py` | 426 | 26 | 26 | 0 | helpers | helpers | route/api, db/session, import-state | | `tests/test_endpoint_owner_scope_followup.py` | 414 | 11 | 11 | 0 | security | owner_scope | route/api, db/session, filesystem | -| `tests/test_endpoint_probing.py` | 411 | 34 | 30 | 6 | uncategorized | endpoint_probing | route/api, db/session, import-state | +| `tests/test_api_chat_security.py` | 404 | 22 | 8 | 0 | security | security | route/api, db/session, import-state, filesystem, async/threading | | `tests/test_imap_leak_fixes.py` | 404 | 15 | 15 | 0 | uncategorized | imap_leak_fixes | route/api, db/session, security, filesystem | | `tests/test_companion_readonly.py` | 402 | 17 | 17 | 0 | uncategorized | companion_readonly | db/session, import-state | -| `tests/test_api_chat_security.py` | 401 | 22 | 8 | 0 | security | security | route/api, db/session, import-state, filesystem, async/threading | | `tests/test_upload_handler_atomicity.py` | 401 | 9 | 9 | 0 | uncategorized | upload_handler_atomicity | filesystem, async/threading | -| `tests/test_run_focus.py` | 399 | 47 | 44 | 0 | uncategorized | run_focus | security, filesystem, subprocess/script, ui/static | -| `tests/test_auth_regressions.py` | 375 | 15 | 15 | 0 | security | auth | route/api, db/session, import-state, async/threading | -| `tests/test_calendar_owner_scope.py` | 345 | 7 | 7 | 0 | security | owner_scope | route/api, db/session, import-state, filesystem, async/threading, ui/static | -| `tests/test_null_owner_gates.py` | 342 | 20 | 20 | 0 | security | owner | route/api, db/session, import-state | -| `tests/test_agent_migration_manifest.py` | 340 | 15 | 15 | 0 | uncategorized | agent_migration_manifest | import-state, filesystem | -| `tests/test_calendar_recurrence.py` | 338 | 19 | 19 | 0 | services | calendar | - | -| `tests/test_tool_policy.py` | 330 | 13 | 13 | 0 | uncategorized | tool_policy | import-state, async/threading | -| `tests/test_workspace_confine.py` | 328 | 18 | 18 | 0 | uncategorized | workspace_confine | route/api, filesystem, subprocess/script, async/threading | -| `tests/test_diffusion_server_security.py` | 325 | 14 | 14 | 0 | security | security | route/api, import-state, security, filesystem, async/threading, ui/static | +| `tests/test_auth_regressions.py` | 370 | 15 | 15 | 0 | security | auth | route/api, db/session, import-state, async/threading | +| `tests/test_calendar_recurrence.py` | 356 | 20 | 20 | 0 | services | calendar | - | +| `tests/test_task_cookbook_admin_gate.py` | 350 | 10 | 10 | 0 | services | cookbook | route/api, db/session, import-state, filesystem, async/threading | ## Split planning candidates @@ -165,53 +169,69 @@ These are planning candidates only. A later split PR still needs a focused manua | File | Why included | Setup/risk signals | Suggested handling | |---|---|---|---| -| `tests/test_model_routes.py` | 1778 lines, 139 collected tests | route/api, db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_security_regressions.py` | 1224 lines, 92 collected tests | route/api, db/session, import-state, security, filesystem, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_provider_classification.py` | 67 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_cookbook_helpers.py` | 912 lines, 65 collected tests | route/api, filesystem, subprocess/script, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_shell_routes.py` | 481 lines, 63 collected tests | route/api, import-state, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_model_routes.py` | 2099 lines, 163 collected tests | route/api, db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_security_regressions.py` | 1515 lines, 98 collected tests | route/api, db/session, import-state, security, filesystem, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_cookbook_helpers.py` | 958 lines, 69 collected tests | route/api, filesystem, subprocess/script, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_shell_routes.py` | 538 lines, 69 collected tests | route/api, import-state, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_endpoint_probing.py` | 497 lines, 61 collected tests | route/api, db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_pr_blocker_audit.py` | 964 lines, 58 collected tests | import-state, security, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_provider_endpoints.py` | 58 collected tests | subprocess/script | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_agent_loop.py` | 469 lines, 52 collected tests | db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_service_health.py` | 472 lines, 47 collected tests | async/threading | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_run_focus.py` | 399 lines, 47 collected tests | security, filesystem, subprocess/script, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_llm_core_temperature.py` | 41 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_endpoint_probing.py` | 411 lines, 34 collected tests | route/api, db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_research_routes_path_confinement.py` | 565 lines, 58 collected tests | route/api, security, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_run_focus.py` | 492 lines, 55 collected tests | security, filesystem, subprocess/script, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_agent_loop.py` | 500 lines, 54 collected tests | db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_manage_mcp_command_allowlist.py` | 45 collected tests | db/session, subprocess/script, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_provider_classification.py` | 42 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_review_regressions.py` | 1429 lines, 41 collected tests | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_chat_helpers.py` | 582 lines, 37 collected tests | route/api, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_model_context.py` | 314 lines, 36 collected tests | db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_email_oauth.py` | 798 lines, 34 collected tests | route/api, db/session, security, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_llm_core_anthropic_temp_omit.py` | 32 collected tests | db/session | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_chat_helpers.py` | 31 collected tests | route/api | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_provider_detection.py` | 31 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_model_context.py` | 30 collected tests | db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_endpoint_resolver.py` | 30 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_embedding_lanes.py` | 1104 lines, 29 collected tests | filesystem | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_redos_verdict_continuation.py` | 30 collected tests | route/api | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_upload_limits_centralized.py` | 29 collected tests | import-state, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_email_oauth.py` | 580 lines, 28 collected tests | route/api, db/session, security, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_review_regressions.py` | 930 lines, 26 collected tests | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_rename_user_owner_sync.py` | 686 lines, 26 collected tests | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_cookbook_docker_access.py` | 339 lines, 28 collected tests | route/api, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_rename_user_owner_sync.py` | 740 lines, 27 collected tests | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_taxonomy.py` | 27 collected tests | security, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_endpoint_resolver_urls.py` | 27 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | | `tests/test_helpers_import_state.py` | 426 lines, 26 collected tests | route/api, db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_taxonomy.py` | 26 collected tests | security, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_tool_path_confinement.py` | 24 collected tests | import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_copilot.py` | 23 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_workspace_confine.py` | 527 lines, 25 collected tests | route/api, filesystem, subprocess/script, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_chat_route_tool_policy.py` | 344 lines, 25 collected tests | filesystem, ui/static | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_tool_path_confinement.py` | 303 lines, 25 collected tests | import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_copilot.py` | 25 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_llm_core_temperature_reasoning.py` | 25 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_provider_endpoints_url_building.py` | 25 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_bg_job_tools.py` | 23 collected tests | filesystem, async/threading | Good first manual-review candidate if test themes are cohesive. | | `tests/test_research_utils.py` | 23 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_api_chat_security.py` | 401 lines, 22 collected tests | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_api_chat_security.py` | 404 lines, 22 collected tests | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_tool_support_heuristic.py` | 22 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_platform_compat.py` | 318 lines, 21 collected tests | import-state, filesystem, subprocess/script | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_platform_compat.py` | 322 lines, 21 collected tests | import-state, filesystem, subprocess/script | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_context_compactor.py` | 21 collected tests | db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_prompt_security.py` | 21 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | -| `tests/test_null_owner_gates.py` | 342 lines, 20 collected tests | route/api, db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_fenced_inline_args.py` | 21 collected tests | db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_cache_affinity_local_only.py` | 21 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_model_capability_readers.py` | 646 lines, 20 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_calendar_recurrence.py` | 356 lines, 20 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_null_owner_gates.py` | 332 lines, 20 collected tests | route/api, db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_gallery_endpoint_hardening.py` | 326 lines, 20 collected tests | route/api, security, filesystem, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_redos_llm_parsers.py` | 20 collected tests | No obvious setup signals from static scan. | Good first manual-review candidate if test themes are cohesive. | +| `tests/test_code_nav_tools.py` | 20 collected tests | db/session, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_youtube_handler_consolidation.py` | 20 collected tests | route/api, import-state | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_calendar_recurrence.py` | 338 lines | No obvious setup signals from static scan. | Plan split boundaries before editing. | -| `tests/test_workspace_confine.py` | 328 lines | route/api, filesystem, subprocess/script, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_tool_policy.py` | 475 lines | import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_fenced_example_not_executed_for_native_models.py` | 345 lines | async/threading | Plan split boundaries before editing. | | `tests/test_api_token_routes.py` | 578 lines | route/api, db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_companion_readonly.py` | 402 lines | db/session, import-state | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_set_admin.py` | 317 lines | route/api, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_llm_core_ollama.py` | 324 lines | async/threading | Plan split boundaries before editing. | | `tests/test_imap_leak_fixes.py` | 404 lines | route/api, db/session, security, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_auth_regressions.py` | 375 lines | route/api, db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_auth_regressions.py` | 370 lines | route/api, db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_agent_migration_manifest.py` | 340 lines | import-state, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_mcp_email_decode_header_spaces.py` | 327 lines | route/api, db/session, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_diffusion_server_security.py` | 325 lines | route/api, import-state, security, filesystem, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_tool_policy.py` | 330 lines | import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_upload_handler_cleanup.py` | 831 lines | route/api, db/session, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_email_owner_scope.py` | 656 lines | route/api, db/session, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_upload_routes_owner_scope.py` | 344 lines | route/api, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_endpoint_owner_scope_followup.py` | 414 lines | route/api, db/session, filesystem | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_upload_routes_owner_scope.py` | 315 lines | route/api, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | -| `tests/test_email_owner_scope.py` | 474 lines | route/api, db/session, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_composer_arrow_up_recall_js.py` | 308 lines | filesystem, subprocess/script, ui/static | Plan split boundaries before editing. | +| `tests/test_task_cookbook_admin_gate.py` | 350 lines | route/api, db/session, import-state, filesystem, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | +| `tests/test_email_test_connection_oauth.py` | 436 lines | route/api, db/session, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_upload_handler_atomicity.py` | 401 lines | filesystem, async/threading | Plan split boundaries before editing. | | `tests/test_kv_cache_invalidation_2927.py` | 463 lines | route/api, db/session, import-state, async/threading | Defer mechanical split until setup/risk boundaries are mapped. | | `tests/test_calendar_owner_scope.py` | 345 lines | route/api, db/session, import-state, filesystem, async/threading, ui/static | Defer mechanical split until setup/risk boundaries are mapped. | @@ -226,28 +246,35 @@ Before using any of these files as a split target, first decide whether the taxo | File | Lines | Collected tests | Sub-area | Signals | Suggested follow-up | |---|---:|---:|---|---|---| +| `tests/test_endpoint_probing.py` | 497 | 61 | endpoint_probing | route/api, db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_pr_blocker_audit.py` | 964 | 58 | pr_blocker_audit | import-state, security, filesystem | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_agent_loop.py` | 469 | 52 | agent_loop | db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_service_health.py` | 472 | 47 | service_health | async/threading | Review taxonomy mapping before using as a split target. | -| `tests/test_run_focus.py` | 399 | 47 | run_focus | security, filesystem, subprocess/script, ui/static | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_endpoint_probing.py` | 411 | 34 | endpoint_probing | route/api, db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_chat_helpers.py` | 264 | 31 | chat_helpers | route/api | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_model_context.py` | 251 | 30 | model_context | db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_endpoint_resolver.py` | 148 | 30 | endpoint_resolver | - | Review taxonomy mapping before using as a split target. | +| `tests/test_run_focus.py` | 492 | 55 | run_focus | security, filesystem, subprocess/script, ui/static | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_agent_loop.py` | 500 | 54 | agent_loop | db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_review_regressions.py` | 1429 | 41 | review_regressions | route/api, db/session, import-state, filesystem, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_chat_helpers.py` | 582 | 37 | chat_helpers | route/api, filesystem, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_model_context.py` | 314 | 36 | model_context | db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_redos_verdict_continuation.py` | 80 | 30 | redos_verdict_continuation | route/api | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_upload_limits_centralized.py` | 110 | 29 | upload_limits_centralized | import-state, filesystem | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_review_regressions.py` | 930 | 26 | review_regressions | route/api, db/session, import-state, filesystem, async/threading | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_taxonomy.py` | 145 | 26 | taxonomy | security, ui/static | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_copilot.py` | 170 | 23 | copilot | - | Review taxonomy mapping before using as a split target. | +| `tests/test_taxonomy.py` | 151 | 27 | taxonomy | security, ui/static | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_endpoint_resolver_urls.py` | 95 | 27 | endpoint_resolver_urls | - | Review taxonomy mapping before using as a split target. | +| `tests/test_workspace_confine.py` | 527 | 25 | workspace_confine | route/api, filesystem, subprocess/script, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_copilot.py` | 182 | 25 | copilot | - | Review taxonomy mapping before using as a split target. | +| `tests/test_bg_job_tools.py` | 174 | 23 | bg_job_tools | filesystem, async/threading | Review taxonomy mapping before using as a split target. | | `tests/test_tool_support_heuristic.py` | 166 | 22 | tool_support_heuristic | - | Review taxonomy mapping before using as a split target. | -| `tests/test_platform_compat.py` | 318 | 21 | platform_compat | import-state, filesystem, subprocess/script | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_platform_compat.py` | 322 | 21 | platform_compat | import-state, filesystem, subprocess/script | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_context_compactor.py` | 233 | 21 | context_compactor | db/session, import-state, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_fenced_inline_args.py` | 186 | 21 | fenced_inline_args | db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_cache_affinity_local_only.py` | 104 | 21 | cache_affinity_local_only | - | Review taxonomy mapping before using as a split target. | +| `tests/test_model_capability_readers.py` | 646 | 20 | model_capability_readers | - | Review taxonomy mapping before using as a split target. | +| `tests/test_code_nav_tools.py` | 198 | 20 | code_nav_tools | db/session, filesystem, async/threading | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_youtube_handler_consolidation.py` | 104 | 20 | youtube_handler_consolidation | route/api, import-state | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_workspace_confine.py` | 328 | 18 | workspace_confine | route/api, filesystem, subprocess/script, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_tool_policy.py` | 475 | 18 | tool_policy | import-state, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_fenced_example_not_executed_for_native_models.py` | 345 | 18 | fenced_example_not_executed_for_native_models | async/threading | Review taxonomy mapping before using as a split target. | | `tests/test_companion_readonly.py` | 402 | 17 | companion_readonly | db/session, import-state | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_set_admin.py` | 317 | 17 | set_admin | route/api, import-state, filesystem, async/threading | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_imap_leak_fixes.py` | 404 | 15 | imap_leak_fixes | route/api, db/session, security, filesystem | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_agent_migration_manifest.py` | 340 | 15 | agent_migration_manifest | import-state, filesystem | Review taxonomy and setup/risk boundaries before any split. | -| `tests/test_tool_policy.py` | 330 | 13 | tool_policy | import-state, async/threading | Review taxonomy and setup/risk boundaries before any split. | +| `tests/test_upload_handler_cleanup.py` | 831 | 13 | upload_handler_cleanup | route/api, db/session, filesystem, async/threading | Review taxonomy and setup/risk boundaries before any split. | | `tests/test_upload_handler_atomicity.py` | 401 | 9 | upload_handler_atomicity | filesystem, async/threading | Review taxonomy mapping before using as a split target. | | `tests/test_kv_cache_invalidation_2927.py` | 463 | 8 | kv_cache_invalidation_2927 | route/api, db/session, import-state, async/threading | Review taxonomy and setup/risk boundaries before any split. | @@ -259,14 +286,16 @@ Files still in the `uncategorized` taxonomy area are listed separately below so | File | Lines | Collected tests | Area | Sub-area | Signals | Why this is a candidate | |---|---:|---:|---|---|---|---| -| `tests/test_provider_classification.py` | 188 | 67 | services | provider | - | 67 collected tests | -| `tests/test_provider_endpoints.py` | 241 | 58 | services | provider | subprocess/script | 58 collected tests | -| `tests/test_llm_core_temperature.py` | 196 | 41 | services | llm | - | 41 collected tests | -| `tests/test_provider_detection.py` | 148 | 31 | services | provider | - | 31 collected tests | -| `tests/test_embedding_lanes.py` | 1104 | 29 | services | embedding | filesystem | 1104 lines, 29 collected tests | +| `tests/test_provider_classification.py` | 115 | 42 | services | provider | - | 42 collected tests | +| `tests/test_chat_route_tool_policy.py` | 344 | 25 | routes | route | filesystem, ui/static | 344 lines, 25 collected tests | +| `tests/test_llm_core_temperature_reasoning.py` | 133 | 25 | services | llm | - | 25 collected tests | +| `tests/test_provider_endpoints_url_building.py` | 86 | 25 | services | provider | - | 25 collected tests | | `tests/test_research_utils.py` | 97 | 23 | services | research | - | 23 collected tests | | `tests/test_prompt_security.py` | 203 | 21 | security | security | - | 21 collected tests | -| `tests/test_calendar_recurrence.py` | 338 | 19 | services | calendar | - | 338 lines | +| `tests/test_calendar_recurrence.py` | 356 | 20 | services | calendar | - | 356 lines, 20 collected tests | +| `tests/test_redos_llm_parsers.py` | 201 | 20 | services | llm | - | 20 collected tests | +| `tests/test_llm_core_ollama.py` | 324 | 16 | services | llm | async/threading | 324 lines | +| `tests/test_composer_arrow_up_recall_js.py` | 308 | 11 | js | js | filesystem, subprocess/script, ui/static | 308 lines | ## High-risk candidates to defer first @@ -274,21 +303,21 @@ These files may still be split later, but not as the first implementation slice | File | Lines | Collected tests | High-risk signals | |---|---:|---:|---| -| `tests/test_model_routes.py` | 1778 | 139 | db/session, import-state, route/api | -| `tests/test_security_regressions.py` | 1224 | 92 | db/session, import-state, route/api, security | -| `tests/test_cookbook_helpers.py` | 912 | 65 | route/api | -| `tests/test_shell_routes.py` | 481 | 63 | import-state, route/api | +| `tests/test_model_routes.py` | 2099 | 163 | db/session, import-state, route/api | +| `tests/test_security_regressions.py` | 1515 | 98 | db/session, import-state, route/api, security | +| `tests/test_cookbook_helpers.py` | 958 | 69 | route/api | +| `tests/test_shell_routes.py` | 538 | 69 | import-state, route/api | +| `tests/test_endpoint_probing.py` | 497 | 61 | db/session, import-state, route/api | | `tests/test_pr_blocker_audit.py` | 964 | 58 | import-state, security | -| `tests/test_agent_loop.py` | 469 | 52 | db/session, import-state | -| `tests/test_run_focus.py` | 399 | 47 | security | -| `tests/test_endpoint_probing.py` | 411 | 34 | db/session, import-state, route/api | +| `tests/test_research_routes_path_confinement.py` | 565 | 58 | route/api, security | +| `tests/test_run_focus.py` | 492 | 55 | security | +| `tests/test_agent_loop.py` | 500 | 54 | db/session, import-state | +| `tests/test_manage_mcp_command_allowlist.py` | 168 | 45 | db/session | +| `tests/test_review_regressions.py` | 1429 | 41 | db/session, import-state, route/api | +| `tests/test_chat_helpers.py` | 582 | 37 | route/api | +| `tests/test_model_context.py` | 314 | 36 | db/session, import-state | +| `tests/test_email_oauth.py` | 798 | 34 | db/session, route/api, security | | `tests/test_llm_core_anthropic_temp_omit.py` | 94 | 32 | db/session | -| `tests/test_chat_helpers.py` | 264 | 31 | route/api | -| `tests/test_model_context.py` | 251 | 30 | db/session, import-state | -| `tests/test_upload_limits_centralized.py` | 110 | 29 | import-state | -| `tests/test_email_oauth.py` | 580 | 28 | db/session, route/api, security | -| `tests/test_review_regressions.py` | 930 | 26 | db/session, import-state, route/api | -| `tests/test_rename_user_owner_sync.py` | 686 | 26 | db/session, import-state, route/api | ## Rules for future split PRs @@ -313,7 +342,7 @@ Do not start a split PR from this planning issue alone if the file's boundaries This document was generated with: ```bash -.venv/bin/python tests/tools/build_oversized_test_split_plan.py +venv/bin/python tests/tools/build_oversized_test_split_plan.py ``` ## Freshness check @@ -321,6 +350,6 @@ This document was generated with: After editing the builder or rebasing the branch, regenerate the plan and confirm no unexpected plan drift: ```bash -.venv/bin/python tests/tools/build_oversized_test_split_plan.py +venv/bin/python tests/tools/build_oversized_test_split_plan.py git diff --exit-code -- tests/OVERSIZED_TEST_SPLIT_PLAN.md ``` diff --git a/tests/tools/build_oversized_test_split_plan.py b/tests/tools/build_oversized_test_split_plan.py index 855945c1c..671b646d5 100644 --- a/tests/tools/build_oversized_test_split_plan.py +++ b/tests/tools/build_oversized_test_split_plan.py @@ -441,6 +441,10 @@ def write_report(metrics: list[FileMetric], node_count_total: int) -> None: lines = [ "# Oversized Test File Split Plan", "", + "> [!NOTE]", + "> This is generated planning material based on the current test tree.", + "> It does not define runtime behaviour or approve any test-file split.", + "", "## Purpose", "", "This document plans future oversized test-file splits using current repo data.", @@ -508,7 +512,7 @@ def write_report(metrics: list[FileMetric], node_count_total: int) -> None: "This document was generated with:", "", "```bash", - ".venv/bin/python tests/tools/build_oversized_test_split_plan.py", + "venv/bin/python tests/tools/build_oversized_test_split_plan.py", "```", "", "## Freshness check", @@ -516,7 +520,7 @@ def write_report(metrics: list[FileMetric], node_count_total: int) -> None: "After editing the builder or rebasing the branch, regenerate the plan and confirm no unexpected plan drift:", "", "```bash", - ".venv/bin/python tests/tools/build_oversized_test_split_plan.py", + "venv/bin/python tests/tools/build_oversized_test_split_plan.py", "git diff --exit-code -- tests/OVERSIZED_TEST_SPLIT_PLAN.md", "```", "",