|
| 1 | +# Student Chat v3 — Follow-Up Roadmap (handoff) |
| 2 | + |
| 3 | +- Date: 2026-07-27. Author: agent session on PR #5197. |
| 4 | +- Branch: `claude/student-chat-v3-design-3459db` → `v3`, |
| 5 | + [PR #5197](https://github.com/uzh-bf/klicker-uzh/pull/5197), head `acc424981`. |
| 6 | +- Parent plan: [2026-07-26-pr-5197-student-chat-v3-design-alignment-plan.md](./2026-07-26-pr-5197-student-chat-v3-design-alignment-plan.md) |
| 7 | + (execution history + environment recipe). Earlier plans: 2026-07-19 reskin, |
| 8 | + 2026-07-23 production readiness. |
| 9 | +- Audience: junior dev picking this up without session context. Every item has |
| 10 | + Do/Check steps. Read `docs/chat-platform.md` first — it is the ground truth |
| 11 | + for the chat app. |
| 12 | + |
| 13 | +## How to work on this |
| 14 | + |
| 15 | +- Env: devcontainer worktree stack per `CLAUDE.md` + plan §"Environment + |
| 16 | + verification recipe". All pnpm/prisma/tests run in-container |
| 17 | + (`devrouter exec . -- ...`), Playwright runs on host |
| 18 | + (`.agents/skills/klicker-playwright-e2e`). Browser verification with |
| 19 | + `agent-browser` is mandatory for UI changes. |
| 20 | +- Gotchas that cost us hours (details in plan Progress, 2026-07-27 entry): |
| 21 | + don't run `pnpm --filter @klicker-uzh/chat check` while browsing the app |
| 22 | + (typegen 404s routes; remedy: touch route files); Turbopack EMFILE crash → |
| 23 | + kill `turbo run dev` in-container, `devrouter ensure` from the worktree dir; |
| 24 | + `docker exec` psql heredocs need `-i`; host-run Playwright needs a plain TCP |
| 25 | + proxy to Postgres (node-postgres cannot use the SNI route) — see |
| 26 | + `playwright/global-setup.ts` + the e2e skill. |
| 27 | +- Public repo: no secrets, no `.env`, no personal data in any commit. |
| 28 | + |
| 29 | +## W0 — Land PR #5197 (now, ~0.5d) |
| 30 | + |
| 31 | +- Problem: PR is review-complete but not merged. Merge authority = maintainer. |
| 32 | +- Do: |
| 33 | + 1. Watch CI on `acc424981`. Known flake: Playwright shard 5 |
| 34 | + (G-elements-mc/U-catalog) — rerun failed jobs once before debugging. |
| 35 | + 2. Attach UI screenshots to the PR (CLI cannot upload). Recapture per plan |
| 36 | + §"Environment + verification recipe": seeded four-source answer, |
| 37 | + branch pager 2/2 after a root edit, image-analyzed chip en/de, amber |
| 38 | + blockquote callout, thread-row mode subtitle. 1440x900 + 390x844. |
| 39 | + 3. Triage any new bot findings (Greptile/CodeRabbit) on their threads; |
| 40 | + verify before implementing. |
| 41 | +- Check: CI green, screenshots visible in PR body/comments, no unanswered |
| 42 | + review threads. Then hand to maintainer for merge. |
| 43 | + |
| 44 | +## W1 — Live-model verification round (after key, ~1d) |
| 45 | + |
| 46 | +- Problem: every model-behavior claim on the branch is unverified — the local |
| 47 | + stack has no `UPSTREAM_OPENAI_API_KEY`, so all citation/orthography checks |
| 48 | + ran against seeded tool parts, not a live model. |
| 49 | +- Do (needs a dev model key injected into the devcontainer env at |
| 50 | + `devrouter ensure` time; never commit it): |
| 51 | + 1. Citation contract: ask a doc_query-backed chatbot factual questions; |
| 52 | + confirm answers emit `[n]` markers that resolve to the rendered source |
| 53 | + cards, and that repeat sources reuse their number |
| 54 | + (`apps/chat/src/lib/prompts/citationInstructions.ts`). |
| 55 | + 2. Orthography contract: German answers use ss/real umlauts, never ae/oe/ue |
| 56 | + (`withLanguageStyleContract`, unconditional in the chat route). |
| 57 | + 3. Multi-step runs: credits decrease per `calcCost`, reasoning/tool |
| 58 | + streaming renders, image attachment turn produces the analyzed chip live. |
| 59 | +- Check: notes + screenshots on the follow-up PR or issue; failures become |
| 60 | + prompt-contract fixes, not UI changes (UI degrades gracefully by design — |
| 61 | + bad markers render as plain text). |
| 62 | + |
| 63 | +## W2 — Citation system phase 2 (needs doc-query service work, ~1-2w) |
| 64 | + |
| 65 | +- Problem: display quality is capped by the doc_query payload. Blocked |
| 66 | + gap-map items: source thumbnails, transcript hover previews, media |
| 67 | + durations, video deep links. |
| 68 | +- Do (contract: UI renders whatever `normalizeSourcesFromParts` yields, so |
| 69 | + service upgrades never need a UI rework — see plan §"Citation system — |
| 70 | + phase 2" and ADR 0004): |
| 71 | + 1. doc-query service: per-source `excerpt` in answer mode, stable |
| 72 | + `source_id`, media metadata (real video timestamp field, thumbnail ref). |
| 73 | + 2. klicker: signed URLs to open course-material sources; extend |
| 74 | + `apps/chat/src/lib/sources/` normalizer + cards for the new fields. |
| 75 | + 3. Eval harness asserting `[n]` markers ground in returned sources. |
| 76 | +- Check: unit tests over the new payload shapes; e2e with seeded new-shape |
| 77 | + parts; existing tests keep passing (backward compatibility with the three |
| 78 | + current payload shapes is a hard requirement). |
| 79 | + |
| 80 | +## W3 — Telemetry repair (~2-3d) |
| 81 | + |
| 82 | +- Problem: Langfuse traces do not export (OTel peer mismatch, recorded in |
| 83 | + `docs/chat-platform.md`); message-feedback mirroring to Langfuse is |
| 84 | + disabled pending that repair. |
| 85 | +- Do: fix the exporter wiring in `apps/chat` telemetry setup, then re-enable |
| 86 | + vote mirroring in the feedback route and confirm scores land on the derived |
| 87 | + trace ids. |
| 88 | +- Check: a live chat turn produces a trace in Langfuse; a thumbs-up appears |
| 89 | + as a score on that trace; killswitch env still works. |
| 90 | + |
| 91 | +## W4 — Small hardening items (independent, ~0.5d each) |
| 92 | + |
| 93 | +1. URL-gate guard: add a test or lint convention so any future doc_query |
| 94 | + field feeding an `href` must pass `isUrlLike` |
| 95 | + (`apps/chat/src/lib/sources/`). Check: test fails if a card/preview href |
| 96 | + bypasses the gate. |
| 97 | +2. `withHashSuffix` edge: a server name longer than ~45 chars would push |
| 98 | + `doc_query` out of the kept prefix and silently disable |
| 99 | + sources/citations/chips for that server (documented in |
| 100 | + `docs/chat-platform.md`). Decide: keep documented, or warn/log when a |
| 101 | + configured MCP server name exceeds the safe length. Check: unit test on |
| 102 | + `lib/config/toolNames.ts`. |
| 103 | +3. Axe: one known moderate finding (landmark/region + sidebar) from the |
| 104 | + accessibility pass. Re-run the a11y suite, fix or formally accept. |
| 105 | +4. `useAISDKRuntime` transport swap: verified follow-up per ADR 0003 |
| 106 | + (`docs/adr/0003-chat-framework-upgrade.md`). Own branch; do not mix with |
| 107 | + feature work. |
| 108 | + |
| 109 | +## W5 — Environment chores (local dev, not release-blocking) |
| 110 | + |
| 111 | +1. Upstream seed bugs (junior-executable, own PR): |
| 112 | + `seedAssessmentCourse` fails P2025 via `recomputeDerivedPermissions` |
| 113 | + (`packages/util/src/permissions/element.ts:339`, nested connect to a |
| 114 | + missing Element) and `packages/prisma-data/src/seedAccounts.ts:13` upsert |
| 115 | + is non-idempotent (`where` uses the user id, `create` writes an eduid |
| 116 | + string → P2002 on reseed). Both break the devcontainer post-create seed; |
| 117 | + its retry loop masks the first error. Check: raw seed runs twice cleanly |
| 118 | + against a fresh DB in-container. |
| 119 | +2. Multi-stack `postgres` alias collision on the shared devnet: one stack's |
| 120 | + post-create can reset another worktree's DB. Machine-local issue; fix |
| 121 | + belongs in devrouter/compose aliasing, not this repo's app code. Until |
| 122 | + then: always run `devrouter ensure/exec` from the checkout you mean. |
| 123 | + |
| 124 | +## W6 — Parked design decisions (need a design ruling first) |
| 125 | + |
| 126 | +- Recorded as deliberate non-changes in the PR body; do not implement without |
| 127 | + a ruling: text logo vs `KlickerLogo.png` in the sidebar; segmented mode |
| 128 | + switcher vs mockup dropdown; chatbot-identity header vs course-code sidebar |
| 129 | + header (chat is chatbot-scoped and has no course data today). |
| 130 | + |
| 131 | +## Suggested order |
| 132 | + |
| 133 | +W0 now. W1 as soon as a dev key exists. W4.1/W4.2 and W5.1 anytime (small, |
| 134 | +independent). W3 before any feature relying on tracing. W2 is the next real |
| 135 | +feature epic and deserves its own plan file per the sliced workflow. W6 only |
| 136 | +after design input. |
0 commit comments