docs: Step 4 testability refactor — list-of-changes + 2 task specs

autodev existing-code Step 4 (Code Testability Revision) — invoked
refactor skill in guided mode. Phase 0 (baseline) + Phase 1 (discovery
+ validation) + Phase 2 (analysis + task decomposition) artifacts.

list-of-changes.md identifies two surgical fixes required before the
67-scenario blackbox suite (already specified in _docs/02_document/
tests/) can run against the SUT:

  C01 — env-gate JWKS RequireHttps on ASPNETCORE_ENVIRONMENT=E2ETest
       (architecture.md Open Risks Section 6 prescribes this; the
       mock issuer in e2e/docker-compose.test.yml serves plain HTTP)

  C02 — DNS-resolve RABBITMQ_HOST in FailsafeProducer.ProcessQueue
       (IPAddress.Parse currently throws on every drain cycle when
       host is a service name; latent production-relevant bug, not
       just a test-env issue)

Two task specs in _docs/02_tasks/todo/ (3 story points total).
Independent — no inter-task dependency.

Tracker: local — Atlassian MCP reported errored at task-creation
time. Deferred Jira writes (epic + 2 tickets) recorded in
_docs/_process_leftovers/2026-05-14_testability-tracker.md for
replay when MCP is restored.

Items explicitly deferred to Step 8 Refactor are enumerated in
list-of-changes.md "Deferred to Step 8 Refactor" — including the
FailsafeProducer static helper (F3), the JWKS GetAwaiter().GetResult()
hot path, RB-05/06/08 backlog items, and the MediaService ffprobe
empty-catch.

State: Step 4 in_progress, sub_step 3 (phase-2-task-decomposition).
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-14 20:19:27 +03:00
parent 03f879206e
commit 13e9731a8f
12 changed files with 775 additions and 0 deletions
@@ -0,0 +1,65 @@
# Baseline Metrics — 01-testability-refactoring
**Run**: 01-testability-refactoring
**Date**: 2026-05-14
**Mode**: guided (testability)
**Scope**: minimal-surgical refactor to make the documented test suite runnable. Many baseline categories are **N/A** by design because no executable test suite exists yet (this run produces the *prerequisites* for the suite to be implemented in Step 6).
## Goals (from `list-of-changes.md` Summary)
1. Unblock authenticated-endpoint tests by gating the JWKS retriever's HTTPS requirement on `ASPNETCORE_ENVIRONMENT=E2ETest`.
2. Unblock outbox-drain tests by fixing the `IPAddress.Parse` assumption in `FailsafeProducer` so DNS hostnames (the documented and operationally normal case) resolve correctly.
Both goals derive directly from `_docs/02_document/tests/` and `_docs/02_document/architecture.md` Open Risks §6.
## Acceptance Criteria
This run completes when:
- C01 and C02 are applied to source and build cleanly under `dotnet build src/`.
- The refactored code preserves every existing behavior outside the documented testability surface (verified by code review in Phase 6, not by an executing test suite that does not yet exist).
- `architecture.md` Open Risks §6 is updated (entry retired, replaced by the implemented gating).
- A `testability_changes_summary.md` is written and presented to the user.
## Baseline Metrics
| Metric Category | Captured? | Value / Reason |
|----------------|-----------|----------------|
| Coverage (overall / unit / blackbox / critical paths) | **N/A** | No executable test suite exists in this repo today. `_docs/02_document/tests/` contains 67 *test specifications* but zero implemented tests. This is precisely why Step 4 (testability) precedes Step 6 (Implement Tests). |
| Cyclomatic complexity (avg + top 5) | Captured (rough) | `src/Auth/JwtExtensions.cs` — 1 method (`AddJwtAuth`), cyclomatic ~3 (one inline resolver lambda with a kid-null branch). `src/Services/FailsafeProducer.cs``DrainQueue` is the hot function, cyclomatic ~7 (foreach + nested foreach + 3 branches for operation type). No top-5 needed for a 2-file scope. |
| LOC (target files) | Captured | `JwtExtensions.cs` = 89 LOC. `FailsafeProducer.cs` = 206 LOC. |
| Tech debt ratio | **N/A** | No SonarQube / dotnet-counters baseline in this repo. The architecture compliance baseline (`_docs/02_document/architecture_compliance_baseline.md`) is the qualitative substitute — verdict PASS_WITH_WARNINGS, 0 Critical, 0 High, 1 Medium, 2 Low. |
| Total / critical / major code smells | Captured (qualitative) | From baseline: F1 (Medium — DatasetService writes annotation table — out of scope here, RB-08), F2 (Low — ClassesController bypasses service — out of scope, RB-06), F3 (Low — `FailsafeProducer.EnqueueAsync` static — accepted tech debt). None in the C01/C02 affected lines. |
| Response times P50/P95/P99 | **N/A** | No load harness yet; perf tests are spec'd in `_docs/02_document/tests/performance-tests.md` but not implemented. Step 15 (Performance Test) is where these get measured. |
| CPU / Memory baseline | **N/A** | Same as above. |
| Throughput | **N/A** | Same as above. |
| Dependency count (target files) | Captured | `JwtExtensions.cs` deps: `Microsoft.AspNetCore.Authentication.JwtBearer`, `Microsoft.IdentityModel.Protocols`, `Microsoft.IdentityModel.Tokens` (all pinned in `src/Azaion.Annotations.csproj`). `FailsafeProducer.cs` deps: `LinqToDB`, `RabbitMQ.Stream.Client`, `MessagePack`, `System.Net` (BCL). No new dependencies added by C01/C02. |
| Outdated dependencies | **N/A** | Out of scope for testability. |
| Security vulnerabilities | **N/A** | Step 14 (Security Audit) — separate concern. The change does not introduce new attack surface (C01 narrows by env, C02 same threat model). |
| Build time | Captured | Not measured today; not material to a 2-file change. Phase 6 will run `dotnet build` and confirm it remains green. |
| Test execution time | **N/A** | No tests yet. |
| Deployment time | **N/A** | Out of scope. |
## Functionality Inventory — affected surface
| Endpoint / Background work | File(s) | Affected by | Behavioral change visible to a consumer? |
|----------------------------|---------|-------------|-----------------------------------------|
| All `[Authorize]`-protected endpoints (everything except `/health`) | `src/Auth/JwtExtensions.cs` | C01 | In `ASPNETCORE_ENVIRONMENT=E2ETest`, the SUT will fetch JWKS over HTTP. In all other environments (Development, Production), behavior is identical — `RequireHttps=true` remains the default. |
| `FailsafeProducer` (`BackgroundService`) drain loop | `src/Services/FailsafeProducer.cs` | C02 | When `RABBITMQ_HOST` is a literal IP: no behavioral change. When `RABBITMQ_HOST` is a DNS hostname: the producer now connects (previous behavior: throws `FormatException` every 10 s, outbox never drains). |
| `AnnotationService.CreateAnnotation``FailsafeProducer.EnqueueAsync` (static, synchronous outbox insert) | `src/Services/AnnotationService.cs:102` | not affected | No change. |
| Public API surface (DTOs, OpenAPI shape) | `src/DTOs/`, controllers | not affected | No change. |
## Reproducibility
- Source state captured by git commit at the start of this run (next commit after `_docs/_autodev_state.md` step-4 in_progress write).
- Both files have local line numbers documented in `list-of-changes.md` for unambiguous before/after diffing.
- No external tooling required beyond `dotnet build` and a `grep` over the two affected files post-change.
## Self-verification
- [x] RUN_DIR created with prefix `01-testability-refactoring` (no prior `NN-*` folders in `_docs/04_refactoring/`).
- [x] Goals documented; map 1:1 to `list-of-changes.md` entries.
- [x] Acceptance criteria stated and measurable.
- [x] Metric categories captured OR explicitly marked N/A with reason.
- [x] Functionality inventory covers every public-API impact of C01 and C02.
- [x] Measurements are reproducible from the listed files + a clean checkout.