AI skill: SKILL.md, AI contract, scrubbed references, eval fixture (d)

- rpa-dashboard-ai/SKILL.md: trigger description and the shared question flow;
  points at the no-AI frontend.md, themes and palette instead of copying them.
- templates/contract.md: runs, review rows, endpoints and the server approve gate.
- Superbill extracts: patient names and the client name removed, every file
  carries an EXAMPLE ONLY banner. tests/test_reference_scan.py checks both skills
  for patient data, internal IPs, credentials and keys.
- tests/fixtures/d-ai-extraction and its eval entry, which runs page_check_ai
  on the built folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
VasanthandClaude Opus 5.5 committed 2026-10-16 15:13:55 +05:30
1 parent 91495935b9
commit 8951ac05a5
30 files changed
+372 -26

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
# Dashboard data contract (AI)
Everything in the no-AI contract (`../rpa-dashboard-no-ai/templates/contract.md`)
applies unchanged: the `{event, data}` envelope, its events, its actions and its rules.
The AI dashboard adds extraction runs, review rows and the approve gate. These shapes
come from the Superbill prototype, trimmed.
## Shapes
```
Run { job_id, document, status: pending|queued|running|done|failed, model,
pages_done, pages_total, summary: { green, amber, red, blank, unscored } | null,
approved, error }
ReviewRow { row_id, field, value, band: green|amber|red|blank|unscored,
score, reason, verified, corrected_value }
```
- `summary` counts the run's rows per band. It is `null` until the run is `done`.
- `score` is the field's worst word score, or `null` when it has none.
- `corrected_value` is `null` until a reviewer saves a value different from `value`.
## Endpoints (web: `{API_BASE}` + path, JSON in and out)
| Method and path | What it does |
|---|---|
| `GET /runs` | `{runs: [Run]}`. The page opens the first one. |
| `GET /runs/{job_id}` | One `Run`. |
| `GET /runs/{job_id}/review` | `{rows: [ReviewRow]}`. Empty until the run is `done`. |
| `GET /runs/{job_id}/document` | The source document (PDF or image) shown beside the fields. |
| `PATCH /review/{row_id}` | Body `{corrected_value?, verified}`. Patches one row, returns it. |
| `POST /runs/{job_id}/verify-remaining` | Verifies every flagged row not yet verified. Returns `{verified: n}`. |
| `POST /runs/{job_id}/approve` | **The approve gate.** `409 {detail}` while the run isn't done or any flagged row is unverified, else `200 {ok: true}`. |
Errors answer with a non-2xx status and `{detail: "<why>"}`. The page shows `detail`.
## Rules
- **Bands** come from `templates/web/bands.py` and nowhere else: green ≥0.95, amber
0.90–0.95, red <0.90. A field takes its worst word score. A blank mandatory field
is `blank`, whatever its score. No scores is `unscored`.
- **Flagged** = every band but green. Each flagged row must be verified before approval.
- **The server enforces the gate.** The page disables nothing that matters for safety:
it asks, and shows the server's refusal.
- **Drafts:** the page sends nothing while a reviewer types. Save sends one PATCH per
edited row (with `verified: true`). Leaving with unsaved edits asks first.
- **Polling:** while a run is `queued` or `running`, the page polls `GET /runs/{job_id}`
every 1.5s and shows "page X of Y". It stops when the run settles.
- **Caveat:** the legend always shows that colour reflects print clarity, not
correctness.
`templates/web/server_stub.py` implements all of this on sample data, standard library
only. A real backend serves the same endpoints with the same rules.