[AZ-511] classColors carve-out to src/class-colors/ (closes F3)

Move src/features/annotations/classColors.ts to its own component directory
src/class-colors/ with a proper barrel; update the 4 consumer imports to go
through the barrel; remove the F3-pending exemption from STC-ARCH-01 and from
the architecture test fixture; clean up the 5 coupled doc/script touchpoints.
Closes baseline finding F3 and retires the 5-coupled-places carry-over surface
logged in LESSONS.md 2026-05-12.

- Add `class-colors` to scripts/check-arch-imports.mjs COMPONENT_DIRS so deep
  imports past the new barrel are caught symmetric to every other component.
- Replace the architecture test "exemption WORKS" fixture with the stronger
  "deep import into class-colors NOW FAILS" assertion (Risk 4 mitigation).
- module-layout.md: Layout Rules + Per-Component Mapping (11_class-colors,
  06_annotations, 03_shared-ui) + Verification Needed #1 + shared/class-colors
  block all updated to reflect the new home.
- 11_class-colors/description.md: Caveats §7 + Module Inventory updated.
- architecture_compliance_baseline.md: F3 marked CLOSED with full pre-resolution
  context preserved (mirrors AZ-485/F4 + AZ-486/F7 pattern); F4 carry-forward
  exemption note retired.
- 04_verification_log.md: open questions #1 + #8 marked RESOLVED.
- Build passes with no circular-import warnings (AC-4); fast suite 231/13
  skipped green (AC-5); static profile green (AC-3 — zero exemptions remain).

Batch report: _docs/03_implementation/batch_14_cycle3_report.md

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-13 03:08:36 +03:00
parent 70fb452805
commit c368f60853
19 changed files with 228 additions and 69 deletions
+17 -16
View File
@@ -15,8 +15,8 @@
## Layout Rules
1. Each component owns ONE OR MORE top-level directories (or top-level files) under `src/`. The mapping is NOT 1:1 — `00_foundation` owns three sibling directories (`src/types/`, `src/hooks/`, `src/i18n/`), `05_flights` spans `src/features/flights/` AND a separate `mission-planner/` port-source root, and `10_app-shell` owns top-level files (`App.tsx`, `main.tsx`, `index.css`, `vite-env.d.ts`).
2. Shared code does **not** live under `src/shared/` today — there is no `shared/` directory. Two helper modules (`11_class-colors/classColors.ts` and `06_annotations/CanvasEditor.tsx`) are physically misplaced and consumed across components; both are flagged in the `## Verification Needed` block. A `src/shared/` directory is a Step 4 testability candidate.
3. **Public API per component is the barrel `src/<component>/index.ts`** (AZ-485 / F4). Every component except `10_app-shell` (which is a top-level file collection — `App.tsx`, `main.tsx`, etc., never imported as a unit) exposes its Public API through a root barrel. Cross-component imports MUST go through the barrel — `import { api } from '../api'`, not `from '../api/client'`. The `STC-ARCH-01` static gate (`scripts/check-arch-imports.mjs`, wired into `scripts/run-tests.sh --static-only`) fails the build on cross-component deep imports. Intra-component imports (relative `./`) remain free. **One F3-pending exemption**: `src/features/annotations/classColors` is imported directly because the file is logically owned by `11_class-colors` but physically lives under `06_annotations`; re-exporting it through the `06_annotations` barrel creates a circular import (AnnotationsPage → DetectionClasses → 06_annotations barrel → AnnotationsPage). The exemption disappears when F3 moves the file.
2. Shared code does **not** live under `src/shared/` today — there is no `shared/` directory. One helper module (`06_annotations/CanvasEditor.tsx`) remains physically misplaced and consumed across components; it is flagged in the `## Verification Needed` block. (`11_class-colors` was lifted to its own component directory `src/class-colors/` by AZ-511 / F3.) A `src/shared/` directory is a Step 4 testability candidate.
3. **Public API per component is the barrel `src/<component>/index.ts`** (AZ-485 / F4). Every component except `10_app-shell` (which is a top-level file collection — `App.tsx`, `main.tsx`, etc., never imported as a unit) exposes its Public API through a root barrel. Cross-component imports MUST go through the barrel — `import { api } from '../api'`, not `from '../api/client'`. The `STC-ARCH-01` static gate (`scripts/check-arch-imports.mjs`, wired into `scripts/run-tests.sh --static-only`) fails the build on cross-component deep imports. Intra-component imports (relative `./`) remain free. **No exemptions today** (the prior F3 carry-over for `features/annotations/classColors` was removed by AZ-511 when the file moved to its own component).
4. Cross-cutting concerns (logging, config, error handling, telemetry): no dedicated infrastructure today. `console.error` / silent catches are the closest thing — recorded in module findings.
5. Tests: there are **zero tests** under `src/`. The only test file is `mission-planner/src/test/jsonImport.test.ts`, which can't run because Jest isn't installed (00_discovery.md §11.5). Test layout is therefore TBD; suggest `src/<component>/__tests__/` per the standard React convention when tests are added (autodev Step 56).
@@ -38,11 +38,11 @@
### Component: `11_class-colors`
- **Epic**: TBD
- **Directories**: (none today — physical file lives at `src/features/annotations/classColors.ts`, which is owned by `06_annotations` on disk). Logical owner is this component; physical move to `src/shared/classColors.ts` (or `src/components/detection/classColors.ts`) is a Step 4 testability task.
- **Public API**: `getClassColor`, `getClassNameFallback`, `getPhotoModeSuffix`, `FALLBACK_CLASS_NAMES` — exported from `src/features/annotations/classColors.ts`. **No barrel** today because the file is physically inside `06_annotations`; consumers import the path directly under the F3-pending exemption documented in Layout Rule #3 and enforced by STC-ARCH-01. When F3 moves the file to its own component directory, a `src/<new-home>/index.ts` barrel will replace the direct path import and the STC-ARCH-01 exemption will be removed.
- **Internal**: module-private `CLASS_COLORS` constant.
- **Owns**: pending — see Verification Needed item #1.
- **Epic**: AZ-509 (carve-out delivered by AZ-511)
- **Directories**: `src/class-colors/` (lifted from `src/features/annotations/` by AZ-511; see `architecture_compliance_baseline.md` F3 — CLOSED)
- **Public API** (via `src/class-colors/index.ts` barrel): `getClassColor`, `getClassNameFallback`, `getPhotoModeSuffix`, `FALLBACK_CLASS_NAMES`.
- **Internal**: module-private `CLASS_COLORS` constant inside `classColors.ts`.
- **Owns**: `src/class-colors/**`
- **Imports from**: (none — Layer 0/1, no internal imports)
- **Consumed by**: `03_shared-ui` (DetectionClasses), `06_annotations` (CanvasEditor, AnnotationsPage, AnnotationsSidebar)
@@ -78,7 +78,7 @@
- `FlightContext.tsx``FlightProvider`, `useFlight`
- **Internal**: none — every file in `src/components/` is consumed externally today
- **Owns**: `src/components/**`
- **Imports from**: `00_foundation`, `11_class-colors` (physical: `../features/annotations/classColors`), `01_api-transport`, `02_auth`
- **Imports from**: `00_foundation`, `11_class-colors` (via `src/class-colors/index.ts` barrel since AZ-511), `01_api-transport`, `02_auth`
- **Consumed by**: `10_app-shell` (mounts `Header` + `FlightProvider`), every feature page (consumes `useFlight`, `ConfirmDialog`, `DetectionClasses`)
### Component: `04_login`
@@ -112,10 +112,9 @@
- **Public API** (via `src/features/annotations/index.ts` barrel):
- `AnnotationsPage` (route component)
- `CanvasEditor`**also imported by `07_dataset`** (cross-feature edge, see `architecture_compliance_baseline.md` F2). The barrel re-exports `CanvasEditor` to keep the consumer compliant with STC-ARCH-01 until F2 closes the edge.
- **NOT re-exported** through this barrel: `classColors` symbols (`getClassColor`, `getClassNameFallback`, `getPhotoModeSuffix`, `FALLBACK_CLASS_NAMES`). Re-exporting them would create a circular barrel import (`AnnotationsPage → DetectionClasses → 06_annotations barrel → AnnotationsPage`). Consumers import `src/features/annotations/classColors` directly under the F3-pending exemption recorded in Layout Rule #3 and in STC-ARCH-01.
- **Internal**: `MediaList.tsx`, `VideoPlayer.tsx`, `AnnotationsSidebar.tsx`
- **Owns**: `src/features/annotations/**` EXCEPT `classColors.ts` (logically owned by `11_class-colors`; physical home pending refactor)
- **Imports from**: `00_foundation`, `11_class-colors`, `01_api-transport`, `03_shared-ui`
- **Owns**: `src/features/annotations/**`
- **Imports from**: `00_foundation`, `11_class-colors` (via barrel since AZ-511), `01_api-transport`, `03_shared-ui`
- **Consumed by**: `10_app-shell` (route); `07_dataset` (imports `CanvasEditor` directly — see Verification Needed)
### Component: `07_dataset`
@@ -186,11 +185,13 @@
> No `src/shared/` directory exists today. Two cross-cutting concerns are tracked here as **proposed** shared modules; they require a physical file move scheduled for Step 4 (testability) or Step 8 (refactor).
### shared/class-colors (proposed; current physical location: `src/features/annotations/classColors.ts`)
### shared/class-colors — RESOLVED by AZ-511
The class-colors helper is no longer "proposed shared / physical-misplaced". It moved to its own component directory `src/class-colors/` with a proper barrel; see Per-Component Mapping for `11_class-colors` above. The entry is kept here as a back-pointer for readers following older links.
- **Owner component**: `11_class-colors`
- **Purpose**: Detection-class fallback color, fallback name, PhotoMode suffix.
- **Owned by**: pending move task — current physical file is under `06_annotations`'s owns-glob, which makes it ambiguous. Workaround: until moved, treat `classColors.ts` as `OWNED` by tasks targeting `11_class-colors` and `READ-ONLY` to all other tasks (including those targeting `06_annotations`).
- **Physical location**: `src/class-colors/`
- **Public API**: `src/class-colors/index.ts`
- **Consumed by**: `03_shared-ui/DetectionClasses`, `06_annotations` (CanvasEditor, AnnotationsPage, AnnotationsSidebar)
### shared/canvas-editor (proposed; current physical location: `src/features/annotations/CanvasEditor.tsx`)
@@ -221,11 +222,11 @@ The `Blackbox Tests` cross-cutting component sits **outside** this table. It imp
The following inferences could not be made cleanly from code alone. They are surfaced for the user to confirm or override at the Step 2.5 BLOCKING gate.
1. **Physical home of `11_class-colors`**. The component is logically Layer 0/1 shared kernel, but its physical file lives inside `06_annotations`'s owns-glob (`src/features/annotations/classColors.ts`). Until the file is moved (proposed: `src/shared/classColors.ts`), the implement skill must apply the special-case rule documented under `shared/class-colors` above (READ-ONLY for `06_annotations` tasks even though the file is inside that component's directory). **Decision needed**: schedule the file move at Step 4 / Step 8, or accept the special-case rule indefinitely?
1. ~~**Physical home of `11_class-colors`**~~**RESOLVED by AZ-511 (F3)**. The file moved to `src/class-colors/classColors.ts` with a `src/class-colors/index.ts` barrel; consumers import via the barrel; STC-ARCH-01 has no exemptions. The `06_annotations` owns-glob no longer carves out `classColors.ts`.
2. **Physical home of `CanvasEditor.tsx`**. Same shape: it lives under `06_annotations` and is consumed cross-feature by `07_dataset`. Proposed: `src/components/canvas/CanvasEditor.tsx` (or a new `06b_canvas` component). **Decision needed**: keep the same-layer cross-feature edge, or schedule the lift?
3. ~~No barrel exports anywhere~~**resolved by AZ-485 (F4)**. Every component now exposes a `src/<component>/index.ts` barrel; cross-component imports go through it; `STC-ARCH-01` enforces it. One F3-pending exemption (`classColors`) remains documented in Layout Rule #3 above and in `architecture_compliance_baseline.md`.
3. ~~No barrel exports anywhere~~**resolved by AZ-485 (F4)**. Every component now exposes a `src/<component>/index.ts` barrel; cross-component imports go through it; `STC-ARCH-01` enforces it. The original F3-pending exemption (`classColors`) was closed by AZ-511 — there are no STC-ARCH-01 exemptions today.
3a. ~~Hardcoded `/api/<service>/` URLs scattered across callsites~~**resolved by AZ-486 (F7)**. The single source of truth is `src/api/endpoints.ts` (re-exported via the `01_api-transport` barrel from rule #3). Every production callsite of `api.*` and `createSSE()` uses an `endpoints.*` builder; the colocated `src/api/endpoints.test.ts` pins every URL string and serves as the wire-contract documentation. The `STC-ARCH-02` static gate (`scripts/check-arch-imports.mjs --mode=api-literals`, wired into `scripts/run-tests.sh --static-only`) fails the build on any new hardcoded `/api/<service>/` literal under `src/`. Exemptions: `src/api/endpoints.ts` (the contract owner) and any `*.test.ts` / `*.test.tsx` under `src/` (test files are exempt because tests legitimately assert URL strings — MSW handlers, contract tests, etc.).