Documentation
¶
Index ¶
- Variables
- func ComputeConceptStatus(reviewCount int, intervalDays float64) string
- func NextState(s CardState, rating Rating) (stability, difficulty float64, intervalDays int)
- type CardState
- type ConceptForReview
- type ConceptHistoryRow
- type DueReview
- type LearningStatsResult
- type Rating
- type Store
- func (s *Store) CountDueReviews(ctx context.Context) (int, error)
- func (s *Store) CreateConcept(ctx context.Context, title, content string, tags []string) (*db.Concept, error)
- func (s *Store) DueReviews(ctx context.Context, limit int) ([]DueReview, error)
- func (s *Store) GetScheduleState(ctx context.Context, scheduleID uuid.UUID) (CardState, error)
- func (s *Store) LearningStats(ctx context.Context) (*LearningStatsResult, error)
- func (s *Store) ListConcepts(ctx context.Context, limit int) ([]db.Concept, error)
- func (s *Store) ListForAIReview(ctx context.Context, minReviewCount int) ([]ConceptForReview, error)
- func (s *Store) ReviewHistory(ctx context.Context) ([]ConceptHistoryRow, error)
- func (s *Store) ReviewedSince(ctx context.Context, since time.Time, limit int) ([]DueReview, error)
- func (s *Store) SoftPruneDecayed(ctx context.Context, cutoff time.Time, strengthThreshold float64) (int64, error)
- func (s *Store) SubmitReview(ctx context.Context, scheduleID uuid.UUID, currentState CardState, ...) error
- func (s *Store) UpdateConceptStatus(ctx context.Context, id uuid.UUID, status string) error
- func (s *Store) WithTx(tx pgx.Tx) *Store
- type StoreIface
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("learning: not found")
ErrNotFound is returned when a requested entity does not exist.
Functions ¶
func ComputeConceptStatus ¶
ComputeConceptStatus maps review metrics to a human-readable learning stage. "new": review_count=0; "learning": 1-4; "reviewing": 5-14; "mastered": review_count>=15 AND interval_days>30. Exported so both Postgres and SQLite stores can use the same logic.
Types ¶
type ConceptForReview ¶
type ConceptForReview struct {
ID uuid.UUID
Title string
Content string
ReviewCount int
Stability float64
}
ConceptForReview holds the fields needed by the AI reviewer to evaluate whether a concept has been mastered or is no longer helpful.
type ConceptHistoryRow ¶
type ConceptHistoryRow struct {
ID uuid.UUID `json:"id"`
Title string `json:"title"`
Tags []string `json:"tags"`
ReviewCount int `json:"review_count"`
FirstReviewedAt *time.Time `json:"first_reviewed_at,omitempty"`
LastReviewedAt *time.Time `json:"last_reviewed_at,omitempty"`
IntervalDays float64 `json:"interval_days"`
NextReviewAt *time.Time `json:"next_review_at,omitempty"`
Status string `json:"status"` // "new"|"learning"|"reviewing"|"mastered"
}
ConceptHistoryRow is returned by ReviewHistory. It combines a concept record with its associated review_schedule statistics.
type DueReview ¶
type DueReview struct {
ConceptID uuid.UUID `json:"concept_id"`
ScheduleID uuid.UUID `json:"schedule_id"`
Title string `json:"title"`
Content string `json:"content"`
Stability float64 `json:"stability"`
Difficulty float64 `json:"difficulty"`
DueDate time.Time `json:"due_date"`
ReviewCount int `json:"review_count"`
}
DueReview represents a concept with its associated review schedule.
type LearningStatsResult ¶
type LearningStatsResult struct {
TotalReviews int `json:"total_reviews"`
Reviews7d int `json:"reviews_7d"`
Mastered int `json:"mastered"`
TotalConcepts int `json:"total_concepts"`
StreakDays int `json:"streak_days"`
}
LearningStatsResult is the response shape for GET /api/learning/stats.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store handles all database operations for the Learning bounded context.
func NewStore ¶
NewStore returns a Store backed by the given connection pool scoped to the optional workspace. nil workspaceID = legacy unscoped mode.
func (*Store) CountDueReviews ¶
CountDueReviews returns the total number of concepts currently due for review.
func (*Store) CreateConcept ¶
func (s *Store) CreateConcept(ctx context.Context, title, content string, tags []string) (*db.Concept, error)
CreateConcept inserts a concept and its initial review schedule.
func (*Store) DueReviews ¶
DueReviews returns concepts whose review is due, up to the given limit.
func (*Store) GetScheduleState ¶
GetScheduleState returns the current CardState for scheduleID, scoped to the store's configured workspace. See StoreIface.GetScheduleState (Ω7 fix) for the full rationale. Raw SQL (not sqlc) matches the pattern already used by ReviewHistory/LearningStats in this same file.
func (*Store) LearningStats ¶
func (s *Store) LearningStats(ctx context.Context) (*LearningStatsResult, error)
LearningStats returns aggregate learning statistics. interval is approximated as stability * 9 (FSRS target-90% formula). StreakDays counts consecutive days (ending today) on which at least one review was submitted, based on last_review_at in review_schedule.
func (*Store) ListConcepts ¶
ListConcepts returns up to limit concepts ordered by created_at DESC, scoped to the configured workspace.
func (*Store) ListForAIReview ¶
func (s *Store) ListForAIReview(ctx context.Context, minReviewCount int) ([]ConceptForReview, error)
ListForAIReview returns active concepts that have at least minReviewCount completed reviews, ordered by review count descending.
func (*Store) ReviewHistory ¶
func (s *Store) ReviewHistory(ctx context.Context) ([]ConceptHistoryRow, error)
ReviewHistory returns all concepts joined with their review schedule, sorted by last_review_at DESC NULLS LAST (un-reviewed concepts appear last). interval_days is approximated as stability * 9 (the FSRS target-90%-retention formula used in NextState). Status is computed in Go from review_count and the derived interval.
func (*Store) ReviewedSince ¶
ReviewedSince returns DueReview entries whose last_review_at >= since, scoped to the configured workspace. Used by the timeline aggregator.
func (*Store) SoftPruneDecayed ¶
func (s *Store) SoftPruneDecayed(ctx context.Context, cutoff time.Time, strengthThreshold float64) (int64, error)
SoftPruneDecayed implements decay.PrunerStore for the concepts table. It sets archived_at=NOW() on concepts that are:
- not already archived (archived_at IS NULL)
- older than cutoff (created_at < cutoff)
- Ebbinghaus strength < strengthThreshold
Decisions table is NEVER touched by this method.
func (*Store) SubmitReview ¶
func (s *Store) SubmitReview(ctx context.Context, scheduleID uuid.UUID, currentState CardState, rating Rating) error
SubmitReview applies the FSRS algorithm and updates the review schedule.
func (*Store) UpdateConceptStatus ¶
UpdateConceptStatus sets the status column of the given concept. Valid values are "active", "mastered", and "not_helpful".
type StoreIface ¶
type StoreIface interface {
CreateConcept(ctx context.Context, title, content string, tags []string) (*db.Concept, error)
DueReviews(ctx context.Context, limit int) ([]DueReview, error)
// GetScheduleState returns the current CardState for scheduleID, scoped
// to the store's configured workspace. Returns ErrNotFound when no
// review_schedule row matches. Ω7 fix (mcp-surface spec, backend-
// security-design.md §2.1 — LLM tool input is adversarial): submit_review
// used to accept stability/difficulty/review_count as caller-supplied
// "current state" params instead of the MCP handler reading them from
// here; an omitted/zero review_count silently routed a mature schedule
// through SubmitReview's initial-review branch and overwrote it with a
// fresh, much shorter interval. SubmitReview's own currentState
// parameter is unchanged (still used directly by internal/handler's HTTP
// path and internal/scheduler) — this is an additive method, not a
// signature change to SubmitReview.
GetScheduleState(ctx context.Context, scheduleID uuid.UUID) (CardState, error)
SubmitReview(ctx context.Context, scheduleID uuid.UUID, currentState CardState, rating Rating) error
CountDueReviews(ctx context.Context) (int, error)
ListForAIReview(ctx context.Context, minReviewCount int) ([]ConceptForReview, error)
UpdateConceptStatus(ctx context.Context, id uuid.UUID, status string) error
// ReviewHistory returns all concepts with their review summary, sorted by
// last_reviewed_at DESC NULLS LAST (new concepts appear last).
ReviewHistory(ctx context.Context) ([]ConceptHistoryRow, error)
// LearningStats returns aggregate stats across all concepts and reviews.
LearningStats(ctx context.Context) (*LearningStatsResult, error)
// ListConcepts returns up to limit concepts ordered by created_at DESC,
// scoped to the configured workspace.
ListConcepts(ctx context.Context, limit int) ([]db.Concept, error)
// ReviewedSince returns review_schedule rows where last_review_at >= since,
// scoped to the configured workspace. Used by the timeline aggregator.
ReviewedSince(ctx context.Context, since time.Time, limit int) ([]DueReview, error)
}
StoreIface is the backend-agnostic contract for the Learning (FSRS) bounded context.