Skip to content

Commit 93e47d4

Browse files
authored
Merge pull request #1 from i-d-e/claude/analyze-project-X6xZd
Monorepo-Schnitt: TEI-Korpus + Schema in ride-static eingezogen
2 parents b675e3e + 20fe21d commit 93e47d4

176 files changed

Lines changed: 238478 additions & 230 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@
22
# requirements.md N10 (one workflow file) and pipeline.md "GitHub Actions
33
# workflow (Phase 15)".
44
#
5-
# Status: SKELETON. Steps marked "Phase 8+" are placeholders that fail
6-
# loudly until the corresponding pipeline phase lands. The deploy chain
7-
# (upload-pages-artifact + deploy-pages) is the modern Actions-based
8-
# Pages flow — no /docs folder, no committed build output.
9-
#
10-
# Triggers:
11-
# - push to main on changes that affect TEI sources, content, or pipeline
12-
# - manual dispatch from the Actions tab
13-
#
14-
# The ride corpus is checked out as a sibling at ../ride so that the
15-
# REPO_ROOT.parent / "ride" pattern in scripts/*.py works unchanged in CI.
5+
# The TEI corpus and schema now live in this repo under issues/{N}/reviews/
6+
# and schema/. Per-issue pictures still live in i-d-e/ride under
7+
# issues/issue{NN}/{slug}/pictures/ and are pulled in via the asset pipeline.
8+
# The picture sibling is checked out alongside so REPO_ROOT.parent / "ride"
9+
# resolves at build time; when pictures move into this repo too, the second
10+
# checkout can drop.
1611

1712
name: build
1813

@@ -26,18 +21,18 @@ on:
2621
- "static/**"
2722
- "config/**"
2823
- "content/**"
24+
- "issues/**"
25+
- "schema/**"
2926
- "tests/**"
3027
- "requirements.txt"
3128
- ".github/workflows/build.yml"
3229
workflow_dispatch:
3330

34-
# Pages deploys need exactly these permissions; nothing else.
3531
permissions:
3632
contents: read
3733
pages: write
3834
id-token: write
3935

40-
# Don't queue overlapping deploys; the latest push always wins.
4136
concurrency:
4237
group: pages
4338
cancel-in-progress: true
@@ -51,7 +46,10 @@ jobs:
5146
with:
5247
path: ride-static
5348

54-
- name: Checkout ride corpus (sibling)
49+
# Pictures still live in the i-d-e/ride sibling repo. The asset
50+
# pipeline reads them via REPO_ROOT.parent / "ride" / "issues" / ...
51+
# When pictures move into ride-static, drop this step.
52+
- name: Checkout ride pictures (sibling, pictures only)
5553
uses: actions/checkout@v4
5654
with:
5755
repository: i-d-e/ride
@@ -64,17 +62,13 @@ jobs:
6462
cache: pip
6563
cache-dependency-path: ride-static/requirements.txt
6664

67-
# WeasyPrint links Pango/Cairo at import time. The Ubuntu runner
68-
# ships a partial GTK stack; install the WeasyPrint-listed runtime
69-
# libs explicitly so `import weasyprint` succeeds in CI.
7065
- name: Install WeasyPrint system libraries
7166
run: sudo apt-get update && sudo apt-get install -y libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz-subset0
7267

7368
- name: Install dependencies
7469
working-directory: ride-static
7570
run: pip install -r requirements.txt
7671

77-
# Cache the 4 MB TEI P5 subset between runs; pipeline.md "Re-deployment flow".
7872
- name: Cache TEI P5 subset
7973
uses: actions/cache@v4
8074
with:
@@ -85,7 +79,6 @@ jobs:
8579
working-directory: ride-static
8680
run: python -m pytest -q
8781

88-
# Tier 1 — independent extractors. Could parallelise; sequential is cheap and ordered.
8982
- name: Discovery scripts (Tier 1)
9083
working-directory: ride-static
9184
run: |
@@ -109,33 +102,11 @@ jobs:
109102
python scripts/render_data.py
110103
python scripts/render_schema.py
111104
112-
# Phase 13 lives here once it lands: pre-build RelaxNG + Schematron validation
113-
# against ../ride/schema/ride.odd, with a per-file report.
114-
# - name: Pre-build validation (Phase 13)
115-
# working-directory: ride-static
116-
# run: python -m src.validate
117-
118-
# Phase 8+ — the actual site build.
119-
# base-url is the path prefix under which Pages serves the site. For
120-
# https://<owner>.github.io/<repo>/ this is "/<repo>" (the implicit
121-
# GitHub-Pages-project-page convention). When a custom domain is
122-
# configured (e.g. https://ride.i-d-e.de/), drop the flag so paths
123-
# resolve from the root instead.
124-
- name: Build site (Phase 8+)
105+
- name: Build site
125106
working-directory: ride-static
126-
run: |
127-
if [ -f src/build.py ] || python -c "import src.build" 2>/dev/null; then
128-
python -m src.build --base-url=/${{ github.event.repository.name }} --pdf
129-
else
130-
echo "::warning::src.build is not implemented yet (Phase 8). Emitting placeholder site/."
131-
mkdir -p site
132-
echo "<!doctype html><title>ride-static</title><h1>build pending</h1>" > site/index.html
133-
fi
134-
135-
# Phase 11 — Pagefind index. Indexes site/ after the build, writes the
136-
# client-side runtime under site/pagefind/. Picked up by static/js/pagefind.js
137-
# via the data-pagefind-ui container in base.html.
138-
- name: Build Pagefind index (Welle 9)
107+
run: python -m src.build --base-url=/${{ github.event.repository.name }} --pdf
108+
109+
- name: Build Pagefind index
139110
working-directory: ride-static
140111
run: npx -y pagefind --site site
141112

CLAUDE.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ TEI XML → Python/Jinja → HTML/PDF, deployed via GitHub Actions.
88

99
## Hard rules
1010

11-
- **TDD with real-corpus drive.** Every script and parser module ships with pytest coverage. **Integration tests use the real corpus** (`../ride/tei_all/*.xml`) — parse a real review and assert the resulting domain shape, rather than constructing `Review`/`Section`/`Block` instances directly from synthetic dataclass values. Synthetic-from-dataclass construction is technical debt: it locks tests to the model contract while bypassing the parser, hiding parser regressions. **Pure-function unit tests** (regex, classifier, formatter) may use synthetic inputs because the function signature is the only data form richer than that — document this in the test docstring. **Edge cases that genuinely do not exist in the corpus** (truly unparseable URLs, future-proofing branches) keep a synthetic fixture but the docstring names the case as an explicit exception. Real-corpus tests skip cleanly when `../ride/` is absent so the unit suite runs on a fresh clone.
11+
- **TDD with real-corpus drive.** Every script and parser module ships with pytest coverage. **Integration tests use the real corpus** (`issues/{N}/reviews/*-tei.xml`) — parse a real review and assert the resulting domain shape, rather than constructing `Review`/`Section`/`Block` instances directly from synthetic dataclass values. Synthetic-from-dataclass construction is technical debt: it locks tests to the model contract while bypassing the parser, hiding parser regressions. **Pure-function unit tests** (regex, classifier, formatter) may use synthetic inputs because the function signature is the only data form richer than that — document this in the test docstring. **Edge cases that genuinely do not exist in the corpus** (truly unparseable URLs, future-proofing branches) keep a synthetic fixture but the docstring names the case as an explicit exception. Real-corpus tests skip cleanly when the corpus is absent so the unit suite runs on a partial checkout.
1212
- **`knowledge/` is a clean Obsidian-style vault — Markdown plus referenced image attachments.** Generated JSON belongs in `inventory/`. Cross-references inside the vault use `[[wikilink]]` notation. Hand-written filenames are lowercase. Image attachments (e.g. `image-workflow.png`) live next to the Markdown that references them, the conventional Obsidian-vault layout.
1313
- **`inventory/` is gitignored** (visible, no leading dot). Always regeneratable from scripts.
1414
- **Anomalies are explicit.** Known data quirks (no `<back>`, `<num value="3">`, `<list rend="numbered">`, etc. — see `knowledge/data.md`) become named branches in the parser. Unknown ones must raise.
@@ -30,8 +30,12 @@ ride-static/
3030
render/, build.py html, pdf, refs, assets, build CLI
3131
templates/html/ Jinja templates
3232
static/ css/, js/, fonts/
33-
config/ element-mapping.yaml + per-issue YAML configs
33+
config/ element-mapping.yaml, navigation.yaml
3434
content/ editorial Markdown: about, imprint, criteria, reviewers
35+
issues/{N}/ TEI corpus, grouped per issue
36+
metadata.yaml editorially curated issue metadata (DOI, editors, …)
37+
reviews/*-tei.xml the TEI review files for this issue
38+
schema/ ride.odd + ride.rng — RIDE TEI ODD + compiled RelaxNG
3539
inventory/ Generated JSON artifacts — gitignored
3640
_cache/ Cached upstream downloads (e.g. p5subset.xml)
3741
knowledge/ Obsidian-style vault, .md only, wikilinks for cross-refs
@@ -64,13 +68,14 @@ Cross-references inside `knowledge/` use **Obsidian wikilinks** (`[[filename]]`
6468

6569
Generated docs (`data.md`, `schema.md`) must not be edited by hand — changes go into `scripts/render_data.py` / `render_schema.py`. Hand-written docs are the only place where wikilinks may be added directly.
6670

67-
Source corpus lives in the **sibling** directory `../ride/`:
71+
The TEI corpus and schema live **inside this repo**:
6872

69-
- `../ride/tei_all/*.xml` — 107 reviews
70-
- `../ride/schema/ride.odd` — RIDE-specific TEI ODD
71-
- `../ride/issues/` — per-issue dirs with images
73+
- `issues/{N}/reviews/*-tei.xml` — 111 reviews, grouped by issue number (`biblScope @n`)
74+
- `issues/{N}/metadata.yaml` — per-issue editorial metadata (DOI, editors, contribution order, …)
75+
- `schema/ride.odd` — RIDE-specific TEI ODD
76+
- `schema/ride.rng` — compiled RelaxNG used by `src/validate.py`
7277

73-
Scripts dereference this via `REPO_ROOT.parent / "ride" / ...`.
78+
Path lookups go through `src/_corpus.py` (`iter_tei_files`, `find_tei`, `CORPUS_ROOT`, `SCHEMA_ODD`, …). Per-issue **pictures** still live in the sibling repo `i-d-e/ride` under `../ride/issues/issue{NN}/{slug}/pictures/`; the asset pipeline reads them via `REPO_ROOT.parent / "ride"` and degrades cleanly when the sibling is absent. When pictures move into this repo too, that fallback drops.
7479

7580
## Stage 0/1 outputs
7681

CONTRIBUTING.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,17 @@ Goal of this document: any new contributor reaches a productive state within hal
44

55
## Setup
66

7-
Requirements: Python 3.11, git, a checkout of the sibling corpus repo at `../ride/`.
7+
Requirements: Python 3.11, git.
88

99
```sh
1010
git clone <this-repo>
11-
git clone <ride-corpus-repo> ../ride # the TEI source corpus
12-
1311
cd ride-static
1412
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
1513
pip install -r requirements.txt
1614
python -m pytest tests/
1715
```
1816

19-
If `../ride/` is not present, the parser still runs and 87 of 88 tests pass — only the real-corpus smoke test skips. Discovery scripts in `scripts/` need `../ride/` to do anything useful.
17+
The TEI corpus ships in this repo under `issues/{N}/reviews/`, no separate clone is needed. Per-issue **picture assets** still live in `i-d-e/ride`; clone it as a sibling (`git clone <ride-corpus-repo> ../ride`) only if you need figures to render in the local build — the pipeline degrades cleanly without it.
2018

2119
## Repository layout
2220

@@ -36,7 +34,7 @@ See `CLAUDE.md` for the layout reference. In short:
3634

3735
These are the project's non-negotiables. Codified for clarity, not for ceremony.
3836

39-
- **TDD.** Every script and parser module ships with pytest using synthetic TEI fixtures. The parser also has one real-corpus smoke test that skips when `../ride/` is absent.
37+
- **TDD.** Every script and parser module ships with pytest. Integration tests drive off the real corpus shipped under `issues/{N}/reviews/`; pure-function unit tests may use synthetic inputs.
4038
- **`knowledge/` stays clean.** Hand-written and generated `.md` only. No JSON, no scripts, no notebooks. Cross-references between knowledge docs use `[[wikilink]]` notation.
4139
- **`inventory/` is gitignored.** Always regeneratable from scripts. Never edit by hand.
4240
- **Anomalies are explicit.** Known data quirks become named branches in the parser. Unknown ones must raise.
@@ -61,7 +59,7 @@ If a documented decision conflicts with the code, fix the code. If the code is r
6159

6260
**Commits.** Short title in the form `Area: what changed`, e.g. `Parser: integrate body into parse_review`. Body is optional — use it when the *why* needs explaining. Sign with the standard `Co-Authored-By` trailer if pair-coding with an agent.
6361

64-
**Tests.** Synthetic fixtures live inline in test files. Real-corpus smoke tests skip via `pytest.skip` when `../ride/` is absent. Each new script or parser module gets its own `tests/test_<name>.py`. Assert exact output paths when scripts write files (see `tests/test_odd_extract.py` for the canonical example).
62+
**Tests.** Synthetic fixtures live inline in test files. Real-corpus tests find files via `src._corpus.find_tei("slug")` or iterate via `iter_tei_files()`. Each new script or parser module gets its own `tests/test_<name>.py`. Assert exact output paths when scripts write files (see `tests/test_odd_extract.py` for the canonical example).
6563

6664
**Type hints.** Domain types are immutable: `@dataclass(frozen=True)` with `tuple[...]` for sequences (hashability). Optional fields default to `None`, never to mutable defaults.
6765

Journal.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,37 @@ Three persistence layers run in parallel for this project: `CLAUDE.md` for proje
3030

3131
---
3232

33+
## 2026-05-12 — Monorepo-Schnitt: TEI-Korpus + Schema in ride-static eingezogen
34+
35+
**Ziel:** Den TEI-Korpus aus `i-d-e/ride` ins eigene Repo holen, damit ride-static nicht mehr von einem zweiten Checkout abhängt, und die Issue-Metadaten dabei direkt neben den TEI-Dateien gruppieren.
36+
37+
**Erledigt:**
38+
- 111 TEI-Reviews aus `i-d-e/ride/tei_all/` per `biblScope @n` ausgewertet und in `issues/{N}/reviews/{slug}-tei.xml` einsortiert; Schema (`ride.odd` + `ride.rng`) liegt nun unter `schema/` im Repo-Root.
39+
- 22 YAML-Issue-Configs von `content/issues/{N}.yaml` nach `issues/{N}/metadata.yaml` umgezogen; `content/issues/` entfernt.
40+
- Neues Helfer-Modul `src/_corpus.py` (`iter_tei_files`, `find_tei`, `CORPUS_ROOT`, `SCHEMA_ODD`, `SCHEMA_RNG`, `corpus_available`) ersetzt den verteilten `REPO_ROOT.parent / "ride" / "tei_all"`-Pattern.
41+
- Alle Pfad-Konstanten in `scripts/{inventory,structure,sections,refs,ids,taxonomy,odd_extract}.py`, `src/build.py`, `src/validate.py`, `src/render/issues_config.py` umgestellt; Globs auf `**/*.xml` bzw. `*/reviews/*.xml` / `*/metadata.yaml`.
42+
- 21 Test-Dateien automatisiert auf `find_tei("slug")` + neue Globs migriert; Skip-Mechanismus von `test_parser_assets.py` zeigt jetzt auf den Bilder-Sibling.
43+
- CI (`.github/workflows/build.yml`) verschlankt: `i-d-e/ride` wird nur noch wegen der Picture-Assets als Sibling geklont; alle anderen Schritte greifen auf das in-repo TEI-/Schema-Layout zu.
44+
- Doku synchronisiert: `CLAUDE.md`, `README.md`, `CONTRIBUTING.md`, `docs/extending.md`, `knowledge/architecture.md`, `knowledge/pipeline.md` — Layout-Tabellen, Stakeholder-Eingangspunkte, Hard-Rule-Quote, "107 reviews"→"111 reviews".
45+
- Tests: 468 passed, 7 skipped (die Asset-Picture-Tests, weil `../ride/` in der Sandbox fehlt).
46+
47+
**Entscheidungen:**
48+
- **Per-Issue-Layout `issues/{N}/{metadata.yaml, reviews/*-tei.xml}` statt flachem `corpus/tei_all/`.** Begründung: alles zu einem Issue an einem Ort, Editor sieht Metadaten und Reviews nebeneinander; YAML-Membership wäre eine zweite Wahrheit gegenüber `biblScope @n`, darum bleibt die TEI-Header-Zuordnung kanonisch.
49+
- **Schema unter `schema/` im Root, nicht unter `corpus/schema/`.** Begründung: das Schema ist Validierungs-Vertrag, nicht Korpus-Inhalt — gleiche Trennung wie zwischen `src/` und `tests/`.
50+
- **Pictures (~437 MB, 888 Dateien) bleiben vorerst im Sibling `i-d-e/ride`.** Begründung: Repo-Größe und Klon-Zeit; LFS-Quota würde belastet. Die Asset-Pipeline degradiert sauber, wenn Sibling fehlt; CI klont den Sibling weiterhin nur für Bilder.
51+
- **`src/_corpus.py` als zentrale Wahrheit für Pfade.** Begründung: vor der Migration war `REPO_ROOT.parent / "ride" / "tei_all"` in ~35 Dateien dupliziert; bei der nächsten Layout-Änderung muss nur dieses Modul angefasst werden.
52+
- **CI: zweiter Checkout bleibt, aber explizit als "pictures only" dokumentiert.** Wenn die Bilder migriert werden, fällt der Step weg.
53+
54+
**Offen:**
55+
- Bilder-Migration: 437 MB in 22 Issue-Ordnern, vermutlich via Git-LFS. Eigene Entscheidung in einer separaten Session.
56+
- `RIDE_ROOT` in `src/build.py` und `_RIDE_ROOT` in `tests/test_parser_assets.py` zeigen noch auf den Sibling — kann erst entfallen, wenn die Bilder hier liegen.
57+
- Knowledge-Doku-CI: Drift zwischen generiertem `knowledge/data.md` und aktuellem Korpus könnte auffliegen, wenn CI strict läuft (4 neue Reviews seit Phase 10-Refresh).
58+
- Phase 15.B (WCAG-Audit, Matomo-Secrets, Custom-Domain) weiterhin offen — unabhängig von dieser Umstrukturierung.
59+
60+
**Nächster Einstieg:** Lokal `python -m src.build` ohne `../ride/` laufen lassen und prüfen, dass der AssetReport sauber alle fehlenden Bilder meldet statt zu crashen. Wenn das durchläuft, ist die Layout-Migration end-to-end verifiziert.
61+
62+
---
63+
3364
## 2026-04-29 — Phase 10-Rest: Data-Charts (R9) live
3465

3566
**Ziel:** Den letzten inhaltlichen Brocken aus Phase 10 abräumen — aggregierte Bar-Charts auf `/data/charts/` aus dem realen Korpus statt des seit Welle 6 stehenden Placeholder-Markdown.

0 commit comments

Comments
 (0)