Skip to content

Commit 0c8dbfe

Browse files
authored
feat: polish full-stack evaluation demo flow (#20)
Co-authored-by: fengting124 <fengting124@users.noreply.github.com>
1 parent db71c84 commit 0c8dbfe

10 files changed

Lines changed: 356 additions & 13 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ cd model-services\nonescape-mini
9898
```
9999

100100
Detailed Windows, WSL, and SSH-server setup notes are in `docs/local-development.md`.
101+
For the evaluation workflow demo, follow `docs/fullstack-evaluation-demo.md`.
101102

102103
## Documentation
103104

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Use these when setting up or operating the project.
2222
server setup guidance.
2323
- [Smoke Test Workflow](smoke-test-workflow.md): end-to-end verification after
2424
services are running.
25+
- [Full-Stack Evaluation Demo](fullstack-evaluation-demo.md): admin UI to Java
26+
backend evaluation workflow without model weights.
2527

2628
## Architecture And Contracts
2729

@@ -49,3 +51,5 @@ These documents are useful for understanding how the project evolved.
4951
4. If discussing architecture, read
5052
[Model Integration Framework](model-integration-framework.md) and
5153
[Async Detection Jobs](async-detection-jobs.md).
54+
5. If demonstrating the project, run through
55+
[Full-Stack Evaluation Demo](fullstack-evaluation-demo.md).

docs/fullstack-evaluation-demo.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Full-Stack Evaluation Demo
2+
3+
This how-to shows how to demonstrate the evaluation workflow from the admin UI
4+
through the Java backend and persistence layer. It uses the deterministic
5+
evaluation model client, so it does not require model weights or a GPU.
6+
7+
## Audience
8+
9+
Use this document when preparing an interview demo, local verification, or a PR
10+
review that needs to exercise evaluation creation and execution.
11+
12+
## Current Status
13+
14+
The evaluation workflow supports:
15+
16+
- Creating an evaluation run from a CSV manifest.
17+
- Persisting run state and sample rows in the Java backend.
18+
- Executing the run through the evaluation model-client boundary.
19+
- Recording aggregate metrics: accuracy, precision, recall, and F1.
20+
- Retrying failed runs through the same service boundary.
21+
- Inspecting runs and wrong samples in `/admin/evaluations`.
22+
23+
The workflow does not download or require real model weights yet. GPU-backed
24+
model inference remains deferred until the project runs on a prepared server.
25+
26+
## Prerequisites
27+
28+
- Node.js 24 or newer.
29+
- Java and Maven for the Spring Boot backend.
30+
- PostgreSQL and Redis for the default backend profile.
31+
- Docker Compose if you want to run the full infrastructure from
32+
`infra/docker-compose.yml`.
33+
34+
If Docker is not ready on the local machine, use `mvn -B test` to verify the
35+
evaluation service with the H2-backed test profile. Full interactive UI
36+
execution still needs a running backend.
37+
38+
## Demo Steps
39+
40+
1. Start the backend infrastructure.
41+
42+
```powershell
43+
docker compose -f infra/docker-compose.yml up --build
44+
```
45+
46+
2. Start the frontend in another terminal.
47+
48+
```powershell
49+
npm install
50+
npm run dev
51+
```
52+
53+
3. Open the admin evaluation page.
54+
55+
```text
56+
http://localhost:5173/admin/evaluations
57+
```
58+
59+
4. Use the default manifest or paste a small manifest:
60+
61+
```csv
62+
filename,groundTruthLabel
63+
real_001.jpg,AUTHENTIC
64+
fake_001.jpg,SYNTHETIC
65+
```
66+
67+
5. Click `Create Evaluation`.
68+
69+
6. Select the created run and click `Run`.
70+
71+
7. Confirm the page displays:
72+
73+
- `COMPLETED` status.
74+
- Completed sample count.
75+
- Accuracy, precision, recall, and F1.
76+
- Wrong or failed samples when predictions do not match labels.
77+
78+
8. Click `Retry` only when a run failed and should be executed again.
79+
80+
## Backend-Only Verification
81+
82+
When Docker is not available, verify the Java evaluation path with tests:
83+
84+
```powershell
85+
cd backend-java
86+
mvn -B test
87+
```
88+
89+
Key tests:
90+
91+
- `EvaluationControllerTest`
92+
- `EvaluationExecutionServiceTest`
93+
- `EvaluationMetricsCalculatorTest`
94+
- `EvaluationRepositoryTest`
95+
- `DeterministicEvaluationModelClientTest`
96+
97+
These tests prove the service boundary, retry behavior, metric calculation, and
98+
database mapping without requiring model weights.
99+
100+
## Frontend Error Behavior
101+
102+
If the frontend is running but the Java backend is not available, admin pages
103+
show:
104+
105+
```text
106+
Backend API unavailable. Start the Java backend and try again.
107+
```
108+
109+
This message is intentionally clearer than the raw Vite proxy `502` response.
110+
It does not hide real backend validation errors: JSON `message`, `error`, and
111+
`detail` fields are still surfaced directly to the user.
112+
113+
## Verification
114+
115+
Run these checks before claiming the demo workflow is ready:
116+
117+
```powershell
118+
npm run test
119+
npm run lint
120+
npm run build
121+
cd backend-java
122+
mvn -B test
123+
```
124+
125+
For a full interactive demo, also create and run one evaluation from
126+
`/admin/evaluations` after the backend infrastructure is running.
127+
128+
## Related Docs
129+
130+
- `docs/documentation-standards.md`
131+
- `docs/model-integration-framework.md`
132+
- `docs/smoke-test-workflow.md`
133+
- `docs/project-improvement-roadmap.md`

docs/project-worklog.md

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -440,24 +440,63 @@ Why these matter:
440440
local storage.
441441
- They created the foundation for later evaluation and robustness work.
442442

443+
### 2026-07-09: Full-Stack Evaluation Demo Polish
444+
445+
Branch:
446+
447+
```text
448+
feature/fullstack-evaluation-demo-smoke
449+
```
450+
451+
Commit:
452+
453+
```text
454+
See the PR commit history after merge.
455+
```
456+
457+
What changed:
458+
459+
- Added a small frontend test boundary for API error formatting.
460+
- Converted raw gateway failures into a clear backend availability message.
461+
- Documented the admin evaluation demo path from frontend to Java backend.
462+
463+
Why:
464+
465+
- The evaluation workflow already existed, but the demo story needed a cleaner
466+
operator experience when the backend is offline.
467+
- Interviewers should be able to distinguish implemented evaluation execution
468+
from deferred GPU model-weight work.
469+
470+
Verification:
471+
472+
- `npm run test`
473+
- `npm run lint`
474+
- `npm run build`
475+
- `mvn -B test`
476+
477+
Deferred:
478+
479+
- Full interactive Docker demo remains pending until Docker is available.
480+
- Real model weights remain deferred until a GPU server is prepared.
481+
443482
## Next Recommended Work
444483

445-
Continue Phase B from `docs/project-improvement-roadmap.md`:
484+
Continue Phase B from `docs/project-improvement-roadmap.md` with a narrower
485+
verification and insight branch:
446486

447487
```text
448-
feature/evaluation-frontend
488+
feature/evaluation-result-insights
449489
```
450490

451491
Scope:
452492

453-
- Add an evaluation list and detail page.
454-
- Display status, attempts, aggregate metrics, and sample rows.
455-
- Show wrong-sample filtering first; confusion matrix can follow in a later
456-
polish branch.
457-
- Keep the existing frontend visual style.
493+
- Add a small confusion matrix or label breakdown to `/admin/evaluations`.
494+
- Add clearer empty states for runs with no wrong samples.
495+
- Keep the deterministic model boundary until GPU weights are available.
496+
- Preserve the current frontend visual style.
458497

459498
Reason:
460499

461-
The backend now has a measurable evaluation workflow. The next interview-visible
462-
step is to make the evaluation result easy to inspect without changing the
463-
project into a broad dashboard.
500+
The project now has evaluation execution and a usable admin workbench. The next
501+
interview-visible step is to make model quality easier to explain without
502+
expanding scope into training, video detection, or heavy model operations.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Full-Stack Evaluation Demo Smoke Implementation Plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4+
5+
**Goal:** Make the existing evaluation backend and admin evaluation page easier to demo as one full-stack workflow without downloading model weights.
6+
7+
**Architecture:** Keep the Java backend as the business and persistence boundary, keep model execution behind the existing evaluation client interface, and keep the React admin UI visual style unchanged. This branch only improves frontend API error messaging, adds a small frontend test boundary, and documents a repeatable demo path.
8+
9+
**Tech Stack:** React 18, TypeScript, Vite, Node built-in test runner, Spring Boot Java backend, Maven, existing deterministic evaluation model client.
10+
11+
## Global Constraints
12+
13+
- Do not download model weights.
14+
- Do not replace the current frontend visual style.
15+
- Do not fake successful backend data in the frontend.
16+
- Keep API calls centralized in `src/api/backend.ts`.
17+
- Keep docs concise and aligned with `docs/documentation-standards.md`.
18+
- Verify with `npm run test`, `npm run lint`, `npm run build`, and `mvn -B test`.
19+
20+
---
21+
22+
### Task 1: Add A Frontend API Error Parsing Test
23+
24+
**Files:**
25+
- Modify: `package.json`
26+
- Create: `src/api/errorMessage.test.ts`
27+
28+
**Interfaces:**
29+
- Produces: expected behavior for `formatApiErrorMessage(status: number, bodyText: string): string`
30+
- Consumes later: `src/api/errorMessage.ts`
31+
32+
- [ ] Add a `test` script using Node's built-in test runner:
33+
34+
```json
35+
"test": "node --test --experimental-strip-types src/api/errorMessage.test.ts"
36+
```
37+
38+
- [ ] Create `src/api/errorMessage.test.ts` with assertions for backend JSON errors, Vite proxy 502 errors, plain text errors, and empty responses.
39+
40+
- [ ] Run `npm run test`.
41+
42+
Expected: FAIL because `src/api/errorMessage.ts` does not exist yet.
43+
44+
### Task 2: Implement Reusable API Error Formatting
45+
46+
**Files:**
47+
- Create: `src/api/errorMessage.ts`
48+
- Modify: `src/api/backend.ts`
49+
50+
**Interfaces:**
51+
- Produces: `formatApiErrorMessage(status: number, bodyText: string): string`
52+
- `src/api/backend.ts` must call the formatter after `response.text()`.
53+
54+
- [ ] Implement `formatApiErrorMessage`.
55+
- [ ] Parse backend JSON bodies with `message`, `error`, or `detail` fields.
56+
- [ ] Map `502`, `503`, and `504` to:
57+
58+
```text
59+
Backend API unavailable. Start the Java backend and try again.
60+
```
61+
62+
- [ ] Preserve non-empty plain text errors for other statuses.
63+
- [ ] Use `Request failed with status ${status}` for empty bodies.
64+
- [ ] Run `npm run test`.
65+
66+
Expected: PASS.
67+
68+
### Task 3: Document The Demo Workflow
69+
70+
**Files:**
71+
- Create: `docs/fullstack-evaluation-demo.md`
72+
- Modify: `docs/README.md`
73+
- Modify: `README.md`
74+
- Modify: `docs/project-worklog.md`
75+
76+
**Interfaces:**
77+
- Produces a durable runbook that explains how to demo evaluation creation, execution, metrics inspection, and known local environment limits.
78+
79+
- [ ] Add a how-to document with audience, current status, step-by-step run commands, verification checklist, and deferred Docker/GPU work.
80+
- [ ] Link it from `docs/README.md`.
81+
- [ ] Add a short pointer in root `README.md`.
82+
- [ ] Add a dated worklog entry for the branch.
83+
84+
### Task 4: Verify And Publish
85+
86+
**Files:**
87+
- All changed files.
88+
89+
**Interfaces:**
90+
- Produces a pushed branch and PR.
91+
92+
- [ ] Run `npm run test`.
93+
- [ ] Run `npm run lint`.
94+
- [ ] Run `npm run build`.
95+
- [ ] Run `mvn -B test` from `backend-java`.
96+
- [ ] Run `git diff --check`.
97+
- [ ] Commit as `feat: polish full-stack evaluation demo flow`.
98+
- [ ] Push `feature/fullstack-evaluation-demo-smoke`.
99+
- [ ] Open a PR and wait for CI.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"dev": "vite",
88
"build": "tsc -b && vite build",
99
"lint": "eslint .",
10+
"test": "node --test --experimental-strip-types src/api/errorMessage.test.ts",
1011
"preview": "vite preview"
1112
},
1213
"dependencies": {

src/api/backend.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { formatApiErrorMessage } from './errorMessage';
2+
13
export type DetectionStatus = 'QUEUED' | 'INFERENCING' | 'COMPLETED' | 'FAILED';
24
export type EvaluationStatus = 'QUEUED' | 'RUNNING' | 'COMPLETED' | 'FAILED';
35
export type ModelLabel = 'AUTHENTIC' | 'SYNTHETIC' | 'UNCERTAIN';
@@ -159,8 +161,8 @@ async function apiRequest<T>(path: string, init?: RequestInit): Promise<T> {
159161
});
160162

161163
if (!response.ok) {
162-
const message = await response.text();
163-
throw new ApiError(message || `Request failed with status ${response.status}`, response.status);
164+
const bodyText = await response.text();
165+
throw new ApiError(formatApiErrorMessage(response.status, bodyText), response.status);
164166
}
165167

166168
return response.json() as Promise<T>;

src/api/errorMessage.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import assert from 'node:assert/strict';
2+
import test from 'node:test';
3+
4+
import { formatApiErrorMessage } from './errorMessage.ts';
5+
6+
test('uses backend JSON message when present', () => {
7+
const message = formatApiErrorMessage(400, '{"message":"Manifest must contain a header row."}');
8+
9+
assert.equal(message, 'Manifest must contain a header row.');
10+
});
11+
12+
test('uses backend JSON error fallback when message is absent', () => {
13+
const message = formatApiErrorMessage(404, '{"error":"Evaluation not found."}');
14+
15+
assert.equal(message, 'Evaluation not found.');
16+
});
17+
18+
test('maps gateway failures to a backend availability hint', () => {
19+
const message = formatApiErrorMessage(502, 'Bad Gateway');
20+
21+
assert.equal(message, 'Backend API unavailable. Start the Java backend and try again.');
22+
});
23+
24+
test('preserves non-empty plain text errors for non-gateway statuses', () => {
25+
const message = formatApiErrorMessage(409, 'Evaluation is already running.');
26+
27+
assert.equal(message, 'Evaluation is already running.');
28+
});
29+
30+
test('falls back to status text when the response body is empty', () => {
31+
const message = formatApiErrorMessage(418, '');
32+
33+
assert.equal(message, 'Request failed with status 418');
34+
});

0 commit comments

Comments
 (0)