# Architecture Gap Audit - 2026-07-02

Scope: active workspace only. Excluded nested `.worktrees/`, `.wt-tray-popup-dashboard-int/`, and `.wt-session-limits-menu-int/` copies from code assessment.

Verification notes:
- Python pytest API collected and ran 87 tests: `87 passed in 0.45s`.
- `rtk pytest --collect-only -q` and `rtk pytest tests --collect-only -q` both returned `Pytest: No tests collected`; the default RTK verification path is not exercising this suite.
- No project `CONTEXT.md` or `docs/adr/` exists.

## Critical Product Gaps

1. Tray popup dashboard is not implemented.
   - Evidence: `account_card.py`, `popup_window.py`, `tests/test_account_card.py`, and `tests/test_popup_window.py` are missing.
   - Evidence: code search found no active-code hits for `popup`, `dashboard`, `AccountCard`, or `PopupWindow`.
   - Contract source: `docs/plans/2026-07-01-tray-popup-dashboard.md`.
   - Problem: the code still centers on tray menu rendering in `indicator.py`, so the planned dashboard interface has no seam or adapter.

2. Session reset timestamps and time-left display are absent.
   - Evidence: no active-code hits for `resets_at`, `checked_at`, `primary_resets_at`, or `secondary_resets_at`.
   - Evidence: `AccountSnapshot` starts at `health_client.py:20` and only carries status plus usage percentages.
   - Contract source: `docs/specs/2026-07-01-session-limits-menu-design.md`.
   - Problem: the health snapshot interface is too shallow for the documented UI contract.

3. Health cache freshness is implemented by file mtime, not snapshot data.
   - Evidence: `cdx.py:130` implements `load_health`; stale handling prints from `cdx.py:136`, `cdx.py:140`, `cdx.py:146`, `cdx.py:150`.
   - Evidence: `health_client.py:88` writes cache, but there is no `checked_at` field.
   - Problem: cache validity is not part of the health cache interface, so every consumer must infer freshness externally.

4. Claude health is read but never produced.
   - Evidence: `cld.py:31` reads `claude_health_cache.json`.
   - Evidence: `AccountHealthClient.fetch` at `health_client.py:32` is Codex-specific and spawns `codex app-server`.
   - Evidence: `Indicator._refresh_all` only iterates `self.registry.list()` at `indicator.py:646`, not the Claude registry.
   - Problem: `cld` can only consume a cache that no module owns.

5. Claude stale-health errors say `cdx`.
   - Evidence: `cld.py:7` imports `load_health` from `cdx.py`.
   - Evidence: `cdx.py:136` hardcodes `cdx: health cache missing or stale; proceeding without health data`.
   - Problem: the command-router seam is not deep enough; generic logic leaks Codex-facing text.

6. Claude routing assumes `CLAUDE_CONFIG_DIR` works without the required probe/fallback.
   - Evidence: `cld.py:39` unconditionally sets `CLAUDE_CONFIG_DIR`.
   - Contract source: `docs/superpowers/specs/2026-07-01-claude-code-account-switcher-design.md` requires proving the config-dir env var or rejecting unsupported per-invocation routing.
   - Problem: the adapter claims isolation without a verified interface.

7. Claude account lifecycle is not implemented in the tray.
   - Evidence: `_build_account_column_menu` only appends Manage Accounts for the Codex registry at `indicator.py:548` and `indicator.py:552`.
   - Evidence: `_build_manage_accounts_item` at `indicator.py:555` always reads `self.registry.list()` at `indicator.py:563`.
   - Contract source: Claude spec says manage actions are scoped to each tool.
   - Problem: the dual-tool UI is display-only for Claude management.

8. Dual Codex/Claude state is keyed only by slug.
   - Evidence: `_menu_items[account.slug]` is assigned at `indicator.py:483` and `indicator.py:549`.
   - Evidence: snapshots are looked up by `account.slug` at `indicator.py:107`, `indicator.py:469`, and `indicator.py:640`.
   - Problem: same slug across Codex and Claude collides at the tray module interface. The seam needs a tool-qualified account key.

9. Claude registry migration is a no-op.
   - Evidence: `AccountRegistry.migrate_legacy` returns early for non-Codex at `account_registry.py:65`.
   - Evidence: startup constructs `claude_registry` at `systray_codex_switcher.py:90` but only calls `registry.migrate_legacy()` at `systray_codex_switcher.py:89`.
   - Problem: existing Claude credentials are not onboarded into the documented account registry.

10. Seeded routing rules are hard-coded to personal slugs and projects.
    - Evidence: `systray_codex_switcher.py:18` to `systray_codex_switcher.py:28` and `systray_codex_switcher.py:29` to `systray_codex_switcher.py:39`.
    - Problem: first-run behavior is coupled to one workstation and can route to accounts that do not exist.

11. CLI wrappers are not installable command modules.
    - Evidence: `cdx.py`, `cld.py`, and `systray_codex_switcher.py` have mode `664` and no shebang.
    - Problem: docs talk about `cdx` and `cld`, but the repository only contains Python source files unless external install steps create wrappers.

12. Autostart packaging is machine-local.
    - Evidence: `packaging/codex-account-switcher.desktop:4` hardcodes `/home/user/Projects/systray-ai/systray_codex_switcher.py`.
    - Problem: the packaging interface is not portable and has no install module to rewrite paths.

13. Icon installation is not automated.
    - Evidence: icon source exists at `icons/codex-account-switcher.svg`, but no install script or verification module exists.
    - Contract source: plan requires installing under `~/.local/share/icons/hicolor/scalable/apps`.
    - Problem: runtime tray presentation depends on manual host state.

14. Fallback notification exists for Codex only.
    - Evidence: `cdx.py:210` uses `notify-send`; `cld.py` has no `notify-send`.
    - Problem: fallback behavior is inconsistent across the two command adapters.

## Architectural Deepening Gaps

15. `Indicator` is doing too many jobs.
    - Evidence: `indicator.py:197` starts repair/add orchestration, `indicator.py:452` rebuilds menus, `indicator.py:603` starts refresh behavior, `indicator.py:676` writes health cache.
    - Problem: the module interface is almost as complex as its implementation. Deleting it would scatter account flow, refresh, GTK, and cache behavior across callers.
    - Deepening direction: create a non-GTK tray account-flow module and leave `Indicator` as an adapter.

16. Health cache needs its own store module.
    - Evidence: cache writing is in `health_client.py:88`; stale reads are duplicated in `cdx.py:130`; tray load/write is in `indicator.py:676` and `indicator.py:682`.
    - Problem: freshness, schema tolerance, and atomicity are not localized.
    - Deepening direction: make the health snapshot store the interface.

17. Command routing needs a tool adapter seam.
    - Evidence: `cld.py:7` imports generic helpers from `cdx.py`; `cdx.py:174` and `cld.py:15` duplicate routing flow with tool-specific endings.
    - Problem: there are two adapters, so the seam is real, but the interface is still named and shaped around Codex.
    - Deepening direction: `CommandRouter` plus `CodexAdapter` and `ClaudeAdapter`.

18. Shared non-credential state sync is inside Account Registry.
    - Evidence: `account_registry.py:185` through `account_registry.py:319` owns dynamic shared-state merge/link behavior.
    - Problem: account metadata and Codex state migration are different concepts behind one interface.
    - Deepening direction: `SharedCodexState` module called by the Codex adapter.

19. Account identity is not tool-qualified.
    - Evidence: `Account` starts at `account_registry.py:23` and carries `codex_home` as the home field even when `AccountRegistryKind.CLAUDE` is active.
    - Problem: interface vocabulary forces Claude through Codex concepts.
    - Deepening direction: tool-qualified account reference plus neutral account-home naming.

20. Device-auth orchestration lives in the tray adapter.
    - Evidence: `_run_repair_flow` at `indicator.py:208` and `_run_add_account_flow` at `indicator.py:244` coordinate process start, prompt dialog creation, commit/rollback, snapshots, notifications, and menu rebuilds.
    - Problem: the most failure-prone behavior is tested through fake GTK and private tray methods.
    - Deepening direction: device-auth account operation module returning flow events.

21. GTK fallback/test widgets live in production dialog code.
    - Evidence: fallback classes start in `device_auth_dialog.py:25`; production dialog starts at `device_auth_dialog.py:211`.
    - Problem: test adapter and production adapter are fused.
    - Deepening direction: widget factory or explicit headless adapter seam.

22. Subprocess protocols are not explicit modules.
    - Evidence: Codex app-server protocol is embedded in `health_client.py:32`; device auth process protocol is embedded in `device_auth.py:33`.
    - Problem: callers depend on subprocess side effects without a protocol-level interface.
    - Deepening direction: protocol adapters with typed request/response contracts.

23. Routing defaults are seeded separately from registry contents.
    - Evidence: `seed_routing_rules` starts at `systray_codex_switcher.py:55`; hard-coded rules are defined at `systray_codex_switcher.py:18`.
    - Problem: routing can name accounts absent from the account registry.
    - Deepening direction: first-run routing seed should derive from registry or produce an explicit setup-required state.

24. The tray title/menu model is implicit.
    - Evidence: `indicator.py:121` updates title, `_account_label` starts at `indicator.py:148`, `_rebuild_menu` starts at `indicator.py:452`.
    - Problem: UI state is assembled directly into GTK widgets, leaving no testable tray model.
    - Deepening direction: build a tray view-model interface and render it through GTK.

25. Threading and idle scheduling are local implementation details of `Indicator`.
    - Evidence: `_start_background_thread` at `indicator.py:593`, `_default_idle_add` at `indicator.py:586`, refresh generation at `indicator.py:643`.
    - Problem: concurrency policy is entangled with menu rendering and account operations.
    - Deepening direction: scheduler seam with deterministic tests.

## Test And Verification Gaps

26. RTK test route does not run tests.
    - Evidence: `rtk pytest --collect-only -q` returned `Pytest: No tests collected`.
    - Evidence: Python pytest API collected 87 tests and all passed.
    - Problem: the documented/required command prefix is not aligned with actual verification.

27. Production modules contain uncollected pytest tests.
    - Evidence: test functions begin in `device_auth.py:260` and `device_auth_dialog.py:397`.
    - Problem: running `pytest tests` never executes them; they create false confidence.

28. Indicator tests are oversized and private-method oriented.
    - Evidence: `tests/test_indicator.py` is 1543 lines and defines a large fake GTK harness.
    - Problem: tests validate implementation wiring rather than a stable tray/account-flow interface.

29. No tests cover popup dashboard because the module does not exist.
    - Evidence: missing `tests/test_account_card.py` and `tests/test_popup_window.py`.
    - Problem: planned first-screen UI contract has no test surface.

30. No tests cover reset timestamps or `checked_at`.
    - Evidence: code search found no active-code hits for those fields.
    - Problem: session-limit compatibility tests only cover the percentage subset.

31. No default root verification command is trustworthy yet.
    - Evidence: RTK route says no tests; direct Python API says 87 passed.
    - Problem: future agents can easily report green from the wrong command.

32. No ADRs record rejected architecture decisions.
    - Evidence: `docs/adr/` is missing.
    - Problem: recurring reviews will re-suggest or re-litigate the same deepening choices.

33. No domain glossary exists.
    - Evidence: `CONTEXT.md` is missing.
    - Problem: module names and seams cannot be anchored to stable project vocabulary.

## Repo Hygiene Gaps

34. Nested worktree copies are present under the repo root and not ignored.
    - Evidence: `.worktrees/`, `.wt-tray-popup-dashboard-int/`, and `.wt-session-limits-menu-int/` exist in the workspace scan.
    - Evidence: `.gitignore` only ignores `.claude/`, `__pycache__/`, and `.pytest_cache/`.
    - Problem: repo-wide analyzers see duplicate/stale implementations unless every tool manually excludes them.

35. Project is flat as feature count grows.
    - Evidence: all production Python modules are at repo root.
    - Problem: multi-tool account routing, tray UI, health protocols, and packaging have no package-level locality.

36. Packaging, runtime, and development concerns share the root.
    - Evidence: wrappers, tray entrypoint, registry, health, GTK, docs, packaging, and tests all sit one level apart.
    - Problem: AI navigation and ownership are weak; shallow modules are easy to edit in the wrong direction.

37. There is no install/uninstall module.
    - Evidence: packaging docs require manual copying for desktop/icon files; source files are not executable.
    - Problem: host integration is not reproducible.

38. No lint/type gate is visible.
    - Evidence: repository has `pytest.ini` only; no mypy, ruff, pyproject, tox, or nox config was found in active workspace.
    - Problem: interface drift is caught only by unit tests.

39. No runtime smoke test exists for actual command wrappers.
    - Evidence: tests call `main()` functions and monkeypatch exec/subprocess, but there is no installed `cdx`/`cld` executable path.
    - Problem: command packaging can break while unit tests stay green.

40. No manual verification checklist status is recorded.
    - Evidence: plan checkboxes remain unchecked across docs.
    - Problem: implemented subset and manually verified host behavior cannot be distinguished from planned work.

## Suggested Deepening Order

1. Fix verification first: make the required RTK path collect and run the same 87 tests, then move embedded production tests into `tests/`.
2. Add `CONTEXT.md` with project vocabulary: account registry, tool account, selected default, routing rules, health snapshot, shared Codex state, tray model, device-auth operation.
3. Build the missing health snapshot store before adding more UI. It unlocks reset timestamps, `checked_at`, Codex/Claude cache separation, and cleaner routing tests.
4. Introduce tool-qualified account identity before expanding Claude features. This prevents slug collisions and keeps Codex/Claude adapters honest.
5. Extract tray account-flow and tray view-model modules before implementing the popup dashboard. Otherwise the dashboard will duplicate `Indicator` orchestration.
6. Implement packaging/install as a small module with tests after the command-router seam is stable.
