Document the v2 operator migration
This commit is contained in:
@@ -44,8 +44,9 @@ the durable copied session input.
|
||||
|
||||
### Read-only effective pipeline inspection
|
||||
|
||||
`narratio config validate`, `narratio config show`, and `narratio config
|
||||
sources` use the same `--config`, `--campaign`, `--campaign-file`, and
|
||||
`narratio config validate`, `narratio config show`, `narratio config sources`,
|
||||
and `narratio config artifacts` use the same `--config`, `--campaign`,
|
||||
`--campaign-file`, and
|
||||
`--profile` selection rules as pipeline commands, but do not select, discover,
|
||||
or load a session. They resolve configured typed credential references as part
|
||||
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
|
||||
root, profile, and effective digest. `config show` emits the normalized
|
||||
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
|
||||
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.
|
||||
|
||||
`config diff` compares normalized field values rather than YAML text or source
|
||||
@@ -78,14 +81,14 @@ difference.
|
||||
### Migrating to the maintained bundle
|
||||
|
||||
Use the [production/testing bundle](../examples/production-testing/pipeline.yml)
|
||||
as the complete copyable migration reference. Split stable pipeline settings
|
||||
into explicit additive imports and place production/testing differences in the
|
||||
fixed `profiles/production.yml` and `profiles/testing.yml` overlays. Convert
|
||||
campaign
|
||||
rosters to [canonical party input](integrations/party.md), then express
|
||||
character work as families. Inspect the result
|
||||
with `config validate`, `config show`, and `config sources`; use `config diff`
|
||||
to review profiles before running a session. Unversioned party documents are
|
||||
as the complete copyable migration reference. Keep production settings in the
|
||||
base, split them into explicit additive imports, and place testing differences
|
||||
in the fixed `profiles/testing.yml` overlay. Put ordinary artifacts and families
|
||||
in the recommended one-definition files shown by that bundle. Convert campaign
|
||||
rosters to [canonical party input](integrations/party.md), then express character
|
||||
work as families. Inspect the result with `config validate`, `config show`,
|
||||
`config sources`, and `config artifacts`; use `config diff default testing` to
|
||||
review the overlay before running a session. Unversioned party documents are
|
||||
rejected.
|
||||
|
||||
### 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 and party inputs inspected before typed loading are limited to 8 MiB.
|
||||
- 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.
|
||||
- Required stable files (`speakers_file`, `autocorrect_file`, `glossary_file`,
|
||||
`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
|
||||
exact named configured definitions become the effective set for that invocation,
|
||||
regardless of their `enabled` value. The effective-set resolver itself does not
|
||||
expand dependencies; the analyze work planner closes those targets over their
|
||||
configured prerequisite graph. 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
|
||||
expand dependencies. Configuration has already materialized the sorted union of
|
||||
explicit ordering edges and configured-artifact input edges, and the analyze
|
||||
work planner closes targets over that one concrete prerequisite graph.
|
||||
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
|
||||
lookups remain concrete configured-artifact identities.
|
||||
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.
|
||||
|
||||
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,
|
||||
remote-session download, secret loading, adapter composition, workspace
|
||||
remote-session download, adapter composition, workspace
|
||||
initialization, manifest access, or cleanup. A pipeline with retained artifact
|
||||
family declarations must resolve its selected campaign before ordinary pipeline
|
||||
validation, which expands its canonical-party members and generated publish
|
||||
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
|
||||
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
|
||||
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
|
||||
loads. When campaign
|
||||
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.
|
||||
|
||||
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
|
||||
sorted records describe defaulted, expanded concrete configuration—not source
|
||||
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
|
||||
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.
|
||||
without creating a session or run. Use `narratio config artifacts` to review the
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
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.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
|
||||
|
||||
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”;
|
||||
`examples/README.md`, existing example bundles and their loader test,
|
||||
|
||||
@@ -11,18 +11,26 @@ in the [configuration reference](../docs/config.md).
|
||||
WhisperX URL.
|
||||
- [Production-shaped pipeline](pipeline.production.yml): S3 storage, publish,
|
||||
external tools, and configured Scriptorium artifacts.
|
||||
- [Production/testing split bundle](production-testing/pipeline.yml): explicit
|
||||
`conf.d` imports, a production default, and selectable production/testing
|
||||
overlays. It also demonstrates canonical-party artifact families and a
|
||||
testing-only disabled artifact. Validate it with:
|
||||
- [Production-base/testing-overlay bundle](production-testing/pipeline.yml):
|
||||
explicit `conf.d` imports, one ordinary artifact per `artifacts/<key>.yml`,
|
||||
one family per `artifact-families/<key>.yml`, and the fixed
|
||||
`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
|
||||
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
|
||||
read-only.
|
||||
These inspection commands load configuration and resolve explicit credential
|
||||
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
|
||||
pipeline section with explanatory comments.
|
||||
- [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
|
||||
annotated pipelines. They use fictional campaign content and reserved example
|
||||
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:
|
||||
binary: scriptorium
|
||||
config_path: ./scriptorium/config.yml
|
||||
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:
|
||||
enabled: true
|
||||
for_each: party.characters
|
||||
prompt_id: dnd.character_items
|
||||
profile_id: production-placeholder
|
||||
output_path_pattern: artifacts/characters/{character_id}/items.md
|
||||
member_dependencies: [character_meta]
|
||||
inputs:
|
||||
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
|
||||
modules: [glossary, grammar]
|
||||
output_schema: audita-v1
|
||||
model: narratio-production-model-placeholder
|
||||
validation_model: narratio-production-validator-placeholder
|
||||
|
||||
normalize:
|
||||
output_path: transcripts/final.json
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
# Copyable production/testing pipeline entry point. Every fragment is named
|
||||
# explicitly; Narratio never scans conf.d automatically.
|
||||
# Copyable production-base/testing-overlay entry point. ConfigKit expands only
|
||||
# these explicit path and glob imports; Narratio never scans directories itself.
|
||||
configkit:
|
||||
imports:
|
||||
- path: conf.d/platform.yml
|
||||
- path: conf.d/storage.yml
|
||||
- path: conf.d/transcript.yml
|
||||
- path: conf.d/artifacts.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:
|
||||
artifacts:
|
||||
session_recap:
|
||||
profile_id: testing-placeholder
|
||||
player_handout:
|
||||
profile_id: testing-placeholder
|
||||
testing_notes:
|
||||
enabled: false
|
||||
output_path: artifacts/testing-notes.md
|
||||
|
||||
@@ -253,11 +253,11 @@ func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testi
|
||||
}
|
||||
|
||||
var validated bytes.Buffer
|
||||
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath, "--profile", "production"}, &validated); err != nil {
|
||||
t.Fatalf("validate production profile: %v", err)
|
||||
if err := ConfigValidate(context.Background(), []string{"--config", pipelinePath, "--campaign-file", campaignPath}, &validated); err != nil {
|
||||
t.Fatalf("validate production base: %v", err)
|
||||
}
|
||||
if !strings.Contains(validated.String(), "profile=production") {
|
||||
t.Fatalf("validate output = %q, want production profile", validated.String())
|
||||
if !strings.Contains(validated.String(), "profile=none") {
|
||||
t.Fatalf("validate output = %q, want unprofiled production base", validated.String())
|
||||
}
|
||||
for _, command := range []func(context.Context, []string, io.Writer) error{ConfigShow, ConfigSources} {
|
||||
if err := command(context.Background(), []string{
|
||||
@@ -268,7 +268,7 @@ func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testi
|
||||
}
|
||||
var diff bytes.Buffer
|
||||
if err := ConfigDiff(context.Background(), []string{
|
||||
"production", "testing", "--config", pipelinePath, "--campaign-file", campaignPath,
|
||||
"default", "testing", "--config", pipelinePath, "--campaign-file", campaignPath,
|
||||
}, &diff); err != nil {
|
||||
t.Fatalf("compare profiles: %v", err)
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func TestAssembledSplitBundleCommandsUseOneEffectiveFamilyConfiguration(t *testi
|
||||
}
|
||||
|
||||
func TestAssembledSplitBundleProfileSwitchRecordsProvenanceAndLimitsReuse(t *testing.T) {
|
||||
production := loadAssembledSplitBundleConfig(t, "production")
|
||||
production := loadAssembledSplitBundleConfig(t, "")
|
||||
testingCfg := loadAssembledSplitBundleConfig(t, "testing")
|
||||
workspace := t.TempDir()
|
||||
production.Pipeline.Workspace.Root = workspace
|
||||
@@ -365,7 +365,7 @@ func TestAssembledSplitBundleProfileSwitchRecordsProvenanceAndLimitsReuse(t *tes
|
||||
if !reflect.DeepEqual(productionRuns, make([]int, len(names))) {
|
||||
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))
|
||||
testingStages := assembledSemanticStages(names, providers, testingRuns)
|
||||
@@ -415,7 +415,9 @@ func assertAssembledProvenance(t *testing.T, store *manifest.LocalStore, summary
|
||||
t.Fatal(err)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,12 +370,12 @@ func TestConfigCommandsInspectMaintainedSplitBundleWithoutRuntimeState(t *testin
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
if !strings.Contains(diff.String(), "audita.model") {
|
||||
|
||||
@@ -285,15 +285,19 @@ func TestExamplesLoadAndValidate(t *testing.T) {
|
||||
t.Fatalf("load split bundle campaign: %v", err)
|
||||
}
|
||||
for _, profile := range []struct {
|
||||
name string
|
||||
model string
|
||||
name string
|
||||
selection string
|
||||
model string
|
||||
}{
|
||||
{name: "production", model: "narratio-production-model-placeholder"},
|
||||
{name: "testing", model: "narratio-testing-model-placeholder"},
|
||||
{name: "production base", model: "narratio-production-model-placeholder"},
|
||||
{name: "testing", selection: "testing", model: "narratio-testing-model-placeholder"},
|
||||
} {
|
||||
t.Run(profile.name, func(t *testing.T) {
|
||||
selected := profile.name
|
||||
pipeline, err := LoadPipelineWithOptions(pipelinePath, PipelineLoadOptions{Profile: &selected})
|
||||
options := PipelineLoadOptions{}
|
||||
if profile.selection != "" {
|
||||
options.Profile = &profile.selection
|
||||
}
|
||||
pipeline, err := LoadPipelineWithOptions(pipelinePath, options)
|
||||
if err != nil {
|
||||
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 {
|
||||
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 {
|
||||
t.Fatalf("selected profile = %#v, want %q", selectedProfile, profile.name)
|
||||
selectedProfile, selected := SelectedPipelineProfile(cfg.Pipeline)
|
||||
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{
|
||||
"session_recap",
|
||||
"player_handout",
|
||||
"character_meta_arannis",
|
||||
"character_meta_brenna",
|
||||
"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" {
|
||||
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 {
|
||||
t.Fatalf("canonical party = %#v", cfg.Party)
|
||||
}
|
||||
@@ -340,7 +356,18 @@ func TestExamplesLoadAndValidate(t *testing.T) {
|
||||
if len(cfg.Pipeline.Publish.Outputs) != 3 {
|
||||
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"]
|
||||
if !exists || artifact.Enabled {
|
||||
t.Fatalf("testing-only disabled artifact = %#v", artifact)
|
||||
|
||||
Reference in New Issue
Block a user