Files
brain-of-reese/.agents/user_stories/steering-notes.md
T
ducoterra dbf2af26c6 refactor(agents): migrate .agent/ planning tree to .agents/
Standardize on the .agents/ directory (shared with project skills):
phases/, user_stories/, reports/, screenshots/, validate.sh, and
phase-sessions/ + pipeline.log all move to .agents/ (git mv preserves
history; runtime artifacts move alongside).

Updates every reference in AGENTS.md, README.md, .gitignore, app
docstrings, and test story headers. Historical KB content in data/
and the runtime pipeline.log transcript are left untouched.
2026-09-05 10:57:07 -04:00

2.4 KiB
Raw Blame History

Story: Tune How Brain Answers (Steering Notes)

Phase: 15_steering_notes.md · E2E: tests/e2e/test_steering.py

Narrative

As a user, when an answer isn't quite right (too chatty, wrong assumption, missing context), I want to tune Brain right there: a short instruction ("be more concise", "assume I'm on NixOS") that is stored in the database and read into the system prompt so every future reply follows it.

  • Given an answer I don't like
  • When I click "Tune" under it and save an instruction
  • Then the note is persisted in Postgres, shown in the tuning panel (where it can be removed), and injected into the system prompt of every subsequent turn — verifiable in the answer.

Acceptance criteria

  1. New steering_notes table (id, note, created_at) via Alembic migration 0003.
  2. Stateless API: GET /api/steering (newest first), POST /api/steering (1–2000 chars, 201 / 422), DELETE /api/steering/{id} (204 / 404).
  3. System prompt: when notes exist, a <tuning> section (numbered notes, char-budgeted) is appended to both HIGH and DEFLECT prompts; when none exist, the prompt is byte-identical to today's.
  4. Per-turn log line gains tuning=N.
  5. UI: "Tune" button under every completed brain answer (deflected too) → inline form → save → confirmation; header "Tuning" toggle lists notes with per-note delete; all labeled, live regions, ≥44px targets, Phase-08 tokens.
  6. Notes render as text (XSS-safe).
  7. Unit + integration green, app/ coverage >90%, story E2E green in isolation, one --no-gpg-sign commit.

Playwright Mapping Rule

Test Scenario → tests/e2e/test_steering.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_tune_under_answer_persists_and_steers — answer → Tune → note "STEEER-MARKER be concise" → saved → next answer contains the marker (note reached the system prompt) → note visible in panel with count.
  2. test_delete_note_stops_steering — delete from panel → count 0 → next answer has no marker.
  3. test_note_rendered_as_text_xss_safe — note with <script> renders as visible escaped text, never executes.
  4. test_tuning_panel_a11y — toggle aria-expanded, region label, delete buttons labeled, live region announces save/delete.