# How memory_feedback Signals Influence Page Salience and Decay Thresholds

> Discover how memory_feedback signals control page salience and decay thresholds in akitaonrails/ai-memory. Learn to manage agent memory retention and prevent data eviction.

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

---

**The `memory_feedback` mechanism allows agents to directly adjust a page's salience score by raising or lowering it by `SALIENCE_STEP`, or resetting it to the floor when marked stale, which indirectly determines whether the page's retention score falls below the `cold_threshold` and becomes eligible for eviction.**

The `akitaonrails/ai-memory` repository implements a semantic memory store for AI agents where content naturally decays over time. The `memory_feedback` signal serves as the critical interface for agents to communicate content utility, directly manipulating the **salience** value that acts as a multiplier in the retention formula to control eviction priorities.

## The Feedback-to-Salience Pipeline

When an agent submits a `memory_feedback` signal, the store executes a three-phase transaction in [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs) to translate subjective utility into an objective retention score.

### Looking Up Current Salience

First, the system locates the target page and retrieves its current salience value. In [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs) at lines 51–57, the `record_page_feedback` function queries the latest page version, falling back to the default salience if no prior feedback exists.

### Computing the New Salience

Next, the pure helper `salience_after_feedback` in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) (lines 41–53) calculates the adjusted value based on the `FeedbackKind`:

- **Helpful** → increases salience by `SALIENCE_STEP`
- **NotHelpful** → decreases salience by `SALIENCE_STEP`
- **Stale** or **Wrong** → immediately drops salience to `SALIENCE_MIN` (the floor value)

The result is clamped between `SALIENCE_MIN` (0.25) and `SALIENCE_MAX` (2.0) as defined in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) at lines 22–30.

### Persisting Changes

Finally, the transaction appends a record to the `page_feedback` table and updates the `salience` column in the `pages` table (defined in [`crates/ai-memory-store/src/page.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/page.rs) at lines 250–260). This occurs in [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs) at lines 86–92, ensuring the new salience is immediately available to the retention calculator.

## Salience Bounds and Calculation Constants

The salience adjustment operates within strict bounds to prevent runaway values:

```rust
// From crates/ai-memory-store/src/decay.rs
pub const SALIENCE_MIN: f64 = 0.25;
pub const SALIENCE_MAX: f64 = 2.0;
pub const SALIENCE_STEP: f64 = 0.25; // Typical step size

```

A **Helpful** signal increments salience by the step size, making the page more resistant to time-based decay. Conversely, **NotHelpful** decrements it, accelerating the page's path toward the eviction threshold.

## From Salience to Retention Score

Salience directly influences the **retention score** computed in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) (lines 13–30). The formula treats salience as a multiplier on the time-decay term:

```

retention_score = salience × exp(-λ × age) + access_reinforcement

```

Where:
- `salience` is the current value stored in the page row
- `λ` (lambda) is the decay coefficient from `DecayParams`
- `age` is the time since creation

Because the time term is multiplicative, raising salience lifts the overall score above the `cold_threshold` (default 0.20), protecting the page from the forget-sweep job. Lowering salience (via negative feedback) reduces the score and can push the page below the threshold, marking it for eviction.

## Recording Feedback in Practice

### Using the Rust API

The low-level `record_page_feedback` function in [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs) provides direct access:

```rust
use ai_memory_store::{
    ops::record_page_feedback,
    decay::DecayParams,
};
use ai_memory_core::{FeedbackKind, UserId, PagePath, WorkspaceId, ProjectId};

fn give_feedback(
    conn: &mut rusqlite::Connection,
    ws: WorkspaceId,
    proj: ProjectId,
    path: &PagePath,
) -> anyhow::Result<()> {
    // Mark the page as helpful with a short reason
    let (page_id, new_salience) = record_page_feedback(
        conn,
        ws,
        proj,
        path,
        FeedbackKind::Helpful,
        Some("the answer was spot-on"),
        Some(UserId::new()),        // author (optional)
        &DecayParams::default(),    // tuned decay coefficients
    )?
    .expect("page must exist");
    
    println!("Page {page_id} now has salience {new_salience}");
    Ok(())
}

```

### Using the CLI

The `ai-memory` binary exposes feedback functionality to shell scripts and manual curation:

```bash

# Record a "not helpful" feedback on a page

ai-memory memory_feedback \
    --workspace my_ws \
    --project my_proj \
    --path docs/quickstart.md \
    --kind not_helpful \
    --reason "out-of-date example"

```

The CLI forwards the request to the MCP server, which executes the same `record_page_feedback` logic against the SQLite backing store.

## Measuring the Impact on Decay

You can observe how feedback alters retention priorities by comparing scores before and after salience adjustments:

```rust
use ai_memory_store::{decay::{RetentionScore, DecayParams}, decay::retention_score};

let params = DecayParams::default();
let age_days = 30.0;
let access_count = 5;
let days_since_access = Some(1.0);

// No feedback (salience = default)
let score_no_fb = retention_score(&params, age_days, access_count, days_since_access, None);

// After a "Helpful" feedback (salience increased by SALIENCE_STEP)
let elevated_salience = params.salience_default + 0.25; // SALIENCE_STEP
let score_helpful = retention_score(&params, age_days, access_count, days_since_access, Some(elevated_salience));

println!("Score before feedback: {score_no_fb}");
println!("Score after helpful feedback: {score_helpful}");

```

The second score will be higher because the elevated salience boosts the time-decay component, keeping the page above the `cold_threshold` longer than unhelpful or neutral content.

## Summary

- The `memory_feedback` signal directly modifies the `salience` column in [`crates/ai-memory-store/src/page.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/page.rs) via the `record_page_feedback` transaction.
- Salience adjustments are computed by `salience_after_feedback` in [`decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/decay.rs), clamped between 0.25 and 2.0.
- **Helpful** feedback increases salience by `SALIENCE_STEP`, while **Stale** or **Wrong** feedback resets it to the floor value.
- Salience acts as a multiplier in the retention formula (`salience × exp(-λ × age)`), directly influencing whether the score remains above the `cold_threshold` (0.20).
- Pages falling below the threshold become eligible for eviction during the forget-sweep job.

## Frequently Asked Questions

### What happens to salience when a page is marked as Stale or Wrong?

When feedback is submitted with `FeedbackKind::Stale` or `FeedbackKind::Wrong`, the `salience_after_feedback` function immediately sets the page's salience to `SALIENCE_MIN` (0.25) regardless of its previous value. This aggressive penalty ensures outdated or incorrect information is rapidly deprioritized for eviction.

### How does salience interact with the time-decay formula?

Salience multiplies the exponential time-decay term in the retention calculation. According to the implementation in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs), the formula uses `salience · exp(-λ · age)` as the time component. A higher salience offsets the decay effect, while a lower salience accelerates the score's decline toward the `cold_threshold`.

### What are the maximum and minimum salience values?

The system enforces hard bounds defined in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs): `SALIENCE_MIN` is set to **0.25** and `SALIENCE_MAX` is **2.0**. The `salience_after_feedback` function clamps all computed values to this range, preventing extreme outliers in retention scoring.

### Is a user ID required when submitting memory feedback?

No, the author parameter is optional. The `record_page_feedback` function signature accepts `Option<UserId>` for the author field, allowing automated agents or anonymous processes to submit feedback without attribution. The feedback record is still appended to the `page_feedback` table with a null author if none is provided.