Review: Mood → Moments analysis module¶
Date: 2026-08-19
Scope: moments module, View → Mood → Moments UI, and relationship to Highlights / future Slice concepts
Status: Shipped behaviour reviewed; no code changes in this review
Summary¶
The Moments panel is meant to give users a short, ranked list of salient quotes from the notebook with Jump to page navigation. In practice, absolute scores cluster around 0.6, the bar chart looks flat, and the numeric score reads like a calibrated “importance meter” when it is really a relative ranking helper with a low ceiling when mood signals are absent.
The module delivers a cheap deterministic browse aid; it does not reliably surface “moments” in a human, autobiographical sense.
Intended user value¶
Layer |
Stated intent |
|---|---|
Module catalogue |
“Moments worth revisiting” |
View UI caption |
“Salient quotes from the notebook” |
Wave 1 delivery plan |
“Unusual / emotionally strong / high-information passages” |
Primary action |
Ranked quotes + Jump to page → Reading |
What it is not: ROADMAP.md explicitly separates Mood → Moments (analysis salience over quoted pages) from post-1.0 Slice (user-confirmed life episodes). TERMS.md repeats that distinction.
Related surface: Summaries → Highlights uses a different heuristic (unique words + length + position) and feeds the summary pipeline. Moments is the Mood-facing “revisit these pages” surface.
Implementation (fork, not parity)¶
TranscriptX moments used speech dynamics (momentum, pauses). Transcribe records a fork — notebook salience without those signals (analysis_port_pins.md, analysis-result.md).
Module:
src/transcribe/analysis/modules/moments.pyAlgorithm id:
notebook_salience_fork_v1Payload:
moments_payload_v1— top-N ranked units with scores, per-feature breakdown, quotes, evidenceSoft parents (optional):
emotion,sentiment,topic_shift— consumed when published and fresh; not hard dependenciesConfig:
analysis.moments.top_n(default 10)
Batch order runs mood parents before moments (emotion 54, sentiment 31, topic_shift 52, moments 58), so a full Analyse preset should enrich scores when those modules succeed.
Scoring formula¶
Each analysis unit (typically a page) receives a composite score in [0, 1]:
Component |
Weight |
Source |
|---|---|---|
Length |
35% |
Token count after stopword removal, capped at 40 tokens → 1.0 |
Information |
25% |
Mean pseudo-IDF within the notebook (rarer tokens on that unit score higher) |
Emotion |
20% |
|
Sentiment |
15% |
|
Topic shift |
5% |
1.0 if unit is a |
Top-N units by score are published; the UI shows a bar chart, a quote list with scores, and jump buttons (analysis_product_views.py).
Findings¶
1. Scores cluster at 0.6¶
Observed behaviour: many notebooks show Moments scores at or near 0.6 with little spread on the bar chart.
Cause A — hard ceiling without mood signals: When emotion, sentiment, and topic shift contribute nothing, the maximum score is:
0.35 × 1.0 + 0.25 × 1.0 = 0.60
Pages that are long enough (≥40 content tokens) and lexically “rich enough” (high within-notebook IDF) cannot score above 0.60 unless soft features add weight.
Cause B — homogeneous units: Diary-style notebooks often have pages of similar length and vocabulary. Length and information components correlate across units, so ranks differ only slightly.
Cause C — weak mood differentiation: Emotion uses lexicon hit density; neutral journal prose often yields low intensities. Sentiment uses magnitude only (|compound|), so neutral text still contributes little.
Cause D — display rounding: The product list formats scores as {score:.3g}, so values such as 0.598 and 0.605 both render as 0.6, hiding small rank differences.
Cause E — reduced soft features: If moments runs without fresh emotion / sentiment / topic_shift results, the envelope is partial: true with warning reduced_soft_features. Ranking then relies almost entirely on length + within-notebook IDF — a weak salience signal for personal notebooks.
Check Advanced on the Moments panel for soft_features_present and per-row features in the payload.
2. Absolute scores imply false precision¶
The UI presents a 0–1 score beside each quote and in a bar chart. Users reasonably interpret this as “strength of moment.” The implementation only guarantees relative ordering within one notebook run. Scores are not comparable across notebooks or runs and are not calibrated to human “moment” salience.
3. Product promise vs. delivered signal¶
Wave 1 described “unusual / emotionally strong / high-information passages.” Lexical length + within-doc IDF detects longer, slightly more vocabulary-diverse pages, not necessarily emotional peaks or narrative turning points. With soft parents, mood helps only when lexicons/models produce spread — which is often limited on handwritten journal text.
4. Naming friction¶
“Moments” suggests autobiographical episodes. Roadmap and terms already warn this is not Slice. The UI caption (“Salient quotes”) is more accurate than the nav label but easy to miss.
What users should use it for today¶
Relative ranking — treat the list as “top N pages by this heuristic,” not as absolute importance.
Quote skim + jump — read the truncated quote; use Jump to page when something looks worth revisiting.
Best with full mood stack — Thorough (or Custom including
emotion,sentiment,topic_shift) gives moments the best chance to spread scores above 0.6.
Recommendations (not scheduled)¶
Prioritized options for a future usability or analysis hardening pass:
Priority |
Option |
Rationale |
|---|---|---|
High |
Rank-first UI — show #1…#N prominently; de-emphasize or hide raw 0–1 scores |
Matches actual semantics; fixes “everything is 0.6” confusion |
High |
Feature breakdown in product UI — chips or sub-bars for length / information / emotion / sentiment / shift |
Makes the heuristic legible without opening Advanced JSON |
Medium |
Rescale or normalize scores for display (e.g. min–max within the published top-N or full unit set) |
Spreads bar chart visually while preserving order |
Medium |
Stronger copy — caption or tooltip explaining fork, soft parents, and non-absolute scores |
Sets expectations; link to this review or known limitations |
Medium |
Surface |
Users know when they are seeing lexical-only ranking |
Low |
Algorithm revisit — paragraph-level units ( |
More engineering; may overlap Highlights; needs contract bump |
Any algorithm change should bump algorithm_version, update analysis-result.md if payload semantics change, and add regression tests in tests/services/test_analysis_wave1d.py.
References¶
Module: moments.py
UI: analysis_product_views.py (
render_moments_product)Contract: analysis-result.md —
moments_payload_v1, fork semanticsRuntime guide: runtime/analysis.md — View → Mood → Moments
Roadmap note: ROADMAP.md — Moments ≠ Slice
Visual intent: analysis_visual_compare.md