Storylines: the same site told several ways, one per visitor, counted
docs / deploy (push) Successful in 3s
Test / test (push) Successful in 1m1s

Any text a person reads may be a list, one entry per storyline, every
list the same length. A visitor is given one storyline for the whole
site and reads it on every page and in every mail about their case.
Records and events carry the storyline; GET /report gives counts per
bucket, storyline and state, and nothing else.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-30 15:11:27 +02:00
co-authored by Claude Fable 5.1
parent cc3107e502
commit f395ace556
24 changed files with 561 additions and 45 deletions
+23
View File
@@ -13,12 +13,16 @@ use serde::{Deserialize, Serialize};
// Loading is server-only; the rest is shared with the browser build.
#[cfg(feature = "ssr")]
mod gitea;
#[cfg(feature = "ssr")]
mod variants;
mod handlers;
mod markdown;
mod validate;
#[cfg(feature = "ssr")]
pub use gitea::*;
#[cfg(feature = "ssr")]
pub use variants::*;
pub use handlers::*;
pub use markdown::*;
pub use validate::*;
@@ -1073,6 +1077,25 @@ pub fn resolve_question(
#[cfg(feature = "ssr")]
pub fn build_questions(
files: &[(String, String)],
) -> anyhow::Result<std::collections::HashMap<String, Question>> {
// The first storyline, once every list of texts has been held to
// the site's arity (see `variants.rs`); the machinery reads this
// one, and `build_storylines` builds the rest for the visitors.
variants::arity(files)?;
build_one_storyline(&variants::storyline(files, 0))
}
/// Every storyline of the content, each a full map of questions.
#[cfg(feature = "ssr")]
pub fn build_storylines(files: &[(String, String)]) -> anyhow::Result<variants::Storylines<std::collections::HashMap<String, Question>>> {
let arity = variants::arity(files)?;
let each = (0..arity).map(|n| build_one_storyline(&variants::storyline(files, n))).collect::<anyhow::Result<Vec<_>>>()?;
Ok(variants::Storylines { each })
}
#[cfg(feature = "ssr")]
fn build_one_storyline(
files: &[(String, String)],
) -> anyhow::Result<std::collections::HashMap<String, Question>> {
// Sections first: (directory prefix, config), shallowest first so a
// later (deeper) section overrides an outer one field-by-field.