Skip to content

Commit 0815f9f

Browse files
marcarlclaude
andcommitted
Add ADR-004: Markdown as intermediate format
Documents the architectural decision to use Markdown as an intermediate format between JSON source data and all output formats (HTML, Git, Vector). Key points: - Single source of truth for parsing logic - Human-readable for code review and debugging - Standard tooling and ecosystem - Flexible for adding new output formats Also updates README.md to include both ADR-003 and ADR-004 in the index. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 65cc655 commit 0815f9f

2 files changed

Lines changed: 229 additions & 0 deletions

File tree

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# ADR-004: Markdown som mellanformat
2+
3+
## Status
4+
5+
Accepterad
6+
7+
## Kontext och problembeskrivning
8+
9+
För att konvertera SFS-författningar från källdata (JSON) till olika output-format (HTML, Git, vektorembeddings) behövde vi välja en arkitektur för dataflödet.
10+
11+
Huvudalternativen var:
12+
13+
1. **Direkt konvertering**: JSON → HTML, JSON → Git, JSON → Vector (separata pipelines)
14+
2. **Mellanformat**: JSON → [Mellanformat] → (HTML/Git/Vector/etc)
15+
16+
Utmaningarna var:
17+
18+
- **Code duplication**: Varje exporter skulle behöva implementera samma parsing-logik
19+
- **Konsistens**: Hur garantera att HTML-versionen och Git-versionen är identiska?
20+
- **Mänsklig läsbarhet**: Utvecklare och bidragsgivare måste kunna granska output
21+
- **Versionskontroll**: Ska mellan-representationen kunna versionshanteras?
22+
- **Temporal processing**: Var i kedjan ska temporal filtrering appliceras?
23+
- **Underhållbarhet**: Ändringar i parsing-logik ska inte kräva uppdateringar i alla exporters
24+
25+
## Beslut
26+
27+
Vi använder **Markdown med HTML-taggar** som mellanformat mellan JSON-källdata och alla output-format.
28+
29+
### Arkitektur
30+
31+
```
32+
JSON (Regeringskansliet)
33+
34+
[format_sfs_text_as_markdown]
35+
36+
Markdown med <section>-taggar och selex:-attribut
37+
38+
├─→ [apply_temporal] → Markdown (rent) → HTML
39+
├─→ [apply_temporal] → Markdown (rent) → Git commits
40+
├─→ [apply_temporal] → Markdown (rent) → Vector embeddings
41+
└─→ Markdown (med taggar) → Publiceras som md-markers
42+
```
43+
44+
### Varför Markdown?
45+
46+
**Mänsklig läsbarhet**:
47+
```markdown
48+
## 1 kap. Inledande bestämmelser
49+
50+
### 1 §
51+
Denna lag gäller för...
52+
```
53+
54+
**Semantisk struktur** (behålls via HTML i Markdown):
55+
```html
56+
<section class="kapitel" selex:ikraft_datum="2025-01-01">
57+
## 1 kap. Inledande bestämmelser
58+
...
59+
</section>
60+
```
61+
62+
**Versionskontroll**:
63+
- Markdown är text-baserat → perfekt för Git diff
64+
- Granskare kan läsa ändringar direkt på GitHub
65+
- Merge conflicts är läsbara och lösbara
66+
67+
### Implementation
68+
69+
**Steg 1: JSON → Markdown** (`formatters/format_sfs_text.py`)
70+
- Konverterar JSON-strukturen till Markdown-rubriker
71+
- Lägger till `<section>`-taggar med CSS-klasser
72+
- Extraherar och annoterar temporal metadata som `selex:`-attribut
73+
74+
**Steg 2: Markdown → Output-format**
75+
- **HTML**: `markdown.markdown()` + custom extensions → HTML
76+
- **Git**: Temporal filtrering + commit med markdown-filer
77+
- **Vector**: Temporal filtrering + chunking + embedding
78+
- **md-markers**: Ingen transformation (publiceras som är)
79+
80+
## Konsekvenser
81+
82+
### Positiva
83+
84+
- **Single source of truth**: All parsing-logik finns på ett ställe (`format_sfs_text.py`)
85+
- **Konsistens**: Alla output-format utgår från samma Markdown-representation
86+
- **Granskning**: Pull requests visar Markdown-diff som är läsbar för människor
87+
- **Flexibilitet**: Lätt att lägga till nya output-format
88+
- Vill du ha PDF? Konvertera Markdown → PDF med pandoc
89+
- Vill du ha EPUB? Markdown → EPUB med tooling
90+
- **Standard tooling**: Markdown har enormt ekosystem (parsers, linters, previewers)
91+
- **Hybrid format**: HTML-i-Markdown ger både läsbarhet och semantik
92+
- **Debug-vänligt**: Kan inspektera Markdown-filer manuellt vid problem
93+
- **Cacheable**: Markdown-filer kan sparas och återanvändas
94+
- **Testbarhet**: Enkelt att skriva tester mot Markdown-output
95+
96+
### Negativa
97+
98+
- **Extra konverteringssteg**: JSON → Markdown → HTML tar mer tid än direkt JSON → HTML
99+
- Mitigering: Prestandan är acceptabel, och flexibiliteten väger tyngre
100+
101+
- **HTML-i-Markdown komplexitet**: Inte alla Markdown-renderare hanterar HTML perfekt
102+
- Mitigering: Vi använder beprövade bibliotek (`markdown` för Python)
103+
104+
- **Temporal metadata i HTML-attribut**: Okonventionellt för Markdown
105+
- Mitigering: Dokumenterat i ADR-001, fungerar i praktiken
106+
107+
- **Två Markdown-varianter**: `md-markers` (med taggar) vs `md` (rent)
108+
- Mitigering: Tydlig separation, olika användningsfall
109+
110+
### Tekniska konsekvenser
111+
112+
- **Format-specificering**: `--formats md-markers` vs `--formats md`
113+
- `md-markers`: Bevarar all metadata, för vidare processing
114+
- `md`: Rendad version efter temporal filtrering
115+
116+
- **Temporal processing**: Sker EFTER Markdown-generering
117+
- Markdown → `apply_temporal(target_date)` → Rendad Markdown
118+
119+
- **Lazy evaluation**: Temporal filtrering kan postponas till senare
120+
- `md-markers` sparar alla möjligheter öppna
121+
122+
## Alternativ som övervägdes
123+
124+
### 1. Direkt JSON → HTML/Git/Vector
125+
126+
**Fördelar**:
127+
- Snabbare (färre steg)
128+
- Enklare arkitektur
129+
130+
**Varför inte valt**:
131+
- Code duplication: Varje exporter måste parsa JSON
132+
- Konsistensproblem: Olika exporters kan tolka JSON olika
133+
- Ingen human-readable mellanrepresentation
134+
- Svårt att granska output (JSON är inte läsbart som Markdown)
135+
136+
### 2. XML som mellanformat (TEI eller custom)
137+
138+
```xml
139+
<law id="2024:100">
140+
<chapter number="1">
141+
<heading>Inledande bestämmelser</heading>
142+
<paragraph number="1">
143+
<text>Denna lag gäller...</text>
144+
</paragraph>
145+
</chapter>
146+
</law>
147+
```
148+
149+
**Fördelar**:
150+
- Strikt struktur med validering
151+
- Etablerad standard (TEI) inom juridisk text
152+
153+
**Varför inte valt**:
154+
- Mindre läsbart för människor
155+
- Högre inlärningströskel
156+
- Mindre ekosystem än Markdown
157+
- Svårare att granska i pull requests
158+
- Overkill för vårt användningsfall
159+
160+
### 3. JSON som mellanformat (normaliserad struktur)
161+
162+
**Varför inte valt**:
163+
- Inte mänskligt läsbart
164+
- Svårt att versionskontrollera (JSON diff är svårläst)
165+
- Inget naturligt sätt att representera flytande text med rubriker
166+
167+
### 4. AST (Abstract Syntax Tree)
168+
169+
```python
170+
{
171+
"type": "document",
172+
"children": [
173+
{"type": "chapter", "number": "1", "heading": "..."},
174+
{"type": "paragraph", "number": "1", "content": "..."}
175+
]
176+
}
177+
```
178+
179+
**Varför inte valt**:
180+
- Rent programmatiskt format, inte läsbart
181+
- Måste serialiseras för att inspekteras
182+
- Ingen standard representation
183+
- Kan inte versionskontrolleras meningsfullt
184+
185+
## Relaterade beslut
186+
187+
- [ADR-001](001-semantiska-temporal-taggar.md) - Selex-attribut i Markdown
188+
- [ADR-003](003-git-commits-historiska-datum.md) - Markdown-filer committas till Git
189+
190+
## Noteringar
191+
192+
- **Implementationer**:
193+
- `formatters/format_sfs_text.py` - JSON → Markdown konvertering
194+
- `formatters/frontmatter_manager.py` - YAML frontmatter i Markdown
195+
- `temporal/apply_temporal.py` - Temporal filtrering av Markdown
196+
- `exporters/html/html_export.py` - Markdown → HTML med `markdown.markdown()`
197+
- `exporters/vector/chunking.py` - Markdown → Chunks för embeddings
198+
199+
- **Markdown flavor**: CommonMark-kompatibel med HTML-extension
200+
- Rubriker: Standard Markdown (`##`, `###`, `####`)
201+
- Paragrafer: Standard Markdown (dubbla radbrytningar)
202+
- Semantik: HTML `<section>` och `<article>` taggar
203+
- Links: Standard Markdown-länkar + auto-linking
204+
205+
- **Frontmatter**: YAML frontmatter för metadata
206+
```yaml
207+
---
208+
beteckning: "2024:100"
209+
rubrik: "Lag om exempel"
210+
ikraft_datum: "2025-01-01"
211+
---
212+
```
213+
214+
- **Fördelar med två varianter**:
215+
- **md-markers**: För vidare processing, AI-analys, temporal queries
216+
- **md**: För publicering, läsning, GitHub Pages
217+
218+
- **Future-proof**: Om nya output-format behövs (PDF, DOCX, LaTeX):
219+
- Använd befintlig Markdown → Konvertera med standard tooling
220+
- Ingen ändring i core parsing-logik behövs
221+
222+
- **Exempel på Markdown-ekosystem som vi drar nytta av**:
223+
- `python-markdown`: Markdown → HTML konvertering
224+
- GitHub/GitLab: Automatisk rendering av `.md` filer
225+
- Markdown linters: Kvalitetskontroll av output
226+
- Markdown previewers: Live-förhandsvisning under utveckling
227+
- Pandoc: Potentiell framtida konvertering till andra format

docs/adr/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Vi använder [MADR](https://adr.github.io/madr/) (Markdown Any Decision Records)
2222
|-----|-------|--------|
2323
| [ADR-001](001-semantiska-temporal-taggar.md) | Semantiskt val av taggar för temporal data | Accepterad |
2424
| [ADR-002](002-import-fran-regeringskansliet.md) | Import från Regeringskansliet istället för PDF-crawling | Accepterad |
25+
| [ADR-003](003-git-commits-historiska-datum.md) | Git-commits med historiska datum för versionshistorik | Accepterad |
26+
| [ADR-004](004-markdown-som-mellanformat.md) | Markdown som mellanformat | Accepterad |
2527

2628
## Skapa en ny ADR
2729

0 commit comments

Comments
 (0)