From 2071a24391c6e923458b2c941fe06ccaea9cb0eb Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Mon, 11 May 2026 10:14:12 +0300 Subject: [PATCH] [AZ-485] [AZ-486] Phase B Step 9: F4 barrels + F7 endpoints task specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes Step 9 New Task cycle 1. Two refactor tasks created under epic AZ-447 to address architecture compliance baseline findings: - AZ-485 (5 pts) — F4 Public API barrels per component + STC-ARCH-01 - AZ-486 (5 pts) — F7 endpoint builders (endpoints.ts) + STC-ARCH-02 (depends on AZ-485; Jira "Blocks" link set) F1 (mission-planner duplication) deliberately deferred. Baseline routes it through 7+ Phase B port-group cycles requiring decompose pass into its own Epic; out of scope for new-task. _autodev_state.md advances to Step 10 (Implement), awaiting invocation for AZ-485 first. Co-authored-by: Cursor --- _docs/02_tasks/_dependencies_table.md | 9 +- .../AZ-485_refactor_public_api_barrels.md | 133 +++++++++++++++ .../todo/AZ-486_refactor_endpoint_builders.md | 158 ++++++++++++++++++ _docs/_autodev_state.md | 17 +- 4 files changed, 309 insertions(+), 8 deletions(-) create mode 100644 _docs/02_tasks/todo/AZ-485_refactor_public_api_barrels.md create mode 100644 _docs/02_tasks/todo/AZ-486_refactor_endpoint_builders.md diff --git a/_docs/02_tasks/_dependencies_table.md b/_docs/02_tasks/_dependencies_table.md index 82c8cde..e587581 100644 --- a/_docs/02_tasks/_dependencies_table.md +++ b/_docs/02_tasks/_dependencies_table.md @@ -11,13 +11,18 @@ | AZ-452 | C05 — `getApiBase()` accessor | AZ-447 | 3 | None | | AZ-453 | C06 — `navigateToLoginImpl()` accessor | AZ-447 | 2 | None | | AZ-454 | C07 — Document `setToken/getToken` | AZ-447 | 1 | None | +| AZ-485 | C08 (Phase B) — Public API barrels + STC-ARCH-01 | AZ-447 | 5 | None | +| AZ-486 | C09 (Phase B) — Endpoint builders (endpoints.ts) + STC-ARCH-02 | AZ-447 | 5 | AZ-485 | ### Notes (AZ-447) - Epic AZ-447 is the umbrella for the autodev existing-code Step 4 testability run (`01-testability-refactoring`). - AZ-448 and AZ-449 share `src/features/flights/flightPlanUtils.ts` and should land in one commit to avoid a mid-state where the URL still hardcodes a base while the key is externalized. -- Total: 14 complexity points across 7 tasks. **Status: closed** — all tasks done (see `_docs/04_refactoring/01-testability-refactoring/FINAL_report.md`). -- Every task fit the existing-code flow Step 4 allowed-change list (externalize hardcoded URLs/credentials, wrap globals in thin accessors, comment-only documentation). Deferred items are in `_docs/04_refactoring/01-testability-refactoring/deferred_to_refactor.md`. +- C01–C07 (AZ-448 … AZ-454) totalled 14 complexity points; closed in Phase A (see `_docs/04_refactoring/01-testability-refactoring/FINAL_report.md`). +- C08 (AZ-485) and C09 (AZ-486) are Phase B additions covering architecture baseline findings **F4** and **F7** — the two High/Medium baseline findings the Step 4 batch deferred. They share AZ-447 because they are mechanical testability refactors of the same shape; total 10 additional complexity points across the two tasks. +- AZ-486 depends on AZ-485 — `endpoints` ships through the `src/api` barrel introduced by AZ-485, and a "Blocks" link is set in Jira. +- **F1** (mission-planner duplication, Critical) is deliberately NOT in this epic. Per baseline routing it requires 7+ port-group Phase B feature cycles; it will be decomposed in a separate `/decompose` session and own its own Epic. +- Deferred Step 4 items remain in `_docs/04_refactoring/01-testability-refactoring/deferred_to_refactor.md` for traceability. --- diff --git a/_docs/02_tasks/todo/AZ-485_refactor_public_api_barrels.md b/_docs/02_tasks/todo/AZ-485_refactor_public_api_barrels.md new file mode 100644 index 0000000..89471cb --- /dev/null +++ b/_docs/02_tasks/todo/AZ-485_refactor_public_api_barrels.md @@ -0,0 +1,133 @@ +# Public API barrels per component + deep-import migration + +**Task**: AZ-485_refactor_public_api_barrels +**Name**: Add Public API barrels and migrate cross-component imports +**Description**: Introduce `index.ts` barrels for every component, narrow each component's Public API to the symbols listed in `module-layout.md`, replace every cross-component deep import with a barrel import, and add a static check that flags future deep imports. Closes architecture baseline finding **F4**. +**Complexity**: 5 points +**Dependencies**: None +**Component**: cross-cutting (00–10) — coordinated edit across `src/api/`, `src/auth/`, `src/components/`, `src/features/**/`, `src/hooks/`, `src/i18n/`, `src/App.tsx`, plus every test importer +**Tracker**: AZ-485 +**Epic**: AZ-447 + +## Problem + +`_docs/02_document/architecture_compliance_baseline.md` Finding **F4** (High / Architecture): no component currently exposes a barrel `index.ts` (the sole barrel today is `src/types/index.ts`, owned by `00_foundation`). Cross-component imports use file-name granularity (`import { api } from '../api/client'`, `import { useFlight } from '../components/FlightContext'`, …). Consequence: + +1. There is no enforceable Public API surface — every internal file is de-facto public. +2. Any internal split / rename inside a component is a breaking change to ~10 importers. +3. Phase 7 architecture compliance ("Public API respect") cannot fail in this codebase because everything is public. +4. The next time `module-layout.md` flags a Public-API drift, no static gate exists to catch it. + +`module-layout.md` Layout Rules #3 records the same observation and lists this as a Step 4 testability candidate; Step 4 deferred it to Phase B (`_autodev_state.md::step_2_baseline_routing: per-finding-recommended`). + +## Outcome + +- Every component listed in `module-layout.md`'s "Per-Component Mapping" exposes its Public API through a barrel `index.ts` at the component root (10 new files; `src/types/index.ts` is unchanged). +- Every cross-component import in `src/**` and `tests/**` resolves through a component barrel — no remaining deep imports of another component's internal files. `mission-planner/**` is exempt (untouched per F1's deferred convergence plan). +- A static check (added to `scripts/run-tests.sh`) fails the static profile if any new `src/**` or `tests/**` file imports a non-barrel path from another component. +- `_docs/02_document/module-layout.md` Layout Rules #3 is rewritten to describe the post-change state ("Each component exposes its Public API via `src//index.ts`. Cross-component imports MUST use the barrel. The static gate `STC-ARCH-01` enforces this."). +- All existing fast + static profiles remain green after the migration. + +## Scope + +### Included +- Create 10 new barrels (`src/api/index.ts`, `src/auth/index.ts`, `src/components/index.ts`, `src/features/{login,flights,annotations,dataset,admin,settings}/index.ts`, `src/hooks/index.ts`, `src/i18n/index.ts`). Each barrel re-exports ONLY the symbols listed for that component in `module-layout.md`'s "Per-Component Mapping" → "Public API (de-facto)". +- Replace every cross-component deep import (~30 sites across `src/App.tsx`, every feature page that imports from another component, and every `tests/**` and colocated `*.test.tsx` that imports a production symbol from another component) with a barrel import. +- Add a new static check `STC-ARCH-01` to `scripts/run-tests.sh` that fails the static profile if any `src/**` or `tests/**` file (excluding the barrel itself, `mission-planner/**`, and intra-component imports) imports a non-barrel path from a different component. +- Update `_docs/02_document/module-layout.md` Layout Rules #3 to reflect the post-change state and add `STC-ARCH-01` to the Static Checks inventory (if such a list exists; otherwise document inline). + +### Excluded +- `src/types/index.ts` is already a barrel — left unchanged. +- `mission-planner/**` — untouched (F1's deferred convergence plan; will be deleted in the final Phase B port cycle per the baseline). +- F2 (`07_dataset → 06_annotations` cross-feature edge for `CanvasEditor`) — `CanvasEditor` STAYS in the `06_annotations` barrel's Public API list (the cross-feature edge is grandfathered in `module-layout.md` and is closed by F2, not F4). +- F3 (`classColors.ts` physical/logical owner split) — the file remains physically under `src/features/annotations/`; F4 lists it in the `06_annotations` barrel for now. Physical move is F3's own task. +- New runtime behavior — this is a structural refactor only. + +## Acceptance Criteria + +**AC-1: Every component has a barrel exposing only its Public API** +Given the post-change repo, +When `src//index.ts` is read for every component listed in `module-layout.md`, +Then the file exists, every named export matches a symbol in that component's "Public API (de-facto)" line in `module-layout.md`, and no internal-only file's symbol is re-exported. + +**AC-2: No cross-component deep imports remain in production code** +Given the post-change repo, +When `ripgrep "^(import|export).*from\s+['\"]\.\.\/[a-z][^'\"]*\/[A-Za-z][^'\"]+['\"]" src/` is run, excluding intra-component paths (paths that resolve to the same component's owned directory), +Then no match is found. + +**AC-3: No cross-component deep imports remain in tests** +Given the post-change repo, +When the same ripgrep is run across `tests/**`, `e2e/**`, and colocated `**/*.test.{ts,tsx}` files, +Then no match is found OUTSIDE the documented testability exemptions in `module-layout.md` "Blackbox Tests" entry (test infrastructure may import testability accessors like `setToken`, `setNavigateToLogin`, `AuthProvider`, and i18n directly per the existing exemption — those continue to use barrel paths now that the barrels re-export them). + +**AC-4: Static gate STC-ARCH-01 fails on a newly-introduced deep import** +Given the post-change static profile, +When a synthetic test file is added that imports `'../api/client'` instead of `'../api'` (or equivalent for another component), +Then `bash scripts/run-tests.sh --static` exits non-zero with `STC-ARCH-01` named in the failure line. + +**AC-5: Static gate STC-ARCH-01 passes on the migrated codebase** +Given the post-change repo, +When `bash scripts/run-tests.sh --static` runs, +Then it exits zero and the static report shows `STC-ARCH-01` as PASS. + +**AC-6: Fast profile remains green** +Given the post-change repo, +When `bash scripts/run-tests.sh --fast` runs, +Then it reports the same PASS / SKIP / FAIL counts as the pre-change baseline (163 PASS / 13 SKIP / 0 FAIL per `_docs/03_implementation/test_run_report.md`), with zero new failures and zero regressions in skip-classification. + +**AC-7: module-layout.md reflects the new convention** +Given the post-change repo, +When `_docs/02_document/module-layout.md` Layout Rules #3 is read, +Then it states "Each component exposes its Public API via `src//index.ts`. Cross-component imports MUST use the barrel. The static gate `STC-ARCH-01` enforces this." and the Verification Needed item referencing the missing barrels is removed (or marked closed by this task's tracker ID). + +## Non-Functional Requirements + +**Performance** +- Initial JS bundle gzipped size MUST remain ≤ 2 MB (existing `STC-PERF01`). Barrel re-exports tree-shake under Vite's production rollup, so no regression expected. + +**Compatibility** +- No runtime behavior change. The fast + e2e suites are the contract; both stay green. + +**Maintainability** +- Future internal renames inside a component MUST not require import-path edits outside that component (validated by AC-2/AC-3 + STC-ARCH-01). + +## Unit Tests + +| AC Ref | What to Test | Required Outcome | +|--------|--------------|------------------| +| AC-1 | Each barrel file re-exports only documented symbols | Re-export list matches `module-layout.md`'s Public API line for that component (test reads both files and compares) | +| AC-4 | Synthetic deep-import detection | `STC-ARCH-01` fails when a fixture file with a deep import is added | +| AC-5 | Static check on the real codebase | `STC-ARCH-01` passes | + +## Blackbox Tests + +| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | +|--------|-------------------------|--------------|-------------------|----------------| +| AC-2 | Repo after migration | `ripgrep` for cross-component deep imports in `src/` | Zero matches | Maintainability | +| AC-3 | Repo after migration | `ripgrep` for cross-component deep imports in `tests/`, `e2e/`, colocated tests | Zero matches outside documented exemptions | Maintainability | +| AC-6 | Fast profile | `scripts/run-tests.sh --fast` | 163 PASS / 13 SKIP / 0 FAIL (matches `_docs/03_implementation/test_run_report.md`) | Compat | + +## Constraints + +- All 10 barrels + import migration + static check MUST land in ONE commit to keep mid-state green (partial migration breaks the static gate on intermediate commits). If commit size is impractical, split per-component but always under one PR atomic to merge. +- The barrel files are OWNED by each respective component (e.g. `src/api/index.ts` is OWNED by `01_api-transport` tasks); the static check addition to `scripts/run-tests.sh` is OWNED by `Blackbox Tests` per `module-layout.md`. +- No new dependencies. The static check uses `ripgrep` (already used elsewhere in `scripts/run-tests.sh`). +- `mission-planner/**` MUST be untouched. + +## Risks & Mitigation + +**Risk 1: A cohort import-path edit misses a transitive import path → fast suite goes red on TypeScript "module not found"** +- *Risk*: ~30 import statements across many files; mechanical edit can miss one. +- *Mitigation*: Run `bun tsc -b --noEmit` (or the project's `lint:tests` script) after every per-component batch; commit only when type-check is green. AC-6 (full fast profile) is the final gate. + +**Risk 2: Vite tree-shaking regression — barrel re-exports drag in optional sub-modules** +- *Risk*: A barrel that re-exports rarely-used symbols can defeat tree-shaking and inflate the bundle. +- *Mitigation*: STC-PERF01 already caps gzipped bundle at 2 MB and runs in the static profile. The migration must keep that gate green. If bundle regresses, split the barrel into eager + lazy re-export blocks per Vite's recommendations. + +**Risk 3: `CanvasEditor` cross-feature edge (F2) confuses the static check** +- *Risk*: `src/features/dataset/DatasetPage.tsx` legitimately imports `CanvasEditor` from `src/features/annotations/`. STC-ARCH-01 must allow this when it goes through the `06_annotations` barrel but flag the legacy direct path. +- *Mitigation*: After migration, the dataset import becomes `import { CanvasEditor } from '../annotations'` — passes the barrel-path check. F2's eventual `CanvasEditor` lift is independent of this task. + +## Contract + +This task produces the Public API contract for 10 components — the barrel re-export lists ARE the contract. The contract surface for each component is documented inline at `_docs/02_document/module-layout.md` "Per-Component Mapping" → "Public API (de-facto)"; this task does not create a new contract file but DOES update Layout Rules #3 to declare the barrel files as the canonical Public API surface (no longer "de-facto"). diff --git a/_docs/02_tasks/todo/AZ-486_refactor_endpoint_builders.md b/_docs/02_tasks/todo/AZ-486_refactor_endpoint_builders.md new file mode 100644 index 0000000..4fc38f9 --- /dev/null +++ b/_docs/02_tasks/todo/AZ-486_refactor_endpoint_builders.md @@ -0,0 +1,158 @@ +# Endpoint builders — replace hardcoded `/api//...` strings + +**Task**: AZ-486_refactor_endpoint_builders +**Name**: Introduce `endpoints.ts` and replace hardcoded API paths +**Description**: Add `src/api/endpoints.ts` exporting typed endpoint builders, replace every hardcoded `/api//...` string literal in production code with the corresponding builder call, and add a static check that flags new string literals. Closes architecture baseline finding **F7**. +**Complexity**: 5 points +**Dependencies**: AZ-485_refactor_public_api_barrels (F4 lands first so `endpoints` ships through the `src/api` barrel) +**Component**: `01_api-transport` (owner of new file + barrel re-export) + every component that calls `api.*` or `createSSE`: `02_auth`, `03_shared-ui`, `06_annotations`, `07_dataset`, `08_admin`, `09_settings`, `05_flights` +**Tracker**: AZ-486 +**Epic**: AZ-447 + +## Problem + +`_docs/02_document/architecture_compliance_baseline.md` Finding **F7** (Medium / Architecture): every `api.*()` and `createSSE()` callsite repeats `/api//` as a string literal. ~25 hardcoded paths across 11 source files (`src/auth/AuthContext.tsx`, `src/api/client.ts`, `src/features/{admin,settings,annotations,dataset,flights}/**`, `src/components/{FlightContext,DetectionClasses}.tsx`). + +Consequences (per ADR-006 Consequences and the baseline doc): +1. Every test fixture must duplicate paths — and MSW handlers, e2e stubs, and unit tests all drift independently. +2. Any nginx-route rename (ADR-006 prefix-strip changes) touches every feature. +3. There is no single source of truth for the wire-contract paths. + +`module-layout.md` Verification Needed item references the same observation. Step 4 (testability) deferred this finding to Phase B per the per-finding routing decision. + +## Outcome + +- A new module `src/api/endpoints.ts` exports a typed `endpoints` object with function-form builders for every path in use today. +- Every callsite of `api.get/post/put/upload/del` and `subscribeSSE`/`createSSE` across `src/**` (excluding `src/api/endpoints.ts` itself and test files) uses an `endpoints.*` call — no string literals matching `/api//` remain in production code. +- The `endpoints` symbol is re-exported from `src/api/index.ts` (the F4 barrel). +- A new static check `STC-ARCH-02` fails the static profile if any production file (excluding `endpoints.ts`, tests, and MSW handlers) contains a string literal matching `/api//`. +- Unit tests assert each builder returns the contract-correct URL string. +- MSW handlers and e2e stubs continue to match the exact same URLs — no wire-contract change. +- `_docs/02_document/module-layout.md` adds `endpoints.ts` to the `01_api-transport` Public API and adds `STC-ARCH-02` to the static-check inventory. + +## Scope + +### Included +- New file `src/api/endpoints.ts` with the `endpoints` object — function form everywhere, e.g.: + - `endpoints.admin.authRefresh()` → `'/api/admin/auth/refresh'` + - `endpoints.admin.users()` → `'/api/admin/users'` + - `endpoints.admin.user(id)` → `` `/api/admin/users/${id}` `` + - `endpoints.flights.aircrafts()` → `'/api/flights/aircrafts'` + - `endpoints.flights.liveGps(flightId)` → `` `/api/flights/${flightId}/live-gps` `` + - `endpoints.annotations.classes()`, `endpoints.annotations.annotations()`, `endpoints.annotations.dataset()`, `endpoints.annotations.datasetBulkStatus()`, `endpoints.annotations.datasetClassDistribution()`, `endpoints.annotations.mediaBatch()`, `endpoints.annotations.settingsSystem()`, `endpoints.annotations.settingsDirectories()`, `endpoints.annotations.settingsUser()`, `endpoints.annotations.detection(query?)`, … +- Update `src/api/index.ts` (barrel from F4) to re-export `endpoints`. +- Replace ~25 hardcoded path literals in: + - `src/auth/AuthContext.tsx` + - `src/api/client.ts` (the refresh callsite) + - `src/features/admin/AdminPage.tsx` + - `src/features/settings/SettingsPage.tsx` + - `src/features/annotations/AnnotationsPage.tsx` + - `src/features/annotations/AnnotationsSidebar.tsx` + - `src/features/annotations/MediaList.tsx` + - `src/features/dataset/DatasetPage.tsx` + - `src/features/flights/FlightsPage.tsx` + - `src/components/FlightContext.tsx` + - `src/components/DetectionClasses.tsx` +- Add unit tests in `src/api/endpoints.test.ts` (one assertion per builder verifying the literal URL string — the test file IS the contract). +- Add static check `STC-ARCH-02` to `scripts/run-tests.sh` (ripgrep `'/api/[a-z-]+/'` across `src/**` excluding `endpoints.ts` and `*.test.{ts,tsx}` and `tests/**`). +- Update `_docs/02_document/module-layout.md` `01_api-transport` row to add `endpoints` to Public API and add `STC-ARCH-02` to the static-check inventory. + +### Excluded +- F6 (introduce `src/shared/`) — `endpoints.ts` lives at `src/api/endpoints.ts` for now (under `01_api-transport`). When/if F6 lands later it can move to `src/shared/endpoints.ts` with no callsite change (barrel insulates callers). +- The base URL itself (`/api`) — `getApiBase()` already exists in `src/api/client.ts` and is handled separately. `endpoints.ts` returns paths starting with `/api/`; the client prepends the base. +- Tests and MSW handlers — tests CAN use `endpoints.*` for readability, but their hardcoded paths are not in scope of this task's deletion sweep. The static check explicitly exempts test paths. +- `mission-planner/**` — untouched (deferred per F1). +- Any change to wire-contract paths. The literal URL strings produced by builders MUST exactly match the strings currently in code (and exactly match what MSW/e2e stubs intercept today). + +## Acceptance Criteria + +**AC-1: All current paths have builders** +Given the post-change `src/api/endpoints.ts`, +When the unit test enumerates every builder and asserts the produced URL, +Then every URL currently in source (per the F7 inventory above) is reproduced exactly — character-identical to today's literal. + +**AC-2: No hardcoded `/api//` literals remain in production** +Given the post-change repo, +When `ripgrep "'/api/[a-z-]+/"` runs over `src/**` excluding `src/api/endpoints.ts`, `**/*.test.{ts,tsx}`, and `tests/**`, +Then zero matches are found. + +**AC-3: Static gate STC-ARCH-02 fails on a synthetic literal** +Given the post-change static profile, +When a synthetic edit reintroduces `await api.get('/api/admin/users/me')` to any production file, +Then `bash scripts/run-tests.sh --static` exits non-zero with `STC-ARCH-02` named in the failure line. + +**AC-4: Static gate STC-ARCH-02 passes on the migrated codebase** +Given the post-change repo, +When `bash scripts/run-tests.sh --static` runs, +Then it exits zero and the static report shows `STC-ARCH-02` as PASS. + +**AC-5: Fast profile remains green** +Given the post-change repo, +When `bash scripts/run-tests.sh --fast` runs, +Then it reports the same PASS / SKIP / FAIL counts as the pre-change baseline (163 PASS / 13 SKIP / 0 FAIL plus the new `endpoints.test.ts` PASSes) with zero new failures and zero regressions. + +**AC-6: Endpoint builders are exposed through the F4 barrel** +Given the post-change repo, +When any production file imports `{ endpoints }` from `'../api'` (or relative equivalent), +Then the import resolves through `src/api/index.ts` and `endpoints` is the typed object defined in `src/api/endpoints.ts`. + +**AC-7: MSW handlers and e2e stubs continue to match** +Given the post-change repo, +When the fast and (deferred-but-runnable) e2e profiles run, +Then every MSW intercept hits its target unchanged — no "intercepted a request without a matching request handler" error appears, confirming character-identical URLs. + +## Non-Functional Requirements + +**Performance** +- Initial JS bundle gzipped size MUST remain ≤ 2 MB (existing `STC-PERF01`). The `endpoints` object is tree-shakeable per builder; impact ≤ 1 KB. + +**Maintainability** +- A nginx-route rename (per ADR-006) requires editing one file (`endpoints.ts`) — validated by AC-2. + +**Compatibility** +- Zero wire-contract change (validated by AC-1 character-equality + AC-7 MSW + e2e). + +## Unit Tests + +| AC Ref | What to Test | Required Outcome | +|--------|--------------|------------------| +| AC-1 | Every builder produces the contract-correct URL string | `endpoints.admin.authRefresh()` === `'/api/admin/auth/refresh'`; same for every builder, character-identical | +| AC-1 | Builders that take params interpolate correctly | `endpoints.admin.user('abc')` === `'/api/admin/users/abc'` | +| AC-3 | STC-ARCH-02 fails on synthetic deep-literal | Static profile non-zero, error names `STC-ARCH-02` | +| AC-4 | STC-ARCH-02 passes on migrated codebase | Static profile zero, STC-ARCH-02 PASS row | +| AC-6 | `endpoints` is re-exported from `src/api/index.ts` | `import { endpoints } from 'src/api'` resolves; the imported value is identical to the one in `src/api/endpoints.ts` | + +## Blackbox Tests + +| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References | +|--------|-------------------------|--------------|-------------------|----------------| +| AC-2 | Repo after migration | `ripgrep "'/api/[a-z-]+/"` over `src/` minus exemptions | Zero matches | Maintainability | +| AC-5 | Fast profile | `scripts/run-tests.sh --fast` | 163 PASS + new `endpoints.test.ts` PASSes / 13 SKIP / 0 FAIL | Compat | +| AC-7 | Fast profile | MSW unhandled-request gate | No "intercepted a request without a matching request handler" errors | Compat | + +## Constraints + +- Lands AFTER 01_refactor_public_api_barrels (F4). The `endpoints` symbol is re-exported from `src/api/index.ts` (the barrel); without F4, callsites would deep-import from `src/api/endpoints` and reintroduce the F4 violation. +- The literal URLs produced by builders MUST be character-identical to today's literals. AC-1 validates this in unit tests; AC-7 validates it against MSW handlers; the (deferred) e2e profile validates it against the suite-e2e nginx routes. +- All changes land in ONE commit (the static check would otherwise fail on intermediate commits). +- `mission-planner/**` MUST be untouched. + +## Risks & Mitigation + +**Risk 1: A path literal is missed and remains in source** +- *Risk*: 25 sites is enough for a manual edit to miss one. The miss would not show up in fast tests (MSW intercepts both styles); STC-ARCH-02 is the only gate that catches it. +- *Mitigation*: STC-ARCH-02 is the SINGLE source of truth for "no literals remain". The static profile is run BEFORE commit; commit is blocked if STC-ARCH-02 fails. + +**Risk 2: An optional query-string param is missed in the builder API** +- *Risk*: e.g. `endpoints.annotations.detection()` may need to accept an optional `imageId` query string; missing the param forces the caller back to string concatenation, defeating the abstraction. +- *Mitigation*: Inventory the existing callsites BEFORE writing builders. Every callsite's full URL shape (path + query) must map cleanly to one builder. Document the inventory in the batch report. + +**Risk 3: F6 lands later and `endpoints.ts` needs to move to `src/shared/endpoints.ts`** +- *Risk*: A future F6 task may move the file. +- *Mitigation*: Acceptable. Callers import from the `src/api` barrel (or whatever barrel ends up re-exporting `endpoints` after the move). A single barrel edit re-routes all consumers. This is exactly the benefit F4 was meant to provide. + +## Contract + +This task produces the wire-path contract for the UI ↔ nginx layer. The contract surface IS the `endpoints` object as exported from `src/api/endpoints.ts`. The accompanying unit test (`src/api/endpoints.test.ts`) asserts every URL string and serves as the contract documentation — any future path change MUST update both the builder and the test in the same commit. + +A standalone contract file at `_docs/02_document/contracts/api-transport/endpoints.md` MAY be added in a follow-up task; for this task the test file is the authoritative contract per `module-layout.md`'s "code-derived documentation" pattern. diff --git a/_docs/_autodev_state.md b/_docs/_autodev_state.md index 3951f6f..c208a7d 100644 --- a/_docs/_autodev_state.md +++ b/_docs/_autodev_state.md @@ -2,13 +2,13 @@ ## Current Step flow: existing-code -step: 9 -name: New Task -status: in_progress +step: 10 +name: Implement +status: not_started sub_step: - phase: 1 - name: gather-feature-description - detail: "" + phase: 0 + name: awaiting-invocation + detail: "Step 9 closed; AZ-485 (F4 barrels) + AZ-486 (F7 endpoints) ready in todo/; AZ-485 first (AZ-486 depends on barrel)" retry_count: 0 cycle: 1 tracker: jira @@ -29,3 +29,8 @@ step_3_ac_gap_handling: rollback-to-6c (option A) `_docs/03_implementation/cumulative_review_batches_04-06_cycle1_report.md`, `_docs/03_implementation/cumulative_review_batches_07-08_cycle1_report.md` (cycle close — Phase A wrap, no batch 9). +- Phase B started. Step 9 (New Task) cycle 1 closed: + - AZ-485 (F4 — Public API barrels + STC-ARCH-01, 5 pts, no deps) + - AZ-486 (F7 — Endpoint builders + STC-ARCH-02, 5 pts, blocked by AZ-485) + - F1 (mission-planner convergence) deliberately not created — needs `/decompose` for 7+ port-group cycles in its own Epic. +- Step 10 (Implement) starts with AZ-485 — `Blackbox Tests` owns the static-check addition and the `tests/**` import-path migration; production component teams own their barrel files per `module-layout.md`.