first pass at the newspaper builder
Test / test (push) Has been cancelled

This commit is contained in:
2026-09-14 11:57:22 +10:00
commit bec1eaac87
497 changed files with 178953 additions and 0 deletions
@@ -0,0 +1,20 @@
<!-- INVARIANT: examples are single-line HTML comments so a fresh template parses to total=0 (MEMORY_EMPTY). Do NOT un-comment or split across lines. t100 guards this. -->
> This file is kept up to date automatically while the stage runs. Add observations at the review step, not by editing here directly.
## Interpretations
<!-- example: 2026-05-29T10:14:32Z — chose REST over GraphQL; the consuming team only needs CRUD, revisit if subscriptions land -->
## Deviations
<!-- example: 2026-05-29T10:14:32Z — skipped the optional caching layer the stage prose suggested; the dataset is small enough that it adds risk -->
## Tradeoffs
<!-- example: 2026-05-29T10:14:32Z — picked TDD over BDD this run; the team is unit-first and the domain is well-understood -->
## Open questions
<!-- example: 2026-05-29T10:14:32Z — confirm the retention window with compliance before the next stage hardens the schema -->
2026-09-13T11:31:00Z — Interpretation — Multi-page (FR1) is a must-have; scope expanded by Q3 to crosswords, comics, and an xkcd-style front-page cartoon tied to the occasion
2026-09-13T11:31:00Z — Interpretation — AI route is local Ollama, model granted deepseek-v4-flash:cloud; AI draft is optional (FR8) and must never send content to a cloud service
2026-09-13T11:31:00Z — Tradeoff — Photo auto-balancing (Q4=b) gives a natural newspaper flow but adds layout complexity; kept as FR6.2 with text-safe fallback
2026-09-13T11:34:00Z — Interpretation — User resolved OQ1-OQ4 during the learnings turn: crosswords built from user content; genuine xkcd (searched on the real site) as the front-page cartoon; dynamic masthead metadata; whole-first-pass AI then per-article human review
2026-09-13T11:34:00Z — Tradeoff — OQ1 wants a genuine xkcd fetched at generation time, which is a network read at authoring time; reconciled with the local-only/zero-network constraints by embedding the fetched cartoon as a local asset so the delivered page stays self-contained and offline-capable
2026-09-13T11:34:00Z — Deviation — requirements.md edited after the advisory review receipt (relaxed change control: CHANGE_ACCEPTED, no recovery review needed)
@@ -0,0 +1,102 @@
# Requirements Analysis — Questions
> Fill in each `[Answer]:` tag. Options A-E plus X (Other). The file is the
> authoritative record of your requirements decisions.
## Q1: Edition length
Should the generator produce a single self-contained page, or support multi-page newspapers that flow across printed A4 sheets?
A) Single page — the whole newspaper is one page, printed on one A4 sheet
B) Multi-page — content flows across multiple A4 sheets with automatic page breaks (recommended for a real newspaper feel)
C) Single long scrolling page that the browser splits across sheets when printing
X) Other (please specify)
[Answer]: B its a must have I want this to work across pages
## Q2: Masthead & issue identity
Does the newspaper need a classic newspaper masthead (title banner, date/issue line, volume)?
A) Yes — a title banner plus a date / issue / "Volume X" line (recommended)
B) Title banner only, no date/issue metadata
C) No masthead — just the article layout
X) Other (please specify)
[Answer]: A
## Q3: Article types / sections
Which content types should the layout support? (choose all that apply)
A) Lead/front-page story
B) Interior news articles with headings + bylines
C) Pull quotes / sidebars / fact boxes
D) A "schedule" or "events" block (e.g. ceremony / reception timetable)
E) A lighter section (messages/letters, well-wishes, memory corner)
X) Other (please specify)
[Answer]: A, B, C, D, E, and X - i want crosswords and comics as well please, I'd love a little xkcd that somehow relates to the main page (you'll have to pull this obvoiusly with context)
## Q4: Photos and images
Should articles support embedded photos/images, or is the newspaper text-focused?
A) Photos supported — images placed per article with captions (recommended)
B) Photos supported, layout auto-balances them into columns
C) Text only — no image support needed for now
X) Other (please specify)
[Answer]: B
## Q5: Visual theme
What visual style should the newspaper have? (This drives the print CSS.)
A) Classic broadsheet: black ink on white/cream, serif headlines and body, column rules (recommended)
B) Cream/off-white paper tint with ink text — a warmer, vintage wedding feel
C) A color-accented modern tabloid (one accent color for section headers)
X) Other (please specify)
[Answer]: A
## Q6: Auto-generated copy
The generator may optionally call AI to draft the newspaper copy before rendering. Which AI route should we use, given the project must stay fully local with no external services?
A) Local AI via Ollama (runs on the LAN, never leaves the machine) — recommended
B) No AI generation — the script only renders copy I provide
C) An external AI API (cloud LLM) — requires a key and sends content off-machine
X) Other (please specify)
[Answer]: A ollama is on this laptop and ready to go. You are free to use deepseek-v4-flash:cloud
## Q7: Print fidelity
Any fixed target for the printed output (page count, margins, print quality)?
A) Fluid — content auto-flows across as many A4 pages as it needs, with sensible margins and clean page breaks (recommended)
B) Fixed target — fit within a set page count (e.g. exactly 2 A4 pages) regardless of content
C) Tune margins/typography for maximum A4 ink-jet crispness
X) Other (please specify)
[Answer]: Fluid
## Consolidated Summary Confirmation
> Summary of your seven requirements answers before the requirements document is generated:
>
> - Edition length: **multi-page** — content flows across multiple A4 sheets with automatic page breaks (must-have)
> - Masthead: **yes** — title banner plus date / issue / "Volume X" line
> - Article types (all selected): lead story, interior articles with bylines, pull quotes/sidebars/fact boxes, schedule/events block, lighter messages/well-wishes corner — plus **crosswords and comics**, and an **xkcd-style front-page cartoon** relating to the day
> - Photos: **auto-balanced into columns** per article
> - Visual theme: **classic broadsheet** — black ink on white/cream, serif headlines and body, column rules
> - AI route: **local Ollama** (granted `deepseek-v4-flash:cloud` for copy generation)
> - Print fidelity: **fluid** — flows across as many A4 pages as needed, sensible margins, clean page breaks
Does this all look correct before I generate the requirements artifact?
- Looks correct
- Request changes
[Answer]: Looks correct
@@ -0,0 +1,197 @@
# Requirements — Wedding Newspaper Generator
## Intent Analysis
The user is building a wedding-newspaper generator: a tool to take authored
content — the stories, schedules, messages, and inside jokes of a wedding — and
render them as a genuine-feeling newspaper. The deep goal is not just "generate
HTML" but to produce a keepsake that reads, on real paper, like a newspaper
published the day of the wedding: classic broadsheet look, a proper masthead,
crosswords and comics, and a front-page cartoon that ties the occasion together.
The product must be fully local: the generator runs on the couple's laptop,
content is private, and nothing is published beyond the machine. The output is
a self-contained HTML page opened directly (`file://`) and printed to A4 from
the browser's own print dialog. Because a printed multi-page newspaper is the
central deliverable, layout fidelity on paper — clean automatic page breaks,
content flowing across sheets — is a first-class, non-negotiable requirement.
## Functional Requirements
### FR1 — Multi-page newspaper output (MUST)
The generator SHALL produce a newspaper that flows across multiple A4 sheets
with automatic page breaks when content exceeds one page; it MUST NOT be
limited to a single page.
- FR1.1 — When the total content exceeds one A4 sheet, the output MUST
continue onto subsequent sheets with a clean break between pages.
- FR1.2 — Page breaks MUST occur at section or article boundaries where
possible (never splitting a single article's body awkwardly mid-paragraph
unless unavoidable).
- FR1.3 — Each printed page MUST be self-consistent: page numbers, running
headers/footers, and masthead continuation render correctly across sheets.
### FR2 — Classic newspaper masthead (MUST)
- FR2.1 — The front page SHALL render a title (masthead) banner.
- FR2.2 — The masthead SHALL include a date line, an issue number, and a
"Volume X" line.
- FR2.3 — The masthead SHALL be styled in the classic broadsheet manner
(large serif title, rule lines above and below).
### FR3 — Article types (MUST)
The layout SHALL support all of the following content types, mapped from
markdown into newspaper sections:
- FR3.1 — Lead / front-page story (a large featured article on page one).
- FR3.2 — Interior news articles with headings and bylines.
- FR3.3 — Pull quotes, sidebars, and fact boxes (standalone callout styling,
not just body paragraphs).
- FR3.4 — A "schedule" or "events" block (e.g. ceremony / reception
timetable), rendered as a clearly formatted table.
- FR3.5 — A lighter section (messages / letters / well-wishes / memory
corner) distinct in visual weight from hard news.
### FR4 — Crosswords and comics ("the funnies") (MUST)
- FR4.1 — The generator SHALL build crossword puzzles **from content the user
provides** (grid + across/down clues derived from user-supplied words/theme
words and clues), not from a fixed built-in set.
- FR4.2 — The generator SHALL support comic-strip blocks (one or more panels
with art + dialogue), including beyond a single cartoon.
- FR4.3 — Crossword and comic blocks MUST remain printable and legible on A4.
- FR4.4 — The "fun" section is first-class: it may include other word puzzles
(e.g. word search / "find-a-word") and other comics (e.g. Dilbert, Garfield,
or a tasteful equivalent) so long as they are funny and print cleanly.
### FR5 — Front-page cartoon tied to the occasion (MUST)
- FR5.1 — The front page SHALL render an xkcd-style or genuine single-panel
cartoon that relates to the wedding / the couple / the day.
- FR5.2 — The cartoon SHALL be generated with awareness of context: the
couple, the occasion and the day's details inform its subject, so it feels
like it belongs rather than a generic cartoon.
- FR5.3 — The cartoon SHALL be rendered entirely on-machine (see NFR3
Local-only and NFR4 Zero-network); the final printed page never depends on a
remote resource.
- FR5.4 — A genuine xkcd cartoon MAY be sourced from the real xkcd site
(searched for one related to the occasion) as a generation-time input; if
one is fetched, it SHALL be embedded locally so the delivered page remains
self-contained and print-capable offline.
### FR6 — Photos and images (MUST)
- FR6.1 — Articles SHALL support embedded photos/images placed per article.
- FR6.2 — The layout SHALL auto-balance images into the column structure so
they flow naturally with text.
- FR6.3 — Images SHALL support optional captions and byline/credit lines.
### FR7 — Content ingestion (MUST)
- FR7.1 — Content is authored as Markdown (and/or plain text) files and
read by the generator.
- FR7.2 — The generator SHALL produce a single self-contained `newspaper.html` —
the printed artifact — from the ingested content.
- FR7.3 — The generated page SHALL provide a live-load path (native file
picker / drag-and-drop) so alternate content can be swapped in and rendered
without regenerating (matches affirmed practice: user-granted reads only).
- FR7.4 — Photos are optional inputs: when photos are supplied, the layout
SHALL embed them (per FR6); when none are supplied, the layout SHALL generate
cleanly without photographs (never fabricate placeholder images).
- FR7.5 — Newspaper metadata (masthead title, couple names, date, issue
number, volume) is dynamic and SHALL be supplied at generation time rather
than hard-coded, so a new issue can be produced without editing the code.
### FR8 — Optional AI draft support (SHOULD)
- FR8.1 — The generator MAY call a local AI to draft newspaper copy (lead
story, filler articles, pull quotes) before the final render.
- FR8.2 — AI-drafted copy MUST be authored into content exactly as if
hand-written, then flow through the same layout pipeline.
- FR8.3 — The AI route MUST be local Ollama only; the granted model is
`deepseek-v4-flash:cloud`. No content SHALL be sent to an external/cloud
service.
- FR8.4 — AI generation SHALL run the whole first-pass newspaper, then STOP
for per-article human review: the user SHALL be able to approve, request
edits, or replace any single article's copy before the final render. This
review is per-article; approved articles stay unchanged while others are
revised and re-rendered.
## Non-Functional Requirements
- NFR1 (Printability) — The page MUST print cleanly to A4 from the browser's
own print dialog, with no clipping and correct margins. (MUST)
- NFR2 (Layout integrity) — Print CSS MUST keep every section, article,
image, and puzzle inside the sheet with no overflow, orphaned columns, or
broken page breaks. (MUST)
- NFR3 (Local-only) — Everything must run purely from the local filesystem;
the page MUST never be served or deployed beyond localhost. (MUST)
- NFR4 (Zero network) — The page SHALL make zero network requests (no CDN
fonts, no remote `<script>`/`<style>`/assets), so it is fully functional
offline from `file://`. Fonts, images, and any asset ship with the page.
(MUST)
- NFR5 (Content read policy) — Content SHALL be read only through
user-granted means (native file picker / drag-and-drop); the page SHALL NOT
rely on `fetch()` of sibling local files (opaque-origin CORS blocks it in
stock browsers). (MUST)
- NFR6 (Pure, dependency-free render) — The output SHALL be pure HTML5 + CSS
+ vanilla JS with no build step and no external dependencies. (MUST)
- NFR7 (Fidelity to markdown) — The markdown→HTML transform SHALL preserve
content exactly (no mangled quotes, em-dashes, escaping, or dropped
sections). (MUST)
- NFR8 (Classic aesthetic) — The visual theme SHALL be classic broadsheet:
black ink on white/cream, serif headlines and body, and column rules.
(SHOULD, from Q5=a)
- NFR9 (AI isolation) — Any AI generation SHALL be an optional, opt-in step
that never runs when not requested, and SHALL keep all content local
(Ollama). (MUST)
## Constraints
- C1 — The project runs on the wedding couple's local machine, never published.
- C2 — Node.js is available but the Python (3.14) + `uv` runtime is the
affirmed primary path; the generator is a Python static generator.
- C3 — Output must be a self-contained static HTML file; no server process is
required or desired at print time.
- C4 — Only local Ollama is permitted for AI; no external/cloud LLM API.
- C5 — A4 is the fixed print format.
## Assumptions
- A1 — The couple prefers print realism (classic broadsheet) over modern web
styling for the printed keepsake.
- A2 — "Fluid" pagination (flow onto as many A4 pages as needed) is preferred
over forcing a fixed page count (Q7=a).
- A3 — Photos will be supplied as local image files referenced from content;
the generator embeds them (self-contained output).
- A4 — The xkcd-style cartoon is generated by the local AI with contextual
awareness of the couple and day, then rendered as an SVG/embedded image.
- A5 — Crosswords are authored as structured puzzle data (grid + clues)
provided in content, then laid out by the generator.
- A6 — A default visual identity (title, accent) can be supplied by the user
but is not required for the generator to produce a valid first output.
## Out of Scope
- OS1 — Deploying or hosting the newspaper anywhere (web, static host,
printer service).
- OS2 — Sending any content or generation to an external/cloud AI service.
- OS3 — Dynamic server-side rendering or a persistent runtime service.
- OS4 — A full WYSIWYG editor UI (content stays in markdown/text files).
- OS5 — Non-A4 print formats (US Letter, tabloid) in this iteration.
## Open Questions
- OQ1 (RESOLVED) — Crosswords and other "fun" puzzles are **built from user-provided
content**; the fun section may include other comics that are funny, and the
xkcd-style cartoon should be a genuine xkcd searched on the real site when
possible.
- OQ2 (RESOLVED) — Photos are handled when supplied; if none are supplied,
no photos are generated or fabricated.
- OQ3 (RESOLVED) — Newspaper masthead metadata (title, names, date, issue,
volume) is dynamic and brought in at generation time.
- OQ4 (RESOLVED) — AI generation runs the whole first-pass newspaper, then
provides a per-article human review mechanism (approve / request edits /
replace any single article) before the final render.