mirror of
https://github.com/azaion/annotations.git
synced 2026-06-21 16:51:07 +00:00
03f879206e
This commit captures everything produced during autodev existing-code Steps 1 (Document), 2 (Architecture Baseline Scan), and 3 (Test Spec), together with the targeted auth + CORS re-sync triggered on 2026-05-14 when codebase drift was detected at Step 4 entry. None of this work was previously committed. Step 1 (Document) — 50+ _docs/02_document/ files: problem, solution, architecture, system flows, glossary, module-layout, per-component specs (01..06), modules, deployment, diagrams, data model, FINAL report, verification log, discovery. Step 2 (Architecture Baseline) — architecture_compliance_baseline.md. Verdict PASS_WITH_WARNINGS (0 Critical, 0 High, 1 Medium, 2 Low). No High/Critical findings; auto-chained to Step 3 per existing-code flow. Step 3 (Test Spec) — _docs/02_document/tests/* (67 scenarios across blackbox, security, resilience, resource-limit, performance), plus e2e/docker-compose.test.yml, e2e/seed/run.sh, scripts/run-tests.sh, scripts/run-performance-tests.sh. Coverage 88% over the active scope (40 of 45 items covered, 6 RB-deferred, 5 documented-as-uncovered). Targeted auth + CORS re-sync — replaces the deleted in-house token issuer with a JWKS-verifier model. AuthController and TokenService removed; JwtExtensions switched from HS256 symmetric to ES256 over admin's JWKS. ConfigurationResolver and CorsConfigurationValidator added under src/Infrastructure/. ADR-002 and ADR-006 retired; SEC-01, SEC-02, SEC-03 marked Closed. One new testability risk recorded in architecture.md Open Risks Section 6 (JWKS HTTPS gating). Source changes: - src/Auth/JwtExtensions.cs (modified) — ES256, JWKS, alg pinning - src/Program.cs (modified) — DI wiring for ConfigurationResolver and CorsConfigurationValidator - src/Controllers/AuthController.cs (deleted) — no in-service issuance - src/Services/TokenService.cs (deleted) — same - src/Infrastructure/ConfigurationResolver.cs (new) - src/Infrastructure/CorsConfigurationValidator.cs (new) - .env.example (new) — required env var documentation - .gitignore (updated) Cross-repo coordination: _docs/cross-repo/flights_h1_h2_h3_change_spec captures the change-spec for downstream services that consumed the now deleted /auth endpoints. Co-authored-by: Cursor <cursoragent@cursor.com>
11 KiB
11 KiB
Step 4 — Verification Log
Verification pass over _docs/02_document/ against src/ source.
Scope
Documents verified:
architecture.mdsystem-flows.mddata_model.mddeployment/{containerization,ci_cd_pipeline,environment_strategy,observability}.mddiagrams/flows/{flow_annotation_create,flow_sse_subscription,flow_failsafe_drain}.md- (sanity re-check only)
module-layout.md,components/*/description.md,modules/*.md
Method
For each generated artifact:
- Extracted code-entity references (controllers, services, methods, DTOs, env vars, table/column names, route paths).
- Cross-referenced each against the actual source (
src/Program.cs,src/Controllers/*,src/Services/*,src/Database/*,src/Enums/*,src/DTOs/*,.woodpecker/build-arm.yml,src/Dockerfile). - Re-traced each system flow's mermaid sequence against the corresponding service/controller code.
- Listed corrections, applied them inline to the affected files, and recorded them below.
Counts
| Item | Verified | Corrected | Open question |
|---|---|---|---|
| Controllers + their routes | 6 | 0 | 0 |
| Services + their public methods | 8 | 0 | 0 |
| DB tables / columns | 9 / ~60 | 0 | 5 (lazy upsert / media.duration / class catalog mutability / id collision / outbox JSON shape) |
| Enums | 7 | 0 | 0 |
| Env vars | 8 | 0 | 0 |
| Flows | 8 | 4 (F1, F7, F8, dependencies table) | 6 (consolidated below) |
| ADRs | 7 | 1 (ADR-004 hash details) | 0 |
Module-level coverage: 11 / 11 modules documented; 6 / 6 components assembled.
Corrections applied inline
architecture.md
- Internal communication table: tightened to reflect that SSE publish + outbox enqueue happen only on
CreateAnnotation; outbox enqueue is gated bysystem_settings.silent_detection. Added explicit row notingDatasetServicewrites are silent on SSE/outbox today. - ADR-004 (annotation id hash): replaced "hash of bytes" with the actual
ComputeHashstrategy —XxHash64over a deterministic sample (length prefix + head/middle/tail 1 KB for inputs > 3072 bytes; full bytes otherwise). Documented collision implication. - Open Architectural Risks: rewrote with verified findings — silent Update/Delete/dataset paths,
silent_detectionsemantics, F1 non-atomicity, staticEnqueueAsyncvs project rule. - Section 4 "Data flow summary": split into Create-only / Update-and-friends / read paths, removed the inaccurate claim that thumbnails are produced inline by Create.
system-flows.md
- F1 sequence + data flow + error scenarios: replaced with the verified ordering — image file → optional media row → annotation → detections (
BulkCopyAsync) → label file → SSE publish → conditional outbox enqueue. Removed thumbnail write from the Create path. - F7 ("Reset call missed" risk): removed — verified that
SettingsServicecallspathResolver.Reset()at lines 71 and 85 ofServices/SettingsService.cs. Replaced with a "Verified" note. - F8 (Dataset bulk status): rewrote —
DatasetService.UpdateStatusandBulkUpdateStatusissue directUPDATE annotations SET statusstatements only. They do NOT publish SSE and do NOT enqueue the outbox. Updated routes (PATCH /dataset/{id}/status,POST /dataset/bulk-status) and error scenarios accordingly. - Flow Dependencies table: corrected F1 row (gating + Create-only), F3 row (only F1 Create publishes), F8 row (no SSE / no outbox today).
diagrams/flows/flow_annotation_create.md
- Replaced sequence + flowchart to match the verified F1 ordering (image first, optional media, label, SSE, conditional outbox); thumbnail removed.
- Added note that Update/UpdateStatus/Delete are silent today.
diagrams/flows/flow_sse_subscription.md, flow_failsafe_drain.md
- No structural corrections needed; spot-checked sequence vs
AnnotationsController.Events,AnnotationEventService,FailsafeProducer.EnqueueAsync. Notes already capture multi-drainer dedupe and channel-unbounded back-pressure concerns.
data_model.md
- No structural corrections; verified every column name and default against
Database/DatabaseMigrator.csandDatabase/Entities/*.cs. Spot-quirk (detection_classesids 9 + 10 share#000080) is pre-existing and noted.
deployment/*
- No structural corrections; verified
.woodpecker/build-arm.ymlstep-by-step,Dockerfiletwo-stage build,Program.csenv-var fallbacks.
Confirmed entities (sample — full list traced during the pass)
Controllers and routes (file:line where attributes were inspected):
AnnotationsController—Controllers/AnnotationsController.cs:10–80—[Route("annotations")],[Authorize(Policy = "ANN")], all listed routes match.MediaController—Controllers/MediaController.cs:10–55—[Route("media")],[Authorize(Policy = "ANN")], routes:POST,POST /batch,GET,GET /{id}/file,DELETE /{id}.DatasetController—Controllers/DatasetController.cs:9–41—[Route("dataset")],[Authorize(Policy = "DATASET")], routes:GET,GET /{annotationId},PATCH /{annotationId}/status,POST /bulk-status,GET /class-distribution.SettingsController—Controllers/SettingsController.cs:10–66—[Route("settings")], segmentssystem,directories,camera,usereach with GET + PUT.ClassesController—Controllers/ClassesController.cs:9–13—[Route("classes")],[Authorize], single[HttpGet].AuthController— removed in the auth refactor; annotations no longer mints or refreshes tokens.JwtExtensions.AddJwtAuth(verifier-only, ES256 over admin's JWKS) is the sole auth wiring inProgram.cs.
Services:
AnnotationService.CreateAnnotation(Services/AnnotationService.cs:13–104) — verified sequence used to rewrite F1.AnnotationService.UpdateAnnotation/UpdateStatus/DeleteAnnotation— verified that none publish SSE or enqueue outbox.DatasetService.UpdateStatus/BulkUpdateStatus(Services/DatasetService.cs:75–94) — verified silent on SSE / outbox.SettingsService— verifiedpathResolver.Reset()calls at lines 71, 85.FailsafeProducer.EnqueueAsync— confirmed as the public outbox-write helper, called byAnnotationService.CreateAnnotationonly.
Tables / migrator (Database/DatabaseMigrator.cs):
- All 9 tables referenced in
data_model.mdexist with the columns and defaults as documented; idempotentCREATE TABLE IF NOT EXISTS+ALTER TABLE … IF NOT EXISTS;detection_classesseed of 19 rows withON CONFLICT DO NOTHING.
Env vars (Program.cs):
- Required (fail-fast via
ConfigurationResolver.ResolveRequiredOrThrow):DATABASE_URL,JWT_ISSUER,JWT_AUDIENCE,JWT_JWKS_URL. - Optional with defaults:
RABBITMQ_HOST,RABBITMQ_STREAM_PORT,RABBITMQ_PRODUCER_USER,RABBITMQ_PRODUCER_PASS,RABBITMQ_STREAM_NAME. - CORS:
CorsConfig:AllowedOrigins(string array) +CorsConfig:AllowAnyOrigin(bool);CorsConfigurationValidator.EnsureSafeForEnvironmentblocks startup inProductionwhen origins are empty andAllowAnyOriginis not explicitly set.
CI (.woodpecker/build-arm.yml):
event: [push, manual],branch: [dev, stage, main],platform: arm64, secret refs,${BRANCH}-armtag, OCI image labels — all verified.
Stakeholder resolutions (closed 2026-05-14)
The six open questions surfaced by this pass were resolved with the maintainer. Authoritative wording lives in architecture.md (ADR-004, ADR-008..ADR-011 + Refactor Backlog RB-01..RB-06). Quick map:
| Question | Resolution | Tracked |
|---|---|---|
| Are silent Update/Delete/dataset-status changes intentional? | No — World B is the design; the drainer (FailsafeProducer.cs:108–123) was already plumbed for Validated + Deleted ops, the producer side was never wired in the new HTTP backend (legacy WPF UI did this directly). Wire all mutations to publish + enqueue. |
ADR-009 / RB-01 |
silent_detection semantics? |
Remove the flag entirely — superseded by the suite e2e harness. | ADR-010 / RB-02 |
| F1 atomicity (FS / DB / outbox)? | Adopt a business-transaction wrapper (transactional outbox); FS writes go post-commit. | ADR-008 / RB-03 |
XxHash64 over sample collision risk? |
Switch to XxHash3.Hash128 over the same sample (file-size-independent — videos can be 3–5 GB). |
ADR-004 / RB-04 |
FailsafeProducer.EnqueueAsync static + DB I/O? |
Accept as-is; documented coderule.mdc deviation. |
(no refactor) |
detection_classes static or admin-managed? |
Admin-managed with read-through cache (PathResolver-style Reset()). |
ADR-011 / RB-06 |
Additional finding while verifying #1
FailsafeProducer.cs:138has an emptycatch { }that swallowsIOExceptionon image read and emits a stream message withimage = null. Directcoderule.mdcviolation ("never suppress errors silently"). Operationally invisible failure mode. Tracked as RB-05 (architecture doc).
Step 4.5 follow-on resolutions (closed 2026-05-14)
Confirmed alongside the Step 4.5 condensed-view approval:
| Question | Resolution | Tracked |
|---|---|---|
Suite vs code: Flight (code) vs mission (suite spec) |
Rename code → Mission*; suite stays canonical |
ADR-012 / RB-07 |
| Stream consumer dedupe contract owner | This service owns it; dedupe by (annotationId, operation, dateTime) baked into the wire message |
ADR-013 / RB-09 |
| Hard-delete vs soft-delete | Soft-delete: status → Deleted (40), files relocated to a new deleted_dir |
ADR-009 (folded in) / RB-01 |
| Tight coupling 04 Dataset ↔ 01 Annotations REST | Decouple — dataset writes flow through AnnotationService via a public domain interface |
RB-08 |
Remaining gaps and uncertainties (carried into Step 6 problem extraction)
media.durationformat: TEXT NOT NULL is permissive; format is unspecified.- Lazy-upsert semantics for
system_settings/directory_settings/camera_settings— confirm services initialize defaults vs rely on user-driven inserts. UserIdbody field vs JWT subject drift — reconcile in suite spec or in code.- No automated tests in repo: addressed by autodev Phase A Steps 3–7.
Completeness score
- 11 / 11 modules documented (
modules/*.md). - 6 / 6 components assembled (
components/*/description.md). - 1 / 1 module-layout file (
module-layout.md). - 1 / 1 architecture file (
architecture.md). - 1 / 1 system-flows file (
system-flows.md) covering 8 flows. - 1 / 1 data-model file (
data_model.md) covering 9 tables. - 4 / 4 deployment files (
deployment/*.md). - 3 flow diagrams (F1, F3, F4) in
diagrams/flows/.
Score: 100% of modules + components covered. Remaining open items are behavioral questions, not coverage gaps.