- New aihr_knowledge_answer_feedback table; unique (tenant, query_norm,
fragment_id) pair keeps submissions idempotent
- POST /api/knowledge/answer-feedback (fragmentIds array), GET pending-review
list, POST /{id}/review — all under existing auth scope
- Down-voted (question, fragment) pairs are filtered from dbSearch fusion
results; if filtering empties the hit list the original results are kept
with an explanatory caution (never degrade to no-answer)
- Feedback table missing/unreachable → filter silently skipped, search
behavior unchanged (degradation chain preserved)
- SnippetResponse gains optional trailing fragmentId (db hits only; seed
fallback stays null); mobile sopPanel adds 👍/👎 with locked state after
submit, up votes auto-marked reviewed to keep the review queue clean
- /turn accepts optional regenerate+style (serious/gentle/detailed/professional);
regenerate short-circuits before rememberTraineeReply — no round advance,
no trainee reply write, no scoring impact; only same-round coachHint evidence
is overwritten
- Style instruction injected into existing LLM turn prompt; LLM missing/failed
returns original hint with explicit message (no fake data)
- Mobile practice page renders 再严肃/再温柔/更细致/更专业 pills under coach
hints; success replaces text with a style note, failure toasts and keeps
original; old clients unaffected (fields appended)
- Treat 'undefined'/'null' localStorage values as absent; clear incomplete
token/clientId pairs and prompt re-login instead of sending broken headers
- Gate authenticated UI on both token and clientId via isAuthenticated
- Reject login responses missing access_token or client_id