# How the memory_feedback Tool Impacts Page Retention and Salience in ai-memory

> Discover how the memory_feedback tool in ai-memory enhances page retention and salience by adjusting scores based on user input. Learn how helpful content gets prioritized and stale content is managed.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: performance
- Published: 2026-08-23

---

**The `memory_feedback` tool directly adjusts a page's salience score based on user feedback—raising it for helpful content, lowering it for unhelpful content, and flooring it to minimum for stale or wrong content—which then multiplicatively affects the retention score that determines eviction priority during forget-sweeps.**

The `memory_feedback` tool in the `akitaonrails/ai-memory` repository provides a quality signaling mechanism that allows users or agents to attach feedback to specific versions of wiki pages. According to the source code in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs), this MCP tool serves as the primary interface for influencing the episodic memory system's retention policies.

## How memory_feedback Modifies Salience Scores

The `memory_feedback` tool operates by writing to the **`page_feedback`** table (defined in migration [`V37__page_feedback.sql`](https://github.com/akitaonrails/ai-memory/blob/main/V37__page_feedback.sql)) and triggering an update to the derived **`pages.salience`** column documented in [`docs/ARCHITECTURE.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md).

### The Four Feedback Kinds

When invoking the tool, you must specify one of four feedback kinds that produce distinct mathematical effects:

- **helpful** — Increments the page's salience by `SALIENCE_STEP` (capped at `SALIENCE_MAX`)
- **not_helpful** — Decrements salience by `SALIENCE_STEP` (floored at `SALIENCE_MIN`)
- **stale** — Forces salience to `SALIENCE_MIN` and creates a lint flag for review
- **wrong** — Forces salience to `SALIENCE_MIN` and creates a lint flag for review

### Salience Calculation Logic in decay.rs

The core mathematics reside in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) within the `salience_after_feedback` function:

```rust
pub fn salience_after_feedback(
    params: &DecayParams,
    current_salience: Option<f64>,
    kind: FeedbackKind,
) -> Option<f64>

```

As implemented around line 141 of [`decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/decay.rs), the function applies stepwise adjustments for helpful and not_helpful feedback, while stale and wrong feedback trigger immediate clamping to the minimum value. This computation occurs transactionally when the feedback is recorded, ensuring the `pages.salience` column reflects the new importance level immediately.

## The Feedback-to-Retention Pipeline

### From MCP Request to Database Update

The end-to-end flow traverses multiple crate boundaries to ensure data consistency:

1. **MCP Server** ([`server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/server.rs) lines 2155-2180): Validates the `memory_feedback` request and forwards to the store
2. **Writer Layer** ([`writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/writer.rs) lines 1054-1061): Provides the async public API `record_page_feedback`
3. **Operations Layer** ([`ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/ops.rs) lines 1651-1706): Executes `ops::record_page_feedback`, which inserts the feedback row and calls `salience_after_feedback` to update the column

The `page_feedback` table serves as the append-only source of truth, while `pages.salience` acts as the cached derived value used by the retention system.

### Retention Score Calculation

Retention is computed by `retention_score_with_breadth` (lines 94-107 in [`decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/decay.rs)), which multiplies salience against decay factors including age and access breadth:

- **Higher salience** (from helpful feedback) increases the retention score, extending the page's lifespan in the episodic store
- **Lower salience** (from negative feedback) reduces the retention score, accelerating candidacy for eviction during the periodic forget-sweep

## Special Handling for Stale and Wrong Feedback

When the `memory_feedback` tool receives **stale** or **wrong** feedback, the system performs two critical actions beyond salience reduction:

1. **Immediate flooring** of salience to `SALIENCE_MIN` via the clamping logic in [`decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/decay.rs)
2. **Lint flag creation** — the function registers a `feedback_flagged` finding that surfaces in the lint pass described in [`ARCHITECTURE.md`](https://github.com/akitaonrails/ai-memory/blob/main/ARCHITECTURE.md) (lines 364-375)

The lint runner periodically queries `open_feedback_findings` in [`reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/reader.rs) (lines 3219-3227) to identify flagged pages for human review. Once a page is rewritten, new feedback rows supersede the old ones, allowing salience to recover.

## Code Examples

### Sending Feedback via MCP

To mark a page as helpful through the MCP interface:

```json
{
  "tool": "memory_feedback",
  "args": {
    "path": "/notes/ai-overview.md",
    "kind": "helpful",
    "reason": "The summary is accurate and concise"
  }
}

```

This request inserts a row into `page_feedback` with `kind = 'helpful'`, raises the page's salience by one step, and increases its retention score for the next forget-sweep evaluation.

### Direct Rust API Usage

For internal crate operations, use the store writer directly:

```rust
let params = DecayParams::default();
store
    .record_page_feedback(
        workspace_id,
        project_id,
        page_path,
        FeedbackKind::NotHelpful,
        Some("The answer was misleading".into()),
        author_id,
    )
    .await?;

```

The `record_page_feedback` method in [`writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/writer.rs) handles the transaction wrapping and calls `salience_after_feedback` to compute the new value before updating the `pages` table.

### Calculating Retention Scores

To inspect how feedback affects retention programmatically:

```rust
let page = store.get_page(page_id).await?;
let retention = decay::retention_score_with_breadth(
    &page,
    /* age_days = */ 30.0,
    /* access_count = */ 5,
    /* access_breadth = */ Some(1.5),
    /* salience_override = */ None,
);
println!("Retention score: {}", retention);

```

Pages with recent **helpful** feedback will show higher retention values compared to those marked **not_helpful** or **stale**, demonstrating the multiplicative impact of salience on the final score.

## Summary

- The **`memory_feedback`** tool provides four feedback kinds (helpful, not_helpful, stale, wrong) that modify page salience through the `salience_after_feedback` function in [`decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/decay.rs).
- **Helpful** feedback increases salience stepwise, while **not_helpful** decreases it; **stale** and **wrong** immediately floor salience to minimum.
- Salience directly multiplies into the **retention score** calculated by `retention_score_with_breadth`, determining eviction priority during forget-sweeps.
- **Stale** and **wrong** feedback automatically create **lint flags** via the `feedback_flagged` system, surfacing pages for human review in [`reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/reader.rs).
- All feedback is stored append-only in the **`page_feedback`** table (migration [`V37__page_feedback.sql`](https://github.com/akitaonrails/ai-memory/blob/main/V37__page_feedback.sql)) with the `pages.salience` column serving as the derived cached value.

## Frequently Asked Questions

### How does helpful feedback affect a page's lifespan in the episodic store?

Helpful feedback raises the page's salience by `SALIENCE_STEP` through the `salience_after_feedback` function. Since `retention_score_with_breadth` multiplies salience against age and access factors, this increase directly boosts the retention score, causing the page to survive longer before becoming eligible for eviction during forget-sweeps.

### What happens when a page receives stale or wrong feedback?

Stale or wrong feedback triggers immediate salience clamping to `SALIENCE_MIN` in [`decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/decay.rs) and registers a `feedback_flagged` lint finding. The page will appear in the output of `open_feedback_findings` in [`reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/reader.rs), alerting human reviewers to rewrite or update the content. The low salience also minimizes the retention score, making the page a high-priority eviction candidate if not updated promptly.

### Where does the memory_feedback tool write its data?

The tool writes to the **`page_feedback`** table defined in migration [`V37__page_feedback.sql`](https://github.com/akitaonrails/ai-memory/blob/main/V37__page_feedback.sql), which serves as the append-only source of truth. The `record_page_feedback` function in [`ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/ops.rs) (lines 1651-1706) then updates the derived **`pages.salience`** column to reflect the new calculated value, ensuring the retention system reads consistent data without scanning the full feedback history.