951 lines
29 KiB
Rust
951 lines
29 KiB
Rust
use std::collections::HashMap;
|
||
|
||
use tidaldb::TidalDb;
|
||
use tidaldb::schema::{EntityId, Timestamp};
|
||
|
||
#[derive(Clone)]
|
||
pub struct SeedItem {
|
||
pub id: u64,
|
||
pub title: String,
|
||
pub source: String,
|
||
pub category: String,
|
||
pub reading_time_min: u32,
|
||
pub description: String,
|
||
pub url: String,
|
||
}
|
||
|
||
/// Map a URL to a stable item ID using FNV-1a.
|
||
///
|
||
/// Produces a deterministic, collision-resistant u64 that is always > 100_000,
|
||
/// keeping it well clear of the seed corpus range (1–100).
|
||
pub fn url_to_item_id(url: &str) -> u64 {
|
||
let mut hash: u64 = 14_695_981_039_346_656_037;
|
||
for byte in url.bytes() {
|
||
hash ^= u64::from(byte);
|
||
hash = hash.wrapping_mul(1_099_511_628_211);
|
||
}
|
||
// Map tiny hashes out of the seed range without clustering.
|
||
if hash <= 100_000 {
|
||
hash.wrapping_add(100_001)
|
||
} else {
|
||
hash
|
||
}
|
||
}
|
||
|
||
const CATEGORIES: &[&str] = &[
|
||
"technology",
|
||
"science",
|
||
"jazz",
|
||
"travel",
|
||
"cooking",
|
||
"design",
|
||
"history",
|
||
"health",
|
||
];
|
||
|
||
fn category_dim(cat: &str) -> usize {
|
||
CATEGORIES.iter().position(|&c| c == cat).unwrap_or(0)
|
||
}
|
||
|
||
/// 8-dim unit vector along the category axis, with small deterministic per-item noise.
|
||
pub fn category_vector(cat: &str, item_id: u64) -> Vec<f32> {
|
||
let dim = category_dim(cat);
|
||
let mut v = vec![0.0f32; 8];
|
||
v[dim] = 0.9;
|
||
|
||
// Deterministic LCG noise so same item always gets same vector.
|
||
let mut state = item_id
|
||
.wrapping_mul(6_364_136_223_846_793_005)
|
||
.wrapping_add(1);
|
||
for x in &mut v {
|
||
state = state
|
||
.wrapping_mul(6_364_136_223_846_793_005)
|
||
.wrapping_add(1);
|
||
let noise = ((state >> 33) as f32 / u32::MAX as f32 - 0.5) * 0.2;
|
||
*x += noise;
|
||
}
|
||
|
||
l2_normalize(&mut v);
|
||
v
|
||
}
|
||
|
||
fn l2_normalize(v: &mut [f32]) {
|
||
let norm: f32 = v.iter().map(|x| x * x).sum::<f32>().sqrt();
|
||
if norm > 1e-9 {
|
||
for x in v.iter_mut() {
|
||
*x /= norm;
|
||
}
|
||
}
|
||
}
|
||
|
||
pub fn default_corpus() -> Vec<SeedItem> {
|
||
let raw: &[(&str, &str, &str, u32, &str, &str)] = &[
|
||
// technology (ids 1–12)
|
||
(
|
||
"Rust's Ownership Model Explained",
|
||
"blog.rustlang.org",
|
||
"technology",
|
||
8,
|
||
"A deep dive into Rust's ownership, borrowing, and lifetimes.",
|
||
"https://blog.rustlang.org/ownership",
|
||
),
|
||
(
|
||
"Building Fast APIs with Axum",
|
||
"tokio.rs",
|
||
"technology",
|
||
6,
|
||
"How to build high-performance HTTP APIs with Axum and Tokio.",
|
||
"https://tokio.rs/axum-guide",
|
||
),
|
||
(
|
||
"WebAssembly in 2025",
|
||
"webassembly.org",
|
||
"technology",
|
||
10,
|
||
"State of the WebAssembly ecosystem and what's coming next.",
|
||
"https://webassembly.org/2025",
|
||
),
|
||
(
|
||
"LLMs Are Not Magic",
|
||
"ml.substack.com",
|
||
"technology",
|
||
7,
|
||
"Demystifying large language models for engineers.",
|
||
"https://ml.substack.com/llms",
|
||
),
|
||
(
|
||
"Kubernetes Cost Optimization",
|
||
"infra.dev",
|
||
"technology",
|
||
9,
|
||
"Practical techniques for cutting your cloud bill.",
|
||
"https://infra.dev/k8s-costs",
|
||
),
|
||
(
|
||
"Database Internals: LSM Trees",
|
||
"db-internals.com",
|
||
"technology",
|
||
12,
|
||
"How log-structured merge trees power modern databases.",
|
||
"https://db-internals.com/lsm",
|
||
),
|
||
(
|
||
"TypeScript 5.5 Features",
|
||
"devblog.ts",
|
||
"technology",
|
||
5,
|
||
"Everything new in TypeScript 5.5 with code examples.",
|
||
"https://devblog.ts/5.5",
|
||
),
|
||
(
|
||
"Zero-Copy Networking in Linux",
|
||
"lwn.net",
|
||
"technology",
|
||
11,
|
||
"io_uring, splice, and the future of zero-copy I/O.",
|
||
"https://lwn.net/zero-copy",
|
||
),
|
||
(
|
||
"AI Code Assistants Compared",
|
||
"dev.to",
|
||
"technology",
|
||
6,
|
||
"GitHub Copilot vs Cursor vs Codeium: real-world benchmarks.",
|
||
"https://dev.to/ai-assistants",
|
||
),
|
||
(
|
||
"Serverless Is Not Stateless",
|
||
"serverless.blog",
|
||
"technology",
|
||
8,
|
||
"Why serverless architectures still need to manage state.",
|
||
"https://serverless.blog/state",
|
||
),
|
||
(
|
||
"Open Source Observability Stack",
|
||
"grafana.com",
|
||
"technology",
|
||
7,
|
||
"Building a full observability pipeline with OSS tools.",
|
||
"https://grafana.com/oss-stack",
|
||
),
|
||
(
|
||
"Columnar Storage for Analytics",
|
||
"clickhouse.blog",
|
||
"technology",
|
||
9,
|
||
"Why column-oriented storage dominates analytical workloads.",
|
||
"https://clickhouse.blog/columnar",
|
||
),
|
||
// science (ids 13–24)
|
||
(
|
||
"The Dark Matter Problem",
|
||
"physics.org",
|
||
"science",
|
||
9,
|
||
"What we know — and don't know — about dark matter.",
|
||
"https://physics.org/dark-matter",
|
||
),
|
||
(
|
||
"CRISPR Off-Target Effects",
|
||
"nature.com",
|
||
"science",
|
||
11,
|
||
"New research on precision genome editing and its risks.",
|
||
"https://nature.com/crispr",
|
||
),
|
||
(
|
||
"Ocean Acidification Accelerates",
|
||
"oceanresearch.edu",
|
||
"science",
|
||
8,
|
||
"Latest measurements show faster-than-predicted pH decline.",
|
||
"https://oceanresearch.edu/acidification",
|
||
),
|
||
(
|
||
"Quantum Entanglement at Scale",
|
||
"quanta.mag",
|
||
"science",
|
||
10,
|
||
"Experiments demonstrating entanglement across 100km distances.",
|
||
"https://quanta.mag/entanglement",
|
||
),
|
||
(
|
||
"Antibiotic Resistance Crisis",
|
||
"who.int",
|
||
"science",
|
||
7,
|
||
"The global health emergency that antibiotics are losing.",
|
||
"https://who.int/amr",
|
||
),
|
||
(
|
||
"How Sleep Cleans Your Brain",
|
||
"neuroscience.review",
|
||
"science",
|
||
6,
|
||
"The glymphatic system and why sleep deprivation is dangerous.",
|
||
"https://neuroscience.review/sleep",
|
||
),
|
||
(
|
||
"Mars Soil Composition Update",
|
||
"nasa.gov",
|
||
"science",
|
||
9,
|
||
"Perseverance rover findings on Martian mineralogy.",
|
||
"https://nasa.gov/mars-soil",
|
||
),
|
||
(
|
||
"Photosynthesis Efficiency Breakthrough",
|
||
"biotech.news",
|
||
"science",
|
||
8,
|
||
"Engineers achieve 12% improvement in plant energy conversion.",
|
||
"https://biotech.news/photosynthesis",
|
||
),
|
||
(
|
||
"The Gut-Brain Axis",
|
||
"microbiome.journal",
|
||
"science",
|
||
10,
|
||
"How intestinal bacteria influence mood and cognition.",
|
||
"https://microbiome.journal/gut-brain",
|
||
),
|
||
(
|
||
"Superconductors at Room Temperature?",
|
||
"condensed.matter.news",
|
||
"science",
|
||
12,
|
||
"Examining the controversial LK-99 claims and new research.",
|
||
"https://condensed.matter.news/superconductors",
|
||
),
|
||
(
|
||
"Mitochondrial DNA Inheritance",
|
||
"genetics.lab",
|
||
"science",
|
||
7,
|
||
"Paternal inheritance of mitochondria: exceptions to the rule.",
|
||
"https://genetics.lab/mitochondria",
|
||
),
|
||
(
|
||
"James Webb Telescope: Year Two",
|
||
"space.telescope.com",
|
||
"science",
|
||
11,
|
||
"Key discoveries from JWST's second year of observations.",
|
||
"https://space.telescope.com/jwst-y2",
|
||
),
|
||
// jazz (ids 25–36)
|
||
(
|
||
"Miles Davis and Modal Jazz",
|
||
"jazzhistory.com",
|
||
"jazz",
|
||
7,
|
||
"How Kind of Blue changed everything about jazz harmony.",
|
||
"https://jazzhistory.com/miles-modal",
|
||
),
|
||
(
|
||
"The Art of Improvisation",
|
||
"berklee.edu",
|
||
"jazz",
|
||
9,
|
||
"Techniques for developing a personal improvisational voice.",
|
||
"https://berklee.edu/improvisation",
|
||
),
|
||
(
|
||
"John Coltrane's Sheets of Sound",
|
||
"jazztimes.com",
|
||
"jazz",
|
||
8,
|
||
"Analysis of Coltrane's density-of-notes approach.",
|
||
"https://jazztimes.com/coltrane",
|
||
),
|
||
(
|
||
"Thelonious Monk's Rhythmic Genius",
|
||
"allaboutjazz.com",
|
||
"jazz",
|
||
6,
|
||
"How Monk's unconventional rhythms shaped modern piano.",
|
||
"https://allaboutjazz.com/monk",
|
||
),
|
||
(
|
||
"Bill Evans and Impressionism",
|
||
"piano.quarterly",
|
||
"jazz",
|
||
10,
|
||
"The harmonic language of Bill Evans and its classical roots.",
|
||
"https://piano.quarterly/evans",
|
||
),
|
||
(
|
||
"Free Jazz: Ornette Coleman",
|
||
"freeform.press",
|
||
"jazz",
|
||
8,
|
||
"Liberation from chord changes and its lasting influence.",
|
||
"https://freeform.press/coleman",
|
||
),
|
||
(
|
||
"Brazilian Jazz Fusion",
|
||
"musica.rio",
|
||
"jazz",
|
||
7,
|
||
"How bossa nova and samba shaped modern jazz harmony.",
|
||
"https://musica.rio/fusion",
|
||
),
|
||
(
|
||
"The Jazz Rhythm Section",
|
||
"drummerworld.com",
|
||
"jazz",
|
||
5,
|
||
"Roles and interactions between bass, drums, and piano.",
|
||
"https://drummerworld.com/rhythm-section",
|
||
),
|
||
(
|
||
"Hard Bop's Social Context",
|
||
"civilrights.music",
|
||
"jazz",
|
||
9,
|
||
"How Art Blakey's music reflected the civil rights era.",
|
||
"https://civilrights.music/hardbop",
|
||
),
|
||
(
|
||
"Vocal Jazz: Sarah Vaughan",
|
||
"singing.academy",
|
||
"jazz",
|
||
6,
|
||
"Technique, range, and phrasing in Vaughan's recordings.",
|
||
"https://singing.academy/vaughan",
|
||
),
|
||
(
|
||
"Electric Miles: Bitches Brew",
|
||
"fusion.history",
|
||
"jazz",
|
||
11,
|
||
"The recording that launched jazz fusion.",
|
||
"https://fusion.history/bitches-brew",
|
||
),
|
||
(
|
||
"Jazz Standards and Their Stories",
|
||
"greatamericansongbook.com",
|
||
"jazz",
|
||
8,
|
||
"Origins of the most-played jazz compositions.",
|
||
"https://greatamericansongbook.com/standards",
|
||
),
|
||
// travel (ids 37–48)
|
||
(
|
||
"Solo Travel in Patagonia",
|
||
"lonelyhiker.com",
|
||
"travel",
|
||
9,
|
||
"A week on the W Trek: logistics, gear, and memories.",
|
||
"https://lonelyhiker.com/patagonia",
|
||
),
|
||
(
|
||
"Japan by Rail Pass",
|
||
"japantravel.guide",
|
||
"travel",
|
||
10,
|
||
"How to maximize the JR Pass for a two-week Japan trip.",
|
||
"https://japantravel.guide/rail",
|
||
),
|
||
(
|
||
"Hidden Gems of Portugal",
|
||
"slowtravel.eu",
|
||
"travel",
|
||
7,
|
||
"Beyond Lisbon: the Alentejo region's villages and wine.",
|
||
"https://slowtravel.eu/portugal",
|
||
),
|
||
(
|
||
"Crossing the Sahara",
|
||
"overland.adventures",
|
||
"travel",
|
||
12,
|
||
"A guide to trans-Saharan routes for experienced overlanders.",
|
||
"https://overland.adventures/sahara",
|
||
),
|
||
(
|
||
"Southeast Asia on $40/Day",
|
||
"budgetbacker.com",
|
||
"travel",
|
||
8,
|
||
"Real costs and tips for Thailand, Vietnam, and Cambodia.",
|
||
"https://budgetbacker.com/sea",
|
||
),
|
||
(
|
||
"Antarctic Expedition Diary",
|
||
"polartravels.net",
|
||
"travel",
|
||
11,
|
||
"Fourteen days on the white continent, firsthand.",
|
||
"https://polartravels.net/antarctica",
|
||
),
|
||
(
|
||
"Urban Photography: Tokyo Streets",
|
||
"streetphoto.jp",
|
||
"travel",
|
||
6,
|
||
"Finding the best photogenic spots in Tokyo's neighborhoods.",
|
||
"https://streetphoto.jp/tokyo",
|
||
),
|
||
(
|
||
"Road Tripping New Zealand",
|
||
"campervanlife.nz",
|
||
"travel",
|
||
9,
|
||
"South Island in a campervan: route and practical tips.",
|
||
"https://campervanlife.nz/south-island",
|
||
),
|
||
(
|
||
"The Camino de Santiago Experience",
|
||
"pilgrim.path",
|
||
"travel",
|
||
8,
|
||
"What nobody tells you about the Camino Frances.",
|
||
"https://pilgrim.path/camino",
|
||
),
|
||
(
|
||
"Morocco's Imperial Cities",
|
||
"wanderlust.maroc",
|
||
"travel",
|
||
7,
|
||
"Fez, Marrakech, Meknes, and Rabat in one trip.",
|
||
"https://wanderlust.maroc/imperial",
|
||
),
|
||
(
|
||
"Slow Travel in Sicily",
|
||
"mediterranean.wander",
|
||
"travel",
|
||
9,
|
||
"Food, history, and beaches on a three-week Sicily circuit.",
|
||
"https://mediterranean.wander/sicily",
|
||
),
|
||
(
|
||
"Iceland in January",
|
||
"nordic.adventures",
|
||
"travel",
|
||
10,
|
||
"Northern lights, geysers, and surviving the darkness.",
|
||
"https://nordic.adventures/iceland-winter",
|
||
),
|
||
// cooking (ids 49–60)
|
||
(
|
||
"The Maillard Reaction Explained",
|
||
"scienceofeating.com",
|
||
"cooking",
|
||
6,
|
||
"Why browning makes food taste better: the chemistry.",
|
||
"https://scienceofeating.com/maillard",
|
||
),
|
||
(
|
||
"Sourdough from Scratch",
|
||
"breadbakers.club",
|
||
"cooking",
|
||
11,
|
||
"Building a starter and baking your first sourdough loaf.",
|
||
"https://breadbakers.club/sourdough",
|
||
),
|
||
(
|
||
"Japanese Knife Skills",
|
||
"culinary.tokyo",
|
||
"cooking",
|
||
8,
|
||
"Mastering the santoku and nakiri for home cooks.",
|
||
"https://culinary.tokyo/knives",
|
||
),
|
||
(
|
||
"Fermentation Fundamentals",
|
||
"cultured.foods",
|
||
"cooking",
|
||
9,
|
||
"Kimchi, miso, and kombucha: the science of fermentation.",
|
||
"https://cultured.foods/fermentation",
|
||
),
|
||
(
|
||
"French Mother Sauces",
|
||
"cordonbleu.tips",
|
||
"cooking",
|
||
7,
|
||
"The five foundations of classical French cuisine.",
|
||
"https://cordonbleu.tips/sauces",
|
||
),
|
||
(
|
||
"Cooking with Cast Iron",
|
||
"homestead.kitchen",
|
||
"cooking",
|
||
5,
|
||
"Seasoning, maintenance, and what cast iron does best.",
|
||
"https://homestead.kitchen/cast-iron",
|
||
),
|
||
(
|
||
"Ramen Broth Deep Dive",
|
||
"ramen.lab",
|
||
"cooking",
|
||
12,
|
||
"Tonkotsu, shio, shoyu, miso: building each from scratch.",
|
||
"https://ramen.lab/broths",
|
||
),
|
||
(
|
||
"Spice Blends of the World",
|
||
"spiceroute.org",
|
||
"cooking",
|
||
7,
|
||
"Za'atar, garam masala, berbere, and how to use them.",
|
||
"https://spiceroute.org/blends",
|
||
),
|
||
(
|
||
"Chocolate Tempering Technique",
|
||
"chocolatier.craft",
|
||
"cooking",
|
||
8,
|
||
"Achieving snap, shine, and bloom resistance in chocolate.",
|
||
"https://chocolatier.craft/tempering",
|
||
),
|
||
(
|
||
"Plant-Based Protein Cooking",
|
||
"vegkitchen.io",
|
||
"cooking",
|
||
6,
|
||
"Tempeh, seitan, and lentils: maximizing flavor and texture.",
|
||
"https://vegkitchen.io/protein",
|
||
),
|
||
(
|
||
"Wine Pairing Fundamentals",
|
||
"sommelier.school",
|
||
"cooking",
|
||
9,
|
||
"How acidity, tannin, and weight guide food-wine pairing.",
|
||
"https://sommelier.school/pairing",
|
||
),
|
||
(
|
||
"Knife Sharpening Guide",
|
||
"bladecraft.com",
|
||
"cooking",
|
||
5,
|
||
"Whetstones, strops, and maintaining a razor edge.",
|
||
"https://bladecraft.com/sharpening",
|
||
),
|
||
// design (ids 61–72)
|
||
(
|
||
"Typography Rules Everyone Breaks",
|
||
"typestudio.co",
|
||
"design",
|
||
7,
|
||
"The ten typography mistakes even experienced designers make.",
|
||
"https://typestudio.co/rules",
|
||
),
|
||
(
|
||
"Dieter Rams: Ten Principles",
|
||
"vitsoe.com",
|
||
"design",
|
||
8,
|
||
"The philosophy behind the world's most influential designer.",
|
||
"https://vitsoe.com/rams",
|
||
),
|
||
(
|
||
"Color Theory for UI Designers",
|
||
"smashingmagazine.com",
|
||
"design",
|
||
9,
|
||
"How to build accessible, beautiful color systems.",
|
||
"https://smashingmagazine.com/color",
|
||
),
|
||
(
|
||
"The Grid System in Print and Web",
|
||
"gridness.net",
|
||
"design",
|
||
6,
|
||
"How 12-column grids evolved from Swiss typography.",
|
||
"https://gridness.net/history",
|
||
),
|
||
(
|
||
"Icon Design Best Practices",
|
||
"icons8.com",
|
||
"design",
|
||
5,
|
||
"Clarity, consistency, and the right level of detail.",
|
||
"https://icons8.com/design-guide",
|
||
),
|
||
(
|
||
"Motion Design Principles",
|
||
"motion.design",
|
||
"design",
|
||
8,
|
||
"Timing, easing, and purposeful animation in UI.",
|
||
"https://motion.design/principles",
|
||
),
|
||
(
|
||
"Design Systems at Scale",
|
||
"figma.design",
|
||
"design",
|
||
10,
|
||
"How Figma, Shopify, and IBM manage design systems.",
|
||
"https://figma.design/systems",
|
||
),
|
||
(
|
||
"The Psychology of Negative Space",
|
||
"whitespace.studio",
|
||
"design",
|
||
6,
|
||
"Why what you leave out matters more than what you include.",
|
||
"https://whitespace.studio/negative",
|
||
),
|
||
(
|
||
"Brutalist Web Design Revival",
|
||
"brutalist.web",
|
||
"design",
|
||
7,
|
||
"Raw HTML aesthetics and their place in modern web design.",
|
||
"https://brutalist.web/revival",
|
||
),
|
||
(
|
||
"Human Factors in Interface Design",
|
||
"nngroup.com",
|
||
"design",
|
||
11,
|
||
"Applying cognitive science to create usable interfaces.",
|
||
"https://nngroup.com/human-factors",
|
||
),
|
||
(
|
||
"Hand-Lettering for Beginners",
|
||
"letteringco.com",
|
||
"design",
|
||
6,
|
||
"Tools, techniques, and practice drills to start lettering.",
|
||
"https://letteringco.com/beginners",
|
||
),
|
||
(
|
||
"Accessible Design Checklist",
|
||
"a11y.project",
|
||
"design",
|
||
8,
|
||
"WCAG 2.2 requirements translated into actionable steps.",
|
||
"https://a11y.project/checklist",
|
||
),
|
||
// history (ids 73–84)
|
||
(
|
||
"The Fall of Constantinople",
|
||
"byzantine.history",
|
||
"history",
|
||
10,
|
||
"1453 and the end of the Eastern Roman Empire.",
|
||
"https://byzantine.history/1453",
|
||
),
|
||
(
|
||
"How the Printing Press Changed Europe",
|
||
"gutenberg.archive",
|
||
"history",
|
||
8,
|
||
"From scarcity to information explosion in 50 years.",
|
||
"https://gutenberg.archive/press",
|
||
),
|
||
(
|
||
"Silk Road Trade Networks",
|
||
"ancientroads.org",
|
||
"history",
|
||
9,
|
||
"How goods, ideas, and disease traveled between civilizations.",
|
||
"https://ancientroads.org/silk-road",
|
||
),
|
||
(
|
||
"The Irish Famine: Causes and Response",
|
||
"ireland.history",
|
||
"history",
|
||
11,
|
||
"Examining the political economy of the Great Hunger.",
|
||
"https://ireland.history/famine",
|
||
),
|
||
(
|
||
"Genghis Khan's Administrative Genius",
|
||
"mongolia.chronicle",
|
||
"history",
|
||
9,
|
||
"How the Mongol Empire managed the largest land empire.",
|
||
"https://mongolia.chronicle/admin",
|
||
),
|
||
(
|
||
"The Haitian Revolution",
|
||
"caribbean.history",
|
||
"history",
|
||
10,
|
||
"The only successful slave revolt in history and its legacy.",
|
||
"https://caribbean.history/haiti",
|
||
),
|
||
(
|
||
"Victorian-Era Technological Anxiety",
|
||
"modernism.review",
|
||
"history",
|
||
7,
|
||
"How the 19th century responded to rapid industrialization.",
|
||
"https://modernism.review/victorian",
|
||
),
|
||
(
|
||
"The Origins of Money",
|
||
"economic.anthropology",
|
||
"history",
|
||
8,
|
||
"From barter myths to commodity money to fiat currency.",
|
||
"https://economic.anthropology/money",
|
||
),
|
||
(
|
||
"Medieval Islamic Science",
|
||
"scholar.islam",
|
||
"history",
|
||
9,
|
||
"How the House of Wisdom preserved and advanced knowledge.",
|
||
"https://scholar.islam/golden-age",
|
||
),
|
||
(
|
||
"World War I: The July Crisis",
|
||
"ww1.centenary",
|
||
"history",
|
||
12,
|
||
"The 37 days that turned assassination into world war.",
|
||
"https://ww1.centenary/july",
|
||
),
|
||
(
|
||
"The Scramble for Africa",
|
||
"colonial.history",
|
||
"history",
|
||
10,
|
||
"The Berlin Conference and partition of a continent.",
|
||
"https://colonial.history/africa",
|
||
),
|
||
(
|
||
"Ancient Roman Supply Chains",
|
||
"logistics.antiquity",
|
||
"history",
|
||
7,
|
||
"How Rome fed a million-person city before refrigeration.",
|
||
"https://logistics.antiquity/rome",
|
||
),
|
||
// health (ids 85–100, 16 items)
|
||
(
|
||
"Zone 2 Cardio Explained",
|
||
"endurance.science",
|
||
"health",
|
||
7,
|
||
"Why low-intensity aerobic work is the foundation of fitness.",
|
||
"https://endurance.science/zone2",
|
||
),
|
||
(
|
||
"Sleep Hygiene That Actually Works",
|
||
"sleepdoctor.com",
|
||
"health",
|
||
6,
|
||
"Evidence-based habits for better sleep quality.",
|
||
"https://sleepdoctor.com/hygiene",
|
||
),
|
||
(
|
||
"Resistance Training for Longevity",
|
||
"muscleandlife.com",
|
||
"health",
|
||
9,
|
||
"How strength training slows aging at the cellular level.",
|
||
"https://muscleandlife.com/longevity",
|
||
),
|
||
(
|
||
"The Science of Intermittent Fasting",
|
||
"metabolic.health",
|
||
"health",
|
||
8,
|
||
"What IF actually does — and doesn't do — to your body.",
|
||
"https://metabolic.health/if",
|
||
),
|
||
(
|
||
"Managing Chronic Inflammation",
|
||
"inflammation.md",
|
||
"health",
|
||
10,
|
||
"Diet, sleep, and stress interventions for inflammation.",
|
||
"https://inflammation.md/chronic",
|
||
),
|
||
(
|
||
"Cold Exposure Benefits and Risks",
|
||
"wim.hof.institute",
|
||
"health",
|
||
7,
|
||
"What the evidence says about cold showers and ice baths.",
|
||
"https://wim.hof.institute/cold",
|
||
),
|
||
(
|
||
"VO2 Max: Your Longevity Metric",
|
||
"peter.attia.md",
|
||
"health",
|
||
9,
|
||
"Why VO2 max predicts lifespan better than most biomarkers.",
|
||
"https://peter.attia.md/vo2max",
|
||
),
|
||
(
|
||
"Gut Health and the Microbiome",
|
||
"fermented.health",
|
||
"health",
|
||
8,
|
||
"Practical steps to improve microbiome diversity.",
|
||
"https://fermented.health/microbiome",
|
||
),
|
||
(
|
||
"Breathing and Autonomic Regulation",
|
||
"breathwork.lab",
|
||
"health",
|
||
6,
|
||
"Box breathing, physiological sighs, and HRV training.",
|
||
"https://breathwork.lab/autonomic",
|
||
),
|
||
(
|
||
"Blue Light and Circadian Disruption",
|
||
"chronobiology.net",
|
||
"health",
|
||
7,
|
||
"How screens affect melatonin and what to do about it.",
|
||
"https://chronobiology.net/blue-light",
|
||
),
|
||
(
|
||
"Sauna Use and Cardiovascular Health",
|
||
"nordic.health.research",
|
||
"health",
|
||
8,
|
||
"Finnish studies on sauna frequency and heart disease risk.",
|
||
"https://nordic.health.research/sauna",
|
||
),
|
||
(
|
||
"Mindfulness-Based Stress Reduction",
|
||
"mbsr.clinic",
|
||
"health",
|
||
10,
|
||
"Eight-week MBSR protocol outcomes and how to practice.",
|
||
"https://mbsr.clinic/protocol",
|
||
),
|
||
(
|
||
"Vitamin D and Immune Function",
|
||
"vitamind.council",
|
||
"health",
|
||
5,
|
||
"Deficiency, supplementation, and what the research shows.",
|
||
"https://vitamind.council/immune",
|
||
),
|
||
(
|
||
"Running Economy and Cadence",
|
||
"running.science",
|
||
"health",
|
||
7,
|
||
"How stride rate affects efficiency and injury risk.",
|
||
"https://running.science/cadence",
|
||
),
|
||
(
|
||
"Cognitive Training and Brain Plasticity",
|
||
"neuro.performance",
|
||
"health",
|
||
9,
|
||
"What actually improves cognitive function with aging.",
|
||
"https://neuro.performance/plasticity",
|
||
),
|
||
(
|
||
"Postural Health in the Desk Era",
|
||
"ergonomics.pro",
|
||
"health",
|
||
6,
|
||
"Evidence-based fixes for tech neck and lower back pain.",
|
||
"https://ergonomics.pro/posture",
|
||
),
|
||
];
|
||
|
||
raw.iter()
|
||
.enumerate()
|
||
.map(
|
||
|(i, &(title, source, category, reading_time, description, url))| SeedItem {
|
||
id: (i + 1) as u64,
|
||
title: title.to_owned(),
|
||
source: source.to_owned(),
|
||
category: category.to_owned(),
|
||
reading_time_min: reading_time,
|
||
description: description.to_owned(),
|
||
url: url.to_owned(),
|
||
},
|
||
)
|
||
.collect()
|
||
}
|
||
|
||
/// Write seed users into the database.
|
||
///
|
||
/// - User 1: cold (no signals)
|
||
/// - User 2: explorer (~10 signals across jazz/science/travel)
|
||
/// - User 3: convergent (~50 signals in technology + jazz)
|
||
pub fn seed_users(db: &TidalDb) -> tidaldb::Result<()> {
|
||
let empty: HashMap<String, String> = HashMap::new();
|
||
|
||
// User 1: cold start
|
||
db.write_user(EntityId::new(1), &empty)?;
|
||
|
||
// User 2: explorer — scattered signals across jazz, science, travel.
|
||
// "share" is a positive engagement signal that updates the preference vector.
|
||
db.write_user(EntityId::new(2), &empty)?;
|
||
let t = Timestamp::now();
|
||
for item_id in [25u64, 13, 37, 26, 14, 38, 27, 15, 39, 28] {
|
||
db.signal_with_context("view", EntityId::new(item_id), 1.0, t, Some(2), None)?;
|
||
}
|
||
// Share top picks from each explored category → seeds preference vector.
|
||
for item_id in [25u64, 13, 37] {
|
||
db.signal_with_context("share", EntityId::new(item_id), 1.0, t, Some(2), None)?;
|
||
}
|
||
|
||
// User 3: convergent — heavy on technology and jazz.
|
||
// Share a selection of tech+jazz to seed the preference vector.
|
||
db.write_user(EntityId::new(3), &empty)?;
|
||
for item_id in 1..=12u64 {
|
||
for _ in 0..3 {
|
||
db.signal_with_context("view", EntityId::new(item_id), 1.0, t, Some(3), None)?;
|
||
}
|
||
db.signal_with_context("save", EntityId::new(item_id), 1.0, t, Some(3), None)?;
|
||
db.signal_with_context("share", EntityId::new(item_id), 1.0, t, Some(3), None)?;
|
||
}
|
||
for item_id in 25..=36u64 {
|
||
for _ in 0..2 {
|
||
db.signal_with_context("view", EntityId::new(item_id), 1.0, t, Some(3), None)?;
|
||
}
|
||
db.signal_with_context("share", EntityId::new(item_id), 1.0, t, Some(3), None)?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|