openvibers/openvibe.vision CHANGELOG.md
CHANGELOG.md
| 1 | # Changelog |
| 2 | |
| 3 | What changed in OpenVibe.Vision, newest first. |
| 4 | |
| 5 | ## Unreleased — VIS-6 |
| 6 | |
| 7 | - Review follow-up: the image pass is fail-closed (harmless text can no longer clear an image it could not judge; |
| 8 | only sex_acts/minor_sexual text may answer, otherwise 503), `preview_url` is https on a first-party host only, and |
| 9 | the operator's page withholds category-2/3 pictures until a logged 60-second Media evidence view. Adds |
| 10 | `vision_review_reveals` and `object_app`/`media_object_id`/`media_app` on a review; Contracts v0.294.0. |
| 11 | - Added the unsafe-image review: exactly three categories in plain words (`fine` including nudity, `sex_acts` never |
| 12 | public, `minor_sexual` always blocked and reported to the operator), `POST /api/v1/review` for Media, Live and |
| 13 | Community, a staff queue at `/review`, one review page with the same three choices and the operator report at |
| 14 | `/review/reports`. Category 3 always makes one `vision_operator_reports` row; nothing is reported outside OpenVibe. |
| 15 | The review stores no image bytes, only an object reference, a sha256 and the model provenance. Migration |
| 16 | `0007_unsafe_image_reviews.sql`; tests `test/review.test.js`. |
| 17 | |
| 18 | ## Unreleased — VIS-5 |
| 19 | |
| 20 | - Added a Streamable HTTP MCP endpoint with eleven tools, protected-resource metadata, token challenges and the |
| 21 | same permission boundaries as the JSON API. Face identity and consent mutation remain person-only API flows. |
| 22 | - Aligned service-token checks with the twenty capability IDs in Contracts 0.240.0. Anonymous local and privacy |
| 23 | tools remain open. Verification gives the same refusal before and after consent until enrollment is complete. |
| 24 | - Publishes `vision.result.ready` and `vision.alert` through OpenVibe.Events when Events is configured. Event |
| 25 | payloads contain provenance and class names, never image bytes, answer text or face templates. |
| 26 | - Publishes through a durable outbox (`event_outbox`, migration `0004_event_outbox.sql`): the event waits in the |
| 27 | table until OpenVibe.Events takes it, so a publish that fails because Events is down or the network blipped is |
| 28 | retried with backoff instead of lost. Delivery is at least once and the event's own id is the idempotency key |
| 29 | Events dedupes on. The relay is off in a drill. |
| 30 | |
| 31 | ## 0.1.0 — 2026-10-28 |
| 32 | |
| 33 | The first version: see with the best model for the job. |
| 34 | |
| 35 | - **Ask a picture.** `POST /api/v1/ask` takes a multipart image, an image data URL or a public `image_url`, plus a |
| 36 | question and one of `ask|describe|identify|count|translate|ocr`. A read question is answered by the local OCR |
| 37 | reader first; anything else goes through OpenVibe.AI. The answer names the engine, model, provider, route, reason, |
| 38 | cost and measured latency. |
| 39 | - **Local OCR first.** `POST /api/v1/ocr` runs Tesseract 5 on this host (one OpenMP thread, a temporary file that is |
| 40 | removed), returns the text, mean confidence and word boxes, and costs zero. `fallback=1` asks AI only when the |
| 41 | local pass found no usable text; a missing binary is an honest 503, never a silent cloud call. |
| 42 | - **Compare side by side.** `POST /api/v1/compare` runs the local reader and up to three AI hints on the same image. |
| 43 | The requested model is only a hint: the provider and model reported are AI's own provenance. Each row carries |
| 44 | success, text, cost and latency; `GET /api/v1/benchmarks` aggregates them per engine/model without subjects. |
| 45 | - **The UI check.** `POST /api/v1/ui-check` reads HTML, a public page URL or a screenshot locally. The static pass |
| 46 | estimates boxes and inline CSS to find overflow, cut-off text, WCAG contrast failures, overlapping positioned |
| 47 | boxes and layering faults (`z-index` without position, a full-viewport fixed box). The screenshot pass uses the |
| 48 | local OCR boxes and sharp pixels. Findings are data: kind, severity, selector, detail, evidence. Design's Arena |
| 49 | calls it with `vision.ui.check`. |
| 50 | - **The AI gateway.** Vision calls OpenVibe.AI's OpenAI-compatible endpoint with a first-party service token |
| 51 | (`ai.run.create`, namespace `ai.*`). AI's routing, quotas, cache, provenance and cost accounting apply. Vision holds |
| 52 | no provider key, adds no provider and calls no paid provider directly. |
| 53 | - **No looks in AI text.** Public AI text goes through `noLooks`; an answer that names a person's looks is replaced by |
| 54 | a neutral sentence. |
| 55 | - **Faces, by purpose, with signed consent.** `POST /api/v1/faces/detect` and `/blur` are open local YuNet privacy |
| 56 | tools with no templates or tracking. Self verification, self search, adult cast tagging and private library |
| 57 | grouping each need their own signed consent (`face_consents`), a local SFace template encrypted with |
| 58 | `VISION_FACE_KEY` (AES-256-GCM), and immediate erasure on opt-out. A cast matcher reads only the named channel's |
| 59 | roster and revoking deletes past tags. Library grouping is region-gated and unknown faces stay unlabelled. |
| 60 | `POST /api/v1/faces/verify` returns a score, threshold and `liveness: "not_checked"`, never an identity. The daily |
| 61 | retention job (off in `VISION_DRILL`) expires templates three years after last use. `npm run models:faces` pins the |
| 62 | YuNet and SFace downloads by URL and SHA-256. Pages: `/people` and `/people/privacy`; `/privacy` stays the shared |
| 63 | legal policy. |
| 64 | - **Network tools, wave 1.** `POST /api/v1/alt` (routed editable alt text), `POST /api/v1/index` and |
| 65 | `GET`/`POST /api/v1/find` (owner-scoped CLIP search), `POST /api/v1/receipt` (local Tesseract first), |
| 66 | `POST /api/v1/product` (CLIP vector plus configured offers), `POST /api/v1/watch` (DETR boxes and scene change) |
| 67 | and `POST /api/v1/moments` (scene histogram plus CLIP prompts). Each answer carries a receipt. `npm run |
| 68 | models:fetch` downloads pinned quantized CLIP and DETR weights; missing weights degrade to an honest 503. |
| 69 | - **Privacy.** General answers store no image bytes: an answer keeps a sha256, the media type, the cleaned text and |
| 70 | the model provenance. Opt-in face uploads, vectors and templates are encrypted. Answers, compare samples, UI checks |
| 71 | and every face row are exported and erased with the person's account. |
| 72 | - **The service.** Network sign-in as OAuth client `vision` (PKCE S256, `vision_at`/`vision_rt`/`vision_oauth`), |
| 73 | truthful readiness, Prometheus metrics on loopback, discovery, a systemd unit, an nginx vhost and CI. Pages are |
| 74 | server-rendered with stable `vi-` ids/classes; `public/css/vision.css` and `public/js/vision.js` are |
| 75 | one-comment placeholders for the main session. |
| 76 | - **Tests.** Migration, SSO, API, OCR, compare/benchmarks, the UI check (including a planted overflow), noLooks, |
| 77 | pages/cache, account export/deletion, faces with a fake ONNX model (consent gates, roster-only matching, |
| 78 | encryption at rest, opt-out, retention, region gate and export/deletion), and the network tools with fake CLIP, |
| 79 | DETR and OCR, each in its own process on a temporary PGlite database with a mock Network, a mock OpenVibe.AI and |
| 80 | local image/page fixtures. |
| 81 |