Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
950b844
Centralize all backend environment access into a single typed, valida…
aaronstevenwhite Jun 17, 2026
3cc1193
Merge pull request #145 from parafovea/refactor/phase-1a-backend-config
aaronstevenwhite Jun 17, 2026
360f1e8
Add a create-release job to release.yml that extracts the matching CH…
aaronstevenwhite Jun 17, 2026
fac87bb
Merge pull request #146 from parafovea/fix/release-workflow-auto-gith…
aaronstevenwhite Jun 17, 2026
d0c633b
Centralize all frontend environment access into a single typed, deep-…
aaronstevenwhite Jun 17, 2026
3bc662d
Merge pull request #147 from parafovea/refactor/phase-1b-frontend-config
aaronstevenwhite Jun 17, 2026
10038a1
Promote the model-service to a single typed pydantic-settings Setting…
aaronstevenwhite Jun 17, 2026
df2c545
Merge pull request #148 from parafovea/refactor/phase-1c-model-servic…
aaronstevenwhite Jun 17, 2026
075576c
Add a CI configuration-drift guard (scripts/check-env-example.mjs, wi…
aaronstevenwhite Jun 17, 2026
fbb6cd3
Merge pull request #149 from parafovea/refactor/phase-1d-config-drift…
aaronstevenwhite Jun 17, 2026
96a7454
Pin Node and pnpm in one place by adding a root .nvmrc (Node 22) and …
aaronstevenwhite Jun 17, 2026
7b27938
Merge pull request #150 from parafovea/refactor/phase-2a-node-pnpm-pin
aaronstevenwhite Jun 17, 2026
206314a
Add a verify-compose CI job that validates all ten docker compose con…
aaronstevenwhite Jun 17, 2026
909a288
Merge pull request #151 from parafovea/refactor/phase-2b-compose-vali…
aaronstevenwhite Jun 17, 2026
eb03c3a
Delete the duplicate server/docker-compose.dev.yml that redefined Pos…
aaronstevenwhite Jun 17, 2026
e6b19c8
Merge pull request #152 from parafovea/refactor/phase-2c-dev-infra-co…
aaronstevenwhite Jun 17, 2026
9b2541c
Consolidate the model-service's orphaned tests directory into the con…
aaronstevenwhite Jun 17, 2026
252963a
Merge pull request #153 from parafovea/refactor/phase-3a-consolidate-…
aaronstevenwhite Jun 17, 2026
7453b6e
Add a root Makefile as the single install/lint/typecheck/test/build e…
aaronstevenwhite Jun 17, 2026
1a11923
Merge pull request #154 from parafovea/refactor/phase-3b-unified-test…
aaronstevenwhite Jun 17, 2026
2994852
Reconcile CI documentation with reality by rewriting the stale workfl…
aaronstevenwhite Jun 17, 2026
dcf10da
Merge pull request #155 from parafovea/refactor/phase-3c-ci-reconcili…
aaronstevenwhite Jun 17, 2026
c7cfc3b
Stop the startup config validation from requiring API_KEY_ENCRYPTION_…
aaronstevenwhite Jun 18, 2026
3f194e0
Merge pull request #156 from parafovea/fix/api-key-encryption-startup…
aaronstevenwhite Jun 18, 2026
b09a655
Extract the personas domain into a PersonaRepository (pure data acces…
aaronstevenwhite Jun 18, 2026
25dddcc
Make the persistent test persona name unique per test (workerIndex pl…
aaronstevenwhite Jun 18, 2026
9f14854
Merge pull request #157 from parafovea/refactor/phase-4-1-personas-se…
aaronstevenwhite Jun 18, 2026
ca12444
Extract the projects domain into a ProjectRepository and ProjectServi…
aaronstevenwhite Jun 18, 2026
bb90695
Merge pull request #158 from parafovea/refactor/phase-4-2-projects-se…
aaronstevenwhite Jun 18, 2026
6950e35
Extract the claims domain into a ClaimRepository and ClaimService, re…
aaronstevenwhite Jun 18, 2026
19caa51
Merge pull request #159 from parafovea/refactor/phase-4-3-claims-serv…
aaronstevenwhite Jun 18, 2026
e77e2f9
Extract the world-state domain into a WorldStateRepository and WorldS…
aaronstevenwhite Jun 18, 2026
646e6d8
Merge pull request #160 from parafovea/refactor/phase-4-4-world-servi…
aaronstevenwhite Jun 18, 2026
2e1bee8
Split the 2232-line import-handler.ts import state machine into focus…
aaronstevenwhite Jun 18, 2026
aaf2a87
Merge pull request #161 from parafovea/refactor/phase-4-5-import-hand…
aaronstevenwhite Jun 18, 2026
293795c
Stand up the OpenAPI to frontend-types generation pipeline by emittin…
aaronstevenwhite Jun 18, 2026
ccac9ec
Merge pull request #162 from parafovea/refactor/phase-4-6a-openapi-fr…
aaronstevenwhite Jun 18, 2026
5e3750b
Decouple the model-service contract layer from the ML stack by removi…
aaronstevenwhite Jun 19, 2026
1d9832d
Merge pull request #163 from parafovea/refactor/phase-4-6b-model-serv…
aaronstevenwhite Jun 19, 2026
4ae665e
Add the server↔model-service contract pipeline by emitting a committe…
aaronstevenwhite Jun 19, 2026
bb3d97d
Merge pull request #164 from parafovea/refactor/phase-4-6b2-model-ser…
aaronstevenwhite Jun 19, 2026
8c76b87
Resolve cross-user object names server-side by adding an optional lin…
aaronstevenwhite Jun 19, 2026
e060f7b
Merge pull request #165 from parafovea/refactor/phase-4-6c-linked-obj…
aaronstevenwhite Jun 19, 2026
2ac946d
Make POST /api/annotations idempotent on an optional client-supplied …
aaronstevenwhite Jun 19, 2026
28cdd11
Merge pull request #166 from parafovea/refactor/phase-4-7-annotation-…
aaronstevenwhite Jun 19, 2026
7db24c2
Fix the annotation autosave idle loop and box duplication by strippin…
aaronstevenwhite Jun 19, 2026
aba44e8
Merge pull request #167 from parafovea/refactor/phase-4-8-annotation-…
aaronstevenwhite Jun 19, 2026
cc4c627
Split the model-service vlm and detection loader modules into one-cla…
aaronstevenwhite Jun 19, 2026
7b82384
Merge pull request #168 from parafovea/refactor/phase-4-9-model-servi…
aaronstevenwhite Jun 19, 2026
7b88130
Consolidate the scattered demo-mode RBAC read-widening into a single …
aaronstevenwhite Jun 19, 2026
39fbf23
Merge pull request #169 from parafovea/refactor/phase-4-10-demo-gatin…
aaronstevenwhite Jun 19, 2026
62c0315
Decompose the 1403-line AnnotationWorkspace component into three cohe…
aaronstevenwhite Jun 20, 2026
abb35c2
Merge pull request #170 from parafovea/refactor/phase-4-8b-annotation…
aaronstevenwhite Jun 20, 2026
34e1f4b
Finalize the 0.5.0 changelog date to the release date.
aaronstevenwhite Jun 20, 2026
b627ef2
Wrap the literal video tag in the useAnnotationState return-type JSDo…
aaronstevenwhite Jun 20, 2026
8f4c60d
Reword the import-module JSDoc and the ImportResultDialog summary so …
aaronstevenwhite Jun 20, 2026
2a3749d
fix: resolve a batch of field-reported bugs (0.5.1) (#173)
aaronstevenwhite Jun 22, 2026
212884f
Finalize the 0.5.1 changelog date to the 2026-06-22 release date in b…
aaronstevenwhite Jun 22, 2026
07ada4c
Merge main into release/0.5.x to reconcile the squash-flattened linea…
aaronstevenwhite Jun 22, 2026
bf61da5
Parse suffix and edge HTTP byte ranges per RFC 7233 in the video stre…
aaronstevenwhite Jun 22, 2026
75f95d0
Make clicking a claim card select it in place on the Claims tab
aaronstevenwhite Jun 24, 2026
ff1ac1b
Bump the version to 0.5.3 and record the claim-card selection fix in …
aaronstevenwhite Jun 24, 2026
2278ad3
fix: stamp project scope on summary and claim writes so collaborators…
aaronstevenwhite Jun 25, 2026
5ecf50a
Merge main into release/0.5.x to reconcile the squash-flattened linea…
aaronstevenwhite Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ All notable changes to the Fovea project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.4] - 2026-06-25

The 0.5.4 patch fixes project-scope and ownership stamping on video summaries and claims ([#181](https://github.com/parafovea/fovea/pull/181)). Project collaborators could not see a teammate's summary or add claims under it because summaries were persisted without their persona's project, and model-generated summaries and extracted claims were left unowned. Nothing is breaking; the API additively gains a `projectId` field on summary and claim responses.

### Fixed

#### Summaries and Claims Are Stamped With Their Persona's Project

- Every video-summary and claim write now stamps `projectId` from the persona (or the parent summary). Previously the interactive summary route (`server/src/routes/summaries.ts`), the summarization and claim-extraction workers (`server/src/queues/setup.ts`), and the auto-created empty summary (`server/src/repositories/ClaimRepository.ts`) all omitted it, so rows were born `projectId = NULL` and were invisible to every project collaborator except the creator — which `403`'d them at the parent-summary read gate when they tried to add claims, and hid the content from project-scoped queries. The summary update path also re-stamps the scope so a previously NULL-scoped row heals on its next save, and a migration backfills existing summaries and claims.

#### Model-Generated Summaries and Extracted Claims Are Owned

- The summarization and claim-extraction queue workers created rows without `createdBy`, leaving model-generated summaries and extracted claims owned by no one (readable only by an admin). The requesting user is now threaded through the queue payload and stamped as the owner on create.

### Added

#### projectId on Summary and Claim API Responses

- The `VideoSummary` and `Claim` API responses now include `projectId`, so clients can reflect a resource's project scope; its prior absence had helped the stamping defect go unnoticed.

## [0.5.3] - 2026-06-24

The 0.5.3 patch fixes a claims-workspace interaction bug ([#177](https://github.com/parafovea/fovea/pull/177)). No API shapes change and nothing is breaking.
Expand Down
2 changes: 1 addition & 1 deletion annotation-tool/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@fovea/annotation-tool",
"private": true,
"version": "0.5.3",
"version": "0.5.4",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
12 changes: 12 additions & 0 deletions annotation-tool/src/api/generated/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4104,6 +4104,7 @@ export interface paths {
processingTimeFusion?: number;
comment?: string | null;
createdBy?: string;
projectId?: string | null;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -4188,6 +4189,7 @@ export interface paths {
processingTimeFusion?: number;
comment?: string | null;
createdBy?: string;
projectId?: string | null;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -4324,6 +4326,7 @@ export interface paths {
processingTimeFusion?: number;
comment?: string | null;
createdBy?: string;
projectId?: string | null;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -4496,6 +4499,7 @@ export interface paths {
processingTimeFusion?: number;
comment?: string | null;
createdBy?: string;
projectId?: string | null;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -4638,6 +4642,7 @@ export interface paths {
processingTimeFusion?: number;
comment?: string | null;
createdBy?: string;
projectId?: string | null;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -4744,6 +4749,7 @@ export interface paths {
processingTimeFusion?: number;
comment?: string | null;
createdBy?: string;
projectId?: string | null;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -4854,6 +4860,7 @@ export interface paths {
metadata?: ("text" | "non-text")[] | null;
comment?: null | string;
createdBy?: null | string;
projectId?: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -5010,6 +5017,7 @@ export interface paths {
metadata?: ("text" | "non-text")[] | null;
comment?: null | string;
createdBy?: null | string;
projectId?: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -5139,6 +5147,7 @@ export interface paths {
metadata?: ("text" | "non-text")[] | null;
comment?: null | string;
createdBy?: null | string;
projectId?: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -5292,6 +5301,7 @@ export interface paths {
metadata?: ("text" | "non-text")[] | null;
comment?: null | string;
createdBy?: null | string;
projectId?: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -6032,6 +6042,7 @@ export interface paths {
metadata?: ("text" | "non-text")[] | null;
comment?: null | string;
createdBy?: null | string;
projectId?: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down Expand Up @@ -11469,6 +11480,7 @@ export interface components {
metadata?: ("text" | "non-text")[] | null;
comment?: null | string;
createdBy?: null | string;
projectId?: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* @file summary-project-scope.spec.ts
* @description End-to-end guard, through the running stack, that a video
* summary and the claims under it are stamped with their persona's project.
* A summary born with projectId = NULL is invisible to project collaborators
* and 403s their claim creation; this spec drives the real create routes and
* asserts the persisted project scope is returned on the API.
*
* The cross-user 403 itself is reproduced in the server integration test
* (test/integration/summary-claim-project-scope.test.ts); E2E worker users are
* system admins that bypass CASL, so here we verify the stamping that the
* authorization relies on.
*/

import { test, expect } from '../../fixtures/test-context.js'

test.describe('Summary project scope', () => {
test('stamps the persona project on summaries and claims created through the stack', async ({
page,
testUser,
testVideo,
}) => {
const api = page.request

// Create a project and a persona scoped to it.
const slug = `scope-${Date.now()}`
const projectRes = await api.post('/api/projects', {
data: { name: `Scope ${slug}`, slug },
})
expect(projectRes.status()).toBe(201)
const projectId = (await projectRes.json()).id

const personaRes = await api.post('/api/personas', {
data: {
name: `Project persona ${slug}`,
role: 'Analyst',
informationNeed: 'Project-scoped authoring',
projectId,
},
})
expect(personaRes.status()).toBe(201)
const personaId = (await personaRes.json()).id

// Create a summary under the project persona.
const summaryRes = await api.post('/api/summaries', {
data: {
videoId: testVideo.id,
personaId,
summary: [{ type: 'text', content: 'A red car drives through the intersection.' }],
},
})
expect(summaryRes.status()).toBe(201)
const summaryId = (await summaryRes.json()).id

// The persisted summary carries the persona's project, not NULL.
const readRes = await api.get(`/api/videos/${testVideo.id}/summaries/${personaId}`)
expect(readRes.status()).toBe(200)
expect((await readRes.json()).projectId).toBe(projectId)

// A claim created under it inherits the same project scope.
const claimRes = await api.post(`/api/summaries/${summaryId}/claims`, {
data: { summaryType: 'video', text: 'The car is red.', audio: ['speech'] },
})
expect(claimRes.status()).toBe(201)

const claimsRes = await api.get(`/api/summaries/${summaryId}/claims`)
expect(claimsRes.status()).toBe(200)
const claims = await claimsRes.json()
expect(claims.length).toBeGreaterThan(0)
expect(claims[0].projectId).toBe(projectId)
})
})
20 changes: 20 additions & 0 deletions docs/docs/project/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ All notable changes to the Fovea project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.4] - 2026-06-25

The 0.5.4 patch fixes project-scope and ownership stamping on video summaries and claims ([#181](https://github.com/parafovea/fovea/pull/181)). Project collaborators could not see a teammate's summary or add claims under it because summaries were persisted without their persona's project, and model-generated summaries and extracted claims were left unowned. Nothing is breaking; the API additively gains a `projectId` field on summary and claim responses.

### Fixed

#### Summaries and Claims Are Stamped With Their Persona's Project

- Every video-summary and claim write now stamps `projectId` from the persona (or the parent summary). Previously the interactive summary route (`server/src/routes/summaries.ts`), the summarization and claim-extraction workers (`server/src/queues/setup.ts`), and the auto-created empty summary (`server/src/repositories/ClaimRepository.ts`) all omitted it, so rows were born `projectId = NULL` and were invisible to every project collaborator except the creator — which `403`'d them at the parent-summary read gate when they tried to add claims, and hid the content from project-scoped queries. The summary update path also re-stamps the scope so a previously NULL-scoped row heals on its next save, and a migration backfills existing summaries and claims.

#### Model-Generated Summaries and Extracted Claims Are Owned

- The summarization and claim-extraction queue workers created rows without `createdBy`, leaving model-generated summaries and extracted claims owned by no one (readable only by an admin). The requesting user is now threaded through the queue payload and stamped as the owner on create.

### Added

#### projectId on Summary and Claim API Responses

- The `VideoSummary` and `Claim` API responses now include `projectId`, so clients can reflect a resource's project scope; its prior absence had helped the stamping defect go unnoticed.

## [0.5.3] - 2026-06-24

The 0.5.3 patch fixes a claims-workspace interaction bug ([#177](https://github.com/parafovea/fovea/pull/177)). No API shapes change and nothing is breaking.
Expand Down
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "docs",
"version": "0.5.3",
"version": "0.5.4",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
Expand Down
2 changes: 1 addition & 1 deletion model-service/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fovea-model-service",
"version": "0.5.3",
"version": "0.5.4",
"description": "AI model inference service for video annotation",
"scripts": {
"dev": "source venv/bin/activate && uvicorn src.main:app --reload --host 0.0.0.0 --port 8000",
Expand Down
2 changes: 1 addition & 1 deletion model-service/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "fovea-model-service"
version = "0.5.3"
version = "0.5.4"
description = "Model service for fovea video annotation tool"
requires-python = ">=3.12"
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "fovea",
"private": true,
"version": "0.5.3",
"version": "0.5.4",
"description": "FOVEA - Flexible Ontology Visual Event Analyzer",
"packageManager": "pnpm@10.15.0",
"engines": {
Expand Down
Loading
Loading