Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,37 @@ cargo clippy --all-targets -- -D warnings || exit 1
3. Если Π΄Π° β€” **ΠžΠ‘Π’ΠΠΠžΠ’Π˜Π‘Π¬** ΠΈ ΠΎΡ‚ΠΊΡ€ΠΎΠΉ обсуТдСниС Π² issue.

Если пропустил этот шаг β€” PR Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΊΡ€Ρ‹Ρ‚ автоматичСски.

---

## TRIOS_PHD β€” PDF rendering rules

The TRIOS PhD monograph PDF pipeline has its own canonical contract.
Every agent touching the renderer, templates, hero images, or chapter
sources MUST read and follow:

- **[docs/pdf-rendering.md](docs/pdf-rendering.md)** β€” canonical pipeline.

Headline rules (full detail in the doc above):

- `TRIOS_PHD_CANONICAL_PIPELINE` β€” Rust TRIOS MCP / `trios-phd` β†’
Railway/Postgres SSOT β†’ Markdown β†’ pandoc β†’ LaTeX β†’ tectonic β†’ PDF.
PDF is an export target, never a source of truth.
- `TRIOS_PHD_RENDERER_FIRST` β€” placement / typography / image changes
go in `templates/chapter.template.tex`, `docs/phd/main.tex`, or
`filters/force-fullwidth-hero.lua`. Never patch individual chapters
for visual concerns and never post-process the PDF.
- `TRIOS_PHD_STYLE_LOCK` β€” white academic title page, serif typography,
large engraved / ornamental S3AI hero panels, book margins, large
images. QA baseline: 150 A4 pages, qpdf clean, 0 duplicate long
paragraphs, 0 duplicate numbered headings, 0 Cyrillic hits, 0
secret / stale / math anomalies, 0 very-short non-empty pages,
at most 1 image-heavy / low-context page (the title page).
- `TRIOS_PHD_NO_IMAGE_TRAIN` β€” hero panels are anchored to the
nearest substantive heading and body, never grouped as a gallery /
image train. Enforced by `\Needspace*{0.58\textheight}` before every
`\section` and `\chapter` (soft keep-together), defined in
`docs/phd/main.tex` and `templates/chapter.template.tex`.
- Hard `\clearpage` before sections / hero figures is **forbidden**:
it produced short title-only pages and was rejected by QA. Tune the
`\Needspace*` reservation size instead.
231 changes: 231 additions & 0 deletions docs/pdf-rendering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# TRIOS PhD PDF Rendering β€” Canonical Rules

This document is the source of truth for how the TRIOS PhD monograph is
rendered to PDF. Every agent and developer touching the renderer, the
templates, or the chapter sources MUST follow these rules.

It is repo-canonical and overrides ad-hoc renderer scripts.

---

## TRIOS_PHD_CANONICAL_PIPELINE

The only supported PDF pipeline is:

```
Rust TRIOS MCP / trios-phd
β”‚
β–Ό
Railway / Postgres (ssot.chapters) ← single source of truth (SSOT)
β”‚
β–Ό
Markdown (body_md + leading hero image)
β”‚
β–Ό pandoc + Lua filter (filters/force-fullwidth-hero.lua)
β”‚ + template (templates/chapter.template.tex
β”‚ or docs/phd/main.tex for the full book)
β–Ό
LaTeX (.tex)
β”‚
β–Ό tectonic
β–Ό
PDF (print/export target β€” NOT a source of truth)
```

Reference entry points:

- Per-chapter compile: `crates/trios-phd` β†’ `trios-phd compile-chapters`
(`crates/trios-phd/src/main.rs`, around the `CompileChapters` subcommand).
- Full book build: `docs/phd/main.tex` (the `book` class scaffold),
compiled by `tectonic` via `trios-phd build-book` /
`trios-phd compile-resilient`.
- Per-chapter pandoc template: `templates/chapter.template.tex`.
- Hero-image Lua filter: `filters/force-fullwidth-hero.lua`.

**Do not invent a parallel ReportLab / Python PDF generator.** PDF is an
export from the renderer; it is not a hand-authored artefact.

---

## TRIOS_PHD_RENDERER_FIRST

If a placement, typography, or image rule must change, change it in the
renderer (template, Lua filter, or `docs/phd/main.tex`), NOT by editing
the per-chapter `.tex` files or by post-processing PDFs.

Order of preference for any structural change:

1. `templates/chapter.template.tex` (per-chapter pandoc template).
2. `docs/phd/main.tex` (book preamble for the full monograph).
3. `filters/force-fullwidth-hero.lua` (Markdown β†’ AST transform).
4. As a last resort: a Rust function in `crates/trios-phd`.

Editing individual chapters is allowed only for content. Visual /
placement / image-train concerns belong to the renderer layer.

---

## TRIOS_PHD_STYLE_LOCK

The accepted PhD visual style is locked:

- White academic title page.
- Serif typography (`DejaVu Serif` for main, math via classic CM).
- Large black-and-white engraved / ornamental TRIOS S3AI hero panels.
- Book-style margins (`docs/phd/main.tex` geometry block).
- Large, centered hero images β€” never thumbnails.

QA baseline (manual build that defines "accepted"):

- 150 A4 pages.
- `qpdf --check`: clean.
- Exact duplicate long paragraphs: 0.
- Duplicate numbered headings: 0.
- Cyrillic hits in the body: 0 (English-only repo docs).
- Secret / stale / math anomaly hits: 0.
- Very short non-empty pages: 0.
- Image-heavy / low-context candidate pages: at most 1 (the title page).

Any renderer change that regresses this baseline is a failure.

---

## TRIOS_PHD_NO_IMAGE_TRAIN

This is the non-negotiable rule that motivates the current renderer
configuration.

### Statement

Hero panels MUST NOT be laid out as a gallery or image train. Each hero
panel must be semantically anchored to the nearest substantive heading
and its body text. A heading must never be orphaned at the bottom of a
page above its hero figure, and hero figures from neighbouring sections
must never collapse into a multi-image train on a single page.

### How it is enforced

A **soft keep-together** vertical reservation, sized to fit a heading
plus a full hero figure (~`0.58\textheight`), is inserted before every
`\section` and `\chapter` via the `needspace` package:

```latex
\usepackage{needspace}

\makeatletter
\let\trios@orig@section\section
\renewcommand{\section}{%
\Needspace*{0.58\textheight}%
\trios@orig@section
}
\let\trios@orig@chapter\chapter
\renewcommand{\chapter}{%
\Needspace*{0.58\textheight}%
\trios@orig@chapter
}
\makeatother
```

This block lives in:

- `docs/phd/main.tex` β€” for the full monograph build.
- `templates/chapter.template.tex` β€” for the per-chapter pandoc build.
- `\chapterhero{}{}` in `templates/chapter.template.tex` is preceded by
`\Needspace*{0.58\textheight}` as well, so the chapter heading + hero
cannot be split.

`\Needspace*` (starred form) is critical: it triggers a page break only
when the remaining vertical space is insufficient AND we are not already
at the top of a page. It does not insert gratuitous breaks.

### Why hard `\clearpage` is FORBIDDEN

`\clearpage` before every section was tried and rejected. It produced
short title-only pages (a heading at the top of a fresh page, then a
hero figure on the next page) and broke the QA baseline. **Never insert
`\clearpage` before sections or hero figures as a workaround.** If a
heading still appears orphaned, raise the reservation size (e.g. to
`0.62\textheight`) β€” do not switch to `\clearpage`.

### What about the Lua filter?

`filters/force-fullwidth-hero.lua` promotes exactly one hero image per
chapter to full text width at block position 1. Additional standalone
images stay where the author placed them, anchored to their nearest
heading. The filter is part of the no-image-train discipline, not in
conflict with it.

### Image size

Hero images remain large, centered, full text width, and PhD-style. The
no-image-train rule is about placement, not about shrinking or removing
images.

---

## QA commands

Run these after any renderer-touching change:

```bash
# Build the per-chapter PDFs (no secrets needed beyond local pandoc + tectonic).
cargo run -p trios-phd -- compile-chapters \
--chapters-dir docs/golden-sunflowers \
--template templates/chapter.template.tex \
--lua-filter filters/force-fullwidth-hero.lua \
--out-dir docs/golden-sunflowers/pdf

# Build the full monograph (requires the full chapter source tree under docs/phd/).
cargo run -p trios-phd -- build-book

# Validate the produced PDF.
qpdf --check build/phd.pdf
pdfinfo build/phd.pdf
pdftotext -layout build/phd.pdf build/phd.txt

# QA scans on the extracted text.
grep -nE '[А-Π―Π°-яЁё]' build/phd.txt || echo "OK: no Cyrillic"
grep -nE 'TODO|FIXME|XXX|STALE' build/phd.txt || echo "OK: no stale markers"
grep -nE '(password|secret|token|api[_-]?key)=' build/phd.txt \
|| echo "OK: no secrets"

# Duplicate-heading and duplicate-paragraph scans live in trios-phd's
# audit subcommand and the tools under tools/page_gate/ β€” run them and
# compare to the baseline:
cargo run -p trios-phd -- audit
```

Visually inspect:

- The title page (white academic, large engraved S3AI panel).
- The first body pages of each Part β€” confirm no section heading sits
alone at the bottom of a page above its hero figure.
- Any chapter that previously triggered an image train β€” confirm only
one hero per chapter at the top, and any in-body images sit with
their semantic owners.

---

## What NOT to do

- Do NOT add `\clearpage` before sections or hero figures.
- Do NOT shrink hero images to "fix" pagination β€” adjust
`\Needspace*{...}` instead.
- Do NOT post-process the rendered PDF to move images.
- Do NOT introduce a parallel Python / ReportLab generator.
- Do NOT edit individual chapter `.tex` files for placement concerns.
- Do NOT print, log, or commit Railway tokens / database passwords
while running the pipeline.

---

## Pointers

- `crates/trios-phd/src/main.rs` β€” Rust orchestration of the pipeline.
- `docs/phd/main.tex` β€” book preamble, includes `needspace` and the
`\section` / `\chapter` keep-together wrapper.
- `templates/chapter.template.tex` β€” per-chapter pandoc template,
includes the same wrapper and `\chapterhero`.
- `filters/force-fullwidth-hero.lua` β€” one-hero-per-chapter promotion.
- `assets/illustrations/` β€” hero panel sources.
- `AGENTS.md` β€” short pointer to this document under TRIOS_PHD.
14 changes: 14 additions & 0 deletions docs/phd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ make pdf
# β†’ out/main.pdf (~969 pages, 182 figures, ~24 MB after gs /ebook compression)
```

### Renderer rules (image placement, keep-together, image-train ban)

The canonical rules for image placement, hero-panel anchoring, and
typography are defined in:

- **[../pdf-rendering.md](../pdf-rendering.md)** β€” `TRIOS_PHD_CANONICAL_PIPELINE`,
`TRIOS_PHD_RENDERER_FIRST`, `TRIOS_PHD_STYLE_LOCK`,
`TRIOS_PHD_NO_IMAGE_TRAIN`.

Headline: hero panels are anchored to the nearest substantive heading
via `\Needspace*{0.58\textheight}` (soft keep-together). Hard
`\clearpage` before sections is forbidden β€” it produced short
title-only pages and was rejected by QA.

---

## πŸ“œ Audit trail
Expand Down
40 changes: 40 additions & 0 deletions docs/phd/main.tex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@

% Float placement helpers (R1/L1)
\usepackage{float}
% TRIOS_PHD_NO_IMAGE_TRAIN β€” soft keep-together for a section heading and the
% hero/context block that follows. We reserve ~0.58\textheight before every
% \section, so a heading is never orphaned at the bottom of a page above a
% hero image. This is the canonical mechanism: a SOFT vertical reservation,
% NOT a hard \clearpage. A hard \clearpage before every section created
% short title-only pages and was rejected by QA.
\usepackage{needspace}
\usepackage{algorithm}
\usepackage{algpseudocode}
\usepackage{epigraph}
Expand Down Expand Up @@ -293,6 +300,39 @@
% Define `invariant` environment as a styled tcolorbox
\newtheorem{invariant}{Invariant}

% =====================================================================
% TRIOS_PHD_NO_IMAGE_TRAIN β€” semantic image anchoring.
%
% Rule: a hero panel must travel with the nearest substantive heading
% and its body text, not float into an image train and not strand a
% heading alone above a figure. We achieve this with a SOFT keep-
% together reservation in front of every \section and \chapter, sized
% so the heading plus a hero figure (~0.58 \textheight) cannot be split
% across a page boundary.
%
% IMPORTANT: this is a SOFT reservation, not \clearpage. A hard
% \clearpage before every section produces short title-only pages and
% was rejected by manual QA. Do not replace this with \clearpage.
%
% Implementation: wrap \section and \chapter so the original command is
% preceded by \Needspace*{0.58\textheight}. \Needspace* (starred form)
% triggers a page break only when the remaining vertical space is
% insufficient AND we are not already at the top of a page β€” so it
% never inserts a gratuitous break.
% =====================================================================
\makeatletter
\let\trios@orig@section\section
\renewcommand{\section}{%
\Needspace*{0.58\textheight}%
\trios@orig@section
}
\let\trios@orig@chapter\chapter
\renewcommand{\chapter}{%
\Needspace*{0.58\textheight}%
\trios@orig@chapter
}
\makeatother

\begin{document}

% Front matter
Expand Down
8 changes: 8 additions & 0 deletions filters/force-fullwidth-hero.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
--- `hero-image` and `hero-caption`, so chapter.template.tex can render
--- it via \chapterhero{}{} at the top.
---
--- TRIOS_PHD_NO_IMAGE_TRAIN: this filter promotes EXACTLY ONE hero image
--- per chapter. Additional standalone images are left in place at their
--- authored positions so they stay semantically anchored to the nearest
--- substantive heading and body text, never grouped as a gallery / image
--- train. The keep-together discipline (\Needspace before \section and
--- \chapter) is enforced in templates/chapter.template.tex and
--- docs/phd/main.tex β€” NOT here, and NOT via \clearpage.
---
--- Pairs with:
--- - templates/chapter.template.tex
--- - migrations/005_hero_fullwidth.sql (which prepends a Markdown image
Expand Down
19 changes: 19 additions & 0 deletions templates/chapter.template.tex
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@
\usepackage{hyperref}
\usepackage{caption}
\usepackage{fontspec} % requires xelatex / lualatex / tectonic
% TRIOS_PHD_NO_IMAGE_TRAIN β€” see docs/pdf-rendering.md.
% Soft keep-together so a section heading is never orphaned above its
% hero image. This is NOT a hard \clearpage (which produces title-only
% pages and was rejected by QA).
\usepackage{needspace}

% Hero figure: ALWAYS full text-width, ALWAYS at the start of the chapter.
% #1 = path or URL of the image (resolved before pandoc invocation)
% #2 = optional caption text (rendered in italic, no figure number)
\newcommand{\chapterhero}[2]{%
% TRIOS_PHD_NO_IMAGE_TRAIN: reserve enough vertical space so the chapter
% heading + hero figure cannot be split. Soft, not \clearpage.
\Needspace*{0.58\textheight}%
\begin{figure}[H]
\centering
\includegraphics[width=\linewidth,keepaspectratio]{#1}%
Expand All @@ -30,6 +38,17 @@
\vspace{0.5em}%
}

% TRIOS_PHD_NO_IMAGE_TRAIN: wrap \section so headings stay with the body
% (and any hero/context block immediately following). SOFT keep-together
% only β€” never a hard \clearpage.
\makeatletter
\let\trios@orig@section\section
\renewcommand{\section}{%
\Needspace*{0.58\textheight}%
\trios@orig@section
}
\makeatother

\begin{document}

% First block of every chapter is the hero image (injected by the Lua filter
Expand Down
Loading