From 802beb2db6b0e87ec0cbbfc6cb44f2d94ece586d Mon Sep 17 00:00:00 2001 From: Accusys Date: Fri, 15 May 2026 10:59:23 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20RCA=20=E2=80=94=20identity=5Fuuid=20mis?= =?UTF-8?q?sing=20+=20file=20identities=20NULL=20appearance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-05-15_RCA_identity_uuid_and_appearance.md | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 docs_v1.0/M4_workspace/2026-05-15_RCA_identity_uuid_and_appearance.md diff --git a/docs_v1.0/M4_workspace/2026-05-15_RCA_identity_uuid_and_appearance.md b/docs_v1.0/M4_workspace/2026-05-15_RCA_identity_uuid_and_appearance.md new file mode 100644 index 0000000..78e7d46 --- /dev/null +++ b/docs_v1.0/M4_workspace/2026-05-15_RCA_identity_uuid_and_appearance.md @@ -0,0 +1,144 @@ +# RCA: Identity UUID Missing + File Identities First/Last Appearance NULL + +**Date**: 2026-05-15 +**Author**: M5 +**Status**: Resolved + +--- + +## Summary + +Two related defects in the identity listing endpoints prevented external systems from using `identity_uuid` for further API calls, and returned null time ranges for face identities. + +| Issue | Endpoint | Symptom | Severity | +|-------|----------|---------|:--------:| +| #2 | `GET /api/v1/identities`
`GET /api/v1/file/:file_uuid/identities` | Response missing `identity_uuid` | High | +| #3 | `GET /api/v1/file/:file_uuid/identities` | `first_appearance` / `last_appearance` always `null` | Medium | + +--- + +## Issue #2 — identity_uuid Missing + +### Root Cause + +Two list endpoints only returned `identity_id` (integer primary key) without `identity_uuid` (public UUID): + +```json +// GET /api/v1/identities — before fix +[{"id": 18276, "name": "PERSON_aeed7134_367", "metadata": {}}] +``` + +```json +// GET /api/v1/file/:uuid/identities — before fix +{"identity_id": 18276, "name": "PERSON_aeed7134_367", ...} +``` + +The `identities` table has both columns: +- `id` (SERIAL INTEGER) — internal FK, used in `face_detections.identity_id` +- `uuid` (UUID, `gen_random_uuid()`) — stable external identifier + +All identity detail/chunks/files/bind routes require `identity_uuid` in the URL path (`/api/v1/identity/:identity_uuid/...`). Without it in the list response, clients had no way to navigate from a list entry to its detail. + +### Code Location + +| File | Line | Issue | +|------|------|-------| +| `src/api/identities.rs:177` | SQL query | `SELECT id, name, metadata FROM identities` — missing `uuid` | +| `src/api/identities.rs:197-200` | Response mapping | `IdentityResponse { id, name, metadata }` — no `identity_uuid` | +| `src/api/identity_api.rs:206-217` | Response mapping | `FileIdentityItem { identity_id, name, ... }` — no `identity_uuid` | +| `src/core/db/postgres_db.rs:2405-2418` | DB query | `get_file_identities` SELECT missing `i.uuid` | + +### Timeline + +| When | What | +|------|------| +| V4.0 | `identity_uuid` existed in DB schema and detail endpoints, but list endpoints never included it | +| 2026-05-14 | M4 reported inability to navigate from identity list to detail/files | +| 2026-05-15 | Fixed in `37799ff` | + +### Fix + +1. **`GET /api/v1/identities`** (`identities.rs`): Query changed to `SELECT id, uuid, name, metadata`; response struct `IdentityResponse` added `identity_uuid: String` +2. **`GET /api/v1/file/:uuid/identities`** (`identity_api.rs` + `postgres_db.rs`): `FileIdentityRecord` added `identity_uuid: Option`; SQL added `i.uuid as identity_uuid`; GROUP BY updated to include `i.uuid` + +### Lesson + +**All list endpoints should expose the stable UUID of the resource, not just the internal integer ID.** The external API surface is UUID-based (`:identity_uuid` in routes), so any endpoint that returns identity references must include the UUID. + +--- + +## Issue #3 — first_appearance / last_appearance Always NULL + +### Root Cause + +The SQL query in `get_file_identities()` hardcoded `NULL::float8` for both fields instead of computing actual frame ranges: + +```sql +-- Before fix +SELECT 0 as id, fd.file_uuid, fd.identity_id::int4, i.name, i.metadata, + COUNT(*)::int4 as face_count, + 0::int4 as speaker_count, + NULL::float8 as first_appearance, -- ← hardcoded NULL + NULL::float8 as last_appearance, -- ← hardcoded NULL + AVG(fd.confidence)::float8 as confidence +FROM face_detections fd +JOIN identities i ON fd.identity_id = i.id +``` + +### Code Location + +| File | Line | Issue | +|------|------|-------| +| `src/core/db/postgres_db.rs:2409-2410` | SQL query | `NULL::float8 as first_appearance, NULL::float8 as last_appearance` | + +The data was available (`face_detections.frame_number`) but never queried. This appears to have been a placeholder left during initial development that was never implemented. + +### Timeline + +| When | What | +|------|------| +| V1.0 (initial) | Query written with `NULL::float8` — never implemented | +| 2026-05-14 | M4 report mentioned identity data quality issues | +| 2026-05-15 | Fixed in `fdcec82` | + +### Fix + +Replaced with actual aggregate queries: + +```sql +-- After fix +MIN(fd.frame_number) as start_frame, +MAX(fd.frame_number) as end_frame, +``` + +Time values are computed in Rust from frame + fps: +```rust +start_time: r.start_frame.map(|sf| sf as f64 / r.fps), +end_time: r.end_frame.map(|ef| ef as f64 / r.fps), +``` + +Also renamed fields to match naming convention: +- `first_appearance` → `start_frame` +- `last_appearance` → `end_frame` +- Added `start_time`, `end_time`, `fps` + +### Lesson + +**Do not commit placeholder SQL with hardcoded NULL values.** If a field is not yet implemented, either omit it from the response or mark it explicitly as `"not_implemented"` rather than returning `null` which suggests the data exists but is missing. + +--- + +## Related Commits + +| Commit | Fix | +|--------|-----| +| `fdcec82` | Issue #3: Start/end frame + time + fps | +| `37799ff` | Issue #2: identity_uuid in list responses | + +## Affected Files + +| File | Changes | +|------|---------| +| `src/api/identities.rs` | SQL query + struct + mapping to include `uuid` | +| `src/api/identity_api.rs` | `FileIdentityItem` + response struct + mapping | +| `src/core/db/postgres_db.rs` | `get_file_identities` query + `FileIdentityRecord` |