# Batch Report

**Batch**: 09 (Phase B cycle 1, batch 1 of 2)
**Tasks**: AZ-485 (Public API barrels + STC-ARCH-01)
**Date**: 2026-05-11
**Cycle**: Phase B feature cycle, Step 10 — Implement
**Total complexity**: 5 pts
**Epic**: AZ-447 (`01-testability-refactoring`)
**Closes**: architecture baseline finding **F4** (`_docs/02_document/architecture_compliance_baseline.md`)

## Task Results

| Task | Status | Files Modified / Added | Tests | AC Coverage | Issues |
|------|--------|------------------------|-------|-------------|--------|
| AZ-485_refactor_public_api_barrels | Done | **11 new barrels** (`src/{api,auth,components,hooks,i18n}/index.ts`, `src/features/{login,flights,annotations,dataset,admin,settings}/index.ts`); **1 new script** (`scripts/check-arch-imports.mjs`); **1 new test** (`tests/architecture_imports.test.ts`); **1 modified runner** (`scripts/run-tests.sh` — `STC-ARCH-01` wired in); **17 production import sites** migrated to barrel paths (App.tsx + every feature page + every `src/components/` consumer); **22 test/colocated test import sites** migrated; **1 doc** (`_docs/02_document/module-layout.md`) — Layout Rules #3 rewritten, Verification Needed #3 closed, every component's Public API line points to its barrel | 4 new architecture tests in `tests/architecture_imports.test.ts` (AC-4 / AC-5 + 2 exemption cases); fast profile re-baselined from 163 → 167 passes (no regressions) | 7 / 7 ACs covered | One **F3-pending exemption** carried forward: `src/features/annotations/classColors` is imported directly (not through the `06_annotations` barrel) to avoid a circular import; documented in the barrel, the consumers, the static check, the module-layout doc, and the new test |

## AC Test Coverage: All 7 ACs covered

| AC | Where | Profile | Status |
|----|-------|---------|--------|
| AC-1 — Every component has a barrel exposing only its Public API | `src/<component>/index.ts` × 11 vs `module-layout.md` Per-Component Mapping → Public API | static (manual cross-check in self-review) | PASS — each barrel's re-export list matches the documented Public API line one-for-one; no internal-only symbol leaks |
| AC-2 — No cross-component deep imports remain in production code | `scripts/check-arch-imports.mjs` scanning `src/` | static (`STC-ARCH-01`) | PASS — 0 deep imports outside the documented F3 exemption |
| AC-3 — No cross-component deep imports remain in tests | same script scanning `tests/` + `e2e/` | static (`STC-ARCH-01`) | PASS — 0 deep imports outside the documented F3 exemption |
| AC-4 — Static gate fails on a newly-introduced deep import | `tests/architecture_imports.test.ts` `AC-4: FAILS when a deep import...` + `AC-4: deep imports inside line comments do not trip the gate` | fast | PASS — the synthetic fixture (`tests/_arch_fixtures/synthetic_deep_import.ts`) flips the script to exit non-zero and emits `STC-ARCH-01 — ...` on stderr |
| AC-5 — Static gate passes on the migrated codebase | `tests/architecture_imports.test.ts` `AC-5: passes on the migrated codebase` + `STC-ARCH-01` run in the static profile | fast + static | PASS — exit code 0, stderr empty |
| AC-6 — Fast profile remains green | `bash scripts/run-tests.sh` (static + fast) | static + fast | PASS — 167 / 13 / 0 (baseline was 163 / 13 / 0 + 4 new architecture tests); 0 regressions |
| AC-7 — module-layout.md reflects the new convention | `_docs/02_document/module-layout.md` Layout Rules #3 + Verification Needed #3 + Conventions table + every component's Public API line | manual review | PASS — Rule #3 names the barrel as the Public API, names `STC-ARCH-01` as the enforcing gate, and the F3-pending exemption is documented inline; Verification Needed #3 marked closed by AZ-485 |

## Design Decisions

1. **Single source of truth for the static check** — `scripts/check-arch-imports.mjs` mirrors the existing `scripts/check-banned-deps.mjs` pattern (AZ-482). The bash function `static_check_no_cross_component_deep_imports` in `scripts/run-tests.sh` is a one-line delegate. The new unit test invokes the script directly with `spawnSync`, so a regex regression in the script trips the test even if the bash glue still reports PASS.
2. **classColors exemption is structural, not stylistic** — Re-exporting `classColors` symbols through the `06_annotations` barrel creates a runtime circular import (`AnnotationsPage → DetectionClasses → 06_annotations barrel → AnnotationsPage`) that materializes as `FALLBACK_CLASS_NAMES === undefined` inside `DetectionClasses`. The exemption is documented in five places (the barrel file, the consumer file, the static-check script's `EXEMPT_RE` comment, `module-layout.md` Layout Rule #3, and the architecture test) so it cannot be forgotten when F3 lands.
3. **`10_app-shell` intentionally has no barrel** — The component is a collection of root-level files (`App.tsx`, `main.tsx`, `index.css`, `vite-env.d.ts`) never imported as a unit. STC-ARCH-01's component allowlist (`api|auth|components|features/[a-z-]+|hooks|i18n`) intentionally omits app-shell; the doc records this explicitly.
4. **Test-file deep-import string concatenation** — `tests/architecture_imports.test.ts` builds its synthetic offending strings via concatenation (`'fr' + 'om'`, `'..' + '/..'`) so the scanner does not flag the test source itself when it walks `tests/`. The fixtures created at runtime go under `tests/_arch_fixtures/` and are torn down in `afterEach`.

## Code Review Verdict: PASS

Self-review (implement skill Step 9 / 10), applied to the 13 new + 17 production + 22 test + 1 runner + 1 doc + 1 script changes:

- **0 Critical, 0 High, 0 Medium, 0 Low findings.**
- **Scope discipline**: every modified file is one of (barrel author, deep-import consumer, static-check author, doc author). The 4 originally-untracked-and-edited test files (`annotations_endpoint`, `destructive_ux`, `form_hygiene`, `overlay_membership`) are pre-existing committed test files where the only edit is import-path migration.
- **No silent error suppression**: `check-arch-imports.mjs` writes the full hit list to stderr before exiting non-zero; the bash delegate propagates the exit code; `run-tests.sh` records the failure into the static CSV.
- **Single-responsibility**: each barrel re-exports its component's documented Public API only. `check-arch-imports.mjs` has one job (detect cross-component deep imports). The new test exercises only that script.
- **No new dependencies**: `check-arch-imports.mjs` uses Node stdlib (`fs`, `path`, `url`) only. The architecture test uses Vitest + Node stdlib.
- **Architecture compliance (Phase 7)**: no layer-direction violations introduced; the only cross-feature edge (`07_dataset → 06_annotations` for `CanvasEditor`, F2) is grandfathered exactly as before — `CanvasEditor` is intentionally re-exported through the `06_annotations` barrel so the consumer is barrel-compliant. STC-ARCH-01 confirms no new cyclic dependencies.

## Auto-Fix Attempts: 1

One auto-fix loop entered during Phase 3 (test import migration):

- **Symptom**: `tests/detection_classes.test.tsx` failed with `TypeError: Cannot read properties of undefined (reading 'map')` after `FALLBACK_CLASS_NAMES` was migrated to import through the `06_annotations` barrel.
- **Diagnosis**: barrel-induced circular import — `AnnotationsPage → DetectionClasses → 06_annotations barrel → AnnotationsPage`. The barrel module evaluated before `classColors` exports were bound, so the symbol resolved to `undefined`.
- **Fix**: remove `classColors` re-exports from the `06_annotations` barrel, document the F3-pending exemption in five places (see Design Decision #2), point the consumer + the test back at the direct path `src/features/annotations/classColors`.
- **Validation**: fast profile back to green; STC-ARCH-01 unit test added an exemption case (`AC-4: still PASSES when only the classColors F3-pending exemption is used`) so the carve-out is regression-tested.

## Stuck Agents: None

No multi-pass investigations beyond the auto-fix above.

## Test Run Summary

- `bun run test:fast` (via `bash scripts/run-tests.sh`) — 27 files / 167 passed / 13 skipped / 21.11 s wall (+4 new tests vs Phase A close at 163; 0 regressions).
- `bash scripts/run-tests.sh --static-only` — 30 / 30 static checks PASS (added `STC-ARCH-01`; no regressions in the existing 29).
- `node scripts/check-arch-imports.mjs` (direct invocation) — exit 0, stderr empty on the migrated codebase; exit 1 on every synthetic fixture in the architecture test.
- `ReadLints` — clean on all 13 new files.
- `git diff --stat` — 41 modified + 13 new files; +113 / -99 net lines; mostly mechanical one-line import path edits.

## Documented Drifts (cumulative across batch)

| Drift | Where | Spec/AC affected | Resolves when |
|-------|-------|------------------|---------------|
| `classColors` symbols cannot flow through the `06_annotations` barrel due to a circular import | `src/features/annotations/index.ts` (export omitted by design); 5 cross-doc mentions | F3 (Medium / Architecture) — `architecture_compliance_baseline.md` | F3 moves `classColors.ts` out of `06_annotations` into its own component directory (`src/shared/classColors.ts` or a dedicated `11_class-colors` directory); F3 closes by adding a `src/<new-home>/index.ts` barrel and removing the STC-ARCH-01 exemption |

(No other drifts surfaced.)

## Phase B Cycle 1 Status

This is **batch 1 of 2** in Phase B cycle 1 (the cycle covers baseline findings F4 + F7 under epic AZ-447). Batch 2 will implement **AZ-486** — endpoint builders in `src/api/endpoints.ts` + `STC-ARCH-02` for hardcoded `/api/<service>/…` paths — which depends on this batch landing first (`endpoints` ships through the new `src/api` barrel; Jira "Blocks" link AZ-485 → AZ-486).

## Next Batch

**AZ-486** (5 pts) — endpoint builders + STC-ARCH-02. Spec already in `_docs/02_tasks/todo/AZ-486_refactor_endpoint_builders.md`.
