Document the v2 operator migration
This commit is contained in:
@@ -44,8 +44,9 @@ the durable copied session input.
|
|||||||
|
|
||||||
### Read-only effective pipeline inspection
|
### Read-only effective pipeline inspection
|
||||||
|
|
||||||
`narratio config validate`, `narratio config show`, and `narratio config
|
`narratio config validate`, `narratio config show`, `narratio config sources`,
|
||||||
sources` use the same `--config`, `--campaign`, `--campaign-file`, and
|
and `narratio config artifacts` use the same `--config`, `--campaign`,
|
||||||
|
`--campaign-file`, and
|
||||||
`--profile` selection rules as pipeline commands, but do not select, discover,
|
`--profile` selection rules as pipeline commands, but do not select, discover,
|
||||||
or load a session. They resolve configured typed credential references as part
|
or load a session. They resolve configured typed credential references as part
|
||||||
of the ordinary ConfigKit load but expose only their environment-variable names;
|
of the ordinary ConfigKit load but expose only their environment-variable names;
|
||||||
@@ -61,10 +62,12 @@ then parses the campaign-owned party and expands concrete artifacts and any
|
|||||||
family publish rules before validation. `config validate` prints the resulting
|
family publish rules before validation. `config validate` prints the resulting
|
||||||
root, profile, and effective digest. `config show` emits the normalized
|
root, profile, and effective digest. `config show` emits the normalized
|
||||||
effective pipeline YAML, with defaults and concrete expansion included but
|
effective pipeline YAML, with defaults and concrete expansion included but
|
||||||
ConfigKit directives and family declarations omitted. `config sources` prints a stable
|
ConfigKit directives and family declarations omitted. This review projection is
|
||||||
|
not promised to be a reloadable authoring document. `config sources` prints a stable
|
||||||
source projection instead of effective values: root/import/profile/default
|
source projection instead of effective values: root/import/profile/default
|
||||||
ownership plus campaign/party and generated-family records. Canonical derived
|
ownership plus campaign/party and generated-family records. Canonical derived
|
||||||
players trace to the party. The [CLI reference](cli.md#config-validate-config-show-config-sources-and-config-diff)
|
players trace to the party. `config artifacts` lists the concrete artifact map,
|
||||||
|
effective dependencies, and defining sources. The [CLI reference](cli.md#config-validate-config-show-config-sources-config-artifacts-and-config-diff)
|
||||||
owns command syntax and output conventions.
|
owns command syntax and output conventions.
|
||||||
|
|
||||||
`config diff` compares normalized field values rather than YAML text or source
|
`config diff` compares normalized field values rather than YAML text or source
|
||||||
@@ -78,14 +81,14 @@ difference.
|
|||||||
### Migrating to the maintained bundle
|
### Migrating to the maintained bundle
|
||||||
|
|
||||||
Use the [production/testing bundle](../examples/production-testing/pipeline.yml)
|
Use the [production/testing bundle](../examples/production-testing/pipeline.yml)
|
||||||
as the complete copyable migration reference. Split stable pipeline settings
|
as the complete copyable migration reference. Keep production settings in the
|
||||||
into explicit additive imports and place production/testing differences in the
|
base, split them into explicit additive imports, and place testing differences
|
||||||
fixed `profiles/production.yml` and `profiles/testing.yml` overlays. Convert
|
in the fixed `profiles/testing.yml` overlay. Put ordinary artifacts and families
|
||||||
campaign
|
in the recommended one-definition files shown by that bundle. Convert campaign
|
||||||
rosters to [canonical party input](integrations/party.md), then express
|
rosters to [canonical party input](integrations/party.md), then express character
|
||||||
character work as families. Inspect the result
|
work as families. Inspect the result with `config validate`, `config show`,
|
||||||
with `config validate`, `config show`, and `config sources`; use `config diff`
|
`config sources`, and `config artifacts`; use `config diff default testing` to
|
||||||
to review profiles before running a session. Unversioned party documents are
|
review the overlay before running a session. Unversioned party documents are
|
||||||
rejected.
|
rejected.
|
||||||
|
|
||||||
### Identity segments
|
### Identity segments
|
||||||
@@ -116,6 +119,11 @@ remote state with an unsafe legacy identity must be migrated before use.
|
|||||||
- Session files must be concrete; unresolved `{{ ... }}` placeholders fail load.
|
- Session files must be concrete; unresolved `{{ ... }}` placeholders fail load.
|
||||||
- Session and party inputs inspected before typed loading are limited to 8 MiB.
|
- Session and party inputs inspected before typed loading are limited to 8 MiB.
|
||||||
- Pipeline defaults are applied before validation.
|
- Pipeline defaults are applied before validation.
|
||||||
|
- Defaults apply only to absent fields. Explicit empty strings, zero values,
|
||||||
|
`false`, and `null` retain ConfigKit's typed meaning and are then checked by
|
||||||
|
Narratio domain validation; they are not silently replaced by defaults.
|
||||||
|
Explicit null optional stage sections stay absent, while required sections
|
||||||
|
fail validation.
|
||||||
- Campaign and session identities must agree.
|
- Campaign and session identities must agree.
|
||||||
- Required stable files (`speakers_file`, `autocorrect_file`, `glossary_file`,
|
- Required stable files (`speakers_file`, `autocorrect_file`, `glossary_file`,
|
||||||
`party_file`) are campaign-owned; the first three may be overridden by the
|
`party_file`) are campaign-owned; the first three may be overridden by the
|
||||||
|
|||||||
@@ -58,10 +58,12 @@ Configured definitions are always registered. Without an explicit selection,
|
|||||||
the effective analyze set contains enabled definitions. With `--artifacts`, the
|
the effective analyze set contains enabled definitions. With `--artifacts`, the
|
||||||
exact named configured definitions become the effective set for that invocation,
|
exact named configured definitions become the effective set for that invocation,
|
||||||
regardless of their `enabled` value. The effective-set resolver itself does not
|
regardless of their `enabled` value. The effective-set resolver itself does not
|
||||||
expand dependencies; the analyze work planner closes those targets over their
|
expand dependencies. Configuration has already materialized the sorted union of
|
||||||
configured prerequisite graph. Availability is separate from executability.
|
explicit ordering edges and configured-artifact input edges, and the analyze
|
||||||
Configuration may normalize a family selection into its concrete generated
|
work planner closes targets over that one concrete prerequisite graph.
|
||||||
members before this resolver runs. The effective set retains optional family
|
Availability is separate from executability. Configuration may normalize a
|
||||||
|
family selection into its concrete generated members before this resolver runs.
|
||||||
|
The effective set retains optional family
|
||||||
and character origin metadata, but its keys, catalog sources, and runtime
|
and character origin metadata, but its keys, catalog sources, and runtime
|
||||||
lookups remain concrete configured-artifact identities.
|
lookups remain concrete configured-artifact identities.
|
||||||
Family publish policies are likewise expanded into ordinary configured-source
|
Family publish policies are likewise expanded into ordinary configured-source
|
||||||
|
|||||||
@@ -53,13 +53,16 @@ the same typed loader and retain the existing post-load identity expectations,
|
|||||||
stable-input precedence, and source-relative path semantics.
|
stable-input precedence, and source-relative path semantics.
|
||||||
|
|
||||||
The application also has a separate read-only inspection resolver for `config
|
The application also has a separate read-only inspection resolver for `config
|
||||||
validate`, `config show`, and `config sources`. It uses the same production root/profile and
|
validate`, `config show`, `config sources`, and `config artifacts`. It uses the same production root/profile and
|
||||||
campaign selection functions, but never routes through session discovery,
|
campaign selection functions, but never routes through session discovery,
|
||||||
remote-session download, secret loading, adapter composition, workspace
|
remote-session download, adapter composition, workspace
|
||||||
initialization, manifest access, or cleanup. A pipeline with retained artifact
|
initialization, manifest access, or cleanup. A pipeline with retained artifact
|
||||||
family declarations must resolve its selected campaign before ordinary pipeline
|
family declarations must resolve its selected campaign before ordinary pipeline
|
||||||
validation, which expands its canonical-party members and generated publish
|
validation, which expands its canonical-party members and generated publish
|
||||||
rules. A pipeline without those declarations may be validated by itself.
|
rules. A pipeline without those declarations may be validated by itself.
|
||||||
|
Secret-directory bootstrap remains invocation-scoped and happens before the
|
||||||
|
ordinary ConfigKit load because explicit typed references must resolve even for
|
||||||
|
inspection.
|
||||||
|
|
||||||
`MarshalEffectivePipeline` is the configuration-owned projection for `config
|
`MarshalEffectivePipeline` is the configuration-owned projection for `config
|
||||||
show`. It serializes one explicit typed safe projection with the existing YAML
|
show`. It serializes one explicit typed safe projection with the existing YAML
|
||||||
@@ -77,6 +80,12 @@ Campaign records identify campaign-owned fields and party inputs; canonical
|
|||||||
derived players point to the party source. The application command only joins these sorted
|
derived players point to the party source. The application command only joins these sorted
|
||||||
records with selection metadata and never reparses configuration files.
|
records with selection metadata and never reparses configuration files.
|
||||||
|
|
||||||
|
`EffectiveArtifactCatalog` projects the same finalized concrete artifact map for
|
||||||
|
`config artifacts`. It derives source identity from each map key, carries sorted
|
||||||
|
effective dependencies, aggregates ConfigKit definition contributors, and adds
|
||||||
|
family/character/party provenance for generated members. It does not inspect
|
||||||
|
files named after artifacts or infer another runtime graph.
|
||||||
|
|
||||||
`config diff` uses a thin paired loader that performs two independent ConfigKit
|
`config diff` uses a thin paired loader that performs two independent ConfigKit
|
||||||
loads. When campaign
|
loads. When campaign
|
||||||
resolution is needed, the command loads one selected campaign and party and
|
resolution is needed, the command loads one selected campaign and party and
|
||||||
|
|||||||
@@ -76,12 +76,15 @@ value from the last value persisted in the session manifest, which helps
|
|||||||
diagnose profile switches without changing resume authority.
|
diagnose profile switches without changing resume authority.
|
||||||
|
|
||||||
Before switching an operational profile, compare its effective meaning with the
|
Before switching an operational profile, compare its effective meaning with the
|
||||||
current selection through `narratio config diff <left-profile> <right-profile>`.
|
production base through `narratio config diff default <profile>`.
|
||||||
The command is read-only and succeeds whether it finds differences or not. Its
|
The command is read-only and succeeds whether it finds differences or not. Its
|
||||||
sorted records describe defaulted, expanded concrete configuration—not source
|
sorted records describe defaulted, expanded concrete configuration—not source
|
||||||
file layout—so it can be used to review model, artifact, and publish changes
|
file layout—so it can be used to review model, artifact, and publish changes
|
||||||
without creating a session or run. Select the same campaign explicitly when
|
without creating a session or run. Use `narratio config artifacts` to review the
|
||||||
profiles could resolve different campaign paths; see the [CLI reference](cli.md#config-validate-config-show-config-sources-and-config-diff) for syntax and record format.
|
concrete artifact identities, definitions, outputs, and dependencies. Select the
|
||||||
|
same campaign explicitly when profiles could resolve different campaign paths;
|
||||||
|
see the [CLI reference](cli.md#config-validate-config-show-config-sources-config-artifacts-and-config-diff)
|
||||||
|
for syntax and record format.
|
||||||
|
|
||||||
## Stage Execution and Continuation Behavior
|
## Stage Execution and Continuation Behavior
|
||||||
|
|
||||||
|
|||||||
@@ -22,5 +22,7 @@ See the [release procedure](../release.md) for creating a candidate and tag.
|
|||||||
When asynchronous publication succeeds, the corresponding Gitea release is the
|
When asynchronous publication succeeds, the corresponding Gitea release is the
|
||||||
canonical source for downloadable binaries and checksums.
|
canonical source for downloadable binaries and checksums.
|
||||||
|
|
||||||
|
- [v2.0.0](v2.0.0.md)
|
||||||
|
- [v1.7.0](v1.7.0.md)
|
||||||
- [v1.6.0](v1.6.0.md)
|
- [v1.6.0](v1.6.0.md)
|
||||||
- [v1.5.0](v1.5.0.md)
|
- [v1.5.0](v1.5.0.md)
|
||||||
|
|||||||
92
docs/releases/v2.0.0.md
Normal file
92
docs/releases/v2.0.0.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# Narratio v2.0.0
|
||||||
|
|
||||||
|
Narratio v2.0.0 replaces its configuration infrastructure with ConfigKit,
|
||||||
|
simplifies the supported release platforms, and makes artifact definitions and
|
||||||
|
their effective dependency graph directly inspectable.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Pipeline roots now use ConfigKit v0.1.1 for strict YAML loading, explicit
|
||||||
|
imports, fixed-path named profiles, provenance, defaults, and typed credential
|
||||||
|
references. The recommended production layout keeps production values in the
|
||||||
|
base, defines each ordinary artifact and artifact family in its own imported
|
||||||
|
file, and keeps testing changes in `profiles/testing.yml`.
|
||||||
|
|
||||||
|
Configured-artifact inputs now create their dependency edges automatically.
|
||||||
|
`narratio config artifacts` reports the finalized concrete catalog, including
|
||||||
|
generated party-family members, without loading a session or initializing
|
||||||
|
runtime adapters.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
This is a breaking configuration and platform release. There is no runtime
|
||||||
|
fallback for the retired Narratio composition/profile catalog, `pipeline.secrets`
|
||||||
|
or `secrets.env_dir`, credential `_env` fields, or the previous YAML
|
||||||
|
presence/default behavior. Defaults apply only to absent values; explicit empty,
|
||||||
|
zero, false, and null values retain their typed meaning and may fail Narratio
|
||||||
|
domain validation.
|
||||||
|
|
||||||
|
The maintained binaries are Linux amd64, Linux arm64, and macOS arm64. Windows
|
||||||
|
and macOS amd64 builds are no longer produced or supported. Existing v1 release
|
||||||
|
notes remain historical descriptions of their releases.
|
||||||
|
|
||||||
|
Inspection commands still avoid session, manifest, workspace, adapter, and
|
||||||
|
remote-service activity, but they are not credential-free loaders: every
|
||||||
|
explicit typed credential reference must resolve. Pipelines containing artifact
|
||||||
|
families also require a campaign so the canonical party can be expanded.
|
||||||
|
`config show` is a secret-safe review projection, not a promised reloadable
|
||||||
|
authoring file.
|
||||||
|
|
||||||
|
## Upgrade
|
||||||
|
|
||||||
|
Migrate each operational bundle before running v2:
|
||||||
|
|
||||||
|
1. Replace old composition syntax with root-owned
|
||||||
|
[`configkit.imports`](../config.md#pipeline-imports-and-profiles). Imports are
|
||||||
|
additive base sources; they do not override one another.
|
||||||
|
2. Fold the old production overlay into the base pipeline. Move testing changes
|
||||||
|
to `profiles/testing.yml`; compare the two independent resolutions with
|
||||||
|
`narratio config diff default testing`.
|
||||||
|
3. Follow the maintained
|
||||||
|
[`examples/production-testing`](../../examples/production-testing/pipeline.yml)
|
||||||
|
layout: one explicit artifact entry per `artifacts/<key>.yml` and one family
|
||||||
|
entry per `artifact-families/<key>.yml`. The map key, not the filename, is the
|
||||||
|
stable artifact identity.
|
||||||
|
4. Move credential files to an untracked `secrets/` directory beside
|
||||||
|
`pipeline.yml`, or pass `--secrets-dir`. Rename S3 fields to `access_key_id`
|
||||||
|
and `secret_access_key`, and rename the Audita field to `llm_api_key`.
|
||||||
|
5. For static S3 credentials, configure both S3 references (commonly
|
||||||
|
`OBJECT_STORAGE_KEY_ID` and `OBJECT_STORAGE_KEY`) and make them resolvable.
|
||||||
|
To use instance roles, workload identity, shared SDK files, or another AWS SDK
|
||||||
|
discovery provider, omit both references. A partial pair is invalid.
|
||||||
|
6. Remove a `depends_on` entry when it only duplicates a
|
||||||
|
`narratio.artifact.<key>` input. Keep explicit entries that express ordering
|
||||||
|
without supplying the upstream output as an input.
|
||||||
|
7. Review ConfigKit's stricter explicit-value/null semantics and correct values
|
||||||
|
that previously acquired defaults after being explicitly empty. Do not use
|
||||||
|
`config show` output as a source migration mechanism.
|
||||||
|
8. Run `config validate`, `config show`, `config sources`, and `config artifacts`
|
||||||
|
with the same profile, campaign, and secrets selection intended for runtime.
|
||||||
|
Resolve the campaign-owned party whenever families are present.
|
||||||
|
9. Update deployment and download automation to one of the three maintained
|
||||||
|
platform assets before removing the v1 binary.
|
||||||
|
|
||||||
|
The [configuration reference](../config.md), [CLI reference](../cli.md), and
|
||||||
|
[maintained examples](../../examples/README.md) are the canonical detailed
|
||||||
|
guides.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Adopted ConfigKit v0.1.1 across pipeline, campaign, session, and party loading
|
||||||
|
while keeping Narratio domain validation and post-campaign expansion explicit.
|
||||||
|
- Added ConfigKit imports and fixed `profiles/<name>.yml` pipeline overlays,
|
||||||
|
unified safe effective show/diff/digest projection, and source provenance.
|
||||||
|
- Added invocation-scoped ConfigKit secrets-directory bootstrap and typed S3 and
|
||||||
|
Audita credential references without exposing resolved values.
|
||||||
|
- Inferred, normalized, and validated configured-artifact input dependencies as
|
||||||
|
part of the one concrete graph consumed by analyze planning and resume logic.
|
||||||
|
- Added `config artifacts` with stable concrete identities, definition sources,
|
||||||
|
effective dependencies, and generated family/party provenance.
|
||||||
|
- Added the maintained production-base/testing-overlay artifact authoring layout.
|
||||||
|
- Reduced release assets and active platform support to Linux amd64/arm64 and
|
||||||
|
macOS arm64.
|
||||||
@@ -426,7 +426,13 @@ Document the command in its canonical CLI owner and link to config layout exampl
|
|||||||
|
|
||||||
## Stage 10 — Finish the operator layout and v2 migration documentation
|
## Stage 10 — Finish the operator layout and v2 migration documentation
|
||||||
|
|
||||||
Status: Pending
|
Status: Complete
|
||||||
|
|
||||||
|
Completion: Reworked the maintained bundle around an unprofiled production base,
|
||||||
|
one-entry artifact and family imports, and a testing overlay; updated the example
|
||||||
|
harness and inspection workflows; consolidated the v2 configuration guidance; and
|
||||||
|
added the v2.0.0 operator migration checklist. Focused documentation/example tests,
|
||||||
|
the offline inspection walkthrough, and the full normal/race suites pass.
|
||||||
|
|
||||||
Read: roadmap “Artifact Definition Ergonomics” and “Compatibility and Migration”;
|
Read: roadmap “Artifact Definition Ergonomics” and “Compatibility and Migration”;
|
||||||
`examples/README.md`, existing example bundles and their loader test,
|
`examples/README.md`, existing example bundles and their loader test,
|
||||||
|
|||||||
@@ -11,18 +11,26 @@ in the [configuration reference](../docs/config.md).
|
|||||||
WhisperX URL.
|
WhisperX URL.
|
||||||
- [Production-shaped pipeline](pipeline.production.yml): S3 storage, publish,
|
- [Production-shaped pipeline](pipeline.production.yml): S3 storage, publish,
|
||||||
external tools, and configured Scriptorium artifacts.
|
external tools, and configured Scriptorium artifacts.
|
||||||
- [Production/testing split bundle](production-testing/pipeline.yml): explicit
|
- [Production-base/testing-overlay bundle](production-testing/pipeline.yml):
|
||||||
`conf.d` imports, a production default, and selectable production/testing
|
explicit `conf.d` imports, one ordinary artifact per `artifacts/<key>.yml`,
|
||||||
overlays. It also demonstrates canonical-party artifact families and a
|
one family per `artifact-families/<key>.yml`, and the fixed
|
||||||
testing-only disabled artifact. Validate it with:
|
`profiles/testing.yml` overlay. Production values live in the base. The
|
||||||
|
bundle demonstrates an input-only artifact dependency, two character families
|
||||||
|
sharing the campaign party, and a testing-only disabled artifact. Inspect it
|
||||||
|
offline with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
narratio config validate --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml
|
narratio config validate --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml
|
||||||
narratio config diff production testing --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml
|
narratio config show --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml --profile testing
|
||||||
|
narratio config sources --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml --profile testing
|
||||||
|
narratio config artifacts --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml --profile testing
|
||||||
|
narratio config diff default testing --config examples/production-testing/pipeline.yml --campaign-file examples/campaigns/sample-campaign/campaign.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
`config show` and `config sources` accept the same selectors and remain
|
These inspection commands load configuration and resolve explicit credential
|
||||||
read-only.
|
references, but do not load a session or create runtime state. This bundle is
|
||||||
|
intentionally local-storage and credential-reference free so the walkthrough
|
||||||
|
needs no tools or cloud services.
|
||||||
- [Full annotated pipeline](pipeline.full.annotated.yml): every implemented
|
- [Full annotated pipeline](pipeline.full.annotated.yml): every implemented
|
||||||
pipeline section with explanatory comments.
|
pipeline section with explanatory comments.
|
||||||
- [Extraction subset pipeline](pipeline.extraction-subset.yml): a focused
|
- [Extraction subset pipeline](pipeline.extraction-subset.yml): a focused
|
||||||
@@ -63,3 +71,9 @@ The examples contain environment-variable names but no credential values. Set
|
|||||||
nonempty synthetic or real values before loading the production-shaped and full
|
nonempty synthetic or real values before loading the production-shaped and full
|
||||||
annotated pipelines. They use fictional campaign content and reserved example
|
annotated pipelines. They use fictional campaign content and reserved example
|
||||||
domains.
|
domains.
|
||||||
|
|
||||||
|
For a deployed bundle, keep credential files out of source control in a
|
||||||
|
`secrets/` directory beside the root `pipeline.yml`, one file per referenced
|
||||||
|
environment-variable name, or select another directory with `--secrets-dir`.
|
||||||
|
Static S3 credentials are optional: omit both S3 credential references to use
|
||||||
|
the AWS SDK discovery chain.
|
||||||
|
|||||||
@@ -1,23 +1,11 @@
|
|||||||
scriptorium:
|
scriptorium:
|
||||||
binary: scriptorium
|
|
||||||
config_path: ./scriptorium/config.yml
|
|
||||||
artifact_families:
|
artifact_families:
|
||||||
character_meta:
|
|
||||||
enabled: true
|
|
||||||
for_each: party.characters
|
|
||||||
prompt_id: dnd.character_meta
|
|
||||||
output_path_pattern: artifacts/characters/{character_id}/meta.md
|
|
||||||
member_vars:
|
|
||||||
character_id: character_id
|
|
||||||
character_name: character.name
|
|
||||||
player_name: player.name
|
|
||||||
class_summary: character.class_summary
|
|
||||||
character_items:
|
character_items:
|
||||||
enabled: true
|
enabled: true
|
||||||
for_each: party.characters
|
for_each: party.characters
|
||||||
prompt_id: dnd.character_items
|
prompt_id: dnd.character_items
|
||||||
|
profile_id: production-placeholder
|
||||||
output_path_pattern: artifacts/characters/{character_id}/items.md
|
output_path_pattern: artifacts/characters/{character_id}/items.md
|
||||||
member_dependencies: [character_meta]
|
|
||||||
inputs:
|
inputs:
|
||||||
character_meta:
|
character_meta:
|
||||||
source: narratio.member_artifact.character_meta
|
source: narratio.member_artifact.character_meta
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
scriptorium:
|
||||||
|
artifact_families:
|
||||||
|
character_meta:
|
||||||
|
enabled: true
|
||||||
|
for_each: party.characters
|
||||||
|
prompt_id: dnd.character_meta
|
||||||
|
profile_id: production-placeholder
|
||||||
|
output_path_pattern: artifacts/characters/{character_id}/meta.md
|
||||||
|
member_vars:
|
||||||
|
character_id: character_id
|
||||||
|
character_name: character.name
|
||||||
|
player_name: player.name
|
||||||
|
class_summary: character.class_summary
|
||||||
11
examples/production-testing/artifacts/player_handout.yml
Normal file
11
examples/production-testing/artifacts/player_handout.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
scriptorium:
|
||||||
|
artifacts:
|
||||||
|
player_handout:
|
||||||
|
enabled: true
|
||||||
|
prompt_id: dnd.player_handout
|
||||||
|
profile_id: production-placeholder
|
||||||
|
output_path: artifacts/player-handout.md
|
||||||
|
inputs:
|
||||||
|
recap:
|
||||||
|
source: narratio.artifact.session_recap
|
||||||
|
required: true
|
||||||
11
examples/production-testing/artifacts/session_recap.yml
Normal file
11
examples/production-testing/artifacts/session_recap.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
scriptorium:
|
||||||
|
artifacts:
|
||||||
|
session_recap:
|
||||||
|
enabled: true
|
||||||
|
prompt_id: dnd.session_recap
|
||||||
|
profile_id: production-placeholder
|
||||||
|
output_path: artifacts/session-recap.md
|
||||||
|
inputs:
|
||||||
|
transcript:
|
||||||
|
source: narratio.transcript.final_trimmed
|
||||||
|
required: true
|
||||||
@@ -10,6 +10,8 @@ audita:
|
|||||||
binary: audita
|
binary: audita
|
||||||
modules: [glossary, grammar]
|
modules: [glossary, grammar]
|
||||||
output_schema: audita-v1
|
output_schema: audita-v1
|
||||||
|
model: narratio-production-model-placeholder
|
||||||
|
validation_model: narratio-production-validator-placeholder
|
||||||
|
|
||||||
normalize:
|
normalize:
|
||||||
output_path: transcripts/final.json
|
output_path: transcripts/final.json
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
# Copyable production/testing pipeline entry point. Every fragment is named
|
# Copyable production-base/testing-overlay entry point. ConfigKit expands only
|
||||||
# explicitly; Narratio never scans conf.d automatically.
|
# these explicit path and glob imports; Narratio never scans directories itself.
|
||||||
configkit:
|
configkit:
|
||||||
imports:
|
imports:
|
||||||
- path: conf.d/platform.yml
|
- path: conf.d/platform.yml
|
||||||
- path: conf.d/storage.yml
|
- path: conf.d/storage.yml
|
||||||
- path: conf.d/transcript.yml
|
- path: conf.d/transcript.yml
|
||||||
- path: conf.d/artifacts.yml
|
|
||||||
- path: conf.d/publish.yml
|
- path: conf.d/publish.yml
|
||||||
|
- glob: artifacts/*.yml
|
||||||
|
- glob: artifact-families/*.yml
|
||||||
|
|
||||||
|
scriptorium:
|
||||||
|
binary: scriptorium
|
||||||
|
config_path: ./scriptorium/config.yml
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
audita:
|
|
||||||
model: narratio-production-model-placeholder
|
|
||||||
validation_model: narratio-production-validator-placeholder
|
|
||||||
|
|
||||||
scriptorium:
|
|
||||||
artifact_families:
|
|
||||||
character_meta:
|
|
||||||
profile_id: production-placeholder
|
|
||||||
character_items:
|
|
||||||
profile_id: production-placeholder
|
|
||||||
@@ -4,6 +4,10 @@ audita:
|
|||||||
|
|
||||||
scriptorium:
|
scriptorium:
|
||||||
artifacts:
|
artifacts:
|
||||||
|
session_recap:
|
||||||
|
profile_id: testing-placeholder
|
||||||
|
player_handout:
|
||||||
|
profile_id: testing-placeholder
|
||||||
testing_notes:
|
testing_notes:
|
||||||
enabled: false
|
enabled: false
|
||||||
output_path: artifacts/testing-notes.md
|
output_path: artifacts/testing-notes.md
|
||||||
|
|||||||
@@ -253,11 +253,11 @@ func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testi
|
|||||||
}
|
}
|
||||||
|
|
||||||
var validated bytes.Buffer
|
var validated bytes.Buffer
|
||||||
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath, "--profile", "production"}, &validated); err != nil {
|
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &validated); err != nil {
|
||||||
t.Fatalf("validate production profile: %v", err)
|
t.Fatalf("validate production base: %v", err)
|
||||||
}
|
}
|
||||||
if !strings.Contains(validated.String(), "profile=production") {
|
if !strings.Contains(validated.String(), "profile=none") {
|
||||||
t.Fatalf("validate output = %q, want production profile", validated.String())
|
t.Fatalf("validate output = %q, want unprofiled production base", validated.String())
|
||||||
}
|
}
|
||||||
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigShow, ConfigSources} {
|
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigShow, ConfigSources} {
|
||||||
if err := command(context.Background(), []string{
|
if err := command(context.Background(), []string{
|
||||||
@@ -268,7 +268,7 @@ func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testi
|
|||||||
}
|
}
|
||||||
var diff bytes.Buffer
|
var diff bytes.Buffer
|
||||||
if err := ConfigDiff(context.Background(), []string{
|
if err := ConfigDiff(context.Background(), []string{
|
||||||
"production", "testing", "--config", pipelinePath, "--campaign-file", campaignPath,
|
"default", "testing", "--config", pipelinePath, "--campaign-file", campaignPath,
|
||||||
}, &diff); err != nil {
|
}, &diff); err != nil {
|
||||||
t.Fatalf("compare profiles: %v", err)
|
t.Fatalf("compare profiles: %v", err)
|
||||||
}
|
}
|
||||||
@@ -330,7 +330,7 @@ func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testi
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAssembledSplitBundleProfileSwitchRecordsProvenanceAndLimitsReuse(t *testing.T) {
|
func TestAssembledSplitBundleProfileSwitchRecordsProvenanceAndLimitsReuse(t *testing.T) {
|
||||||
production := loadAssembledSplitBundleConfig(t, "production")
|
production := loadAssembledSplitBundleConfig(t, "")
|
||||||
testingCfg := loadAssembledSplitBundleConfig(t, "testing")
|
testingCfg := loadAssembledSplitBundleConfig(t, "testing")
|
||||||
workspace := t.TempDir()
|
workspace := t.TempDir()
|
||||||
production.Pipeline.Workspace.Root = workspace
|
production.Pipeline.Workspace.Root = workspace
|
||||||
@@ -365,7 +365,7 @@ func TestAssembledSplitBundleProfileSwitchRecordsProvenanceAndLimitsReuse(t *tes
|
|||||||
if !reflect.DeepEqual(productionRuns, make([]int, len(names))) {
|
if !reflect.DeepEqual(productionRuns, make([]int, len(names))) {
|
||||||
t.Fatalf("production runs = %v, want complete reuse", productionRuns)
|
t.Fatalf("production runs = %v, want complete reuse", productionRuns)
|
||||||
}
|
}
|
||||||
assertAssembledProvenance(t, store, productionSummary, "production", config.EffectivePipelineDigest(production.Pipeline))
|
assertAssembledProvenance(t, store, productionSummary, "", config.EffectivePipelineDigest(production.Pipeline))
|
||||||
|
|
||||||
testingRuns := make([]int, len(names))
|
testingRuns := make([]int, len(names))
|
||||||
testingStages := assembledSemanticStages(names, providers, testingRuns)
|
testingStages := assembledSemanticStages(names, providers, testingRuns)
|
||||||
@@ -415,7 +415,9 @@ func assertAssembledProvenance(t *testing.T, store *manifest.LocalStore, summary
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
value := session.EffectiveConfig
|
value := session.EffectiveConfig
|
||||||
if value == nil || value.SelectedProfile == nil || value.SelectedProfile.Name != profile || value.EffectiveConfigDigest != digest {
|
profileMatches := value != nil && ((profile == "" && value.SelectedProfile == nil) ||
|
||||||
|
(profile != "" && value.SelectedProfile != nil && value.SelectedProfile.Name == profile))
|
||||||
|
if !profileMatches || value.EffectiveConfigDigest != digest {
|
||||||
t.Fatalf("effective configuration provenance = %#v, want profile=%q digest=%q", value, profile, digest)
|
t.Fatalf("effective configuration provenance = %#v, want profile=%q digest=%q", value, profile, digest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,12 +370,12 @@ func TestConfigCommandsInspectMaintainedSplitBundleWithoutRuntimeState(t *testin
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigValidate, ConfigShow, ConfigSources, ConfigArtifacts} {
|
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigValidate, ConfigShow, ConfigSources, ConfigArtifacts} {
|
||||||
if err := command(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath, "--profile", "production"}, io.Discard); err != nil {
|
if err := command(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, io.Discard); err != nil {
|
||||||
t.Fatalf("inspection command %T error = %v", command, err)
|
t.Fatalf("inspection command %T error = %v", command, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var diff bytes.Buffer
|
var diff bytes.Buffer
|
||||||
if err := ConfigDiff(context.Background(), []string{"production", "testing", "--config", pipelinePath, "--campaign-file", campaignPath}, &diff); err != nil {
|
if err := ConfigDiff(context.Background(), []string{"default", "testing", "--config", pipelinePath, "--campaign-file", campaignPath}, &diff); err != nil {
|
||||||
t.Fatalf("ConfigDiff() error = %v", err)
|
t.Fatalf("ConfigDiff() error = %v", err)
|
||||||
}
|
}
|
||||||
if !strings.Contains(diff.String(), "audita.model") {
|
if !strings.Contains(diff.String(), "audita.model") {
|
||||||
|
|||||||
@@ -285,15 +285,19 @@ func TestExamplesLoadAndValidate(t *testing.T) {
|
|||||||
t.Fatalf("load split bundle campaign: %v", err)
|
t.Fatalf("load split bundle campaign: %v", err)
|
||||||
}
|
}
|
||||||
for _, profile := range []struct {
|
for _, profile := range []struct {
|
||||||
name string
|
name string
|
||||||
model string
|
selection string
|
||||||
|
model string
|
||||||
}{
|
}{
|
||||||
{name: "production", model: "narratio-production-model-placeholder"},
|
{name: "production base", model: "narratio-production-model-placeholder"},
|
||||||
{name: "testing", model: "narratio-testing-model-placeholder"},
|
{name: "testing", selection: "testing", model: "narratio-testing-model-placeholder"},
|
||||||
} {
|
} {
|
||||||
t.Run(profile.name, func(t *testing.T) {
|
t.Run(profile.name, func(t *testing.T) {
|
||||||
selected := profile.name
|
options := PipelineLoadOptions{}
|
||||||
pipeline, err := LoadPipelineWithOptions(pipelinePath, PipelineLoadOptions{Profile: &selected})
|
if profile.selection != "" {
|
||||||
|
options.Profile = &profile.selection
|
||||||
|
}
|
||||||
|
pipeline, err := LoadPipelineWithOptions(pipelinePath, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("load split bundle pipeline: %v", err)
|
t.Fatalf("load split bundle pipeline: %v", err)
|
||||||
}
|
}
|
||||||
@@ -314,10 +318,16 @@ func TestExamplesLoadAndValidate(t *testing.T) {
|
|||||||
if cfg.Pipeline.Audita.LLMAPIKey != nil || cfg.Pipeline.Storage.Backend != StorageBackendLocal || cfg.Pipeline.Storage.S3 != nil {
|
if cfg.Pipeline.Audita.LLMAPIKey != nil || cfg.Pipeline.Storage.Backend != StorageBackendLocal || cfg.Pipeline.Storage.S3 != nil {
|
||||||
t.Fatalf("split bundle must remain offline and secret-free: audita=%#v storage=%#v", cfg.Pipeline.Audita, cfg.Pipeline.Storage)
|
t.Fatalf("split bundle must remain offline and secret-free: audita=%#v storage=%#v", cfg.Pipeline.Audita, cfg.Pipeline.Storage)
|
||||||
}
|
}
|
||||||
if selectedProfile, ok := SelectedPipelineProfile(cfg.Pipeline); !ok || selectedProfile.Name != profile.name {
|
selectedProfile, selected := SelectedPipelineProfile(cfg.Pipeline)
|
||||||
t.Fatalf("selected profile = %#v, want %q", selectedProfile, profile.name)
|
if profile.selection == "" && selected {
|
||||||
|
t.Fatalf("production base unexpectedly selected profile %#v", selectedProfile)
|
||||||
|
}
|
||||||
|
if profile.selection != "" && (!selected || selectedProfile.Name != profile.selection) {
|
||||||
|
t.Fatalf("selected profile = %#v, want %q", selectedProfile, profile.selection)
|
||||||
}
|
}
|
||||||
for _, key := range []string{
|
for _, key := range []string{
|
||||||
|
"session_recap",
|
||||||
|
"player_handout",
|
||||||
"character_meta_arannis",
|
"character_meta_arannis",
|
||||||
"character_meta_brenna",
|
"character_meta_brenna",
|
||||||
"character_items_arannis",
|
"character_items_arannis",
|
||||||
@@ -330,6 +340,12 @@ func TestExamplesLoadAndValidate(t *testing.T) {
|
|||||||
if got := cfg.Pipeline.Scriptorium.Artifacts["character_items_arannis"].Inputs["character_meta"].Source; got != "narratio.artifact.character_meta_arannis" {
|
if got := cfg.Pipeline.Scriptorium.Artifacts["character_items_arannis"].Inputs["character_meta"].Source; got != "narratio.artifact.character_meta_arannis" {
|
||||||
t.Fatalf("same-member input source = %q", got)
|
t.Fatalf("same-member input source = %q", got)
|
||||||
}
|
}
|
||||||
|
if got := cfg.Pipeline.Scriptorium.Artifacts["player_handout"].DependsOn; !reflect.DeepEqual(got, []string{"session_recap"}) {
|
||||||
|
t.Fatalf("input-only artifact dependency = %#v", got)
|
||||||
|
}
|
||||||
|
if got := cfg.Pipeline.Scriptorium.Artifacts["character_items_arannis"].DependsOn; !reflect.DeepEqual(got, []string{"character_meta_arannis"}) {
|
||||||
|
t.Fatalf("family input dependency = %#v", got)
|
||||||
|
}
|
||||||
if cfg.Party.Canonical == nil || len(cfg.Party.Canonical.Characters) != 2 {
|
if cfg.Party.Canonical == nil || len(cfg.Party.Canonical.Characters) != 2 {
|
||||||
t.Fatalf("canonical party = %#v", cfg.Party)
|
t.Fatalf("canonical party = %#v", cfg.Party)
|
||||||
}
|
}
|
||||||
@@ -340,7 +356,18 @@ func TestExamplesLoadAndValidate(t *testing.T) {
|
|||||||
if len(cfg.Pipeline.Publish.Outputs) != 3 {
|
if len(cfg.Pipeline.Publish.Outputs) != 3 {
|
||||||
t.Fatalf("publish outputs = %#v, want transcript plus two family outputs", cfg.Pipeline.Publish.Outputs)
|
t.Fatalf("publish outputs = %#v, want transcript plus two family outputs", cfg.Pipeline.Publish.Outputs)
|
||||||
}
|
}
|
||||||
if profile.name == "testing" {
|
catalog, err := EffectiveArtifactCatalog(cfg.Pipeline, cfg.Party)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
wantCatalogSize := 6
|
||||||
|
if profile.selection == "testing" {
|
||||||
|
wantCatalogSize++
|
||||||
|
}
|
||||||
|
if len(catalog) != wantCatalogSize {
|
||||||
|
t.Fatalf("effective artifact catalog has %d records, want %d", len(catalog), wantCatalogSize)
|
||||||
|
}
|
||||||
|
if profile.selection == "testing" {
|
||||||
artifact, exists := cfg.Pipeline.Scriptorium.Artifacts["testing_notes"]
|
artifact, exists := cfg.Pipeline.Scriptorium.Artifacts["testing_notes"]
|
||||||
if !exists || artifact.Enabled {
|
if !exists || artifact.Enabled {
|
||||||
t.Fatalf("testing-only disabled artifact = %#v", artifact)
|
t.Fatalf("testing-only disabled artifact = %#v", artifact)
|
||||||
|
|||||||
Reference in New Issue
Block a user