230a3badc3
Songs always carries a # Song title line so stripping makes sense there, but SES body structure is freeform and may use h1 deliberately. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
150 lines
4.3 KiB
Markdown
150 lines
4.3 KiB
Markdown
# SCHEMA — SES light novel source files
|
|
|
|
Source-file contract for the SES pipeline. Files in `mikkeli/ses-light-novel` must follow this contract to be picked up by the auto-publisher.
|
|
|
|
The schema lives entirely in the YAML frontmatter block at the top of each `.md` file. The body below the frontmatter is plain markdown, rendered to MediaWiki wikitext by Pandoc.
|
|
|
|
## File layout
|
|
|
|
```markdown
|
|
---
|
|
title: Wakkanai
|
|
type: story
|
|
wiki:
|
|
publish: true
|
|
---
|
|
|
|
## Section 1
|
|
### The coast or the shore
|
|
|
|
... body markdown ...
|
|
```
|
|
|
|
The renderer parses the frontmatter, validates required fields, then hands the body to Pandoc. The first-line `# Heading` is preserved — use it if you want an h1 on the rendered page.
|
|
|
|
## Fields
|
|
|
|
### Required
|
|
|
|
#### `title` (string)
|
|
|
|
The MediaWiki page name, without the `SES:` prefix — the pipeline prepends it automatically. MediaWiki capitalises the first letter; lowercase input is fine.
|
|
|
|
Example: `title: Wakkanai` → wiki page `SES:Wakkanai` at URL `/wiki/SES:Wakkanai`.
|
|
|
|
#### `wiki.publish` (boolean)
|
|
|
|
Publishing gate. `true` means the pipeline writes this file to the wiki. `false` means the file is ignored.
|
|
|
|
`wiki` must be a YAML mapping, not a list:
|
|
|
|
```yaml
|
|
# correct
|
|
wiki:
|
|
publish: true
|
|
|
|
# wrong — will be silently skipped
|
|
wiki:
|
|
- publish: true
|
|
```
|
|
|
|
### Optional
|
|
|
|
#### `type` (string)
|
|
|
|
The page type. Drives `[[Category:SES:<type>]]` injection. If omitted, the pipeline falls back to the file's immediate parent directory name (`stories`, `people`, `places`, etc.).
|
|
|
|
Example: `type: story` → `[[Category:SES:story]]`.
|
|
|
|
If neither `type` nor a meaningful directory name is available (file sits at the repo root), the fallback is `uncategorized`.
|
|
|
|
#### `categories` (list of strings)
|
|
|
|
Additional wiki categories to inject beyond the automatic `SES` and `SES:<type>` ones. Each entry becomes `[[Category:<value>]]`.
|
|
|
|
```yaml
|
|
categories:
|
|
- Featured
|
|
```
|
|
|
|
## Body
|
|
|
|
Plain markdown. The body is passed through Pandoc as-is — the first-line `# Heading` is not stripped, so you can use h1 elements freely. Do not embed raw wikitext (`{{Template}}`, raw `[[Wikilinks]]`, etc.) unless you intend the literal output.
|
|
|
|
## Renderer behaviour
|
|
|
|
For each `.md` with `wiki.publish: true`:
|
|
|
|
1. Parse and validate frontmatter.
|
|
2. Pipe the body through `pandoc -f markdown -t mediawiki`.
|
|
4. Prepend the auto-generated banner: `{{Auto-generated|source=<source URL>|commit=<sha>}}`.
|
|
5. Append category tags: `[[Category:SES]]`, `[[Category:SES:<type>]]`, and any entries from `categories`.
|
|
6. Read the current wiki page content via the MediaWiki API; if identical to the generated output, skip the write (idempotency).
|
|
7. If the page exists and does not start with `{{Auto-generated`, skip with a warning (manual page protection).
|
|
8. Otherwise, write the page with an edit summary referencing the source commit.
|
|
|
|
## Implemented scope
|
|
|
|
- Frontmatter parsing and validation
|
|
- `SES:` title prefix
|
|
- Pandoc-based markdown → wikitext body rendering (h1 elements preserved)
|
|
- Banner template injection
|
|
- `Category:SES` + `Category:SES:<type>` injection (type from frontmatter, fallback to parent directory)
|
|
- Additional categories via `categories` list
|
|
- Idempotent writes (no-op skip when content matches)
|
|
- Manual-page protection (skip pages without auto-gen banner)
|
|
- Files without `wiki.publish: true` silently skipped
|
|
|
|
## Not in scope (intentional)
|
|
|
|
- Sibling/cross-page link resolution — write wikilinks directly in the body
|
|
- Separate upload of companion files (no LRC equivalent)
|
|
|
|
## Examples
|
|
|
|
### A story chapter
|
|
|
|
```yaml
|
|
---
|
|
title: Wakkanai
|
|
type: story
|
|
wiki:
|
|
publish: true
|
|
---
|
|
```
|
|
|
|
Wiki page: `SES:Wakkanai`. Categories: `SES`, `SES:story`.
|
|
|
|
### A world entry (type from directory)
|
|
|
|
```yaml
|
|
---
|
|
title: Emms White
|
|
wiki:
|
|
publish: true
|
|
---
|
|
```
|
|
|
|
File at `world/people/emms_white.md`. Type falls back to `people`.
|
|
Wiki page: `SES:Emms White`. Categories: `SES`, `SES:people`.
|
|
|
|
### A draft (not published)
|
|
|
|
```yaml
|
|
---
|
|
title: Helsinki
|
|
type: place
|
|
wiki:
|
|
publish: false
|
|
---
|
|
```
|
|
|
|
## Validation errors the renderer must produce
|
|
|
|
Files without `wiki.publish: true` are silently skipped. The pipeline fails fast only on opted-in files with invalid data:
|
|
|
|
- Missing or empty `title` on a file with `wiki.publish: true`
|
|
- `wiki.publish` present but not a boolean
|
|
- `categories` (if present) is not a list
|
|
- Two publishable source files resolve to the same wiki title
|