Przeglądaj źródła

feat(speaking): allow teacher mode to fire recordSpeakingStart too

Drops the props.type === '2' guard on the recordSpeakingStart provider
so both teacher (type=1) and student (type=2) clients write a record
on fresh "开始对话" click. Teacher mode is useful for self-testing the
tool while authoring; the courseid/userid checks remain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jimmylee 20 godzin temu
rodzic
commit
70f86bd9a4

+ 7 - 8
docs/superpowers/specs/2026-05-08-speaking-record-start-work-design.md

@@ -52,7 +52,7 @@ Three approaches were considered:
 
 ```ts
 provide('recordSpeakingStart', async (sessionId: string) => {
-  if (props.type !== '2') return                  // student client only
+  // both teacher (type=1) and student (type=2) write a record — teacher self-tests, student submits
   if (!sessionId || !props.courseid || !props.userid) return
   try {
     await api.submitWork({
@@ -106,14 +106,13 @@ The resume path (`loadLatestStudentSession`, around line 425) **must not** call
 ### Behavior
 
 - **Triggers** when, and only when:
-  1. `props.type === '2'` (student client)
-  2. `startDialogue()` succeeded — `createSession()` returned and `preparedSession.value.sessionId` is set
-  3. `props.courseid` and `props.userid` are non-empty
+  1. `startDialogue()` succeeded — `createSession()` returned and `preparedSession.value.sessionId` is set
+  2. `props.courseid` and `props.userid` are non-empty
+  3. Either teacher (`props.type === '1'`) or student (`props.type === '2'`) — both modes fire (teacher mode is allowed for self-testing)
 - **Does NOT trigger** in any of these cases:
   - Resume path (`loadLatestStudentSession` finds an active session and jumps to `'chatting'`)
   - Completion path (`handleDialogueComplete`)
-  - Teacher mode (`props.type !== '2'`)
-  - Any precondition missing
+  - Any precondition missing (no sessionId, no courseid, no userid)
 - **Failure handling**: fire-and-forget; failures are `console.error`-logged and never block the dialogue. The speaking session on speaking-api is already created at this point and continues normally.
 - **Idempotency**: enforced purely by the call-site rule above. The pbl-api endpoint has no client-visible idempotency, so a second call with the same payload would create a duplicate record. The fresh-start-only rule is the only guard.
 
@@ -128,8 +127,8 @@ The resume path (`loadLatestStudentSession`, around line 425) **must not** call
   2. The view should auto-resume into `'chatting'` (via `loadLatestStudentSession`).
   3. **No** `addCourseWorks_workPage` call should be observed in this case.
 - **Manual teacher mode**:
-  1. Open the same slide as a teacher (`props.type !== '2'`).
-  2. No `addCourseWorks_workPage` call should fire even if "开始对话" is clicked.
+  1. Open the same slide as a teacher (`props.type === '1'`).
+  2. Clicking "开始对话" SHOULD fire `addCourseWorks_workPage` (teacher mode is allowed; useful for self-testing).
 - **Manual failure handling**:
   1. Block `addCourseWorks_workPage` in DevTools (override response with 500).
   2. Click **开始对话**, observe the dialogue still proceeds to `'chatting'` and `console.error` is logged.

+ 1 - 1
src/views/Student/index.vue

@@ -593,7 +593,7 @@ provide('notifySpeakingProgress', (status: 'active' | 'completed', payload: { co
 })
 
 provide('recordSpeakingStart', async (sessionId: string) => {
-  if (props.type !== '2') return // 只有学生客户端写作业记录
+  // 老师端 (type=1) 与学生端 (type=2) 都允许写作业记录,方便老师自测/学生提交
   if (!sessionId || !props.courseid || !props.userid) return
   try {
     await api.submitWork({