Skip to content
Merged
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
227 changes: 227 additions & 0 deletions docs/adr/001-markdown-som-mellanformat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# ADR-001: Markdown som mellanformat

## Status

Accepterad

## Kontext och problembeskrivning

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.

Huvudalternativen var:

1. **Direkt konvertering**: JSON → HTML, JSON → Git, JSON → Vector (separata pipelines)
2. **Mellanformat**: JSON → [Mellanformat] → (HTML/Git/Vector/etc)

Utmaningarna var:

- **Code duplication**: Varje exporter skulle behöva implementera samma parsing-logik
- **Konsistens**: Hur garantera att HTML-versionen och Git-versionen är identiska?
- **Mänsklig läsbarhet**: Utvecklare och bidragsgivare måste kunna granska output
- **Versionskontroll**: Ska mellan-representationen kunna versionshanteras?
- **Temporal processing**: Var i kedjan ska temporal filtrering appliceras?
- **Underhållbarhet**: Ändringar i parsing-logik ska inte kräva uppdateringar i alla exporters

## Beslut

Vi använder **Markdown med HTML-taggar** som mellanformat mellan JSON-källdata och alla output-format.

### Arkitektur

```
JSON (Regeringskansliet)
[format_sfs_text_as_markdown]
Markdown med <section>-taggar och selex:-attribut
├─→ [apply_temporal] → Markdown (rent) → HTML
├─→ [apply_temporal] → Markdown (rent) → Git commits
├─→ [apply_temporal] → Markdown (rent) → Vector embeddings
└─→ Markdown (med taggar) → Publiceras som md-markers
```

### Varför Markdown?

**Mänsklig läsbarhet**:
```markdown
## 1 kap. Inledande bestämmelser

### 1 §
Denna författning gäller för...
```

**Semantisk struktur** (behålls via HTML i Markdown):
```html
<section class="kapitel" selex:ikraft_datum="2025-01-01">
## 1 kap. Inledande bestämmelser
...
</section>
```

**Versionskontroll**:
- Markdown är text-baserat → perfekt för Git diff
- Granskare kan läsa ändringar direkt på GitHub
- Merge conflicts är läsbara och lösbara

### Implementation

**Steg 1: JSON → Markdown** (`formatters/format_sfs_text.py`)
- Konverterar JSON-strukturen till Markdown-rubriker
- Lägger till `<section>`-taggar med CSS-klasser
- Extraherar och annoterar temporal metadata som `selex:`-attribut

**Steg 2: Markdown → Output-format**
- **HTML**: `markdown.markdown()` + custom extensions → HTML
- **Git**: Temporal filtrering + commit med markdown-filer
- **Vector**: Temporal filtrering + chunking + embedding
- **md-markers**: Ingen transformation (publiceras som är)

## Konsekvenser

### Positiva

- **Single source of truth**: All parsing-logik finns på ett ställe (`format_sfs_text.py`)
- **Konsistens**: Alla output-format utgår från samma Markdown-representation
- **Granskning**: Pull requests visar Markdown-diff som är läsbar för människor
- **Flexibilitet**: Lätt att lägga till nya output-format
- Vill du ha PDF? Konvertera Markdown → PDF med pandoc
- Vill du ha EPUB? Markdown → EPUB med tooling
- **Standard tooling**: Markdown har enormt ekosystem (parsers, linters, previewers)
- **Hybrid format**: HTML-i-Markdown ger både läsbarhet och semantik
- **Debug-vänligt**: Kan inspektera Markdown-filer manuellt vid problem
- **Cacheable**: Markdown-filer kan sparas och återanvändas
- **Testbarhet**: Enkelt att skriva tester mot Markdown-output

### Negativa

- **Extra konverteringssteg**: JSON → Markdown → HTML tar mer tid än direkt JSON → HTML
- Mitigering: Prestandan är acceptabel, och flexibiliteten väger tyngre

- **HTML-i-Markdown komplexitet**: Inte alla Markdown-renderare hanterar HTML perfekt
- Mitigering: Vi använder beprövade bibliotek (`markdown` för Python)

- **Temporal metadata i HTML-attribut**: Okonventionellt för Markdown
- Mitigering: Dokumenterat i ADR-004, fungerar i praktiken

- **Två Markdown-varianter**: `md-markers` (med taggar) vs `md` (rent)
- Mitigering: Tydlig separation, olika användningsfall

### Tekniska konsekvenser

- **Format-specificering**: `--formats md-markers` vs `--formats md`
- `md-markers`: Bevarar all metadata, för vidare processing
- `md`: Rendad version efter temporal filtrering

- **Temporal processing**: Sker EFTER Markdown-generering
- Markdown → `apply_temporal(target_date)` → Rendad Markdown

- **Lazy evaluation**: Temporal filtrering kan postponas till senare
- `md-markers` sparar alla möjligheter öppna

## Alternativ som övervägdes

### 1. Direkt JSON → HTML/Git/Vector

**Fördelar**:
- Snabbare (färre steg)
- Enklare arkitektur

**Varför inte valt**:
- Code duplication: Varje exporter måste parsa JSON
- Konsistensproblem: Olika exporters kan tolka JSON olika
- Ingen human-readable mellanrepresentation
- Svårt att granska output (JSON är inte läsbart som Markdown)

### 2. XML som mellanformat (TEI eller custom)

```xml
<law id="2024:100">
<chapter number="1">
<heading>Inledande bestämmelser</heading>
<paragraph number="1">
<text>Denna författning gäller...</text>
</paragraph>
</chapter>
</law>
```

**Fördelar**:
- Strikt struktur med validering
- Etablerad standard (TEI) inom juridisk text

**Varför inte valt**:
- Mindre läsbart för människor
- Högre inlärningströskel
- Mindre ekosystem än Markdown
- Svårare att granska i pull requests
- Overkill för vårt användningsfall

### 3. JSON som mellanformat (normaliserad struktur)

**Varför inte valt**:
- Inte mänskligt läsbart
- Svårt att versionskontrollera (JSON diff är svårläst)
- Inget naturligt sätt att representera flytande text med rubriker

### 4. AST (Abstract Syntax Tree)

```python
{
"type": "document",
"children": [
{"type": "chapter", "number": "1", "heading": "..."},
{"type": "paragraph", "number": "1", "content": "..."}
]
}
```

**Varför inte valt**:
- Rent programmatiskt format, inte läsbart
- Måste serialiseras för att inspekteras
- Ingen standard representation
- Kan inte versionskontrolleras meningsfullt

## Relaterade beslut

- [ADR-004](004-semantiska-temporal-taggar.md) - Selex-attribut i Markdown
- [ADR-003](003-git-commits-historiska-datum.md) - Markdown-filer committas till Git

## Noteringar

- **Implementationer**:
- `formatters/format_sfs_text.py` - JSON → Markdown konvertering
- `formatters/frontmatter_manager.py` - YAML frontmatter i Markdown
- `temporal/apply_temporal.py` - Temporal filtrering av Markdown
- `exporters/html/html_export.py` - Markdown → HTML med `markdown.markdown()`
- `exporters/vector/chunking.py` - Markdown → Chunks för embeddings

- **Markdown flavor**: CommonMark-kompatibel med HTML-extension
- Rubriker: Standard Markdown (`##`, `###`, `####`)
- Paragrafer: Standard Markdown (dubbla radbrytningar)
- Semantik: HTML `<section>` och `<article>` taggar
- Links: Standard Markdown-länkar + auto-linking

- **Frontmatter**: YAML frontmatter för metadata
```yaml
---
beteckning: "2024:100"
rubrik: "Författning om exempel"
ikraft_datum: "2025-01-01"
---
```

- **Fördelar med två varianter**:
- **md-markers**: För vidare processing, AI-analys, temporal queries
- **md**: För publicering, läsning, GitHub Pages

- **Future-proof**: Om nya output-format behövs (PDF, DOCX, LaTeX):
- Använd befintlig Markdown → Konvertera med standard tooling
- Ingen ändring i core parsing-logik behövs

- **Exempel på Markdown-ekosystem som vi drar nytta av**:
- `python-markdown`: Markdown → HTML konvertering
- GitHub/GitLab: Automatisk rendering av `.md` filer
- Markdown linters: Kvalitetskontroll av output
- Markdown previewers: Live-förhandsvisning under utveckling
- Pandoc: Potentiell framtida konvertering till andra format
141 changes: 141 additions & 0 deletions docs/adr/002-import-fran-regeringskansliet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# ADR-002: Import från Regeringskansliet istället för PDF-crawling

## Status

Accepterad

## Kontext och problembeskrivning

För att konvertera SFS-författningar till olika format behövde vi en källdatakälla. Det finns två huvudsakliga alternativ för att få tillgång till författningstexter:

1. **PDF-crawling**: Ladda ner publicerade PDF:er från olika källor och extrahera text
2. **Strukturerad data-import**: Använda API:er som tillhandahåller strukturerad data (JSON/XML)

Utmaningarna med PDF-crawling:

- Text extraction från PDF är opålitlig (tabeller, fotnoter, formatering går förlorad)
- Ingen semantisk struktur (kapitel, paragrafer, rubriker måste detekteras heuristiskt)
- Temporal metadata (ikraftträdandedatum, upphävanden) finns inte i PDF:en
- OCR-fel vid scannade dokument
- Layout-beroende parsing (när PDF-layouten ändras, bryts parsern)

Alternativen för strukturerad data:

- **Riksdagens API** (`data.riksdagen.se`) - XML-format, fokus på riksdagsarbete
- **Regeringskansliets rättsdatabas** (`beta.rkrattsbaser.gov.se`) - JSON via Elasticsearch API

## Beslut

Vi använder **Regeringskansliets Elasticsearch API** (`beta.rkrattsbaser.gov.se`) som primär källdatakälla för SFS-författningar.

### API-detaljer

- **Endpoint**: `https://beta.rkrattsbaser.gov.se/elasticsearch/SearchEsByRawJson`
- **Format**: JSON via Elasticsearch queries
- **Innehåll**: Fullständig författningstext med strukturerad metadata
- **Metadataexempel**:
- Beteckning (`2024:100`)
- Departement
- Ikraftträdandedatum
- Ändringshistorik
- Rubrikstruktur (avdelningar, kapitel, paragrafer)

## Konsekvenser

### Positiva

- **Strukturerad data**: JSON med tydlig hierarki (avdelningar → kapitel → paragrafer)
- **Rik metadata**: Departement, datum, ändringshistorik inkluderad
- **Tillförlitlighet**: Officiell källa från Regeringskansliet
- **Automatisering**: Enkel att hämta via HTTP POST requests
- **Versionshantering**: Ändringsförfattningar och ursprungsdokument finns
- **Undviker PDF-problem**: Ingen text extraction, ingen OCR, ingen layout-parsing
- **Temporal data**: Ikraftträdande och upphävanden finns i metadata
- **Konsistent format**: Alla författningar i samma JSON-schema

### Negativa

- **Beta-status**: API:et är markerat som "beta", kan förändras
- Mitigering: Versionshantering av downloader-skript, tester för att upptäcka breaking changes
- **Ingen SLA**: Inget officiellt servicenivåavtal eller versionsstöd
- Mitigering: Lokalt cachning av nedladdad JSON i `data/sfs_json/`
- **Proprietärt API**: Regeringskansliets eget format, inte en öppen standard
- Mitigering: Abstraktionslager i `downloaders/` gör byte av källa möjligt
- **Nätverksberoende**: Kräver internetanslutning för initial hämtning
- Mitigering: Offline-körning möjlig med lokalt cachad data

### Tekniska konsekvenser

- **Downloader-arkitektur**: Implementationen i `downloaders/rkrattsbaser_api.py` abstraherar API-anrop
- **Fallback**: `downloaders/riksdagen_api.py` finns som backup-källa vid behov
- **Caching-strategi**: JSON sparas lokalt för att undvika upprepade API-anrop
- **Rate limiting**: Implementerad delay mellan requests för att respektera servern

## Alternativ som övervägdes

### 1. PDF-crawling från Regeringskansliets webbplats

**Varför inte valt**:

- Opålitlig text extraction
- Ingen strukturerad metadata
- Kräver komplex layout-parsing
- Temporal information måste extraheras heuristiskt från text
- Högre underhållskostnad när PDF-format ändras

### 2. Riksdagens API (data.riksdagen.se)

```xml
<dokument>
<beteckning>2024:100</beteckning>
<text>...</text>
</dokument>
```

**Fördelar**:

- Officiellt API med stabil uptime
- XML-format

**Varför inte valt**:

- Fokus på riksdagsarbete, inte konsoliderade författningar
- Mindre detaljerad metadata för författningar
- XML-parsing mer komplext än JSON
- Regeringskansliets data är mer författningsfokuserad

**Notering**: Vi behåller `riksdagen_api.py` som fallback-källa

### 3. Scraping från [svenskforfattningssamling.se](https://svenskforfattningssamling.se/)

**Varför inte valt**:

- Inget officiellt API
- Scraping kan bryta när webbplatsen uppdateras

## Relaterade beslut

- [ADR-004](004-semantiska-temporal-taggar.md) - Temporal metadata kommer från Regeringskansliets API

## Noteringar

- **Implementationer**:
- `downloaders/rkrattsbaser_api.py` - Primär implementation
- `downloaders/riksdagen_api.py` - Backup-källa
- `downloaders/download_sfs_docs.py` - CLI för att hämta författningar

- **Användning**:

```bash
# Hämta specifik författning
python downloaders/download_sfs_docs.py --ids "2024:100" --source rkrattsbaser

# Hämta alla författningar
python downloaders/download_sfs_docs.py --ids all --source rkrattsbaser
```

- **Caching**: Nedladdad JSON sparas i `data/sfs_json/` för offline-användning

- **Rate limiting**: Implementerad 1-sekunds delay mellan requests för att respektera servern

- **Framtidsutsikter**: Om API:et tas bort eller ändras drastiskt kan vi falla tillbaka på Riksdagens API eller implementera en hybrid-lösning
Loading