Skip to content

Add build-story: deterministic reader-facing story page from the published chain - #25

Merged
annefou merged 6 commits into
mainfrom
feat/story-page-generator
Jul 26, 2026
Merged

Add build-story: deterministic reader-facing story page from the published chain#25
annefou merged 6 commits into
mainfrom
feat/story-page-generator

Conversation

@annefou

@annefou annefou commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

What

A new deterministic step that turns a published FORRT chain — or a research synthesis of several chains — into a self-contained HTML article you can send a colleague to read, with every value taken verbatim from the signed nanopublications. It is the reader-facing companion to build-chain-draft, and like it runs off Claude's tokens.

export SCIENCELIVE_API_KEY=...
pixi run build-story          # apex from nanopubs/PUBLISHED.md -> blog/index.html

How it works

  • Reads the chain apex from nanopubs/PUBLISHED.md — the Research Synthesis (step 08) if published, else the Replication Outcome (step 05) — fetches the constellation, and renders blog/index.html.
  • Shape auto-detected: a single replication chain → one story; a research synthesis → a replication-forward synthesis page (what-is-being-replicated card, bottom-line callout, one full-width section per limb, References & citations grouped per limb).
  • Nothing invented: the page aggregates exactly what the platform's View* components show (same field sets, labels, citation rule), restyled into an article; absent fields are omitted, never filled in.
  • Self-contained output: the display font is embedded and the headline figure is downscaled + base64-inlined (Pillow), so it renders identically offline, in a Zenodo archive, or on GitHub Pages.
  • Chips (verdict, confidence, CiTO relation) link to the nanopub that asserts each value; ORCID byline; prominent, collapsible "Cite this" using the permanent w3id URI.

Files

  • scripts/build_story.py — the generator (handles single chain + synthesis)
  • scripts/story_assets/base.css — the stylesheet, carrying the Science Live palette (never edited per project)
  • tests/test_build_story.py — offline unit tests for the pure helpers (prose/label/apex logic); importing the module needs no API key
  • docs/story-page.md — usage + where to publish (GitHub Pages + Zenodo; the platform /np/story route is the canonical hosted mirror)
  • pixi.tomlpillow dependency (already resolved via matplotlib) + build-story task; CLAUDE.md doc-map row + Phase 5 note

Testing

  • pixi run -e tests test120 passed (13 new).
  • Live-built against two real chains (a research synthesis and a single replication) via the dev constellation; both render self-contained HTML.

Notes for review

  • The endpoint defaults to production; SCIENCELIVE_API overrides it (dev testing).
  • The generated blog/ is committed by the researcher after running the task (not produced in this template PR).

annefou added 6 commits July 25, 2026 20:25
…ished chain

scripts/build_story.py turns a published FORRT chain — or a research synthesis of
several chains — into a self-contained HTML article, every value read verbatim from
the signed nanopublications (nothing invented). It is the reader-facing companion to
build-chain-draft, and like it runs off Claude's tokens.

- pixi run build-story reads the chain apex from nanopubs/PUBLISHED.md (the Research
  Synthesis if published, else the Replication Outcome), fetches the constellation,
  and writes blog/index.html. Single-chain vs synthesis is auto-detected.
- Both shapes carry the Science Live palette, an ORCID byline, a prominent citation,
  chips that link to the nanopub asserting each value, and a References & citations
  block. Self-contained output: display font embedded, headline figure downscaled and
  base64-inlined (Pillow), so it renders offline / in a Zenodo archive / on Pages.
- scripts/story_assets/base.css holds the stylesheet (never edited per project).
- Offline unit tests for the pure helpers; docs/story-page.md documents usage and
  where to publish (GitHub Pages + Zenodo; the platform /np/story route is the
  canonical hosted mirror).
… button

- jupyter-book.yml builds the story page as part of the Pages deploy and serves it
  at /blog/ on the same site as the book (best-effort: skipped when the chain is not
  published or SCIENCELIVE_API_KEY is unset, so it never fails the book deploy).
  Re-running the workflow is how you regenerate the blog from the current network.
- A static page cannot securely trigger CI, so the toolbar now links to the live
  version on the Science Live platform ('View on Science Live') instead of a disabled
  'Sign in to regenerate' button.
- Endpoint env reads via 'or' so an empty GitHub Actions vars.SCIENCELIVE_API falls
  back to production rather than becoming an empty string.
…CELIVE_PLATFORM)

Defaults to production; a dev-network replication sets SCIENCELIVE_PLATFORM to its
dev platform host so the link resolves to the right place.
An opt-in layer on top of the deterministic Record tab. If nanopubs/audience.json
exists, the page gains one tab per audience — each banner-labelled AI-generated,
with a recommended reading level, an accessible overview image, and an 'at a glance'
infographic whose colours and ✓/✗ are taken from the signed verdicts (only the lay
labels come from the AI, so the graphic is accurate by construction). No file → the
page is the single Record tab, unchanged.

- audience.json is produced ONCE at build time by the new .claude/agents/audience-writer
  agent (a constrained plain-language rewrite of the record's own text); baked into the
  static HTML, so the reader spends no tokens and nothing AI-written touches the Record.
- Tab icons are inlined Font Awesome 6 (CC BY 4.0) — the Science Live icon family —
  kept self-contained (no CDN). The technical result plots stay Record-only; lay tabs
  reuse only the accessible overview figure.
- nanopubs/audience.json.example documents the shape; docs/story-page.md documents the
  flow; offline tests cover the glance, tab bar, icons and audience loading.
… rebuild it)

Serve whatever blog/index.html exists — freshly built, or a committed snapshot — so
the page shows even when CI cannot rebuild it; no blog/ at all deploys the book alone.
The 'aggregated from the platform's per-nanopublication displays · nothing
invented' banner was a leftover from the mockup (class=mockbar). Its message
is already carried, in a reader-optional place, by the 'How this page is made'
popup — so the always-on uppercase strip was redundant and competed with the
headline for the top of the page. Removed from both render paths.
@annefou
annefou merged commit 6bd3816 into main Jul 26, 2026
3 checks passed
@annefou
annefou deleted the feat/story-page-generator branch July 26, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant