52 lines
2.6 KiB
Markdown
52 lines
2.6 KiB
Markdown
# Story: Global Tuning Manager (No Chat Required, Editable)
|
|
|
|
**Phase:** `27_global_tuning.md` · **E2E:** `tests/e2e/test_global_tuning.py`
|
|
|
|
## Narrative
|
|
|
|
As **the admin (owner)**, I want to **manage my global tuning notes**
|
|
without having to have a chat conversation first, and I want to be able to
|
|
**edit** a note I've already saved — not just create and delete.
|
|
|
|
- **Given** I'm the admin and I have no chat open yet
|
|
- **When** I open the "Tuning" page (from the header)
|
|
- **Then** I can add a new note, edit any existing note inline, list all
|
|
notes, and delete them — and every note is stored in Postgres and read
|
|
into the system prompt of every future turn.
|
|
|
|
## Acceptance criteria
|
|
1. New endpoint `PUT /api/steering/{id}` (200 updated note; 404 unknown;
|
|
422 empty/whitespace/over-2000; 403 anonymous) — the router keeps its
|
|
existing `require_admin` gate.
|
|
2. New page `/tuning.html` (admin-only nav link): a "Add a global tuning
|
|
note" form + a list of notes, each with inline **Edit** (textarea +
|
|
Save/Cancel) and **Delete**.
|
|
3. A note created on `/tuning.html` is persisted and steers future answers
|
|
(no chat turn needed to create it; observable in a later answer).
|
|
4. Editing a note updates its text in the list and in the `<tuning>`
|
|
prompt.
|
|
5. Delete removes the note from the list and the prompt.
|
|
6. The chat-page "Tune" button and header "Tuning" panel (phase 15) are
|
|
unchanged — create + delete still work there.
|
|
7. Anonymous users get 403 on the data and on `PUT`; the header "Tuning"
|
|
link is hidden for anonymous.
|
|
8. UI: landmarks, labeled controls, ≥44px targets, `:focus-visible`,
|
|
contrast ≥4.5:1, live-region announcements, Phase-08 tokens, no-CDN.
|
|
9. Notes render as text (XSS-safe).
|
|
10. Unit + integration green, `app/` coverage >90%, story E2E green in
|
|
isolation, one `--no-gpg-sign` commit.
|
|
|
|
## Playwright Mapping Rule
|
|
**Test Scenario → `tests/e2e/test_global_tuning.py`** (mock LLM, seeded
|
|
KB — the mock echoes the first tuning note into its answer when `<tuning>`
|
|
is present, so prompt injection is observable in the UI):
|
|
1. `test_create_note_without_chat` — `/tuning.html`, add a note, it
|
|
appears in the list + announcer.
|
|
2. `test_edit_note_inline` — Edit → change text → Save → list updated.
|
|
3. `test_delete_note` — Delete → row removed, empty state shows.
|
|
4. `test_edit_note_steers_answer` — create via `/tuning.html`, then a chat
|
|
turn shows the note's marker in the answer.
|
|
5. `test_tuning_page_a11y_and_no_cdn` — landmarks, labels, ≥44px,
|
|
focus-visible, dark theme, all assets local.
|
|
6. `test_anonymous_cannot_manage` — anonymous list empty; `PUT` → 403.
|