decay

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package decay implements the Ebbinghaus forgetting curve strength formula used by the SQLite backend (which cannot run SQL math via EXTRACT EPOCH).

Postgres computes strength inside the knowledge_ranked VIEW using native SQL. SQLite computes strength in Go using ComputeStrength before ordering results.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComputeStrength

func ComputeStrength(importance, baseLambda, ageDays float64, recallCount int) float64

ComputeStrength returns the Ebbinghaus-derived memory strength in [0, 1].

Formula (research-validated):

strength = clamp(importance * exp(-baseLambda * (1 - importance*0.8) * ageDays) * (1 + recallCount * 0.2), 0, 1)

Parameters:

  • importance: intrinsic value of the item in [0, 1]; default 0.5.
  • baseLambda: base decay rate; default 0.1.
  • ageDays: days since last recall (or creation when never recalled).
  • recallCount: number of times the item has been recalled; boosts retention.

Edge cases:

  • ageDays < 0 is clamped to 0 (e.g. clocks skew).
  • importance = 0 → strength = 0 regardless of recall (no value, no retention).
  • baseLambda ≤ 0 falls back to 0.1 to avoid undefined behaviour (exp(-0*age)=1 always).

Types

type AtomPruner

type AtomPruner interface {
	PruneAtoms(ctx context.Context, cutoff time.Time) (int64, error)
}

AtomPruner is the minimal interface the Pruner needs from the atom store. atom.Store (Postgres) and sqlite.AtomStore (SQLite) both satisfy this via duck typing.

type Pruner

type Pruner struct {
	// contains filtered or unexported fields
}

Pruner runs the daily soft-prune job across all eligible stores. Decisions table is intentionally excluded.

func NewPruner

func NewPruner(knowledge, concepts PrunerStore, atoms AtomPruner) *Pruner

NewPruner creates a Pruner. Pass nil for any store to skip pruning it.

func (*Pruner) Run

func (p *Pruner) Run()

Run executes the daily soft-prune cycle. It is designed to be called from the gocron scheduler; all errors are logged at warn level so the scheduler keeps running other jobs.

Context is intentionally NOT the request context — each call creates its own timeout-scoped background context.

type PrunerStore

type PrunerStore interface {
	// SoftPruneDecayed sets archived_at=NOW() on rows where:
	//   - archived_at IS NULL (not already pruned)
	//   - created_at < cutoff (older than 90 days)
	//   - computed strength < threshold
	// Returns the number of rows soft-deleted.
	SoftPruneDecayed(ctx context.Context, cutoff time.Time, strengthThreshold float64) (int64, error)
}

PrunerStore is the minimal interface the Pruner needs from each table store. Only knowledge_items and concepts implement this; decisions is excluded by design (it is an audit trail / truth source).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL