Captures the full output of autodev existing-code Phase A through Step 4 (Code Testability Revision) for the Azaion UI workspace: - Step 1 Document: _docs/02_document/ (FINAL_report, architecture, glossary, components/, modules/, diagrams/, system-flows, module-layout) plus _docs/00_problem/ + _docs/01_solution/ + _docs/legacy/ + _docs/how_to_test + README. - Step 2 Architecture Baseline: architecture_compliance_baseline.md. - Step 3 Test Spec: _docs/02_document/tests/ (environment, test-data, blackbox/performance/resilience/security/ resource-limit tests, traceability-matrix), enum_spec_snapshot, expected_results/results_report.md (98 rows), plus the run-tests.sh + run-performance-tests.sh runners. - Step 4 Code Testability Revision: 01-testability-refactoring/ run dir (list-of-changes C01-C07, deferred_to_refactor, analysis/research_findings + refactoring_roadmap) and the 7 child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/ plus _dependencies_table.md. - _docs/_autodev_state.md pins the cursor at Step 4 / refactor Phase 4 entry so /autodev resumes cleanly. Epic AZ-447 (UI testability gates) tracks the 7 child tasks that will land in subsequent commits. Co-authored-by: Cursor <cursoragent@cursor.com>
20 KiB
Architecture Compliance Baseline
Scope: full existing codebase (src/ deployed tree + mission-planner/ port-source).
Date: 2026-05-10
Mode: code-review baseline (Phase 1 + Phase 7 only).
Verdict: FAIL — 1 Critical, 4 High, 2 Medium, 2 Low. Verdict drives Step 2 → Step 4 / Step 8 routing per flows/existing-code.md; it does NOT block any pipeline.
Inputs read in Phase 1:
_docs/02_document/architecture.md(incl. Architecture Vision P1–P12, ADR-001..010, Mission-planner convergence plan)._docs/02_document/module-layout.md(per-component file ownership, Layer table, Verification Needed #1–#8)._docs/00_problem/restrictions.md,_docs/01_solution/solution.md(project context).
Detection approach: TypeScript import ... from '...' parsing across all .ts / .tsx files; layer resolved via module-layout.md "Per-Component Mapping"; layer comparison against the "Allowed Dependencies (layering)" table.
Findings
| # | Severity | Category | Location | Title |
|---|---|---|---|---|
| F1 | Critical | Architecture | mission-planner/** vs src/features/flights/** |
Mission-planner duplicates 13+ modules of the deployed flights tree |
| F2 | High | Architecture | src/features/dataset/DatasetPage.tsx:9 → ../annotations/CanvasEditor |
Cross-feature same-layer edge — 07_dataset reaches into 06_annotations |
| F3 | High | Architecture | src/features/annotations/classColors.ts |
Physical / logical owner split — 11_class-colors file lives inside 06_annotations |
| F4 | High | Architecture | every component | No Public API barrels — every internal file is de-facto public |
| F5 | High | Architecture | mission-planner/src/flightPlanning/MapView.tsx ↔ MiniMap.tsx |
Pre-existing import cycle inside port-source |
| F6 | Medium | Architecture | (codebase-wide) | No src/shared/ infrastructure for cross-cutting concerns |
| F7 | Medium | Architecture | every api.* / createSSE call site |
Hardcoded /api/<service>/... paths instead of env-driven endpoints |
| F8 | Low | Architecture | _docs/02_document/module-layout.md |
Layering-table inconsistency — Header → useAuth is unannotated |
| F9 | Low | Architecture | mission-planner/src/{main,App,setupTests,vite-env}.tsx |
Inert second Vite entry tree at port-source root |
Finding Details
F1: Mission-planner duplicates 13+ modules of the deployed flights tree (Critical / Architecture)
-
Location:
mission-planner/src/**vssrc/features/flights/**. -
Description: Component
05_flightshas two physical trees (per ADR-009). The port-source duplicates almost every module the deployed tree exposes today AND carries behaviors the deployed tree does not yet have (camera-config side panel, mission JSON I/O, satellite tile provider, richer waypoint-altitude UX). Duplication enumerated below; until convergence completes, the same logic lives in two places and silently drifts. This is the work-list the Architecture Vision (Mission-planner convergence plan) asked Step 2 to surface.Duplicated by name (deployed → port-source):
Deployed ( src/features/flights/)Port-source ( mission-planner/src/.../)Notes AltitudeChart.tsxflightPlanning/AltitudeChart.tsxBoth consumed by their respective panels. AltitudeDialog.tsxflightPlanning/AltitudeDialog.tsxPort-source version uses useLanguage(custom i18n); deployed uses Tailwind.DrawControl.tsxflightPlanning/DrawControl.tsxDeployed uses newGuidfromflightPlanUtils; port-source fromutils.ts.JsonEditorDialog.tsxflightPlanning/JsonEditorDialog.tsxMission JSON I/O — deployed version is a stub vs. port-source's full editor. MapPoint.tsxflightPlanning/MapPoint.tsxBoth import the local pointIcon*set.MiniMap.tsxflightPlanning/MiniMap.tsxPort-source version is half of the F5 cycle. WindEffect.tsxflightPlanning/WindEffect.tsxPort-source pulls useLanguage; deployed usesi18next.WaypointList.tsxflightPlanning/PointsList.tsx(renamed)DnD reorder; same intent, different libs. FlightMap.tsxflightPlanning/MapView.tsx(renamed)The cycle partner. FlightParamsPanel.tsxflightPlanning/LeftBoard.tsx(renamed)Side-panel composition root. FlightsPage.tsxflightPlanning/flightPlan.tsx(renamed)Route component. mapIcons.tsicons/PointIcons.tsx,icons/MapIcons.tsx,icons/SidebarIcons.tsxPort-source uses inline SVG components; deployed uses L.icon.flightPlanUtils.ts(newGuid,calculateDistance,calculateAllPoints,parseCoordinates,getMockAircraftParams)utils.ts(newGuid);services/calculateDistance.ts;services/calculateBatteryUsage.ts;services/AircraftService.ts(mockGetAirplaneParams)Same five symbols, scattered across four files in the port-source. types.ts(FlightPoint,CalculatedPointInfo,MapRectangle,ActionMode,WindParams,AircraftParams,PURPOSES,COORDINATE_PRECISION,TILE_URLS)types/index.ts+constants/{actionModes,purposes,tileUrls,maptypes,languages,translations}.tsPort-source has richer constants tables (mapTypes, languages, translations) the deployed tree lacks. Port-source-only (no deployed counterpart yet — these are the behaviors that must port across Phase B):
flightPlanning/LanguageContext.tsx+LanguageSwitcher.tsx— mission-planner's standalone i18n (deployed usesi18next). DO NOT port; consolidate oni18next.flightPlanning/TotalDistance.tsx— distance + battery readout in the left panel. Behavior the deployed tree does not yet show in the same form.icons/PhoneIcon.tsx(rotate-phone hint),icons/SidebarIcons.tsx(DashedArea / HideSidebar / ShowSidebar).services/WeatherService.ts— wind compute (already partially in deployedflightPlanUtils.ts:60with the hardcoded key — P10 violation).flightPlanning/Aircraft.ts— aircraft entity helpers.config.ts—COORDINATE_PRECISION,GOOGLE_GEOCODE_KEY(second hardcoded-key risk — verify).
-
Suggestion: This is the convergence work-list. Per Architecture Vision (Mission-planner convergence plan):
- NOT a Step 4 testability item — these are behavior ports, not testability surgery.
- NOT a Step 8 refactor item alone — too large for one mechanical refactor; behavior changes break tests.
- Primary home: Phase B feature cycles (one cycle per port group: i18n consolidation; flight-planning UI parity; waypoint-altitude UX; mission JSON I/O; satellite tile provider; weather/battery service; camera-config side panel). Each cycle: New Task → Implement → Run Tests → Test-Spec Sync → Update Docs → Deploy → Retrospective.
- Final Phase B cycle: delete
mission-planner/(its only consumer becomes zero).
-
Task / Epic: feeds
05_flightsStep 3 (Test Spec) — every port target must have an AC for the converged behavior before its Phase B cycle starts.
F2: Cross-feature same-layer edge — 07_dataset reaches into 06_annotations (High / Architecture)
- Location:
src/features/dataset/DatasetPage.tsx:9→import CanvasEditor from '../annotations/CanvasEditor'. - Description:
07_datasetand06_annotationsare both Layer 3 features. Same-layer imports are forbidden except for explicit grandfathered edges. This edge IS grandfathered (module-layout.mdAllowed-Dependencies table footnote †, Verification Needed #2). It is the only Layer-3 ↔ Layer-3 import in the codebase. Until a proper home is chosen, the implement skill must keep treatingCanvasEditor.tsxas READ-ONLY for07_datasettasks. - Suggestion: Lift
CanvasEditor.tsxtosrc/components/canvas/CanvasEditor.tsx(under03_shared-ui) OR to a new06b_canvascomponent. Both options drop the same-layer edge. Decision should ride a Phase B cycle that already touchesCanvasEditor— folding the move into a behavior change is cheaper than a standalone refactor. - Task / Epic: defer to Phase B (when a
CanvasEditor-touching feature lands) or Step 8 refactor (optional).
F3: Physical / logical owner split for classColors.ts (High / Architecture)
- Location:
src/features/annotations/classColors.ts. - Description: The file is under
06_annotations's owns-glob (src/features/annotations/**) but the component spec assigns it to11_class-colors(Layer 0 shared kernel) — three external consumers depend on it (03_shared-ui/DetectionClasses,06_annotations/{CanvasEditor,AnnotationsPage,AnnotationsSidebar}, future07_datasetclass-distribution chart). Module-layout Verification #1 records the workaround:READ-ONLYfor06_annotationstasks. The workaround scales poorly — a new06_annotationscontributor reading only the directory glob will not know the file is off-limits. - Suggestion: Move physical file to
src/shared/classColors.ts(introducing asrc/shared/layer for true Layer-0 utilities) or tosrc/components/detection/classColors.ts(under03_shared-ui). Either move drops the workaround and aligns physical/logical ownership. - Task / Epic: Step 4 testability — minimal, surgical move (rename + import-path update across 4 consumers).
F4: No Public API barrels — every internal file is de-facto public (High / Architecture)
- Location: every component root (no
src/<component>/index.tsexists today; onlysrc/types/index.tsandmission-planner/src/types/index.tsare barrels and they're re-export hubs, not component facades). - Description: Cross-component imports use file-name granularity (
import { api } from '../api/client',import { useFlight } from '../../components/FlightContext', etc.). Consequence: there is no enforceable Public API surface. Any internal refactor inside a component (split a file, rename an export) is a breaking change to every importer. Phase 7 Check #2 ("Public API respect") cannot meaningfully fail in this codebase because everything is public. Module-layout Verification #3 records the same observation. - Suggestion: Step 4 testability candidate — add
src/<component>/index.tsfor every component, re-exporting only the symbols listed in module-layout's "Public API (de-facto)" line for that component. Then a future Phase 7 invocation can flag deep imports as Architecture findings instead of folding into background noise. - Task / Epic: Step 4 testability (single mechanical change per component; ~11 new files + ~30 import-path edits).
F5: Pre-existing import cycle inside port-source (High / Architecture)
- Location:
mission-planner/src/flightPlanning/MapView.tsx(importsMiniMapon line 16) ↔mission-planner/src/flightPlanning/MiniMap.tsx(importsUpdateMapCenterfrom./MapViewon line 2). - Description: A named-handle cycle internal to
mission-planner/. Module-layout Verification #5 +00_discovery.md §7already record it. Not introduced by this scan. The cycle does NOT cross component boundaries (both files belong to05_flightsport-source). The cycle disappears at the end of the convergence (whenmission-planner/is deleted). - Suggestion: No action. Track-only finding. Reason: fixing the cycle inside port-source means moving
UpdateMapCenterto a third file — wasted work given the eventual delete. If the deployed tree gains the same cycle when porting, fix it there. - Task / Epic: (none — closed by mission-planner deletion in the final Phase B cycle).
F6: No src/shared/ infrastructure for cross-cutting concerns (Medium / Architecture)
- Location: codebase-wide. No
src/shared/directory exists today (module-layout Layout Rules #4). - Description: There is no shared logger, no central error envelope, no config loader, no telemetry hook. Each feature page does ad-hoc
console.error+ silent catches (multiple module findings — annotations sidebar AI-detect silent catches, dataset silent catches, settings save withouttry/finally). Onboarding observability or a global error boundary today touches every feature. - Suggestion: Introduce
src/shared/(orsrc/components/util/) at Phase B kickoff with:shared/logger.ts— wrapsconsole.*, adds revision + user context; replace ad-hocconsole.error.shared/config.ts— typedimport.meta.env.*accessor (resolves P10 OpenWeatherMap key + the future env-base-URL refactor).shared/errorBoundary.tsx— application-level boundary (today the SPA has noErrorBoundary— recorded insrc__App-and-main.mdfindings).shared/endpoints.ts— typed endpoint constants (closes F7).
- Task / Epic: Phase B candidate (one cycle for shared infrastructure) OR fold into Step 8 refactor if user picks A on the Step 8 gate.
F7: Hardcoded /api/<service>/... paths instead of env-driven endpoints (Medium / Architecture)
- Location: every call site of
api.*()andcreateSSE()acrosssrc/features/**andsrc/auth/,src/components/FlightContext.tsx,src/components/DetectionClasses.tsx. Approximately 30 call sites. - Description: Consequence of ADR-006 (nginx prefix-strip). Each call site repeats
/api/<service>/<path>as a string literal. Testability suffers — every test fixture must duplicate paths; any nginx-route change touches every feature. Architecture intent (ADR-006 Consequences) explicitly flags this: "The SPA hardcodes /api//... paths in source instead of an env-driven base URL — testability is poor (finding tracked)." - Suggestion: Step 4 testability — introduce
src/shared/endpoints.ts(or per-componentendpoints.tsif shared/ is deferred) that exposes typed builders:endpoints.auth.login(),endpoints.flights.byId(id),endpoints.annotations.media(query), etc. Replace every string-literal path. Allows tests to mock at the endpoints layer rather than at everyfetchcall. Compounds well with F6 ifsrc/shared/lands first. - Task / Epic: Step 4 testability (mechanical extract; per-component cohort).
F8: Layering-table inconsistency — Header → useAuth is unannotated (Low / Architecture)
- Location:
_docs/02_document/module-layout.md— "Allowed Dependencies (layering)" table vs "Per-Component Mapping"03_shared-uirow. - Description: The layering table says Layer 2 may import only from layers 0+1, no same-layer edges. The per-component table explicitly lists
03_shared-ui Imports from: ..., 02_auth. The actual importsrc/components/Header.tsx:3 → ../auth/AuthContextis by design — every header needs the current user. This is not a code violation (the per-component table is authoritative for specific edges); it's a doc bug. - Suggestion: Add a layering-table footnote for
03_shared-uisimilar to the existing07_datasetfootnote: "03_shared-ui importsuseAuthfrom02_auth'sAuthContext— same-layer cross-component edge, permitted as it is the only cross-cutting state-context dependency." Update during Step 4 doc-touchup or fold into Step 13 docs cycle. - Task / Epic: documentation only — no code change.
F9: Inert second Vite entry tree at port-source root (Low / Architecture)
- Location:
mission-planner/src/{main.tsx,App.tsx,setupTests.ts,vite-env.d.ts}. - Description:
mission-planner/src/carries its own Vite entrypoint (main.tsx+App.tsx), test setup file, and env shim. ADR-009 says the deployed Vite build does NOT compile this tree, but there is nothing in the codebase that prevents a future contributor from addingmission-planner/to a Vitebuild.rollupOptions.inputand shipping two SPAs. Architecture intent is "vendored port-source, NOT a deployed component". - Suggestion: Step 4 testability or Step 8 refactor — verify
vite.config.tshas nomission-planner/entry; if Vite ever adds workspace-aware builds, add explicit exclusion. Defer until the convergence retires the directory entirely. - Task / Epic: closed by F1's final delete cycle.
Routing — what feeds where
Per flows/existing-code.md Step 2 → Step 4 / Step 8 rule, High and Critical Architecture findings must either (a) be appended to the testability list-of-changes.md input for Step 4, or (b) be deferred to Step 8 (optional Refactor) via Choose. Recommended routing:
| Finding | Recommended target step | Reason |
|---|---|---|
| F1 | Phase B cycles (NOT Step 4, NOT Step 8) | Behavior ports — need test safety net + per-feature deploy. |
| F2 | Phase B (when a CanvasEditor-touching task lands) |
Fold the lift into a behavior change cycle. |
| F3 | Step 4 testability | Pure file move + import-path update — fits the "smallest fix" rule. |
| F4 | Step 4 testability | 11 new index.ts files + cohort of import-path edits — mechanical. |
| F5 | No action (closed by F1 final delete) | Fixing inside port-source is wasted work. |
| F6 | Phase B (one infra cycle) OR Step 8 refactor | Shared logger / config / endpoints / error boundary — design choice. |
| F7 | Step 4 testability | Endpoint extraction enables tests; depends on F6 if src/shared/ is path. |
| F8 | Documentation touch-up (no step) | Doc-only. |
| F9 | Defer | Closed by F1 final delete. |
The 4 High and 1 Critical findings that should drive a Choose decision now:
- F1 — Phase B work-list (not Step 4, not Step 8).
- F2 — Phase B side-quest (not Step 4, not Step 8).
- F3 — Step 4 candidate.
- F4 — Step 4 candidate.
- F5 — track-only (no decision needed).
Baseline Delta
(N/A — this is the first baseline; no prior report to delta against. Future code-review invocations in cumulative or full mode will emit a Baseline Delta section against this file.)