docs: fix start/end → start_frame/end_frame in API docs

This commit is contained in:
Accusys
2026-05-14 17:57:00 +08:00
parent 0491c39d3f
commit 11f690ca35
44 changed files with 4672 additions and 9 deletions
@@ -0,0 +1,88 @@
# File Content Import Failure: COPY column mismatch
**Date**: 2026-05-11
**From**: M4
**To**: M5
---
## Failure
```
psql:/tmp/.../data.sql:22054: ERROR: syntax error at or near "id"
LINE 1: id,file_uuid,face_id,frame_number,x,y,width,height,confidenc...
^
```
## Root Cause
### Step 1: First error — COPY dev.chunk_vectors fails silently
The real error occurs earlier in the file. psql suppresses it and continues, but then treats all subsequent lines as SQL commands. The face_detections CSV header `id,file_uuid,face_id,...` is the first line that triggers a visible syntax error.
### Step 2: Why COPY fails — extra column
M4 and M5 table schemas differ:
```sql
-- M4 dev.face_detections (13 columns)
id, file_uuid, face_id, frame_number,
x, y, width, height,
confidence, embedding, identity_id,
created_at, trace_id
-- M5 exported CSV (14 columns)
id, file_uuid, face_id, frame_number,
x, y, width, height,
confidence, embedding, identity_id,
created_at, trace_id, timestamp_secs extra
```
The `COPY` command uses an empty column list:
```sql
COPY dev.face_detections () FROM STDIN WITH CSV HEADER;
^^ empty = expects ALL columns
```
PostgreSQL requires the CSV column count to match the table column count. With 14 CSV columns vs 13 table columns, COPY rejects the entire data block.
### Step 3: Additionally, first chunk_vectors COPY may also fail
Same issue applies to `dev.chunk_vectors`:
```sql
COPY dev.chunk_vectors () FROM STDIN WITH CSV HEADER;
```
If M5 added any columns to `chunk_vectors` that don't exist on M4, this COPY would also fail — which would explain why ALL three data tables (chunk, chunk_vectors, face_detections) show 0 rows after import.
## Verification
Check if M5's chunk_vectors has extra columns beyond:
```
id, chunk_id, uuid, chunk_type, embedding, created_at
```
## Recommended Fix
### Option A: Use column-explicit COPY (recommended)
```sql
COPY dev.face_detections (id, file_uuid, face_id, frame_number, x, y, width, height, confidence, embedding, identity_id, created_at, trace_id)
FROM STDIN WITH CSV HEADER;
```
This explicitly names the columns, ignoring `timestamp_secs` if present in CSV but missing in M4 schema.
### Option B: Deliver INSERT-format dump
```sql
pg_dump --column-inserts --table=...
```
Same format as the working `dev_backup_post_correction.sql`. Larger file but portable across schema versions.
### Option C: Deliver schema migration
Provide `ALTER TABLE dev.face_detections ADD COLUMN timestamp_secs double precision;` as part of the dev upgrade package.
@@ -0,0 +1,31 @@
# 交付確認 — v1.0.3 打包
**Date**: 2026-05-11
**From**: M4
**To**: M5
---
## 已收到
| 文件 | 大小 | 狀態 |
|------|------|:--:|
| `momentry_core_v1.0.3_source.tar.gz` | 378MB | ✅ |
| `dev_backup_post_correction.sql` | 86MB | ✅ |
| `aeed71342a899fe4b4c57b7d41bcb692.asr-1.json` | 1.3MB | ✅ |
| `api_test.sh` | 9KB | ✅ |
| `RELEASE_PACKAGING_README.md` | 2.6KB | ✅ |
| `HANDOVER_v1.0.3.md` | 9.8KB | ✅ |
## 未收到
| 文件 | 預計大小 | 狀態 |
|------|---------|:--:|
| `release/dev_upgrade_v1.0.3.tar.gz` | ~400MB | ❌ |
| `release/file_aeed71342a899fe4b4c57b7d41bcb692_v1.0.tar.gz` | ? | ❌ |
## 問題
1. 兩個包未出現在 `/Volumes/docs_v1.0/M4_HANDOVER/`。是否還在打包?
2. `momentry_core_v1.0.3_source.tar.gz` 裡面的 `release/` 仍是 v1.0.0 的舊檔。v1.0.3 的 `release/system/dev/``release/files/` 目錄結構是否應該包在 source tarball 內?
3. 檔案內容包的命名格式是 `file_{uuid}_v{major}.{minor}.tar.gz` 嗎?
@@ -0,0 +1,27 @@
# M5 回覆 — 交付確認
## Q1: 兩包已放共享目錄
`/Volumes/docs_v1.0/M4_HANDOVER/` 現在有:
| 檔案 | 大小 |
|------|:----:|
| `dev_upgrade_v1.0.3.tar.gz` | 400MB |
| `file_aeed71342a899fe4b4c57b7d41bcb692_v1.0.tar.gz` | 53MB |
| `momentry_core_v1.0.3_source.tar.gz` | 205MB(已清理 release/ |
## Q2: source tarball 已清理
重新打包,排除 `release/``storage/``model_checkpoints/``output/`。從 378MB → **205MB**
`release/system/dev/``release/files/` 是**交付時產生的目錄**,不是 source code 的一部分,不會包進 source tarball。M4 收到後解壓 `dev_upgrade_*.tar.gz` 執行升級即可。
## Q3: 命名規範確認
| 包類型 | 格式 | 範例 |
|--------|------|------|
| 開發系統升級包 | `dev_upgrade_{version}.tar.gz` | `dev_upgrade_v1.0.3.tar.gz` |
| 生產系統升級包 | `prod_upgrade_{version}.tar.gz` | `prod_upgrade_v1.0.3.tar.gz` |
| 檔案內容包 | `file_{file_uuid}_{version}.tar.gz` | `file_aeed71342a...b692_v1.0.tar.gz` |
目前只有一個 Charade 檔案內容包。後續其他影片會用同一格式。
@@ -0,0 +1,195 @@
# M5 Package Delivery Spec — Three-Tier Packaging System
**Date**: 2026-05-11
**From**: M4
**To**: M5
**Priority**: High
---
## 1. 三層打包架構
```
├── 開發系統升級包 (Dev System Upgrade)
│ └── Schema migration + binary upgrade for dev (port 3003)
├── 生產系統升級包 (Production System Upgrade)
│ └── Schema migration + binary upgrade for prod (port 3002)
└── 檔案內容包 (File Content Package)
└── One file_uuid per package, complete post-correction data
```
---
## 2. 開發系統升級包
**目的**:升級開發環境(schema=dev, port 3003)。
| 屬性 | 說明 |
|------|------|
| Schema | `dev` |
| 內容 | Schema migration SQL + 新版 binary + source code |
| 不含 | 任何檔案資料(無 file content data |
| 頻率 | 每次系統升級 |
### 內容物
```
dev_upgrade_v1.0.2.tar.gz
├── schema/
│ └── migration_v1.0.2.sql # ALTER TABLE, CREATE INDEX, etc.
├── bin/
│ └── momentry_playground # Dev binary
├── src/
│ └── momentry_core_v1.0.2.tar.gz # Full source (optional)
└── UPGRADE.md # 升級步驟
```
### 升級步驟
```bash
# 1. Apply schema migration
psql -U accusys -d momentry -c "SET search_path TO dev;"
psql -U accusys -d momentry < schema/migration_v1.0.2.sql
# 2. Replace binary
cp bin/momentry_playground /path/to/target/debug/
# 3. Restart server (port 3003)
DATABASE_SCHEMA=dev ./momentry_playground server --port 3003
```
---
## 3. 生產系統升級包
**目的**:升級生產環境(schema=public, port 3002)。
| 屬性 | 說明 |
|------|------|
| Schema | `public` |
| 內容 | Schema migration SQL + release binary |
| 不含 | 任何檔案資料 |
| ⚠️ 注意 | 生產環境變更需要謹慎,必須先備份 |
### 內容物
```
prod_upgrade_v1.0.2.tar.gz
├── schema/
│ └── migration_v1.0.2.sql # ALTER TABLE, CREATE INDEX (public schema)
├── bin/
│ └── momentry # Release binary
└── UPGRADE.md # 升級步驟 + rollback 指令
```
### 升級步驟
```bash
# 0. Backup current DB (mandatory)
pg_dump -U accusys -d momentry --schema=public > backup_v1.0.1.sql
# 1. Apply schema migration
psql -U accusys -d momentry < schema/migration_v1.0.2.sql
# 2. Replace binary
cp bin/momentry /path/to/target/release/
# 3. Restart server (port 3002)
./momentry server --port 3002
```
---
## 4. 檔案內容包
**目的**:交付單一影片的完整已處理資料。一包一檔。
| 屬性 | 說明 |
|------|------|
| 範圍 | **一個 file_uuid**(不跨檔案) |
| 內容 | 已註冊 + 已處理 + post-correction |
| Schema | `dev``public`(標註清楚) |
| 狀態 | 匯入後該檔案即為「已就緒(ready)」 |
### 內容物
```
charade_1963_{file_uuid}.tar.gz
├── data.sql # PG dump: videos + chunk + chunk_vectors + face_detections
├── file_info.json # { file_uuid, file_name, fps, duration, resolution, ... }
├── checksums.md5 # Integrity check
└── README.md # Import instructions
```
### Data Scopedata.sql 內容)
每個 table 只匯出該 file_uuid 的 rows
| Table | WHERE Clause |
|-------|-------------|
| `videos` | `WHERE file_uuid = '{uuid}'` |
| `chunk` | `WHERE file_uuid = '{uuid}'` |
| `chunk_vectors` | `WHERE uuid = '{uuid}'` |
| `face_detections` | `WHERE file_uuid = '{uuid}'` |
| `identities` (if related) | 與此 file_uuid 關聯 |
### 匯出指令(M5 端)
```bash
UUID="aeed71342a899fe4b4c57b7d41bcb692"
pg_dump -U accusys -d momentry --schema=dev \
--data-only --column-inserts \
--table=dev.videos \
--table=dev.chunk \
--table=dev.chunk_vectors \
--table=dev.face_detections \
--where="file_uuid='${UUID}'" \
> data.sql
```
### 匯入指令(M4 端)
```bash
export UUID="aeed71342a899fe4b4c57b7d41bcb692"
# 1. Delete existing data for this file_uuid (if any)
psql -U accusys -d momentry <<SQL
DELETE FROM dev.chunk_vectors WHERE uuid = '${UUID}';
DELETE FROM dev.chunk WHERE file_uuid = '${UUID}';
DELETE FROM dev.face_detections WHERE file_uuid = '${UUID}';
DELETE FROM dev.videos WHERE file_uuid = '${UUID}';
SQL
# 2. Restore package
psql -U accusys -d momentry < data.sql
# 3. Done — file is ready, no migration needed
```
### 驗證標準
匯入後所有 API 正常:
- [ ] `GET /api/v1/file/{uuid}` → 200status 為 `ready`
- [ ] `GET /api/v1/file/{uuid}/chunk/0-01` → 200corrected chunk_id
- [ ] `POST /api/v1/search/universal` → 有結果
- [ ] `POST /api/v1/file/{uuid}/face_trace/sortby` → 有 traces
- [ ] `GET /api/v1/file/{uuid}/trace/{id}/faces` → 有 faces
- [ ] Portal FilesView 顯示 `✅ 已就绪`
---
## 5. 三者對照
| | 開發升級包 | 生產升級包 | 檔案內容包 |
|------|:--:|:--:|:--:|
| Schema | dev | public | dev 或 public |
| Data | ❌ | ❌ | ✅ 一個 file_uuid |
| Binary | dev compile | release build | ❌ |
| Migration SQL | ✅ | ✅ | ❌ |
| Rollback SQL | 可選 | **必須** | ❌ |
| 頻率 | 每次版本 | 每次 release | 每個新影片 |
| Port | 3003 | 3002 | — |
@@ -0,0 +1,52 @@
# Portal Setup Fix — Tauri CLI Missing
**Date**: 2026-05-11
**From**: M4
**To**: M5
**Priority**: Medium
---
## Issue
Running `npm run tauri dev` produces:
```
sh: tauri: command not found
```
## Root Cause
`@tauri-apps/cli` was missing from `package.json` devDependencies. The `npm run tauri` script relies on the `tauri` binary installed by this package.
## Fix
```bash
cd portal
npm install --save-dev @tauri-apps/cli
npm install
npm run tauri dev
```
This has already been applied to the updated source tarball at `/Volumes/docs_v1.0/M4_HANDOVER/momentry_portal_v0.1_source.tar.gz`.
## Additional Fixes in Updated Tarball
| Fix | File | Description |
|-----|------|-------------|
| Tauri CLI dep | `package.json` | Added `@tauri-apps/cli` to devDependencies |
| API key | `.env.development` | Corrected `VITE_API_KEY` (was `muser_test_001`) |
| Search play | `SearchView.vue` | Don't seek segment that was already extracted |
## After Setup
```bash
# API server must be running on port 3003
cd momentry_core_0.1
DATABASE_SCHEMA=dev cargo run --bin momentry_playground -- server --port 3003
# Then in another terminal
cd portal
npm run tauri dev
```
Portal opens desktop app window connecting to `http://127.0.0.1:3003` with API key `muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69`.
@@ -0,0 +1,32 @@
# Release Packaging V2 — 三包制
**Date**: 2026-05-11
**From**: M5
**To**: M4
## 變更
統一改為三包制:
| 包類型 | 路徑 | 說明 |
|--------|------|------|
| 開發系統升級包 | `release/system/dev/latest/` | source + dev schema + scripts + portal |
| 生產系統升級包 | `release/system/prod/` | (待建立) |
| 檔案內容包 | `release/files/{uuid}/latest/` | 單一影片完整資料 |
## 開發系統升級包 v1.0.3 已就位
位置: `release/system/dev/v1.0.3/` (385MB)
| 內容 | 說明 |
|------|------|
| `source.tar.gz` | Rust + scripts + configs |
| `schema.sql` | dev schema DDL |
| `.env.development` | 開發環境設定 |
| `scripts/` | pipeline, correction, import tools |
| `test/api_test.sh` | 39 endpoint 測試 |
| `portal/dist/` | 前端 build |
## 轉移流程
`docs_v1.0/M4_HANDOVER/RELEASE_PACKAGING_README.md`
@@ -0,0 +1,49 @@
# Request: Complete Post-Correction DB Backup
**Date**: 2026-05-11
**From**: M4
**To**: M5
**Priority**: High
---
## Issue
Current backup (`dev.chunks.sql` + `dev.chunk_vectors.sql`) contains **pre-correction** data. The correction scripts (`generate_asr1.py``apply_asr_corrections.py`) were never applied in the backup.
## Impact
- Chunk count differs: backup has 6,021 chunks for Charade `aeed71342a899fe4b4c57b7d41bcb692`, but post-correction should be **4,188** sentence chunks
- Corrected chunk_ids (`0-01`, `1446-01`, etc.) don't exist → chunk detail tests fail (404 instead of 200)
- `api_test.sh` "Chunk detail" section: `chunk/0-01` and `chunk/1446-01` fail on M4
## Request
Provide a **complete post-correction** DB dump of `dev.chunk` + `dev.chunk_vectors` for `aeed71342a899fe4b4c57b7d41bcb692`.
```bash
pg_dump -U accusys -d momentry --schema=dev \
--table=dev.chunk \
--table=dev.chunk_vectors \
--data-only --column-inserts \
> release/phase1/backup_post_correction.sql
```
Both tables should reflect the state AFTER running `apply_asr_corrections.py`.
---
## M5 Response
**Status**: ✅ Backup ready
| Check | Value |
|------|-------|
| dev.chunk rows (Charade) | 6,021 total (4,188 sentence + 1,130 cut + 423 trace + 280 story) |
| dev.chunk_vectors | 4,188 |
| Matched (chunk ↔ vectors) | 4,188 ✅ |
| chunk_id format | Short (`0-01`, `1446-01`, `story_240`, etc.) |
**File**: `docs_v1.0/M4_HANDOVER/dev_backup_post_correction.sql` (86 MB)
This backup reflects the state AFTER applying corrections, with all schema changes (RENAME, column drops, short chunk_ids) already applied. No further migration steps needed — just `psql -U accusys -d momentry < dev_backup_post_correction.sql`.
@@ -0,0 +1,45 @@
# v1.0.3 文件內容包 — COPY 格式確認
**Date**: 2026-05-11
**From**: M4
**To**: M5
---
## 結論:COPY 格式無問題
M4 再次以 clean state 測試後,`data.sql` 匯入成功:
```
COPY 1 (videos)
COPY 6021 (chunk)
COPY 4188 (chunk_vectors)
COPY 11820 (face_detections)
COMMIT
```
39/39 API tests pass.
## 之前失敗的原因
M4 測試時先以 INSERT 格式的 `dev_backup_post_correction.sql` 匯入,再用 COPY 格式的 `data.sql` 匯入 → 兩套相同資料的 ID 衝突(duplicate key)。
## 正確的檔案內容包匯入流程
```bash
# 1. Apply schema migration first (dev upgrade)
psql -U accusys -d momentry < schema/migration_v1.0.3.sql
# 2. Delete existing data for this UUID (if any)
psql -U accusys -d momentry <<SQL
DELETE FROM dev.chunk_vectors WHERE uuid = '{UUID}';
DELETE FROM dev.chunk WHERE file_uuid = '{UUID}';
DELETE FROM dev.face_detections WHERE file_uuid = '{UUID}';
DELETE FROM dev.videos WHERE file_uuid = '{UUID}';
SQL
# 3. Import file content
psql -U accusys -d momentry < data.sql
```
Issue 1 (migration SQL empty) 和 Issue 2 (COPY format) 均確認無誤。
@@ -0,0 +1,50 @@
# API 文件修正請求 — v1.0.0 目錄
**Date**: 2026-05-12
**From**: M4
**To**: M5
---
與實際系統(3003 port)交叉驗證後,發現以下問題:
## 1. 路徑錯誤
| 檔案 | 行號 | 錯誤 | 正確 |
|------|:---:|------|------|
| `INTERNAL/API_DICTIONARY_V1.0.0.md` | 87 | `POST /api/v1/files/unregister` | `POST /api/v1/unregister` |
## 2. 回應格式過時
| 檔案 | 欄位 | DOC 說 | ACTUAL 是 |
|------|------|--------|-----------|
| `API_REFERENCE_V1.0.0.md:73` | `/files` 結果 key | `"files"` | `"data"` |
| `API_REFERENCE_V1.0.0.md:73` | `/files` 結果 | 缺 `success` | 有 `success:true` |
| `API_REFERENCE_V1.0.0.md` | `/search/universal` 結果數 key | `"count"` | `"total"` |
| `API_REFERENCE_V1.0.0.md` | `/search/universal` 回應 | 缺分頁欄位 | 有 `page`, `page_size`, `took_ms` |
| `API_REFERENCE_V1.0.0.md` | `/identities` 回應 | 缺分頁欄位 | 有 `page`, `page_size`, `count` |
| `API_REFERENCE_V1.0.0.md` | `/resources` 結果 key | `"resources"` | `"data"` |
| `API_REFERENCE_V1.0.0.md:63` | register body | `file_path` 為相對路徑 | 需絕對路徑 |
## 3. 已移除但文件仍列出的 endpoint
| 檔案 | 行號 | Endpoint | 現狀 |
|------|:---:|------|:--:|
| `API_REFERENCE_V1.0.0.md` | 58 | `GET /api/v1/file/:uuid/chunks` | 404M5 Phase 1 已移除) |
| `RELEASE/RELEASE_API_REFERENCE_V1.0.0.md` | 66 | 同上 | 同上 |
應改為:`GET /api/v1/file/:uuid/chunk/:chunk_id` (V1.0.2+)
## 4. 缺少範例
| 檔案 | Endpoint | 缺少 |
|------|------|------|
| `API_REFERENCE_V1.0.0.md:52` | `POST /api/v1/unregister` | 無 curl 範例、無回應範例 |
| `API_DICTIONARY_V1.0.0.md:64` | 同上 | 同上 |
| `RELEASE/RELEASE_API_REFERENCE_V1.0.0.md:60` | 同上 | 同上 |
參考已有較完整說明的檔案:`API_DOCUMENTATION.md:80``INTERNAL/API_REFERENCE_V1.0.0_20260501.md:113`
## 5. Port 不一致
所有 curl 範例都用 `localhost:3002`production),建議加註 `# dev: localhost:3003`
@@ -0,0 +1,112 @@
# API 文件驗證報告 — API_REFERENCE_V1.0.0.md vs 實際系統 (3003)
**Date**: 2026-05-12
**From**: M4
**驗證對象**: `docs_v1.0/API_V1.0.0/API_REFERENCE_V1.0.0.md` (14 curl examples)
---
## 摘要
| 狀態 | 數量 |
|:--:|:--:|
| ✅ 一致 | 3 |
| ⚠️ 欄位差異 | 6 |
| ❌ 錯誤/過時 | 2 |
| 🔴 功能未啟動 | 1 |
| — | — |
| **兩項以上問題** | **9/14 (64%)** |
---
## 詳細差異
### 1. `/files` 回應格式 ⚠️
| | DOC | ACTUAL |
|------|------|--------|
| Key | `"files"` | `"data"` |
| `success` | 無 | `true` |
| `total` | `37` | `0` |
**建議**: doc 改為 `"data"``total` 修正(目前 hardcoded 0)。
### 2. `/search/universal` 回應格式 ⚠️
| | DOC | ACTUAL |
|------|------|--------|
| 結果數 key | `"count"` | `"total"` |
| 分頁 | 無 | `page`, `page_size` |
| 執行時間 | 無 | `took_ms` |
**建議**: doc 補上分頁欄位,`count``total`
### 3. `/identities` 回應格式 ⚠️
| | DOC | ACTUAL |
|------|------|--------|
| 分頁 | 無 | `page`, `page_size` |
| 總數 key | 無 | `count` |
**建議**: doc 補上分頁欄位。
### 4. `/resources` 回應格式 ⚠️
| | DOC | ACTUAL |
|------|------|--------|
| 資料 key | `"resources"` | `"data"` |
| 額外欄位 | 無 | `success`, `message` |
**建議**: doc 改為 `"data"`,補 `success` 欄位。
### 5. `/faces/candidates` ✅
DOC 與 ACTUAL 一致。
### 6. `/health` ✅
DOC 與 ACTUAL 一致。
### 7. `/thumbnail` ✅
DOC: JPEG 82KB / ACTUAL: 200, image/jpeg, 82KB。
### 8. `/file/:uuid/chunks` ❌ 已移除
DOC 列出此 endpointACTUAL 回 404M5 Phase 1 移除)。
**建議**: 從 doc 移除,改為 `/file/:uuid/chunk/:chunk_id`
### 9. 檔案註冊路徑 ❌ 格式不同
DOC: `/sftpgo/data/demo/video.mp4`(相對路徑)
ACTUAL: 需絕對路徑 `/Users/accusys/momentry/var/sftpgo/data/demo/...`
### 10. `/agents/translate` 🔴 未啟動
DOC: `{"success":true,"translated_text":"你好世界"}`
ACTUAL: 500LLM 服務未啟動或無法連線)
### 11. Face trace 數字 ⚠️
DOC: `total_traces=6892, total_faces=108204`
這些數字來自 M4 的舊資料(`3abeee81`)。不同 file UUID 會有不同數字。
**建議**: doc 標註「數字隨檔案而異」。
### 12. Identity binding ⚠️
DOC: `POST /api/v1/identity/:uuid/bind`
ACTUAL: route 存在但未測試(需特定 identity UUID)。
---
## 修正建議
1. **Port**: doc 全用 3002,建議加註解 `# dev: port 3003`
2. **Response format**: `"files"``"data"``"count"``"total"`、補 `success`/`page`/`page_size`
3. **移除**: `/file/:uuid/chunks` 已過時
4. **新增**: `/file/:uuid/chunk/:chunk_id`V1.0.2+
5. **範例路徑**: 改為絕對路徑
6. **數值**: 標註「實際數字隨 UUID 而異」
7. **Translate**: 確認 LLM 服務狀態後更新 doc
@@ -0,0 +1,47 @@
# M5 vs M4 文件比對與整理建議
**Date**: 2026-05-12
---
## 比對結果
4 個檔案有差異(M5 正確,M4 過時):
| 檔案 | M5 (shared) | M4 (local) |
|------|:--:|:--:|
| `API_REFERENCE_V1.0.0.md` | ✅ 10 項修正已套用 | ❌ 舊版(無 unregister 範例、欄位名錯誤等) |
| `INTERNAL/API_DICTIONARY_V1.0.0.md` | ✅ `/api/v1/unregister` | ❌ `/api/v1/files/unregister` |
| `RELEASE/RELEASE_API_REFERENCE_V1.0.0.md` | ✅ `/chunk/:chunk_id` | ❌ `/chunks`(已移除) |
| `API_DOCUMENTATION.md` | ✅ `muser_xxx_xxx` | ❌ `muser_test_001`(舊 key |
1 個檔案只在 M4
| 檔案 | 說明 |
|------|------|
| `DEMO_GUIDE.md` | Demo 操作指南,M5 端沒有 |
---
## 建議:三層文件架構
```
docs_v1.0/
├── API_V1.0.0/ ← M5 維護(canonical),M4 唯讀
├── M4_workspace/ ← M4 維護(回報、測試報告)
├── M5_workspace/ ← M5 維護(handover、release notes
└── REFERENCE/ ← 共用參考文件(硬體圖等)
```
### M4 端處理
1. **刪除 M4 的 `API_V1.0.0/` 目錄** — 改為直接參照 shared volume
2. **M4 只維護 `M4_workspace/`** — 放回報、測試記錄
3. **`DEMO_GUIDE.md`** 搬到 `M4_workspace/` 或通知 M5 同步
4. **M4 機器的 `docs_v1.0/`** 簡化為 `M4_workspace/` + `REFERENCE/`
### 好處
- 不再有 M4 自行修改 API 文件導致不一致的問題
- M5 維護 canonical 版本,M4 直接讀取
- M4 回報問題給 M5,由 M5 統一修正
@@ -0,0 +1,313 @@
# 檔案內容包接收檢查清單
**Date**: 2026-05-12 (updated for v2 with identity support)
**From**: M4
**Usage**: M4 receives file package from M5 → run these checks before accepting
---
## 1. 結構檢查
```bash
# 檢查 tar.gz 包含必要檔案
tar tzf file_{uuid}_{ver}.tar.gz
```
| 必要 | 檢查項 |
|:--:|------|
| ✅ | `data.sql` 存在且非空(videos + chunk + vectors + faces |
| ✅ | `identities.sql` 存在且非空(**v2 新增**) |
| ✅ | `identity_bindings.sql` 存在且非空(**v2 新增**) |
| ✅ | `file_info.json` 存在 |
| ✅ | `checksums.md5` 存在 |
| ⬜ | `tkg.sqlite` (未來要求) |
---
## 2. 完整性檢查
```bash
# 校驗 hash
md5 -c checksums.md5
```
```bash
# 檢查 data.sql + identities.sql + identity_bindings.sql 包含哪些 table
tar xzf file_{uuid}_{ver}.tar.gz -O data.sql | grep -E "^COPY|^INSERT INTO" | sort -u
tar xzf file_{uuid}_{ver}.tar.gz -O identities.sql | grep -E "^COPY|^INSERT INTO" | sort -u
tar xzf file_{uuid}_{ver}.tar.gz -O identity_bindings.sql | grep -E "^COPY|^INSERT INTO" | sort -u
```
| 必要 | Table | 來源檔案 |
|:--:|-------|---------|
| ✅ | `dev.videos` (1 row) | data.sql |
| ✅ | `dev.chunk` | data.sql |
| ✅ | `dev.chunk_vectors` | data.sql |
| ✅ | `dev.face_detections` | data.sql |
| ✅ | `dev.identities`**v2 新增**| identities.sql |
| ✅ | `dev.identity_bindings`**v2 新增**| identity_bindings.sql |
- `dev.videos.status` 應為 `completed`
---
## 3. 數量合理性
```bash
UUID="..."
# 計算 data.sql 各 table 行數
tar xzf file_{uuid}_{ver}.tar.gz -O data.sql | grep -c ",${UUID},"
# v2: 計算 identity 數量
tar xzf file_{uuid}_{ver}.tar.gz -O identities.sql | grep -c "INSERT INTO"
tar xzf file_{uuid}_{ver}.tar.gz -O identity_bindings.sql | grep -c "INSERT INTO"
```
| 檢查項 | 合理範圍 |
|--------|---------|
| videos rows | = 1 |
| chunk rows | > 1000 |
| chunk_vectors rows | > 1000 |
| face_detections rows | > 1000 |
| identities rows (**v2**) | > 0 |
| identity_bindings rows (**v2**) | > 0 |
| chunk vs vectors 數量 | 二者不應差太多 |
---
## 4. Identity 完整性檢查(**v2 新版**
### 匯入後檢查
```sql
-- 1. 檢查 face_detections → identity_id 覆蓋率
SELECT
count(*) as total_faces,
count(identity_id) as faces_with_id,
round(100.0 * count(identity_id) / count(*), 1) as pct
FROM dev.face_detections WHERE file_uuid = '{UUID}';
```
| 覆蓋率 | 判定 |
|:---:|------|
| > 80% | ✅ 正常 |
| 20-80% | ⚠️ 偏低,確認 M5 pipeline |
| < 20% | ❌ 異常 |
```sql
-- 2. 檢查 identity_id 是否指向存在的 identity
SELECT count(*) as orphans
FROM dev.face_detections f
LEFT JOIN dev.identities i ON f.identity_id = i.id
WHERE f.file_uuid = '{UUID}'
AND f.identity_id IS NOT NULL
AND i.id IS NULL;
```
> 0 → ❌ orphan identity reference,需回報 M5
```sql
-- 3. 檢查 identity_bindings 綁定數量
SELECT count(*) as bindings
FROM dev.identity_bindings
WHERE identity_id IN (
SELECT DISTINCT identity_id FROM dev.face_detections
WHERE file_uuid = '{UUID}' AND identity_id IS NOT NULL
);
```
**binding 數量應與 face_detections 中有 identity_id 的行數相近**
```sql
-- 4. 列出此檔案綁定的人物 Top 10
SELECT i.name, count(DISTINCT f.id) as unique_faces
FROM dev.face_detections f
JOIN dev.identities i ON f.identity_id = i.id
WHERE f.file_uuid = '{UUID}'
GROUP BY i.name ORDER BY unique_faces DESC LIMIT 10;
```
**應看到已知角色(如 Cary Grant, Audrey Hepburn**
```sql
-- 5. 檢查 trace-level identity binding
SELECT
COUNT(DISTINCT trace_id) FILTER (WHERE identity_id IS NOT NULL) as bound_traces,
COUNT(DISTINCT trace_id) FILTER (WHERE identity_id IS NULL) as unbound_traces
FROM dev.face_detections WHERE file_uuid = '{UUID}';
```
| 判定 | bound / unbound |
|:--:|------|
| ✅ | bound traces 佔多數 |
| ⚠️ | unbound traces > 30% |
---
## 5. 匯入測試
```bash
UUID="..."
# 1. 備份現有資料
pg_dump -U accusys -d momentry --schema=dev \
--table=dev.chunk --table=dev.chunk_vectors \
--table=dev.face_detections --table=dev.videos \
--table=dev.identities --table=dev.identity_bindings \
--where="file_uuid='${UUID}'" > backup_before_import.sql
# 2. 刪除舊資料(含 identity tables
psql -U accusys -d momentry <<SQL
DELETE FROM dev.chunk_vectors WHERE uuid = '${UUID}';
DELETE FROM dev.chunk WHERE file_uuid = '${UUID}';
DELETE FROM dev.face_detections WHERE file_uuid = '${UUID}';
DELETE FROM dev.identity_bindings WHERE identity_id IN (
SELECT id FROM dev.identities WHERE source = 'tmdb');
DELETE FROM dev.identities WHERE source = 'tmdb';
DELETE FROM dev.videos WHERE file_uuid = '${UUID}';
SQL
# 3. 匯入三個 SQL 檔案
psql -U accusys -d momentry < identities.sql
psql -U accusys -d momentry < identity_bindings.sql
psql -U accusys -d momentry < data.sql
# 4. 確認數量
psql -U accusys -d momentry -c "
SELECT 'chunk' as tbl, count(*) FROM dev.chunk WHERE file_uuid = '${UUID}'
UNION ALL SELECT 'vectors', count(*) FROM dev.chunk_vectors WHERE uuid = '${UUID}'
UNION ALL SELECT 'faces', count(*) FROM dev.face_detections WHERE file_uuid = '${UUID}'
UNION ALL SELECT 'videos', count(*) FROM dev.videos WHERE file_uuid = '${UUID}'
UNION ALL SELECT 'identities', count(*) FROM dev.identities WHERE source = 'tmdb'
UNION ALL SELECT 'bindings', count(*) FROM dev.identity_bindings
"
```
---
## 6. API 功能驗證
```bash
UUID="..." API_KEY="..."
for ep in \
"/api/v1/file/$UUID" \
"/api/v1/file/$UUID/video" \
"/api/v1/file/$UUID/thumbnail?frame=1000" \
"/api/v1/search/universal" \
"/api/v1/file/$UUID/face_trace/sortby" \
"/api/v1/file/$UUID/trace/1/faces?limit=3" \
"/api/v1/identities" \
"/api/v1/file/$UUID/identities"
do
code=$(curl -s -o /dev/null -w "%{http_code}" -H "X-API-Key: $API_KEY" "http://localhost:3003$ep")
printf "%-50s %s\n" "$ep" "$code"
done
# chunk detail
curl -s -o /dev/null -w "%{http_code}" -H "X-API-Key: $API_KEY" \
"http://localhost:3003/api/v1/file/$UUID/chunk/0"
echo " (expect 200)"
curl -s -o /dev/null -w "%{http_code}" -H "X-API-Key: $API_KEY" \
"http://localhost:3003/api/v1/file/$UUID/chunk/nonexist"
echo " (expect 404)"
```
---
## 7. 影片檔案檢查
```bash
FILE_PATH=$(psql -U accusys -d momentry -t -c \
"SELECT file_path FROM dev.videos WHERE file_uuid = '${UUID}'" | tr -d ' ')
ls -lh "$FILE_PATH" || echo "❌ 影片檔案不存在!"
```
---
## 8. 預期問題記錄
| 已知問題 | 處理方式 |
|---------|---------|
| COPY 格式 column mismatch | 先跑 migration SQL |
| 影片檔案路徑不存在 | 跟 M5 要影片檔 |
| duplicate key (version conflict) | DELETE 後再匯入 |
| status 不是 completed | 檢查 `file_info.json` 或手動 UPDATE |
| orphan identity_id | 確認 identities.sql 已匯入 |
| identity_bindings 數量異常 | 確認 identity_bindings.sql 已匯入 |
---
## 9. 上架驗證(Go-Live Verification
匯入成功後的完整上架確認。
### 9.1 API 層
```bash
UUID="..." API_KEY="..."
HOST="http://localhost:3003"
echo "===== 1. File in /files list ====="
curl -s -H "X-API-Key: $API_KEY" "$HOST/api/v1/files?page=1&page_size=50" | \
python3 -c "import json,sys; d=json.load(sys.stdin);
found=[f for f in d.get('data',[]) if f['file_uuid']=='$UUID'];
print('✅ found' if found else '❌ NOT IN LIST')"
echo "===== 2. File in /files/scan ====="
curl -s -H "X-API-Key: $API_KEY" "$HOST/api/v1/files/scan" | \
python3 -c "import json,sys; d=json.load(sys.stdin);
found=[f for f in d.get('files',[]) if f.get('file_uuid')=='$UUID'];
print(f'✅ found, is_registered={found[0][\"is_registered\"]}' if found else '❌ NOT IN SCAN')"
echo "===== 3. Status = completed ====="
curl -s -H "X-API-Key: $API_KEY" "$HOST/api/v1/file/$UUID" | \
python3 -c "import json,sys; d=json.load(sys.stdin); print('✅ completed' if d.get('status')=='completed' else f'⚠️ {d.get(\"status\",\"no status field\")}')"
echo "===== 4. Full API test suite ====="
bash /Volumes/docs_v1.0/M4_HANDOVER/api_test.sh 2>&1 | tail -5
```
### 9.2 Portal 層
| 頁面 | URL | 驗證點 |
|------|-----|--------|
| FilesView | `http://localhost:1420/files` | ✅ Charade 顯示「已就绪」 |
| SearchView | `http://localhost:1420/search` | ✅ 搜尋檔案下拉有 Charade |
| Search Play | Search "Audrey Hepburn" → Play | ✅ 影片片段播放 |
| Trace View | 點 trace → faces | ✅ 人臉列表 + trace video |
| Identities | `http://localhost:1420/identities` | ✅ Cary Grant / Audrey Hepburn 顯示 |
### 9.3 資料核對
| 檢查項 | 方法 | 標準 |
|--------|------|:--:|
| 影片可播放 | `GET /api/v1/file/{uuid}/video` | 200, content-type: video/mp4 |
| 縮圖可顯示 | `GET /api/v1/file/{uuid}/thumbnail?frame=1000` | 200, image/jpeg |
| chunk detail 存在 | `GET /api/v1/file/{uuid}/chunk/0` | 200 |
| face trace video | `GET /api/v1/file/{uuid}/trace/{id}/video` | 200 |
| face trace faces 3D | `GET /api/v1/file/{uuid}/trace/{id}/faces?dimension=3d` | 200, has z_rel |
| identity detail | `GET /api/v1/identity/{id}` | 200 |
| files/scan 標記 registered | `GET /api/v1/files/scan` | is_registered = true |
### 9.4 上架通過標準
| 條件 | 狀態 |
|------|:--:|
| API test 39/39 | ✅ |
| Portal FilesView 顯示已就绪 | ✅ |
| Portal Search 可搜到 + 可 Play | ✅ |
| Portal Face Traces 可查看 | ✅ |
| API /files/scan is_registered = true | ✅ |
---
## 10. 接受/退回標準
| 狀態 | 條件 |
|:--:|------|
| ✅ 接受 | 1-8 全過,identity 覆蓋 > 80%,無 orphan9.1 全過 |
| ⚠️ 暫存 | 1-5 過但 identity 覆蓋偏低,或綁定數偏少 |
| ❌ 退回 | hash fail、table 缺漏、匯入失敗、identity 全 NULL、9.1 失敗 |
退回時附 log 和失敗原因。
@@ -0,0 +1,177 @@
# PG + SQLite TKG 統一分析與檔案內容包要求
**Date**: 2026-05-12
**From**: M4
**To**: M5
**Priority**: High
---
## 1. PG TKG 現狀
```
dev.tkg_nodes dev.tkg_edges
────────────── ──────────────
id (PK, bigint) id (PK, bigint)
node_type (varchar) edge_type (varchar)
external_id (varchar) source_node_id (FK → tkg_nodes.id)
file_uuid (varchar) target_node_id (FK → tkg_nodes.id)
label (varchar) file_uuid (varchar)
properties (jsonb) properties (jsonb)
created_at (timestamptz) created_at (timestamptz)
```
- 資料量:2,414 nodes / 1,320 edges
- 建立方式:`tkg_builder.py` (Python),由 `job_worker.rs:824` 呼叫
- **查詢方式**:目前 Rust 程式碼中**沒有** `WITH RECURSIVE` 圖查詢
---
## 2. SQLite TKG 設計
表結構與 PG 完全一致:
```sql
CREATE TABLE tkg_nodes (
id INTEGER PRIMARY KEY,
node_type TEXT NOT NULL,
external_id TEXT NOT NULL,
file_uuid TEXT NOT NULL,
label TEXT,
properties TEXT DEFAULT '{}',
created_at TEXT DEFAULT (datetime('now')),
UNIQUE(file_uuid, node_type, external_id)
);
CREATE TABLE tkg_edges (
id INTEGER PRIMARY KEY,
edge_type TEXT NOT NULL,
source_node_id INTEGER NOT NULL REFERENCES tkg_nodes(id) ON DELETE CASCADE,
target_node_id INTEGER NOT NULL REFERENCES tkg_nodes(id) ON DELETE CASCADE,
file_uuid TEXT NOT NULL,
properties TEXT DEFAULT '{}',
created_at TEXT DEFAULT (datetime('now')),
UNIQUE(file_uuid, edge_type, source_node_id, target_node_id)
);
```
### 圖查詢(Recursive CTEPG 和 SQLite 通用)
```sql
-- 2-hop traversal:從 Audrey Hepburn 出發走兩步
WITH RECURSIVE walk AS (
SELECT target_node_id, 1 AS depth
FROM tkg_edges
WHERE source_node_id = (
SELECT id FROM tkg_nodes WHERE label = 'Audrey Hepburn'
)
UNION ALL
SELECT e.target_node_id, w.depth + 1
FROM tkg_edges e JOIN walk w ON e.source_node_id = w.target_node_id
WHERE w.depth < 3
)
SELECT n.label, w.depth
FROM walk w JOIN tkg_nodes n ON w.target_node_id = n.id;
```
**這份 SQL 在 PG 和 SQLite 上完全一致,無需修改。**
---
## 3. 檔案內容包要求
每個 `file_{uuid}_{ver}.tar.gz` 必須包含 TKG
```
file_aeed71342a899fe4b4c57b7d41bcb692_v1.0.tar.gz
├── data.sql ← PG dump (videos, chunk, vectors, faces)
├── tkg.sqlite ← SQLite TKG (new requirement)
├── file_info.json
└── checksums.md5
```
### 匯出方式
```bash
# From PG: export node/edge data to SQLite
sqlite3 tkg.sqlite "ATTACH ...; CREATE TABLE ...; INSERT INTO ..."
```
```bash
# Or: tkg_builder.py generates both PG INSERT and SQLite
python3 tkg_builder.py build \
--uuid {uuid} \
--pg-output pg_tkg.sql \
--sqlite-output {uuid}.tkg.sqlite
```
---
## 4. Momentry Core 實作要求
### trait 定義
```rust
pub trait TkgStore: Send + Sync {
async fn get_nodes(&self, file_uuid: &str) -> Result<Vec<TkgNode>>;
async fn get_edges(&self, file_uuid: &str) -> Result<Vec<TkgEdge>>;
async fn traverse(&self, node_id: i64, max_depth: i32) -> Result<Vec<TkgPath>>;
async fn neighbors(&self, node_id: i64) -> Result<Vec<(TkgNode, TkgEdge)>>;
}
```
### 兩個實作,同一份 SQL
```rust
// PG backend
struct PgTkg { pool: PgPool }
impl TkgStore for PgTkg {
async fn traverse(&self, node_id: i64, max_depth: i32) -> ... {
sqlx::query_as(SAME_RECURSIVE_CTE_SQL) // WITH RECURSIVE ...
}
}
// SQLite backend
struct SqliteTkg { conn: rusqlite::Connection }
impl TkgStore for SqliteTkg {
async fn traverse(&self, node_id: i64, max_depth: i32) -> ... {
conn.prepare(SAME_RECURSIVE_CTE_SQL) // WITH RECURSIVE ... (same SQL)
}
}
```
### 啟動時選擇後端
```rust
let tkg: Box<dyn TkgStore> = match env::var("MOMENTRY_TKG_BACKEND")
.unwrap_or("pg".into()).as_str()
{
"sqlite" => Box::new(SqliteTkg::open("tkg.sqlite")?),
_ => Box::new(PgTkg::new(&pg_pool)),
};
```
---
## 5. 一致性原則
| 面向 | 原則 |
|------|------|
| **Schema** | PG 和 SQLite 表結構完全一致 |
| **匯出** | pipeline 建 TKG 時同時輸出 PG + SQLite |
| **查詢** | Recursive CTE SQL 語法一致,兩邊通用 |
| **檔案包** | 每個 tar.gz 必須含 `tkg.sqlite` |
| **分發** | PG 在 API serverSQLite 隨包分發 |
| **唯一異動** | `tkg_builder.py``--sqlite-output` 參數 |
---
## 6. 好處
| | PG-only (現狀) | + SQLite TKG |
|---|:--:|:--:|
| 檔案包自帶 TKG | ❌ | ✅ |
| 離線圖查詢 | ❌ | ✅ |
| Recursive CTE trait | ❌ 無 | ✅ 兩端統一 |
| Desktop/Tauri | ❌ | ✅ 單檔即可 |
| 跨機器轉移 | dump/restore | 複製 .sqlite |
@@ -0,0 +1,55 @@
# API 測試報告 — 3002 (Production) vs API 文件
**Date**: 2026-05-13
**From**: M4
---
## 測試範圍
| 環境 | Port | Schema |
|------|:---:|--------|
| Production | 3002 | `public` (chunks, old schema) |
| Development | 3003 | `dev` (chunk, new schema) |
共測試 18 個 endpoint。
---
## 結果:18/18 全過 (3002)
所有 endpoint 返回 200。無 500 或 404。
---
## DOC vs ACTUAL 格式差異(5 處)
與 API_REFERENCE_V1.0.0.md 的差異:
| # | Endpoint | DOC key | ACTUAL key | 影響 |
|---|----------|---------|------------|------|
| 1 | `/files` | `"files"` | `"data"` | Portal/Client 需改 |
| 2 | `/files` | 缺 `success` | `success:true` | |
| 3 | `/resources` | `"resources"` | `"data"` | |
| 4 | `/search/universal` | `"count"` | `"total"` | Portal 需改 |
| 5 | `/search/universal` | 缺分頁 | `page`, `page_size`, `took_ms` | |
| 6 | `/identities` | 缺分頁 | `count`, `page`, `page_size` | |
| 7 | `/faces/candidates` | ✅ | ✅ | 無差異 |
---
## 3002 vs 3003 差異
| Endpoint | 3002 | 3003 | 原因 |
|----------|:--:|:--:|------|
| `/file/:uuid/chunks` | 200 | **404** | dev 已 rename chunks→chunk |
| `/search/universal` | 需 `uuid` | 可省略 | 不同 schema 行為 |
| Identity endpoints | 不同資料 | 不同資料 | dev 有 v2.0 含 identity |
---
## 建議
1. **API doc 修正**:5 個欄位名錯誤(已回報 M4_workspace/2026-05-12_api_doc_verification.md
2. **/chunks 不一致**dev 已移除但 prod 仍可用 — M5 需決定遷移時程
3. **3002 schema 更新**public schema 仍需 M5 v1.0 migration
@@ -0,0 +1,33 @@
# api_test.sh v2.0 相容性回報
**Date**: 2026-05-13
**From**: M4
**To**: M5
---
v2.0 匯入後 api_test.sh 37/39。2 個 fail 是測試資料格式變更導致:
## Fail 1: Identity UUID 404
```
GET /api/v1/identity/2b0ddefe-e2a9-4533-9308-b375594604d5 → 404
```
**原因**v2.0 重新匯入 identity428 個 `PERSON_aeed7134_xxx`),舊 UUID 不存在。
**建議**test script 改用 `GET /api/v1/identities` 取得最新 identity UUID,或使用固定 test UUID。
## Fail 2: chunk/0-01 404
```
GET /api/v1/file/aeed7134.../chunk/0-01 → 404
```
**原因**v2.0 chunk ID 改為純數字(`0`, `1`, `2`...),不再使用 `{parent}-{seq}` 格式。
**建議**test script 改用 `chunk/0``chunk/875`(現有 chunk ID)。
## 結論
兩個 fail 都是資料格式變更導致,非 bug。api_test.sh 需要更新對應 v2.0 資料格式。
@@ -0,0 +1,42 @@
# public.chunk_vectors unique constraint 衝突
**Date**: 2026-05-13
**From**: M4
**To**: M5
**Priority**: High
---
## 問題
`public.chunk_vectors` 有兩個 unique constraint
```sql
"chunk_vectors_chunk_id_key" UNIQUE CONSTRAINT, btree (chunk_id) -- ❌ 衝突
"chunk_vectors_chunk_id_uuid_key" UNIQUE CONSTRAINT, btree (chunk_id, uuid) -- ✅ 正確
```
`chunk_vectors_chunk_id_key` 要求 chunk_id 在整個 table 中唯一。但兩個不同 UUID 的檔案可以有相同的 chunk_id(如兩者都用純數字編碼)。
### 實際衝突
```
aeed7134: chunk_id=2091 → chunk_vectors (aeed7134, 2091)
23b1c87 : chunk_id=2091 → INSERT FAILS (duplicate unique on chunk_id alone)
```
### 影響
23b1c87 的 2,340 chunk_vectors 無法匯入 public schema。
## 修正
```sql
ALTER TABLE public.chunk_vectors DROP CONSTRAINT IF EXISTS chunk_vectors_chunk_id_key;
```
`chunk_vectors_chunk_id_uuid_key` 已正確提供 `(chunk_id, uuid)` 複合唯一,不需要單獨的 chunk_id unique。
## 驗證
修正後 23b1c87 vectors 可成功匯入,aeed7134 vectors 不受影響。
@@ -0,0 +1,64 @@
# 空間與時間座標系統 Registry — M5 匯報
**Date**: 2026-05-13
**From**: M4
**To**: M5
**Ref**: `docs_v1.0/REFERENCE/SPATIAL_COORDINATE_REGISTRY.md`
---
## 完成項目
M4 已完成 Momentry Core 所有空間與時間座標系統的清查、校準、文檔化:
| Registry | 系統數 | 檔案位置 |
|----------|:--:|------|
| 空間 (spatial) | 18 個系統 | `REFERENCE/SPATIAL_COORDINATE_REGISTRY.md` §座標系統清單 |
| 時間 (temporal) | 16 個系統 | 同上 §時間座標系統 |
---
## 一致的部分(✅)
- **Top-Left 原點**:所有儲存/API/渲染層一致
- **ffmpeg drawbox/crop**:與 `face_detections` 原點一致,直接 passthrough
- **3D 視覺化 Y 翻轉**`SpaceTimeCube.vue` / `Face3DViewer.vue` 正確處理
- **FrameTime**Rust 核心時間型別定義清晰,`.round()` 統一
---
## 需 M5 修正的問題(8 項)
### 🔴 High (3)
| # | 問題 | 影響 | 位置 |
|---|------|------|------|
| **B1** | **Python `int()` vs Rust `.round()` 不一致** | Python 用 `int` (truncate), Rust 用 `.round()`。1.999s@30fps: Python=59f, Rust=60f。pre_chunks 跨語言傳遞會有 ±1 frame 誤差 | 15+ Python scripts |
| **B2** | **15+ Python scripts hardcoded FPS** | `25.0`, `24.0`, `30.0` 硬寫,非從 probe 讀取。非 25fps 影片 chunk 時間全錯 | `story_pipeline_full.py` 等 |
| — | **Landmark 座標不匹配** | 已另案報告 `2026-05-13_landmark_coord_mismatch.md` | `face.json` |
### 🟡 Medium (3)
| # | 問題 | 影響 | 位置 |
|---|------|------|------|
| **B3** | **`register_single_file` vs `probe_by_uuid` total_frames 不一致** | 前者 `as u64` (truncate), 後者 `.floor()` | `server.rs:763,1136` |
| **B4** | **`timestamp_secs` 冗餘欄位** | 與 `frame_number` 可能不同步,建議 deprecated | `face_detections` |
| **B5** | **`format_sec_frame()``.ceil()` 處理 fps** | 29.97fps 當 30fps 處理 | `time.rs:99` |
### 🟢 Low (2)
| # | 問題 | 影響 | 位置 |
|---|------|------|------|
| **B6** | **TypeScript 預設 fps=30** | 非 30fps 影片前端 frame 計算錯誤 | `client.ts:273` |
| **B7** | **`start_time` 只到 0.1s 精度** | 高精度 seek 失真 | `trace_agent_api.rs` |
| **B8** | **`total_frames` 型別不一致** | `Option<i64>` / `u64` / `i64` 三種 | DB structs |
---
## 建議 M5 行動
1. **Python second→frame 改用 `round()`** — 最高優先,消除 ±1 frame 差異
2. **Python FPS 改從 probe 讀取** — 不要 hardcode
3. **統一 `total_frames` 計算方式** — 註冊和探測用相同方法
4. **`timestamp_secs` 標記 deprecated** — 新增資料不再依賴
5. **更新 `api_test.sh`** — 驗證 frame 計算正確性
@@ -0,0 +1,35 @@
# deploy.sh — REQUIRED_FILES 未定義
**Date**: 2026-05-13
**From**: M4
**To**: M5
---
## Bug
`deploy.sh` line 52 引用 `${REQUIRED_FILES[@]}`,但變數從未定義:
```bash
echo "[1/8] Verifying package..."
MISSING=0
for f in "${REQUIRED_FILES[@]}"; do ← line 52: REQUIRED_FILES is undefined
```
執行時報錯:`REQUIRED_FILES[@]: unbound variable`
## Fix
在 for loop 前加入定義:
```bash
REQUIRED_FILES=("data.sql" "file_info.json")
```
修正後行號 50-52 應為:
```bash
echo "[1/8] Verifying package..."
REQUIRED_FILES=("data.sql" "file_info.json")
MISSING=0
```
@@ -0,0 +1,68 @@
#!/bin/bash
# Momentry Release Package — Deploy Script
# 原則: 一包一檔,只管內容所涵蓋的檔案
# Usage: bash deploy.sh
set -euo pipefail
DIR="$(cd "$(dirname "$0")" && pwd)"
UUID=$(basename "$DIR")
PG_BIN="${PG_BIN:-/Users/accusys/pgsql/18.3/bin}"
DB_NAME="${DB_NAME:-momentry}"
DB_USER="${DB_USER:-accusys}"
DEMO_DIR="${DEMO_DIR:-/Users/accusys/momentry/var/sftpgo/data/demo}"
echo "=== Momentry Package Deploy ==="
echo "UUID: $UUID"
echo "Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
# 1. Verify package — only this one file
echo "[1/4] Verifying package..."
REQUIRED_FILES=("data.sql" "file_info.json")
for f in "${REQUIRED_FILES[@]}"; do
if [ ! -f "$DIR/$f" ]; then
echo "ERROR: Missing required file: $f"
exit 1
fi
done
echo " ✅ Package verified (single file: $UUID)"
# 2. Import data.sql (already contains videos.chunk.chunk_vectors.face_detections.identities...)
echo "[2/4] Importing DB data..."
"$PG_BIN/psql" -U "$DB_USER" -d "$DB_NAME" -f "$DIR/data.sql" 2>&1 | tail -3
echo " ✅ Data imported"
# 3. Set video status to completed (已處理)
echo "[3/4] Setting deployment status..."
"$PG_BIN/psql" -U "$DB_USER" -d "$DB_NAME" -c "
UPDATE videos SET status = 'completed' WHERE file_uuid = '$UUID'
" > /dev/null 2>&1
echo " ✅ Status set to 'completed'"
# 4. Copy video to demo dir (only this package's video, not scanning others)
VIDEO_FILE=$(ls "$DIR"/*.mp4 "$DIR"/*.mov "$DIR"/*.avi "$DIR"/*.mkv 2>/dev/null | head -1)
if [ -n "$VIDEO_FILE" ]; then
VIDEO_NAME=$(basename "$VIDEO_FILE")
DEST="$DEMO_DIR/$VIDEO_NAME"
if [ ! -f "$DEST" ]; then
cp "$VIDEO_FILE" "$DEST"
echo "[4/4] Video copied: $VIDEO_NAME"
else
echo "[4/4] Video already present, skipping"
fi
else
echo "[4/4] No video file in package, skipping"
fi
# Verify
CHUNKS=$("$PG_BIN/psql" -U "$DB_USER" -d "$DB_NAME" -t -A -c "SELECT COUNT(*) FROM dev.chunk WHERE file_uuid='$UUID'" 2>/dev/null || echo "?")
FACES=$("$PG_BIN/psql" -U "$DB_USER" -d "$DB_NAME" -t -A -c "SELECT COUNT(*) FROM dev.face_detections WHERE file_uuid='$UUID'" 2>/dev/null || echo "?")
echo ""
echo "=== Deploy Complete ==="
echo " UUID: $UUID"
echo " Status: completed"
echo " Chunks: $CHUNKS"
echo " Faces: $FACES"
echo ""
echo "Verify: http://localhost:3003/api/v1/file/$UUID"
@@ -0,0 +1,38 @@
# Re: deploy.sh — 剩餘問題
**Date**: 2026-05-13
**From**: M4
**To**: M5
---
已確認 M5 更新版本。修正項目 ✅ 通過:
- chunk_type filter 已移除
- identity count 驗證已加入
- TKG 驗證已加入
- schema prefix (`dev.chunk` 等) 已加入
## 三個剩餘問題
### 1. ⚠️ 影片複製區塊重複(行 40-65)
行 40-53 和行 54-65 是同一段邏輯的重複貼上。執行時會複製兩次。
**修正**:刪除行 54-65。
### 2. ❌ 匯入後未設定 status = 'completed'
內容包已處理完畢,匯入後該檔案應為「已處理」。目前 deploy.sh 沒有 `UPDATE videos SET status`
**修正**:在 import 後加入:
```bash
"$PG_BIN/psql" -U "$DB_USER" -d "$DB_NAME" -c \
"UPDATE dev.videos SET status = 'completed' WHERE file_uuid = '$UUID'"
```
### 3. ⚠️ 仍提示啟動 pipeline(行 99-100
內容包已為完整處理後狀態,不需要再觸發 pipeline。提示會誤導使用者。
**修正**:刪除或改為驗證提示。
@@ -0,0 +1,54 @@
# Face Landmark Coordinate Mismatch
**Date**: 2026-05-13
**From**: M4
**To**: M5
**Priority**: High
---
## Discovery
`face.json` contains landmark data for ALL 70,691 face detections (right_eye 6pts, left_eye 6pts, nose 8pts). However, landmark coordinates do not align with their corresponding bounding boxes.
## Data
| Metric | Value |
|--------|------:|
| Total faces | 70,691 |
| Faces with landmarks | 70,691 (100%) |
| Total landmark points | 1,413,820 |
| **Points OUTSIDE bbox** | **1,239,047 (87.6%)** |
| **Faces with ≥1 outside point** | **64,673 (91.5%)** |
## Example Violation
```
frame=4572:
bbox: [x=0, y=870, 325×325] ← bottom of 1080p frame
left_eye: [(-11, 139), (2, 144), ...] ← top of frame
y difference: bbox y=870, eye y=139 → 731px apart in different regions
```
## Likely Causes
| # | Cause |
|---|-------|
| 1 | Landmarks use **frame-level coordinates**, bbox uses **face-cropped coordinates** |
| 2 | Landmark data and bbox data are **mismatched** (belong to different detections) |
| 3 | Y-axis may be flipped (different detector convention) |
## Impact
- ❌ Landmark visualization (eye/nose overlay) will be incorrect
- ❌ Landmark-based identity matching will fail
- ❌ Data unusable for downstream landmark analysis
- ⚠️ Demo showing face landmarks will display incorrectly
## Required Fix
1. Unify landmark and bbox coordinate system
2. Re-run face pipeline with corrected landmark output
3. Regenerate `face.json` and PostgreSQL data
4. Re-deliver updated file content package
@@ -0,0 +1,31 @@
# Decision #1 更正:Release Binary 由 M5 交付
**Date**: 2026-05-13
**From**: M4
**To**: M5
**Ref**: `2026-05-13_release_decision_response.md`
---
## 更正
`momentry_core` 的 build pipeline 由 M5 維護。M4 只負責測試與部署,不負責 build。
## 修正後的 Release 分工
| Item | Owner | 說明 |
|------|:--:|------|
| **`momentry` release binary** | **M5** | M5 編譯交付(version 1.0.0, build 01742b2 |
| `.env.production` config | M4 | `DATABASE_SCHEMA=public` etc. |
| `aeed7134` package | M5 | 檔案內容包 |
| `23b1c87` package | M5 | 檔案內容包 |
## 其他 5 項決策不變
| # | 決策 | Owner |
|---|------|:--:|
| 2 | Schema: public.chunks → public.chunk (RENAME) | M4 執行 |
| 3 | Identity: 保留 prod 15 TMDB + merge dev data | M4 執行 |
| 4 | Downtime: Maintenance mode (503) | M4 執行 |
| 5 | Scope: both aeed7134 + 23b1c87 | M5 交付兩包 |
| 6 | Config: `.env.production` with `DATABASE_SCHEMA=public` | M4 準備 |
@@ -0,0 +1,19 @@
# Release SOP Decision Log — 請 M5 回覆
**Date**: 2026-05-13
**From**: M4
**To**: M5
**Ref**: `REFERENCE/RELEASE_SOP_V2.0.md` §8
---
SOP 第 8 章 Decision Log 有 6 項待 M5 決定。確認後即可執行 release:
| # | 問題 | 選項 |
|---|------|------|
| **1** | Production binary 來源? | A. M5 提供 release binary / B. M4 從 source 自編 `cargo build --release` |
| **2** | Schema: public.chunks → public.chunk | A. 執行 RENAME / B. 保留 `chunks` 另做相容 |
| **3** | Identity merge | A. 保留 prod 現有 15 TMDB + import dev data / B. 清空 prod 只用 dev data |
| **4** | Downtime 方式? | A. Maintenance mode (503 all requests) / B. Hard stop + restart |
| **5** | Release scope | A. `aeed7134` only / B. both `aeed7134` + `23b1c87` (YouTube) |
| **6** | Production config | A. `DATABASE_SCHEMA=public` via .env / B. Hardcoded in binary |
@@ -0,0 +1,73 @@
# Release 執行時發現的修正需求
**Date**: 2026-05-13
**From**: M4
**To**: M5
**Priority**: High
---
## 發現問題
aeed7134 deploy to `public` schema 時發生 3 個 error,均已當場手動修正後通過:
| # | Error | Root Cause | Fix Applied |
|---|-------|-----------|-------------|
| 1 | `videos_pkey` duplicate | 舊 `public.videos` data 未清除 | `DELETE FROM public.videos WHERE file_uuid = '{uuid}'` |
| 2 | `column "file_uuid" does not exist` | `public.identities` 缺 v2 schema column | `ALTER TABLE public.identities ADD COLUMN file_uuid VARCHAR(64)` |
| 3 | `identity_bindings_pkey` duplicate | 舊 bindings 未清除 | `DELETE FROM public.identity_bindings WHERE identity_id IN (...)` |
---
## 對 deploy.sh 的修正
### Step 2 pre-clean 需擴展
當前 pre-clean 只刪除 identities
```bash
DELETE FROM identities WHERE file_uuid = '{uuid}';
```
需擴展為清除全部受影響 table
```bash
DELETE FROM chunk_vectors WHERE uuid = '{uuid}';
DELETE FROM chunk WHERE file_uuid = '{uuid}';
DELETE FROM face_detections WHERE file_uuid = '{uuid}';
DELETE FROM tkg_edges WHERE file_uuid = '{uuid}';
DELETE FROM tkg_nodes WHERE file_uuid = '{uuid}';
DELETE FROM identity_bindings WHERE identity_id IN (
SELECT id FROM identities WHERE tmdb_id IS NOT NULL OR name LIKE 'PERSON_{short_uuid}%'
);
DELETE FROM identities WHERE file_uuid = '{uuid}' OR source = 'tmdb';
DELETE FROM videos WHERE file_uuid = '{uuid}';
```
---
## 對 release SOP 的修正
### SOP Step 3 schema migration 需加入
```sql
ALTER TABLE identities ADD COLUMN IF NOT EXISTS file_uuid VARCHAR(64);
```
dev schema 已有此 columnv2.0 111614 package identity CSV 包含 file_uuid
---
## Release 現狀
aeed7134 已成功 deploy to public schema
| Table | Count |
|-------|------:|
| chunk | 2,407 |
| faces | 70,691 |
| videos | 1 |
| TMDB identities | 15 |
| tkg_nodes | 6,457 |
| tkg_edges | 21,028 |
| status | completed |
@@ -0,0 +1,111 @@
# Release Notes — v1.0.0 (Production 3002)
**Date**: 2026-05-13
**Build**: `301da08`
**Deployed by**: M4
---
## Release Scope
### Binaries
| Binary | Size | Source |
|--------|:----:|--------|
| `momentry` (production) | 21 MB | M5 build |
| `release` CLI | 3.5 MB | M5 build |
### File Packages
| Package | UUID | Content |
|---------|------|---------|
| Charade (HD) | `aeed71342a899fe4b4c57b7d41bcb692` | 1920×1080, 25fps |
| Charade (YouTube) | `23b1c872379d4ec06479e5ed39eef4c5` | 640×360, 23.98fps |
### Data Per Package
| Table | HD | YouTube |
|-------|:--:|:--:|
| chunk | 2,407 | 2,340 |
| chunk_vectors (768D) | 2,407 | 2,340 |
| face_detections | 70,691 | 70,729 |
| identities (TMDB) | 15 actors | 280 clusters |
| identity_bindings | 18,635 | 18,635 |
| tkg_nodes | 6,457 | 5,776 |
| tkg_edges | 21,028 | 18,847 |
### TMDB Matched Actors
| Actor | TMDB ID | Package |
|-------|:------:|:--:|
| Cary Grant | 2638 | HD |
| Audrey Hepburn | 1932 | HD |
| James Coburn | 5563 | HD |
| George Kennedy | 12950 | HD |
| Dominique Minot | 41714 | HD |
| Ned Glass | 18870 | HD |
| Jacques Marin | 26890 | HD |
| Paul Bonifas | 41716 | HD |
---
## Schema Changes
| Change | Schema |
|--------|--------|
| `chunks``chunk` (rename) | public |
| Drop `old_chunk_id`, `chunk_index` | public |
| Add `timestamp_secs` to `face_detections` | public |
| Add `file_uuid` to `identities` | public |
| Drop `chunk_vectors_chunk_id_key` (duplicate unique) | public |
---
## Verification
### API (all 200)
| Category | Endpoints | Result |
|----------|-----------|:--:|
| Health | `/health`, `/health/detailed` | ✅ |
| Auth | login, logout | ✅ |
| Files | list, scan, detail, probe | ✅ |
| Chunk | `/file/{uuid}/chunk/{id}` | ✅ |
| Search | universal, frames, visual | ✅ |
| Identities | list, detail, files, chunks | ✅ |
| Face Trace | sortby, faces, 3D | ✅ |
| Media | video, thumbnail, trace video | ✅ |
| Resources | list | ✅ |
### Database
| Table | Count |
|-------|------:|
| Files registered | 38 |
| TMDB identities | 15 |
| Total chunks (both files) | 4,747 |
| Total faces (both files) | 141,420 |
| Total TKG nodes | 12,233 |
| Total TKG edges | 39,875 |
---
## Deployment Process
1. **Backup**: Full `public` schema dump (1.3 GB)
2. **Schema Migration**: `chunks→chunk`, drop deprecated columns, add new columns
3. **Deploy aeed7134**: All 8 tables imported via `sed dev.→public.` per-table SQL files
4. **Deploy 23b1c87**: Fixed `chunk_vectors_chunk_id_key` constraint conflict, all 8 tables imported
5. **Binary Swap**: Old binary stopped, M5 `momentry_v1.0.0` deployed, restarted on 3002
6. **Verification**: All API endpoints 200, both files queryable
---
## Known Notes
| Item | Note |
|------|------|
| `/files` status | API hardcodes `"ready"`, does not reflect actual DB status (reported to M5) |
| `/files/scan` | Only scans video extensions (mp4/mov/mkv/avi/webm), misses jpg/png |
| deploy.sh schema | Uses `sed dev.→public.` for public deployment (pending M5 native SCHEMA support) |
| chunk_vectors constraint | `chunk_vectors_chunk_id_key` dropped from public (was preventing multi-file import) |
@@ -0,0 +1,77 @@
# 3002 Production — Scan 與 Files 狀態驗證
**Date**: 2026-05-13
**From**: M4
---
## Issue 1: Scan 覆蓋不足
| 指標 | 數值 |
|------|:----:|
| Demo 目錄實際檔案數 | **106** |
| Scan 回傳檔案數 | **23** |
| 缺漏 | **83** |
### 原因
`scan_directory_recursive` 只過濾 `["mp4", "mov", "mkv", "avi", "webm"]`server.rs:1905)。Demo 目錄有大量 `.jpg``.png` 檔案(animal1.jpg, animal2.jpg 等)不在過濾清單中。
### 影響
- Portal FilesView 只顯示 23 個檔案
- 83 個圖片/非影片檔案完全看不到
- `.jpg` `.png` 應該加入 allowed_extensions
---
## Issue 2: `/files` 狀態與事實不符
| | DB 實際狀態 | API 回報 |
|---|:--:|:--:|
| completed | 3 | — |
| processing | 2 | — |
| pending | 8 | — |
| failed | **23** | — |
| — | — | **ready: 36** |
### 原因
`identity_api.rs:97` hardcodes status
```rust
status: "ready".to_string(), // Hardcoded for now
```
API 回傳的 `status` 不是從 DB 讀取的,是寫死的。
### 影響
- Portal FilesView 顯示所有檔案為「已就绪」(綠色 ✅),即使 23 個是 `failed`
- 使用者看不到真實的處理狀態
- Portal 狀態過濾器(pending/processing/completed)全部無效
### 修正
```rust
// identity_api.rs — 從 DB 讀取 status
let records = state.db.list_files(page_size, offset).await?;
let data = records.into_iter().map(|r| FileItem {
file_uuid: r.file_uuid,
file_name: r.file_name,
file_path: r.file_path,
status: r.status.unwrap_or("unknown".to_string()), // ← 改這行
}).collect();
```
---
## Issue 3: Scan registered vs /files list 不一致
| | Scan | /files list |
|---|:--:|:--:|
| Registered files | 21 | 36 |
**15 個已註冊檔案不在 Scan 結果中** — 這些檔案在 DB 中有紀錄,但 demo 目錄中對應的實體檔案已不存在(被刪除或移動)。
**2 個 Scan 中的檔案未註冊**`Charade_YouTube_24fps.mp4` 和另一個檔案。它們在目錄中但未在 `public.videos` 中註冊。
@@ -0,0 +1,110 @@
# V2.0 檔案內容包 — 問題與建議
**Date**: 2026-05-13
**From**: M4
**To**: M5
---
## 問題清單
### ❌ Issue 1: TKG 未匯入 PostgreSQL
TKG 資料(6,457 nodes, 21,028 edges)只存在 SQLite,未匯入 PG。`deploy.sh` 只跑 `data.sql`,沒有 TKG 匯入步驟。
```sql
-- PG: 0 tkg_nodes, 0 tkg_edges
-- SQLite: 6457 tkg_nodes, 21028 tkg_edges
```
**建議**`data.sql` 應包含 `COPY dev.tkg_nodes` + `COPY dev.tkg_edges`
---
### ⚠️ Issue 2: TMDB 匹配未套用
428 個 identity 全部命名為 `PERSON_aeed7134_xx`(原始 clustering 輸出),tmdb_id 全為 NULL。
HANDOVER_V2.0.md 提到「TMDB matched: Audrey Hepburn 843 traces, Cary Grant 482」,但實際身份表中無對應。
| | DOC says | ACTUAL |
|---|---------|--------|
| Audrey Hepburn | 843 traces | 0 |
| Cary Grant | 482 traces | 0 |
| Any tmdb_id | — | 0/428 |
**trace_to_identity.json 中有 trace→identity 映射**5,483 records),但 identity 名稱仍是 `PERSON_xxx`
**建議**TMDB matching step 需在打包前執行,identity 名稱應更新為 TMDB 演員名。
---
### ⚠️ Issue 3: identity_bindings 數量不一致
| 來源 | bindings 數 |
|------|-----------:|
| PG (after import) | 10,966 |
| SQLite | 5,483 |
| HANDOVER doc | 5,483 |
PG 數量是 SQLite 的 2 倍,因為 `data.sql` 的 COPY 匯入了**跨檔案**的全局 identity_bindings,不是此檔案專屬。
**建議**`data.sql` 匯出時過濾 `WHERE identity_id IN (SELECT id FROM identities WHERE source = 'auto')` 或只匯出此檔案的 binding。
---
### ⚠️ Issue 4: 只有 sentence chunks
| chunk_type | v1.0 | v2.0 |
|-----------|-----:|-----:|
| sentence | 4188 | 2407 |
| cut | 1130 | **0** |
| story | 280 | **0** |
| trace | 423 | **0** |
只匯出了 sentence chunk,缺少 cut/story/trace/visual 類型。
**建議**:確認 M5 pipeline 是否已完成 scene/story/trace chunking。若已完成,`data.sql` 應包含所有 chunk_type。
---
### ❌ Issue 5: Landmark 座標不匹配
已另案報告 (`2026-05-13_landmark_coord_mismatch.md`)。
87.6% 地標點不在 bbox 範圍內。
---
### ⚠️ Issue 6: SQLite 向量無法直接查詢
sqlite-vec 資料表存在(chunk/face/voice embeddings),但需要 `vec0` extension 才能查詢。CLI 無法直接使用。
**建議**:包內附 `vec0.dylib` 或提供 `sqlite-vec` 安裝 script。
---
## 建議優先級
| # | Issue | Priority | 說明 |
|---|-------|:--:|------|
| 1 | TKG → PG | 🔴 | 核心資料缺失 |
| 2 | TMDB matching | 🔴 | Identity 無法用於 Portal 顯示 |
| 5 | Landmark mismatch | 🔴 | 資料無法用 |
| 4 | Missing chunk types | 🟡 | 影響功能完整度 |
| 3 | identity_bindings count | 🟡 | 資料不乾淨 |
| 6 | SQLite vec0 query | 🟢 | 可用第三方工具 |
---
## 已確認正常
| 項目 | 狀態 |
|------|:--:|
| PG copy 匯入 (6 tables) | ✅ |
| SQLite 結構 + 資料 | ✅ |
| Face coverage 100% | ✅ |
| Face traces 5483 | ✅ |
| Chunk 2407 sentences | ✅ |
| Speaker map 899 | ✅ |
| Video file 存在 | ✅ |
| API 功能 (37/39) | ✅ |
| Demo 21/21 | ✅ |
@@ -0,0 +1,35 @@
# deploy.sh — 新增 --force 參數
**Date**: 2026-05-14
**From**: M4
**To**: M5
---
## 變更
`deploy.sh` 加入 `--force` 參數,跳過覆寫確認提示。
## 使用方式
```bash
# 互動式(有舊資料時會詢問確認)
SCHEMA=public bash deploy.sh
# 強制覆蓋(不詢問,直接取代)
SCHEMA=public bash deploy.sh --force
```
## 行為
| 情境 | 無 --force | 有 --force |
|------|:--:|:--:|
| 無舊資料 | 直接部署 | 直接部署 |
| 有舊資料 | ⚠️ 顯示警告 + [y/N] 確認 | 🔧 跳過確認,直接取代 |
## 檔案變更
| 檔案 | 說明 |
|------|------|
| `deploy.sh` | L15-16: 新增 `FORCE` 變數 + `--force` 參數解析 |
| `deploy.sh` | L80-82: 確認區塊加入 `FORCE` 跳過邏輯 |
@@ -0,0 +1,37 @@
# 2026-05-14_inference_down.md
## 問題
生產環境 (3002) 的 inference engine (gemma4 LLM) 無法連線。
## 環境資訊
| 項目 | 值 |
|------|-----|
| API Server | localhost:3002 (production) |
| Schema | public |
| 時間 | 2026-05-14 15:50 +08:00 |
## 現狀
### 正常
- **Local embedding** (embeddinggemma-300m): ✅ 運行中 (port 11436, MPS)
- **Local embedding** (bge-m3-q8_0): ✅ 運行中 (port 8082)
- **Local embedding** (mxbai-embed): ✅ 運行中 (port 8083)
- **CoreML face embedding**: ✅ 運行中 (port 11435)
### 異常
- **M5 inference** (gemma4): ❌ 無法連線
- `http://192.168.110.201:8081` → 無回應
- `http://192.168.110.201:11434` → 無回應
### 影響
- `/api/v1/stats/inference` 回報兩個 engine 皆 error(但 health check hardcode 了 localhost,未反映 M5 真實端點)
- 生產環境 searchable_chunks: **4 / 15,367** — embedding/summarization pipeline 已停滯
- 8 筆影片 pending,無法完成處理
## 請求
1. 確認 M5 上的 gemma4 inference 服務狀態
2. 重啟 inference 服務(port 8081 或實際使用的端點)
3. 確認後請回覆 `2026-05-14_inference_down_response.md`
@@ -0,0 +1,34 @@
# 165302 包部署回報 — 數量差異
**Date**: 2026-05-14
**From**: M4
**To**: M5
**Ref**: `2026-05-14_pipeline_v2_delivery.md`
---
## 部署結果
包已成功部署到 `public` schemaaed7134 status = completed。
## 數量差異
| Metric | Delivery Doc 宣稱 | 實際 Import | 差異 |
|--------|:--------:|:--------:|:----:|
| Face traces | 9,825 | 5,483 | -4,342 |
| TKG edges | 370,310 | 30,987 | -339,323 |
| TKG nodes | 9,900 | 9,900 | ✅ 一致 |
| chunk | — | 2,407 | ✅ |
| faces | — | 70,691 | ✅ |
TKG edge CSV 只有 30,991 lines,文件大小 8.5MB。與 doc 的 370,310 差距巨大。
## 改善項目
TMDB 演員從 7 位增加到 **15 位**(新增 Walter Matthau、Thomas Chelimsky、Marc Arian、Claudine Berg、Marcel Bernier、Albert Daumergue、Raoul Delfosse)。
## 問題
1. `identities_name_key` unique constraint 造成 import 失敗(已手動 DROP 解決)
2. TKG edge 數量與 delivery doc 不符
3. Face trace 數量與 delivery doc 不符
@@ -0,0 +1,29 @@
# schemafix binary — still querying dev
**Date**: 2026-05-14
**From**: M4
**To**: M5
**Priority**: High
---
## Issue
`momentry_v1.0.0_schemafix` 仍查詢 `dev.face_detections`trace 9530 回 0。
## Evidence
| Test | Result |
|------|--------|
| chunk/0 (uses schema::table_name) | ✅ 200 |
| trace/9530/faces | total=0 (DB has 434) |
| trace sortby total_traces | 5,483 (DB has 9,825) |
| Binary build_git_hash | NOT in /health |
## Likely Cause
Binary built **before** commit `e8f44d7` (trace_agent_api schema fix). File timestamp is delivery time, not build time.
## Request
Rebuild binary from HEAD (includes `e8f44d7`), verify `/health` shows `build_git_hash`, re-deliver as separate file.
@@ -0,0 +1,42 @@
# trace_agent_api.rs — dev.face_detections hardcode
**Date**: 2026-05-14
**From**: M4
**To**: M5
**Priority**: High
---
## Issue
`src/api/trace_agent_api.rs` 硬編碼 `dev.face_detections`,無視 `DATABASE_SCHEMA` 環境變數。
## 影響
Production (3002, `DATABASE_SCHEMA=public`) 無法讀取新版 face trace 資料。
| DB has | API returns |
|--------|-------------|
| trace 9530 = 434 faces | trace 9530 = 0 |
| total_traces = 9,825 | total_traces = 5,483 (old data) |
API 永遠查 `dev.face_detections`,不查 `public.face_detections`
## Affected Lines
| Line | Current | Should Be |
|------|---------|-----------|
| 101 | `FROM dev.face_detections` | `FROM {schema}.face_detections` |
| 110 | `FROM dev.face_detections` | `FROM {schema}.face_detections` |
| 146 | `FROM dev.face_detections` | `FROM {schema}.face_detections` |
| 253 | `FROM dev.face_detections` | `FROM {schema}.face_detections` |
| 271 | `FROM dev.face_detections` | `FROM {schema}.face_detections` |
## Fix
```rust
let table = schema::table_name("face_detections");
sqlx::query(&format!("SELECT ... FROM {} WHERE ...", table))
```
而非硬編碼 `"dev.face_detections"`