---
name: wiki-feedback
title: "Wiki Feedback Queue"
description: Engine substrate for the per-article feedback queue. User flags an article wrong with a note; agent reads the note on next regeneration. Never injected into agent prompts directly — the agent's compile/synthesize/research handlers pull open feedback at call time and inject it as context.
category: _meta
status: active
author: system
metadata:
  priority: 0
---

# Wiki Feedback Queue (engine substrate)

This skill is **engine config**, not agent strategy. Its body is never injected
into agent system prompts. Tuning lives in YAML so users can tweak without
editing Python (Rule 12).

## What it solves

Three independent correction paths for wiki articles:

1. **Manual edit** — user fixes the article in Obsidian / text editor →
   `VaultEditWatcher` fires `wiki_manually_edited` → agent sees the result on
   next prompt context. Captures the **what** (corrected text).
2. **Reject** — user marks the whole article `status: rejected`. Sledgehammer
   for "this needs rework or deletion."
3. **Feedback queue** (this skill) — user flags the gap WITHOUT fixing it
   themselves. Agent reads the user's **why** on next regeneration.

The feedback queue is the strongest learning signal of the three because it
captures the user's reasoning, not just the outcome. A rejection reason
appended as loose markdown blockquote at the end of an article is invisible
to agents; a structured feedback row is read into the LLM prompt when
`compile_wiki` / `synthesize` / `research_kb` regenerates the article.

## Knobs (config/feedback.yaml)

- **`enabled`** (default `true`) — Master switch. When `false`, submit /
  resolve become no-ops; reads return empty. Existing rows persist but are
  dormant. Useful kill switch for users who don't want this surface.
- **`max_note_chars`** (default `2000`) — Notes longer than this are
  truncated with `…` to keep the LLM context bounded.
- **`auto_resolve_on_regenerate`** (default `false`) — When `true`,
  `compile_wiki` auto-marks open feedback as resolved (by="compile_wiki")
  after touching an article. Default false because we don't know if the
  regeneration actually addressed the user's note — safer to let the user
  close it manually after reviewing the new content.
- **`agent_prompt_template`** — How feedback is rendered into the LLM
  prompt. Must include `{note}`. Other placeholders: `{date}`, `{kind}`,
  `{severity}`. Default tells the LLM to address the user's note in its
  regeneration.

## Schema

`wiki_feedback` SQLite table:

| Column | Type | Notes |
|---|---|---|
| id | INTEGER PK | autoincrement |
| slug | TEXT | which article |
| kb | TEXT | which KB (for cross-article filtering) |
| kind | TEXT enum | factual_error / wrong_classification / missing_info / outdated / unclear / other |
| severity | TEXT enum | low / medium / high |
| note | TEXT | user's free-text note |
| status | TEXT enum | open / resolved / dismissed |
| created_at | TEXT ISO | submission time |
| resolved_at | TEXT ISO | when closed |
| resolved_by | TEXT | "user" / "agent" / "compile_wiki" / "fact_checker" |

## Lifecycle

1. User clicks the flag icon on a wiki article → modal: kind dropdown,
   severity, note textarea → `POST /api/wiki/article/{slug}/feedback`
   creates an `open` row.
2. `compile_wiki(slug)` / `synthesize(slug)` / `research_kb(slug, query)` ALL
   call `WikiFeedbackService.render_agent_prompt(slug)` BEFORE the LLM call
   and prepend the rendered notes as a system-message block. The LLM regenerates
   knowing what the user flagged.
3. After regeneration, the user reviews the new content. If satisfied →
   `POST /api/wiki/feedback/{id}/resolve` flips status to `resolved`.
4. If unsatisfied → user submits a new feedback row OR marks `dismissed`
   (with a note explaining why the original feedback was wrong / out of scope).

## Activity events

- **`wiki_feedback_submitted`** (medium importance) — fires on every
  `submit()`. Shows up in the agent's `get_relationship_context()` so even
  if compile/synthesize doesn't run for a while, the agent sees the user
  flagged something.
- **`wiki_feedback_resolved`** (low importance) — fires on every `resolve()`.
  Closure is routine; submission is the signal.

## Architectural rules

- **Feedback is signal, not authority.** A wrong feedback note CAN
  mis-direct the agent. The strict frontmatter normalizer + fact-checker
  daily pass catch gross mistakes. Subjective feedback ("this take is too
  generous on X") relies on user judgment.
- **Three correction paths coexist.** None replaces the others. Manual edit
  for "I'll fix it now," reject for "kill the whole article," feedback for
  "agent, please fix this and learn."
- **Read at call time, not at boot.** The LLM prompt assembly path
  (`compile_wiki` etc.) calls `render_agent_prompt(slug)` synchronously when
  it's about to regenerate. No cron, no batch — the freshest feedback is the
  one that counts.
- **CI guards** locked the wiring: kind/severity enums are closed, prompt
  template must contain `{note}`, submit raises ValueError on invalid input
  rather than silently coercing (so callers see contract violations).
