- 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
- Seed aihr_prompt_template with code=sop_answer (conclusion-first + numbered
steps + citations appended), matching the built-in prompt
- Digest prefers the enabled sop_answer template, falls back to the built-in
constant, and logs prompt_version; answer/keyPoints/cautions contract unchanged