Implemented multiple campaign support via a campaign directory registry with explicit campaign IDs
This commit is contained in:
@@ -28,6 +28,7 @@ Behavior:
|
||||
- strict YAML decode is enabled (`KnownFields(true)`): unknown fields fail.
|
||||
- ordinary local and remote `session.yml` files must be concrete YAML; template placeholders are rejected.
|
||||
- defaults are applied for optional pipeline fields.
|
||||
- campaign identity is selected by ID from the pipeline campaign registry unless `--campaign-file` is used.
|
||||
- campaign-level stable input paths fill missing session input paths.
|
||||
- session-level stable input paths override campaign-level input paths.
|
||||
- campaign config may point `session init` to a session template.
|
||||
@@ -60,11 +61,14 @@ Pipeline config lookup:
|
||||
|
||||
Campaign config lookup:
|
||||
|
||||
- if `--campaign <path>` is provided, that path is used.
|
||||
- if omitted, Narratio searches in order:
|
||||
1. `/usr/local/etc/narratio/campaign.yml`
|
||||
2. `/etc/narratio/campaign.yml`
|
||||
- first existing file wins.
|
||||
- pipeline config is loaded first.
|
||||
- if `--campaign-file <path>` is provided, that path is used.
|
||||
- otherwise, if `--campaign <id>` is provided, Narratio loads:
|
||||
- `{pipeline.campaigns.root}/{id}/campaign.yml`
|
||||
- otherwise, Narratio uses `pipeline.campaigns.default_campaign_id` and loads:
|
||||
- `{pipeline.campaigns.root}/{default_campaign_id}/campaign.yml`
|
||||
- `--campaign` and `--campaign-file` are mutually exclusive.
|
||||
- campaign IDs must be single path segments, not paths.
|
||||
|
||||
Session config lookup:
|
||||
|
||||
@@ -76,7 +80,7 @@ Session config lookup:
|
||||
- if no local session file is found, a positional `<session_id>` is present, storage is configured, and campaign identity is resolved, Narratio loads remote `session.yml` from:
|
||||
- `{root_prefix}/campaigns/{campaign}/sessions/{session_id}/session.yml`
|
||||
- local discovery always runs before remote fallback.
|
||||
- local files in the current working directory are used only when passed explicitly, for example `--config ./pipeline.yml --campaign ./campaign.yml --session ./session.yml`.
|
||||
- local files in the current working directory are used only when passed explicitly, for example `--config ./pipeline.yml --campaign-file ./campaign.yml --session ./session.yml`.
|
||||
|
||||
## 3. Session templating
|
||||
|
||||
@@ -109,6 +113,9 @@ Template behavior for `narratio session init`:
|
||||
### `pipeline.yml`
|
||||
|
||||
```yaml
|
||||
campaigns:
|
||||
root: /usr/local/share/narratio/campaigns
|
||||
default_campaign_id: sample-campaign
|
||||
whisperx:
|
||||
transcribe_url: "https://transcription.example.com/transcribe"
|
||||
```
|
||||
@@ -116,13 +123,14 @@ whisperx:
|
||||
Why this is sufficient:
|
||||
|
||||
- `whisperx.transcribe_url` is required.
|
||||
- `campaigns.default_campaign_id` selects the default campaign when `--campaign` is omitted.
|
||||
- `workspace.root` defaults to `/var/lib/narratio`.
|
||||
- optional sections (`seriatim`, `audita`, `archive`, `scriptorium`, `trim`, `normalize`, etc.) receive defaults or stay inactive.
|
||||
|
||||
### `campaign.yml`
|
||||
|
||||
```yaml
|
||||
campaign: sample-campaign
|
||||
campaign_id: sample-campaign
|
||||
session_template_file: ./session.template.yml
|
||||
inputs:
|
||||
speakers_file: ./speakers.yml
|
||||
@@ -132,7 +140,7 @@ inputs:
|
||||
|
||||
Why this is sufficient:
|
||||
|
||||
- `campaign` supplies the stable campaign identity.
|
||||
- `campaign_id` supplies the stable campaign identity.
|
||||
- stable input files are required and resolve relative to `campaign.yml` when copied during `prepare`.
|
||||
|
||||
### `session.yml`
|
||||
@@ -153,7 +161,8 @@ Why this is sufficient:
|
||||
Minimal local-file usage:
|
||||
|
||||
```bash
|
||||
narratio run 2026-05-03 --config /path/to/pipeline.yml --campaign ./campaign.yml --session ./session.yml
|
||||
narratio run 2026-05-03 --config /path/to/pipeline.yml --campaign sample-campaign --session ./session.yml
|
||||
narratio run 2026-05-03 --config /path/to/pipeline.yml --campaign-file ./campaign.yml --session ./session.yml
|
||||
```
|
||||
|
||||
Previous-session-enabled variant:
|
||||
@@ -166,7 +175,7 @@ inputs:
|
||||
```
|
||||
|
||||
```bash
|
||||
narratio run 2026-05-03 --config /path/to/pipeline.yml --campaign ./campaign.yml --session ./session.yml --previous-session-id 2026-04-26
|
||||
narratio run 2026-05-03 --config /path/to/pipeline.yml --campaign sample-campaign --session ./session.yml --previous-session-id 2026-04-26
|
||||
```
|
||||
|
||||
## 5. Production-oriented config set
|
||||
@@ -187,6 +196,10 @@ storage:
|
||||
access_key_id_env: OBJECT_STORAGE_KEY_ID
|
||||
secret_access_key_env: OBJECT_STORAGE_KEY
|
||||
|
||||
campaigns:
|
||||
root: /srv/narratio/campaigns
|
||||
default_campaign_id: forsaken
|
||||
|
||||
spool:
|
||||
root: /var/spool/narratio
|
||||
delete_audio_after_archive: true
|
||||
@@ -230,7 +243,7 @@ scriptorium:
|
||||
### `campaign.yml`
|
||||
|
||||
```yaml
|
||||
campaign: forsaken
|
||||
campaign_id: forsaken
|
||||
inputs:
|
||||
speakers_file: /srv/narratio/campaigns/forsaken/speakers.yml
|
||||
autocorrect_file: /srv/narratio/campaigns/forsaken/autocorrect.yml
|
||||
@@ -260,7 +273,7 @@ For S3-first operation, upload the same `session.yml` content to:
|
||||
Then run with explicit or discovered pipeline/campaign config and no `--session`:
|
||||
|
||||
```bash
|
||||
narratio run 2026-05-03 --config /usr/local/etc/narratio/pipeline.yml --campaign /usr/local/etc/narratio/campaign.yml --previous-session-id 2026-04-26
|
||||
narratio run 2026-05-03 --config /usr/local/etc/narratio/pipeline.yml --campaign forsaken --previous-session-id 2026-04-26
|
||||
```
|
||||
|
||||
Operational notes:
|
||||
@@ -279,6 +292,8 @@ Operational notes:
|
||||
| --- | --- | --- | --- |
|
||||
| `pipeline.workspace.root` | string | No | `/var/lib/narratio` |
|
||||
| `pipeline.workspace.cleanup_after_archive` | bool | No | `false` |
|
||||
| `pipeline.campaigns.root` | string | No | `/usr/local/share/narratio/campaigns` |
|
||||
| `pipeline.campaigns.default_campaign_id` | string | No | empty |
|
||||
| `pipeline.secrets.env_dir` | string | Conditional | none |
|
||||
| `pipeline.storage.backend` | string | No | empty |
|
||||
| `pipeline.storage.s3.bucket` | string | Conditional | empty |
|
||||
@@ -434,7 +449,7 @@ Restore-related implications:
|
||||
|
||||
| Path | Type | Required | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| `campaign.campaign` | string | Yes | none |
|
||||
| `campaign.campaign_id` | string | Yes | none |
|
||||
| `campaign.session_template_file` | string | No | none |
|
||||
| `campaign.inputs.speakers_file` | string | Yes | none |
|
||||
| `campaign.inputs.autocorrect_file` | string | Yes | none |
|
||||
@@ -448,7 +463,7 @@ Campaign input paths and `campaign.session_template_file` may be absolute or rel
|
||||
| --- | --- | --- | --- |
|
||||
| `session.session_id` | string | Yes | none |
|
||||
| `session.previous_session_id` | string | No | empty |
|
||||
| `session.campaign` | string | No | `campaign.campaign` |
|
||||
| `session.campaign` | string | No | `campaign.campaign_id` |
|
||||
| `session.date` | string | No | empty |
|
||||
| `session.title` | string | No | empty |
|
||||
| `session.inputs.audio_dir` | string | Conditional | empty |
|
||||
@@ -499,8 +514,11 @@ Maintained examples:
|
||||
- `examples/pipeline.minimal.yml`
|
||||
- `examples/pipeline.production.yml`
|
||||
- `examples/pipeline.full.annotated.yml`
|
||||
- `examples/campaign.yml`
|
||||
- `examples/session.template.yml`
|
||||
- `examples/campaigns/sample-campaign/campaign.yml`
|
||||
- `examples/campaigns/sample-campaign/speakers.yml`
|
||||
- `examples/campaigns/sample-campaign/autocorrect.yml`
|
||||
- `examples/campaigns/sample-campaign/glossary.yml`
|
||||
- `examples/campaigns/sample-campaign/session.template.yml`
|
||||
- `examples/session.local-audio.yml`
|
||||
- `examples/session.s3-audio.yml`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user