Add execution metadata to module specifications
This commit is contained in:
@@ -24,7 +24,11 @@ does not repeat their JSON shapes or schemas.
|
|||||||
The D&D registrar registers the family’s artifact codecs, extractors, typed
|
The D&D registrar registers the family’s artifact codecs, extractors, typed
|
||||||
append-order mergers, normalizers, validators, prompt assets, fallback LLM
|
append-order mergers, normalizers, validators, prompt assets, fallback LLM
|
||||||
profile asset, and default validator chains. Each extractor and normalizer has
|
profile asset, and default validator chains. Each extractor and normalizer has
|
||||||
a stable module spec, strict option decoding, and a typed builder.
|
a stable module spec, explicit execution class, strict option decoding, and a
|
||||||
|
typed builder. Scene chunking, every extractor, and NPC normalization are
|
||||||
|
registered as `llm_backed`; the remaining current D&D mergers and normalizers
|
||||||
|
are `deterministic`. The metadata is available to catalog inspection and
|
||||||
|
resolved-pipeline debug data; it does not yet change profile inheritance.
|
||||||
Configuration remains the canonical owner of the exact keys and validator
|
Configuration remains the canonical owner of the exact keys and validator
|
||||||
order.
|
order.
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,13 @@ exceptions. See [D&D Module Internals](dnd.md) rather than adding them here.
|
|||||||
|
|
||||||
A module is a typed implementation registered for one pipeline stage. Its
|
A module is a typed implementation registered for one pipeline stage. Its
|
||||||
`ModuleSpec` is the public-to-the-framework declaration of its stable key,
|
`ModuleSpec` is the public-to-the-framework declaration of its stable key,
|
||||||
stage, required and provided capabilities, artifact kind, and accepted
|
stage, execution class, required and provided capabilities, artifact kind, and
|
||||||
reference slots. The framework uses that declaration to resolve a configured
|
accepted reference slots. The execution class states whether a module is
|
||||||
binding before it builds the implementation.
|
`deterministic` or `llm_backed`; registries retain it for catalog inspection and
|
||||||
|
resolved-pipeline debug data without constructing the module. The framework
|
||||||
|
uses the declaration to resolve a configured binding before it builds the
|
||||||
|
implementation. Profile inheritance and deterministic-profile validation are
|
||||||
|
not implemented at this boundary yet.
|
||||||
|
|
||||||
Implementations that accept options must provide both an option validator and
|
Implementations that accept options must provide both an option validator and
|
||||||
a builder. The validator is used while resolving configuration; the builder
|
a builder. The validator is used while resolving configuration; the builder
|
||||||
@@ -59,10 +63,10 @@ packages depend on production extensions.
|
|||||||
1. Choose the pipeline stage and the typed artifact boundary. Put external
|
1. Choose the pipeline stage and the typed artifact boundary. Put external
|
||||||
input or durable artifact formats in the relevant integration contract,
|
input or durable artifact formats in the relevant integration contract,
|
||||||
not in this guide or in a private LLM response type.
|
not in this guide or in a private LLM response type.
|
||||||
2. Define a stable `ModuleSpec` with the exact capabilities and reference
|
2. Define a stable `ModuleSpec` with an explicit execution class, the exact
|
||||||
slots needed for the operation. Model a producer/consumer handoff as an
|
capabilities, and reference slots needed for the operation. Model a
|
||||||
artifact-compatible slot; configuration then chooses an external file or a
|
producer/consumer handoff as an artifact-compatible slot; configuration
|
||||||
generated binding.
|
then chooses an external file or a generated binding.
|
||||||
3. Implement strict option decoding, construction, and the typed stage
|
3. Implement strict option decoding, construction, and the typed stage
|
||||||
interface. Preserve caller ownership: do not retain mutable request data
|
interface. Preserve caller ownership: do not retain mutable request data
|
||||||
and return defensive copies where an implementation exposes stored data.
|
and return defensive copies where an implementation exposes stored data.
|
||||||
|
|||||||
@@ -166,6 +166,35 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
|
|||||||
assertProductionContains(t, "production prompt assets", assetNames, requiredAssets)
|
assertProductionContains(t, "production prompt assets", assetNames, requiredAssets)
|
||||||
|
|
||||||
catalog := catalogFromRegistries(registries)
|
catalog := catalogFromRegistries(registries)
|
||||||
|
for _, test := range []struct {
|
||||||
|
stage pipeline.ModuleStage
|
||||||
|
key string
|
||||||
|
want contracts.ExecutionClass
|
||||||
|
}{
|
||||||
|
{stage: pipeline.StageInput, key: "seriatim", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageChunk, key: "generic", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageChunk, key: "dnd/scenes", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageExtract, key: "dnd/spells", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageExtract, key: "dnd/npcs", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageExtract, key: "dnd/combat-turns", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageExtract, key: "dnd/item-events", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageExtract, key: "dnd/npc-interactions", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageExtract, key: "dnd/scene-descriptions", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageMerge, key: "appendorder", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageNormalize, key: "noop", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageNormalize, key: "dnd/spells", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageNormalize, key: "dnd/npcs", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: pipeline.StageNormalize, key: "dnd/combat-turns", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageNormalize, key: "dnd/item-events", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageNormalize, key: "dnd/npc-interactions", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageNormalize, key: "dnd/scene-descriptions", want: contracts.ExecutionClassDeterministic},
|
||||||
|
{stage: pipeline.StageOutput, key: "json", want: contracts.ExecutionClassDeterministic},
|
||||||
|
} {
|
||||||
|
got, ok := catalog.ExecutionClass(test.stage, test.key)
|
||||||
|
if !ok || got != test.want {
|
||||||
|
t.Fatalf("production execution class for %s/%s = %q, %t; want %q, true", test.stage, test.key, got, ok, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
converted := registriesFromCatalog(catalog)
|
converted := registriesFromCatalog(catalog)
|
||||||
if converted.ArtifactCodecs != registries.ArtifactCodecs || converted.ArtifactEvidence != registries.ArtifactEvidence || converted.ValidatorChains != registries.ValidatorChains {
|
if converted.ArtifactCodecs != registries.ArtifactCodecs || converted.ArtifactEvidence != registries.ArtifactEvidence || converted.ValidatorChains != registries.ValidatorChains {
|
||||||
t.Fatal("catalog/registry conversion did not preserve artifact and validator registries")
|
t.Fatal("catalog/registry conversion did not preserve artifact and validator registries")
|
||||||
|
|||||||
@@ -19,23 +19,28 @@ func TestRedactedResolvedPipelinePayloadRedactsEveryBinding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolved := pipeline.ResolvedPipeline{
|
resolved := pipeline.ResolvedPipeline{
|
||||||
ID: "redaction-test",
|
ID: "redaction-test",
|
||||||
Digest: "sha256:safe-digest",
|
Digest: "sha256:safe-digest",
|
||||||
Input: bindings["input"],
|
Input: bindings["input"],
|
||||||
Chunk: bindings["chunk"],
|
InputExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
ChunkReferences: redactionTestReferenceTarget(pipeline.StageChunk, "", "chunk-reference-content"),
|
Chunk: bindings["chunk"],
|
||||||
|
ChunkExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
|
ChunkReferences: redactionTestReferenceTarget(pipeline.StageChunk, "", "chunk-reference-content"),
|
||||||
Steps: []pipeline.ResolvedPipelineStep{{
|
Steps: []pipeline.ResolvedPipelineStep{{
|
||||||
ID: "default",
|
ID: "default",
|
||||||
ArtifactLanes: []pipeline.ResolvedArtifactLane{{
|
ArtifactLanes: []pipeline.ResolvedArtifactLane{{
|
||||||
ID: "safe-lane",
|
ID: "safe-lane",
|
||||||
ArtifactKind: "safe/artifact",
|
ArtifactKind: "safe/artifact",
|
||||||
Extract: bindings["extract"],
|
Extract: bindings["extract"],
|
||||||
Merge: bindings["merge"],
|
ExtractExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Normalize: bindings["normalize"],
|
Merge: bindings["merge"],
|
||||||
Validators: []pipeline.ModuleBinding{bindings["lane-validator"]},
|
MergeExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
ExtractReferences: redactionTestReferenceTarget(pipeline.StageExtract, "safe-lane", "extract-reference-content"),
|
Normalize: bindings["normalize"],
|
||||||
MergeReferences: redactionTestReferenceTarget(pipeline.StageMerge, "safe-lane", "merge-reference-content"),
|
NormalizeExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
NormalizeReferences: redactionTestReferenceTarget(pipeline.StageNormalize, "safe-lane", "normalize-reference-content"),
|
Validators: []pipeline.ModuleBinding{bindings["lane-validator"]},
|
||||||
|
ExtractReferences: redactionTestReferenceTarget(pipeline.StageExtract, "safe-lane", "extract-reference-content"),
|
||||||
|
MergeReferences: redactionTestReferenceTarget(pipeline.StageMerge, "safe-lane", "merge-reference-content"),
|
||||||
|
NormalizeReferences: redactionTestReferenceTarget(pipeline.StageNormalize, "safe-lane", "normalize-reference-content"),
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
ValidatorChains: []pipeline.ResolvedValidatorChain{{
|
ValidatorChains: []pipeline.ResolvedValidatorChain{{
|
||||||
@@ -49,7 +54,8 @@ func TestRedactedResolvedPipelinePayloadRedactsEveryBinding(t *testing.T) {
|
|||||||
ArtifactKind: "safe/artifact",
|
ArtifactKind: "safe/artifact",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
Output: bindings["output"],
|
Output: bindings["output"],
|
||||||
|
OutputExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
}
|
}
|
||||||
effective := EffectiveConfig{
|
effective := EffectiveConfig{
|
||||||
Config: Config{Pipelines: map[string]pipeline.PipelineProfile{
|
Config: Config{Pipelines: map[string]pipeline.PipelineProfile{
|
||||||
@@ -88,6 +94,11 @@ func TestRedactedResolvedPipelinePayloadRedactsEveryBinding(t *testing.T) {
|
|||||||
t.Fatalf("resolved pipeline summary does not retain %q: %s", safe, text)
|
t.Fatalf("resolved pipeline summary does not retain %q: %s", safe, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, executionClass := range []string{"input_execution_class\":\"deterministic", "chunk_execution_class\":\"llm_backed", "extract_execution_class\":\"llm_backed", "merge_execution_class\":\"deterministic", "normalize_execution_class\":\"llm_backed", "output_execution_class\":\"deterministic"} {
|
||||||
|
if !strings.Contains(text, executionClass) {
|
||||||
|
t.Fatalf("resolved pipeline summary does not retain %q: %s", executionClass, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
payload.Input.Options["safe"] = "mutated"
|
payload.Input.Options["safe"] = "mutated"
|
||||||
nested := payload.Input.Options["nested"].([]any)[0].([]any)[0].(map[string]any)
|
nested := payload.Input.Options["nested"].([]any)[0].([]any)[0].(map[string]any)
|
||||||
|
|||||||
@@ -115,10 +115,11 @@ func runRegistryBehaviorTests[M any](t *testing.T, testCase registryBehaviorCase
|
|||||||
t.Fatal("Spec() ok = false, want true")
|
t.Fatal("Spec() ok = false, want true")
|
||||||
}
|
}
|
||||||
want := ModuleSpec{
|
want := ModuleSpec{
|
||||||
Key: testCase.key,
|
Key: testCase.key,
|
||||||
Stage: testCase.stage,
|
Stage: testCase.stage,
|
||||||
Provides: []string{"alpha", "beta"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Requires: []string{"source"},
|
Provides: []string{"alpha", "beta"},
|
||||||
|
Requires: []string{"source"},
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("Spec() = %#v, want %#v", got, want)
|
t.Fatalf("Spec() = %#v, want %#v", got, want)
|
||||||
@@ -144,7 +145,7 @@ func runRegistryBehaviorTests[M any](t *testing.T, testCase registryBehaviorCase
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("Spec() ok = false, want true")
|
t.Fatal("Spec() ok = false, want true")
|
||||||
}
|
}
|
||||||
want := ModuleSpec{Key: testCase.key, Stage: testCase.stage}
|
want := ModuleSpec{Key: testCase.key, Stage: testCase.stage, ExecutionClass: contracts.ExecutionClassDeterministic}
|
||||||
if !reflect.DeepEqual(spec, want) {
|
if !reflect.DeepEqual(spec, want) {
|
||||||
t.Fatalf("Spec() = %#v, want %#v", spec, want)
|
t.Fatalf("Spec() = %#v, want %#v", spec, want)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,10 +61,11 @@ func TestInputAdapterRegistryRegisterWithSpecStoresMetadata(t *testing.T) {
|
|||||||
t.Fatal("Spec() ok = false, want true")
|
t.Fatal("Spec() ok = false, want true")
|
||||||
}
|
}
|
||||||
want := ModuleSpec{
|
want := ModuleSpec{
|
||||||
Key: "generic-input",
|
Key: "generic-input",
|
||||||
Stage: StageInput,
|
Stage: StageInput,
|
||||||
Provides: []string{"parsed-source", "source-document"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Requires: []string{"raw-bytes"},
|
Provides: []string{"parsed-source", "source-document"},
|
||||||
|
Requires: []string{"raw-bytes"},
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("Spec() = %#v, want %#v", got, want)
|
t.Fatalf("Spec() = %#v, want %#v", got, want)
|
||||||
@@ -91,7 +92,7 @@ func TestInputAdapterRegistryRegisterStoresDefaultSpec(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("Spec() ok = false, want true")
|
t.Fatal("Spec() ok = false, want true")
|
||||||
}
|
}
|
||||||
want := ModuleSpec{Key: "generic-input", Stage: StageInput}
|
want := ModuleSpec{Key: "generic-input", Stage: StageInput, ExecutionClass: contracts.ExecutionClassDeterministic}
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("Spec() = %#v, want %#v", got, want)
|
t.Fatalf("Spec() = %#v, want %#v", got, want)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const (
|
|||||||
type ModuleSpec struct {
|
type ModuleSpec struct {
|
||||||
Key string
|
Key string
|
||||||
Stage ModuleStage
|
Stage ModuleStage
|
||||||
|
ExecutionClass contracts.ExecutionClass
|
||||||
ArtifactKind contracts.ArtifactKind
|
ArtifactKind contracts.ArtifactKind
|
||||||
Provides []string
|
Provides []string
|
||||||
Requires []string
|
Requires []string
|
||||||
@@ -37,9 +38,14 @@ func defaultModuleSpec(key string, stage ModuleStage) ModuleSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func normalizeModuleSpec(spec ModuleSpec) ModuleSpec {
|
func normalizeModuleSpec(spec ModuleSpec) ModuleSpec {
|
||||||
|
executionClass := contracts.ExecutionClass(strings.TrimSpace(string(spec.ExecutionClass)))
|
||||||
|
if executionClass == "" {
|
||||||
|
executionClass = contracts.ExecutionClassDeterministic
|
||||||
|
}
|
||||||
return ModuleSpec{
|
return ModuleSpec{
|
||||||
Key: strings.TrimSpace(spec.Key),
|
Key: strings.TrimSpace(spec.Key),
|
||||||
Stage: spec.Stage,
|
Stage: spec.Stage,
|
||||||
|
ExecutionClass: executionClass,
|
||||||
ArtifactKind: normalizeArtifactKind(spec.ArtifactKind),
|
ArtifactKind: normalizeArtifactKind(spec.ArtifactKind),
|
||||||
Provides: normalizeCapabilities(spec.Provides),
|
Provides: normalizeCapabilities(spec.Provides),
|
||||||
Requires: normalizeCapabilities(spec.Requires),
|
Requires: normalizeCapabilities(spec.Requires),
|
||||||
@@ -76,6 +82,7 @@ func cloneModuleSpec(spec ModuleSpec) ModuleSpec {
|
|||||||
return ModuleSpec{
|
return ModuleSpec{
|
||||||
Key: spec.Key,
|
Key: spec.Key,
|
||||||
Stage: spec.Stage,
|
Stage: spec.Stage,
|
||||||
|
ExecutionClass: spec.ExecutionClass,
|
||||||
ArtifactKind: spec.ArtifactKind,
|
ArtifactKind: spec.ArtifactKind,
|
||||||
Provides: append([]string(nil), spec.Provides...),
|
Provides: append([]string(nil), spec.Provides...),
|
||||||
Requires: append([]string(nil), spec.Requires...),
|
Requires: append([]string(nil), spec.Requires...),
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestNormalizeModuleSpecDefaultsExecutionClass(t *testing.T) {
|
||||||
|
normalized := normalizeModuleSpec(ModuleSpec{Key: " module ", Stage: StageChunk})
|
||||||
|
if normalized.ExecutionClass != contracts.ExecutionClassDeterministic {
|
||||||
|
t.Fatalf("ExecutionClass = %q, want deterministic compatibility default", normalized.ExecutionClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := cloneModuleSpec(normalized)
|
||||||
|
if !reflect.DeepEqual(cloned, normalized) {
|
||||||
|
t.Fatalf("cloneModuleSpec() = %#v, want %#v", cloned, normalized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateModuleSpecAllowsReferenceSlotsForEligibleStages(t *testing.T) {
|
func TestValidateModuleSpecAllowsReferenceSlotsForEligibleStages(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -156,20 +156,23 @@ type ResolvedReferenceTarget struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResolvedArtifactLane struct {
|
type ResolvedArtifactLane struct {
|
||||||
StepID string
|
StepID string
|
||||||
ID string
|
ID string
|
||||||
ArtifactKind contracts.ArtifactKind `json:"artifact_kind,omitempty"`
|
ArtifactKind contracts.ArtifactKind `json:"artifact_kind,omitempty"`
|
||||||
ArtifactSchemaID string `json:"artifact_schema_id,omitempty"`
|
ArtifactSchemaID string `json:"artifact_schema_id,omitempty"`
|
||||||
ArtifactSchemaName string `json:"artifact_schema_name,omitempty"`
|
ArtifactSchemaName string `json:"artifact_schema_name,omitempty"`
|
||||||
ArtifactSchemaVersion string `json:"artifact_schema_version,omitempty"`
|
ArtifactSchemaVersion string `json:"artifact_schema_version,omitempty"`
|
||||||
ArtifactSchemaDigest string `json:"artifact_schema_digest,omitempty"`
|
ArtifactSchemaDigest string `json:"artifact_schema_digest,omitempty"`
|
||||||
Extract ModuleBinding
|
Extract ModuleBinding
|
||||||
Merge ModuleBinding
|
ExtractExecutionClass contracts.ExecutionClass `json:"extract_execution_class"`
|
||||||
Normalize ModuleBinding
|
Merge ModuleBinding
|
||||||
Validators []ModuleBinding
|
MergeExecutionClass contracts.ExecutionClass `json:"merge_execution_class"`
|
||||||
ExtractReferences ResolvedReferenceTarget `json:"extract_references"`
|
Normalize ModuleBinding
|
||||||
MergeReferences ResolvedReferenceTarget `json:"merge_references"`
|
NormalizeExecutionClass contracts.ExecutionClass `json:"normalize_execution_class"`
|
||||||
NormalizeReferences ResolvedReferenceTarget `json:"normalize_references"`
|
Validators []ModuleBinding
|
||||||
|
ExtractReferences ResolvedReferenceTarget `json:"extract_references"`
|
||||||
|
MergeReferences ResolvedReferenceTarget `json:"merge_references"`
|
||||||
|
NormalizeReferences ResolvedReferenceTarget `json:"normalize_references"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResolvedPipelineStep struct {
|
type ResolvedPipelineStep struct {
|
||||||
@@ -192,14 +195,17 @@ type ResolvedValidator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResolvedPipeline struct {
|
type ResolvedPipeline struct {
|
||||||
ID string
|
ID string
|
||||||
Digest string
|
Digest string
|
||||||
Input ModuleBinding
|
Input ModuleBinding
|
||||||
Chunk ModuleBinding
|
InputExecutionClass contracts.ExecutionClass `json:"input_execution_class"`
|
||||||
ChunkReferences ResolvedReferenceTarget `json:"chunk_references"`
|
Chunk ModuleBinding
|
||||||
Steps []ResolvedPipelineStep
|
ChunkExecutionClass contracts.ExecutionClass `json:"chunk_execution_class"`
|
||||||
ValidatorChains []ResolvedValidatorChain `json:"validator_chains"`
|
ChunkReferences ResolvedReferenceTarget `json:"chunk_references"`
|
||||||
Output ModuleBinding
|
Steps []ResolvedPipelineStep
|
||||||
|
ValidatorChains []ResolvedValidatorChain `json:"validator_chains"`
|
||||||
|
Output ModuleBinding
|
||||||
|
OutputExecutionClass contracts.ExecutionClass `json:"output_execution_class"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllArtifactLanes returns lanes in deterministic step order for read-only
|
// AllArtifactLanes returns lanes in deterministic step order for read-only
|
||||||
@@ -225,6 +231,46 @@ type ModuleCatalog struct {
|
|||||||
Outputs *OutputEncoderRegistry
|
Outputs *OutputEncoderRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutionClass returns the registered execution class for a module selected
|
||||||
|
// by stage and key without constructing the module.
|
||||||
|
func (catalog ModuleCatalog) ExecutionClass(stage ModuleStage, key string) (contracts.ExecutionClass, bool) {
|
||||||
|
var executionClass contracts.ExecutionClass
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
switch stage {
|
||||||
|
case StageInput:
|
||||||
|
var spec ModuleSpec
|
||||||
|
spec, ok = catalog.Inputs.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
case StageChunk:
|
||||||
|
var spec ModuleSpec
|
||||||
|
spec, ok = catalog.Chunkers.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
case StageExtract:
|
||||||
|
var spec ModuleSpec
|
||||||
|
spec, ok = catalog.Extractors.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
case StageMerge:
|
||||||
|
var spec ModuleSpec
|
||||||
|
spec, ok = catalog.Mergers.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
case StageNormalize:
|
||||||
|
var spec ModuleSpec
|
||||||
|
spec, ok = catalog.Normalizers.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
case StageValidate:
|
||||||
|
var spec ValidatorSpec
|
||||||
|
spec, ok = catalog.Validators.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
case StageOutput:
|
||||||
|
var spec ModuleSpec
|
||||||
|
spec, ok = catalog.Outputs.Spec(key)
|
||||||
|
executionClass = spec.ExecutionClass
|
||||||
|
}
|
||||||
|
|
||||||
|
return executionClass, ok
|
||||||
|
}
|
||||||
|
|
||||||
func Binding(module string) ModuleBinding {
|
func Binding(module string) ModuleBinding {
|
||||||
return ModuleBinding{Module: strings.TrimSpace(module)}
|
return ModuleBinding{Module: strings.TrimSpace(module)}
|
||||||
}
|
}
|
||||||
@@ -316,11 +362,13 @@ func ResolvePipeline(profile PipelineProfile, options ResolveOptions, catalog Mo
|
|||||||
return ResolvedPipeline{}, err
|
return ResolvedPipeline{}, err
|
||||||
}
|
}
|
||||||
resolved := ResolvedPipeline{
|
resolved := ResolvedPipeline{
|
||||||
ID: pipelineID,
|
ID: pipelineID,
|
||||||
Input: input,
|
Input: input,
|
||||||
Chunk: chunk,
|
InputExecutionClass: inputModuleSpec.ExecutionClass,
|
||||||
ChunkReferences: referenceTarget(StageChunk, "", chunk.Module, chunkReferences),
|
Chunk: chunk,
|
||||||
Output: resolveBinding(profile.Output, DefaultOutputModule),
|
ChunkExecutionClass: chunkSpec.ExecutionClass,
|
||||||
|
ChunkReferences: referenceTarget(StageChunk, "", chunk.Module, chunkReferences),
|
||||||
|
Output: resolveBinding(profile.Output, DefaultOutputModule),
|
||||||
}
|
}
|
||||||
chunkValidatorChain, err := resolveValidatorChain(pipelineID, "", StageChunk, chunk.Module, chunk.Validators, "", nil, catalog)
|
chunkValidatorChain, err := resolveValidatorChain(pipelineID, "", StageChunk, chunk.Module, chunk.Validators, "", nil, catalog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -386,6 +434,7 @@ func ResolvePipeline(profile PipelineProfile, options ResolveOptions, catalog Mo
|
|||||||
if missing, ok := outputCapabilities.missing(outputSpec.Requires); ok {
|
if missing, ok := outputCapabilities.missing(outputSpec.Requires); ok {
|
||||||
return ResolvedPipeline{}, capabilityError(pipelineID, "", StageOutput, resolved.Output.Module, missing)
|
return ResolvedPipeline{}, capabilityError(pipelineID, "", StageOutput, resolved.Output.Module, missing)
|
||||||
}
|
}
|
||||||
|
resolved.OutputExecutionClass = outputSpec.ExecutionClass
|
||||||
if err := validateResolvedOptions(resolved, catalog, configuredLaneIDs); err != nil {
|
if err := validateResolvedOptions(resolved, catalog, configuredLaneIDs); err != nil {
|
||||||
return ResolvedPipeline{}, err
|
return ResolvedPipeline{}, err
|
||||||
}
|
}
|
||||||
@@ -475,6 +524,7 @@ func resolveArtifactLane(
|
|||||||
}
|
}
|
||||||
lane.ExtractReferences = referenceTarget(StageExtract, laneID, lane.Extract.Module, references)
|
lane.ExtractReferences = referenceTarget(StageExtract, laneID, lane.Extract.Module, references)
|
||||||
lane.ExtractReferences.StepID = strings.TrimSpace(stepID)
|
lane.ExtractReferences.StepID = strings.TrimSpace(stepID)
|
||||||
|
lane.ExtractExecutionClass = extractSpec.ExecutionClass
|
||||||
capabilities.add(extractSpec.Provides...)
|
capabilities.add(extractSpec.Provides...)
|
||||||
|
|
||||||
mergeSpec, err := mergerSpecForArtifact(catalog, lane.Merge.Module, lane.ArtifactKind, artifactType)
|
mergeSpec, err := mergerSpecForArtifact(catalog, lane.Merge.Module, lane.ArtifactKind, artifactType)
|
||||||
@@ -499,6 +549,7 @@ func resolveArtifactLane(
|
|||||||
}
|
}
|
||||||
lane.MergeReferences = referenceTarget(StageMerge, laneID, lane.Merge.Module, mergeReferences)
|
lane.MergeReferences = referenceTarget(StageMerge, laneID, lane.Merge.Module, mergeReferences)
|
||||||
lane.MergeReferences.StepID = strings.TrimSpace(stepID)
|
lane.MergeReferences.StepID = strings.TrimSpace(stepID)
|
||||||
|
lane.MergeExecutionClass = mergeSpec.ExecutionClass
|
||||||
capabilities.add(mergeSpec.Provides...)
|
capabilities.add(mergeSpec.Provides...)
|
||||||
|
|
||||||
normalizeSpec, err := normalizerSpecForArtifact(catalog, lane.Normalize.Module, lane.ArtifactKind, artifactType)
|
normalizeSpec, err := normalizerSpecForArtifact(catalog, lane.Normalize.Module, lane.ArtifactKind, artifactType)
|
||||||
@@ -523,6 +574,7 @@ func resolveArtifactLane(
|
|||||||
}
|
}
|
||||||
lane.NormalizeReferences = referenceTarget(StageNormalize, laneID, lane.Normalize.Module, normalizeReferences)
|
lane.NormalizeReferences = referenceTarget(StageNormalize, laneID, lane.Normalize.Module, normalizeReferences)
|
||||||
lane.NormalizeReferences.StepID = strings.TrimSpace(stepID)
|
lane.NormalizeReferences.StepID = strings.TrimSpace(stepID)
|
||||||
|
lane.NormalizeExecutionClass = normalizeSpec.ExecutionClass
|
||||||
capabilities.add(normalizeSpec.Provides...)
|
capabilities.add(normalizeSpec.Provides...)
|
||||||
|
|
||||||
if len(lane.Validators) > 0 {
|
if len(lane.Validators) > 0 {
|
||||||
@@ -1307,21 +1359,27 @@ func selectedArtifactLanes(pipelineID string, artifacts map[string]ArtifactLaneP
|
|||||||
|
|
||||||
func resolvedPipelineDigest(resolved ResolvedPipeline) (string, error) {
|
func resolvedPipelineDigest(resolved ResolvedPipeline) (string, error) {
|
||||||
withoutDigest := struct {
|
withoutDigest := struct {
|
||||||
ID string
|
ID string
|
||||||
Input ModuleBinding
|
Input ModuleBinding
|
||||||
Chunk ModuleBinding
|
InputExecutionClass contracts.ExecutionClass
|
||||||
ChunkReferences ResolvedReferenceTarget
|
Chunk ModuleBinding
|
||||||
Steps []ResolvedPipelineStep
|
ChunkExecutionClass contracts.ExecutionClass
|
||||||
ValidatorChains []ResolvedValidatorChain
|
ChunkReferences ResolvedReferenceTarget
|
||||||
Output ModuleBinding
|
Steps []ResolvedPipelineStep
|
||||||
|
ValidatorChains []ResolvedValidatorChain
|
||||||
|
Output ModuleBinding
|
||||||
|
OutputExecutionClass contracts.ExecutionClass
|
||||||
}{
|
}{
|
||||||
ID: resolved.ID,
|
ID: resolved.ID,
|
||||||
Input: resolved.Input,
|
Input: resolved.Input,
|
||||||
Chunk: resolved.Chunk,
|
InputExecutionClass: resolved.InputExecutionClass,
|
||||||
ChunkReferences: resolved.ChunkReferences,
|
Chunk: resolved.Chunk,
|
||||||
Steps: resolved.Steps,
|
ChunkExecutionClass: resolved.ChunkExecutionClass,
|
||||||
ValidatorChains: resolved.ValidatorChains,
|
ChunkReferences: resolved.ChunkReferences,
|
||||||
Output: resolved.Output,
|
Steps: resolved.Steps,
|
||||||
|
ValidatorChains: resolved.ValidatorChains,
|
||||||
|
Output: resolved.Output,
|
||||||
|
OutputExecutionClass: resolved.OutputExecutionClass,
|
||||||
}
|
}
|
||||||
encoded, err := json.Marshal(withoutDigest)
|
encoded, err := json.Marshal(withoutDigest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -47,12 +47,18 @@ func TestResolvePipelineWithExplicitModules(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(resolved.Input, ModuleBinding{Module: "text", LLMProfile: "fast"}) {
|
if !reflect.DeepEqual(resolved.Input, ModuleBinding{Module: "text", LLMProfile: "fast"}) {
|
||||||
t.Fatalf("Input = %#v, want trimmed explicit input", resolved.Input)
|
t.Fatalf("Input = %#v, want trimmed explicit input", resolved.Input)
|
||||||
}
|
}
|
||||||
|
if resolved.InputExecutionClass != contracts.ExecutionClassDeterministic {
|
||||||
|
t.Fatalf("InputExecutionClass = %q, want deterministic", resolved.InputExecutionClass)
|
||||||
|
}
|
||||||
if resolved.Chunk.Module != "window" || resolved.Chunk.LLMProfile != "" {
|
if resolved.Chunk.Module != "window" || resolved.Chunk.LLMProfile != "" {
|
||||||
t.Fatalf("Chunk = %#v, want explicit module and empty LLM profile", resolved.Chunk)
|
t.Fatalf("Chunk = %#v, want explicit module and empty LLM profile", resolved.Chunk)
|
||||||
}
|
}
|
||||||
if resolved.Chunk.Options["size"] != 10 {
|
if resolved.Chunk.Options["size"] != 10 {
|
||||||
t.Fatalf("Chunk.Options = %#v, want size option", resolved.Chunk.Options)
|
t.Fatalf("Chunk.Options = %#v, want size option", resolved.Chunk.Options)
|
||||||
}
|
}
|
||||||
|
if resolved.ChunkExecutionClass != contracts.ExecutionClassDeterministic {
|
||||||
|
t.Fatalf("ChunkExecutionClass = %q, want deterministic", resolved.ChunkExecutionClass)
|
||||||
|
}
|
||||||
if len(resolved.Steps) != 1 || resolved.Steps[0].ID != "default" || len(resolved.Steps[0].ArtifactLanes) != 1 {
|
if len(resolved.Steps) != 1 || resolved.Steps[0].ID != "default" || len(resolved.Steps[0].ArtifactLanes) != 1 {
|
||||||
t.Fatalf("resolved steps = %#v, want one default step with one lane", resolved.Steps)
|
t.Fatalf("resolved steps = %#v, want one default step with one lane", resolved.Steps)
|
||||||
}
|
}
|
||||||
@@ -63,6 +69,9 @@ func TestResolvePipelineWithExplicitModules(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(lane.Extract, ModuleBinding{Module: "record-extractor", LLMProfile: "careful"}) {
|
if !reflect.DeepEqual(lane.Extract, ModuleBinding{Module: "record-extractor", LLMProfile: "careful"}) {
|
||||||
t.Fatalf("lane.Extract = %#v, want explicit extractor", lane.Extract)
|
t.Fatalf("lane.Extract = %#v, want explicit extractor", lane.Extract)
|
||||||
}
|
}
|
||||||
|
if lane.ExtractExecutionClass != contracts.ExecutionClassDeterministic || lane.MergeExecutionClass != contracts.ExecutionClassDeterministic || lane.NormalizeExecutionClass != contracts.ExecutionClassDeterministic {
|
||||||
|
t.Fatalf("lane execution classes = %q/%q/%q, want deterministic", lane.ExtractExecutionClass, lane.MergeExecutionClass, lane.NormalizeExecutionClass)
|
||||||
|
}
|
||||||
if lane.Merge.Module != "dedupe" || lane.Normalize.Module != "canonical" {
|
if lane.Merge.Module != "dedupe" || lane.Normalize.Module != "canonical" {
|
||||||
t.Fatalf("lane merge/normalize = %#v/%#v, want explicit modules", lane.Merge, lane.Normalize)
|
t.Fatalf("lane merge/normalize = %#v/%#v, want explicit modules", lane.Merge, lane.Normalize)
|
||||||
}
|
}
|
||||||
@@ -72,11 +81,51 @@ func TestResolvePipelineWithExplicitModules(t *testing.T) {
|
|||||||
if resolved.Output.Module != "ndjson" {
|
if resolved.Output.Module != "ndjson" {
|
||||||
t.Fatalf("Output.Module = %q, want ndjson", resolved.Output.Module)
|
t.Fatalf("Output.Module = %q, want ndjson", resolved.Output.Module)
|
||||||
}
|
}
|
||||||
|
if resolved.OutputExecutionClass != contracts.ExecutionClassDeterministic {
|
||||||
|
t.Fatalf("OutputExecutionClass = %q, want deterministic", resolved.OutputExecutionClass)
|
||||||
|
}
|
||||||
if !strings.HasPrefix(resolved.Digest, "sha256:") {
|
if !strings.HasPrefix(resolved.Digest, "sha256:") {
|
||||||
t.Fatalf("Digest = %q, want sha256 digest", resolved.Digest)
|
t.Fatalf("Digest = %q, want sha256 digest", resolved.Digest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestModuleCatalogExecutionClassLooksUpRegisteredMetadata(t *testing.T) {
|
||||||
|
catalog := newProfileCatalogWithOverrides(t,
|
||||||
|
ModuleSpec{Key: "llm-input", Stage: StageInput, ExecutionClass: contracts.ExecutionClassLLMBacked},
|
||||||
|
ModuleSpec{Key: "llm-chunk", Stage: StageChunk, ExecutionClass: contracts.ExecutionClassLLMBacked},
|
||||||
|
ModuleSpec{Key: "llm-extract", Stage: StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked},
|
||||||
|
ModuleSpec{Key: "llm-merge", Stage: StageMerge, ExecutionClass: contracts.ExecutionClassLLMBacked},
|
||||||
|
ModuleSpec{Key: "llm-normalize", Stage: StageNormalize, ExecutionClass: contracts.ExecutionClassLLMBacked},
|
||||||
|
ModuleSpec{Key: "llm-output", Stage: StageOutput, ExecutionClass: contracts.ExecutionClassLLMBacked},
|
||||||
|
)
|
||||||
|
registerProfileValidatorSpec(t, catalog, ValidatorSpec{Key: "llm-validator", ExecutionClass: contracts.ExecutionClassLLMBacked})
|
||||||
|
|
||||||
|
for _, test := range []struct {
|
||||||
|
stage ModuleStage
|
||||||
|
key string
|
||||||
|
want contracts.ExecutionClass
|
||||||
|
}{
|
||||||
|
{stage: StageInput, key: "llm-input", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: StageChunk, key: "llm-chunk", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: StageExtract, key: "llm-extract", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: StageMerge, key: "llm-merge", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: StageNormalize, key: "llm-normalize", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: StageValidate, key: "llm-validator", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
{stage: StageOutput, key: "llm-output", want: contracts.ExecutionClassLLMBacked},
|
||||||
|
} {
|
||||||
|
t.Run(string(test.stage), func(t *testing.T) {
|
||||||
|
got, ok := catalog.ExecutionClass(test.stage, test.key)
|
||||||
|
if !ok || got != test.want {
|
||||||
|
t.Fatalf("ExecutionClass(%q, %q) = %q, %t; want %q, true", test.stage, test.key, got, ok, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := catalog.ExecutionClass(StageExtract, "missing"); ok {
|
||||||
|
t.Fatal("ExecutionClass() found an unregistered module")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestResolvePipelineAppliesDefaults(t *testing.T) {
|
func TestResolvePipelineAppliesDefaults(t *testing.T) {
|
||||||
resolved, err := ResolvePipeline(PipelineProfile{
|
resolved, err := ResolvePipeline(PipelineProfile{
|
||||||
ID: "defaulted",
|
ID: "defaulted",
|
||||||
@@ -1566,7 +1615,13 @@ func TestResolvedPipelineCanMarshalToCanonicalJSON(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ResolvePipeline() error = %v, want nil", err)
|
t.Fatalf("ResolvePipeline() error = %v, want nil", err)
|
||||||
}
|
}
|
||||||
if _, err := json.Marshal(resolved); err != nil {
|
encoded, err := json.Marshal(resolved)
|
||||||
|
if err != nil {
|
||||||
t.Fatalf("json.Marshal(resolved) error = %v, want nil", err)
|
t.Fatalf("json.Marshal(resolved) error = %v, want nil", err)
|
||||||
}
|
}
|
||||||
|
for _, field := range []string{"input_execution_class", "chunk_execution_class", "extract_execution_class", "merge_execution_class", "normalize_execution_class", "output_execution_class"} {
|
||||||
|
if !strings.Contains(string(encoded), `"`+field+`":"deterministic"`) {
|
||||||
|
t.Fatalf("resolved JSON does not retain %q: %s", field, encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageChunk,
|
Stage: pipeline.StageChunk,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ReferenceSlots: shared.ReferenceSlots(referenceSlotDescriptions),
|
ReferenceSlots: shared.ReferenceSlots(referenceSlotDescriptions),
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func TestNewModuleSpecAndRegister(t *testing.T) {
|
|||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageChunk,
|
Stage: pipeline.StageChunk,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: []string{"source.transcript"},
|
Requires: []string{"source.transcript"},
|
||||||
Provides: []string{"chunks"},
|
Provides: []string{"chunks"},
|
||||||
ReferenceSlots: wantReferenceSlots(),
|
ReferenceSlots: wantReferenceSlots(),
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.CombatTurnListKind,
|
ArtifactKind: dnd.CombatTurnListKind,
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.ItemEventListKind,
|
ArtifactKind: dnd.ItemEventListKind,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestConstructorSpecOptionsAndMetadata(t *testing.T) {
|
|||||||
t.Fatalf("New() error = %v", err)
|
t.Fatalf("New() error = %v", err)
|
||||||
}
|
}
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key, Stage: pipeline.StageExtract, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.item_events"}, ArtifactKind: dnd.ItemEventListKind,
|
Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.item_events"}, ArtifactKind: dnd.ItemEventListKind,
|
||||||
ReferenceSlots: []contracts.ReferenceSlot{
|
ReferenceSlots: []contracts.ReferenceSlot{
|
||||||
{Name: "glossary", Description: referenceSlotDescriptions.Glossary, AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
{Name: "glossary", Description: referenceSlotDescriptions.Glossary, AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
||||||
{Name: "party", Description: referenceSlotDescriptions.Party, AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
{Name: "party", Description: referenceSlotDescriptions.Party, AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.NPCInteractionListKind,
|
ArtifactKind: dnd.NPCInteractionListKind,
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.NPCListKind,
|
ArtifactKind: dnd.NPCListKind,
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ func TestNewRequiresLLMClientAndRejectsAmbiguousReferences(t *testing.T) {
|
|||||||
func TestModuleSpecAndReferenceSlots(t *testing.T) {
|
func TestModuleSpecAndReferenceSlots(t *testing.T) {
|
||||||
got := ModuleSpec()
|
got := ModuleSpec()
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
Requires: []string{"chunks", "source.transcript"},
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Provides: []string{"dnd.npcs"},
|
Requires: []string{"chunks", "source.transcript"},
|
||||||
ArtifactKind: dnd.NPCListKind,
|
Provides: []string{"dnd.npcs"},
|
||||||
|
ArtifactKind: dnd.NPCListKind,
|
||||||
ReferenceSlots: []contracts.ReferenceSlot{
|
ReferenceSlots: []contracts.ReferenceSlot{
|
||||||
{Name: "glossary", Description: "Optional campaign glossary reference material used only for NPC disambiguation.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
{Name: "glossary", Description: "Optional campaign glossary reference material used only for NPC disambiguation.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
||||||
{Name: "party", Description: "Optional party roster reference material used only for NPC disambiguation.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
{Name: "party", Description: "Optional party roster reference material used only for NPC disambiguation.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.SceneDescriptionListKind,
|
ArtifactKind: dnd.SceneDescriptionListKind,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func TestNewRequiresLLMClientAndRejectsAmbiguousReferences(t *testing.T) {
|
|||||||
|
|
||||||
func TestModuleSpecAndReferenceSlots(t *testing.T) {
|
func TestModuleSpecAndReferenceSlots(t *testing.T) {
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key, Stage: pipeline.StageExtract, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.scene_descriptions"}, ArtifactKind: dnd.SceneDescriptionListKind,
|
Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.scene_descriptions"}, ArtifactKind: dnd.SceneDescriptionListKind,
|
||||||
ReferenceSlots: []contracts.ReferenceSlot{
|
ReferenceSlots: []contracts.ReferenceSlot{
|
||||||
{Name: "glossary", Description: "Optional campaign glossary reference material used only to disambiguate scene descriptions.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
{Name: "glossary", Description: "Optional campaign glossary reference material used only to disambiguate scene descriptions.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
||||||
{Name: "party", Description: "Optional party roster reference material used only to disambiguate scene descriptions.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
{Name: "party", Description: "Optional party roster reference material used only to disambiguate scene descriptions.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.SpellListKind,
|
ArtifactKind: dnd.SpellListKind,
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ func TestNewRequiresLLMClientAndReturnsExtractor(t *testing.T) {
|
|||||||
func TestModuleSpec(t *testing.T) {
|
func TestModuleSpec(t *testing.T) {
|
||||||
got := ModuleSpec()
|
got := ModuleSpec()
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageExtract,
|
Stage: pipeline.StageExtract,
|
||||||
|
ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||||
Requires: []string{
|
Requires: []string{
|
||||||
"chunks",
|
"chunks",
|
||||||
"source.transcript",
|
"source.transcript",
|
||||||
|
|||||||
@@ -336,6 +336,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageNormalize,
|
Stage: pipeline.StageNormalize,
|
||||||
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.CombatTurnListKind,
|
ArtifactKind: dnd.CombatTurnListKind,
|
||||||
|
|||||||
@@ -222,11 +222,12 @@ func eventScope(index int) string { return fmt.Sprintf("events[%d]", index) }
|
|||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageNormalize,
|
Stage: pipeline.StageNormalize,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
ArtifactKind: dnd.ItemEventListKind,
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
|
ArtifactKind: dnd.ItemEventListKind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,6 +278,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageNormalize,
|
Stage: pipeline.StageNormalize,
|
||||||
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.NPCInteractionListKind,
|
ArtifactKind: dnd.NPCInteractionListKind,
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ func duplicateWarning(retainedIndex int, removed []int) contracts.Warning {
|
|||||||
func npcScope(index int) string { return fmt.Sprintf("npcs[%d]", index) }
|
func npcScope(index int) string { return fmt.Sprintf("npcs[%d]", index) }
|
||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, Requires: append([]string(nil), requiredCapabilities...), Provides: append([]string(nil), providedCapabilities...), ArtifactKind: dnd.NPCListKind}
|
return pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: append([]string(nil), requiredCapabilities...), Provides: append([]string(nil), providedCapabilities...), ArtifactKind: dnd.NPCListKind}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(registry *pipeline.NormalizerRegistry) error {
|
func Register(registry *pipeline.NormalizerRegistry) error {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func TestModuleContractAndIdentity(t *testing.T) {
|
|||||||
if _, err := DecodeOptions(map[string]any{"unexpected": true}); err == nil {
|
if _, err := DecodeOptions(map[string]any{"unexpected": true}); err == nil {
|
||||||
t.Fatal("DecodeOptions() accepted unknown option")
|
t.Fatal("DecodeOptions() accepted unknown option")
|
||||||
}
|
}
|
||||||
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, Requires: []string{"merged"}, Provides: []string{"normalized"}, ArtifactKind: dnd.NPCListKind}
|
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"merged"}, Provides: []string{"normalized"}, ArtifactKind: dnd.NPCListKind}
|
||||||
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,11 +138,12 @@ func sourceRefLabel(ref source.SourceRef) string {
|
|||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageNormalize,
|
Stage: pipeline.StageNormalize,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
ArtifactKind: dnd.SceneDescriptionListKind,
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
|
ArtifactKind: dnd.SceneDescriptionListKind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ func TestNormalizerContractAndCancellation(t *testing.T) {
|
|||||||
if _, err := DecodeOptions(map[string]any{"unexpected": true}); err == nil {
|
if _, err := DecodeOptions(map[string]any{"unexpected": true}); err == nil {
|
||||||
t.Fatal("DecodeOptions() accepted unknown options")
|
t.Fatal("DecodeOptions() accepted unknown options")
|
||||||
}
|
}
|
||||||
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, Requires: []string{"merged"}, Provides: []string{"normalized"}, ArtifactKind: dnd.SceneDescriptionListKind}
|
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, ExecutionClass: contracts.ExecutionClassDeterministic, Requires: []string{"merged"}, Provides: []string{"normalized"}, ArtifactKind: dnd.SceneDescriptionListKind}
|
||||||
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ func ModuleSpec() pipeline.ModuleSpec {
|
|||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageNormalize,
|
Stage: pipeline.StageNormalize,
|
||||||
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Requires: append([]string(nil), requiredCapabilities...),
|
Requires: append([]string(nil), requiredCapabilities...),
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
ArtifactKind: dnd.SpellListKind,
|
ArtifactKind: dnd.SpellListKind,
|
||||||
|
|||||||
@@ -24,11 +24,12 @@ func TestModuleContractAndStrictOptions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageNormalize,
|
Stage: pipeline.StageNormalize,
|
||||||
Requires: []string{"merged"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Provides: []string{"normalized"},
|
Requires: []string{"merged"},
|
||||||
ArtifactKind: dnd.SpellListKind,
|
Provides: []string{"normalized"},
|
||||||
|
ArtifactKind: dnd.SpellListKind,
|
||||||
ReferenceSlots: []contracts.ReferenceSlot{{
|
ReferenceSlots: []contracts.ReferenceSlot{{
|
||||||
Name: spellcatalog.SpellCatalogReferenceSlot,
|
Name: spellcatalog.SpellCatalogReferenceSlot,
|
||||||
Description: "Optional canonical spell-name catalog used for normalization and duplicate identity.",
|
Description: "Optional canonical spell-name catalog used for normalization and duplicate identity.",
|
||||||
|
|||||||
@@ -90,9 +90,10 @@ func (c *Chunker) Plan(ctx context.Context, req contracts.ChunkRequest) (contrac
|
|||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageChunk,
|
Stage: pipeline.StageChunk,
|
||||||
Provides: []string{"chunks"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
|
Provides: []string{"chunks"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import (
|
|||||||
|
|
||||||
func TestModuleSpecAndRegister(t *testing.T) {
|
func TestModuleSpecAndRegister(t *testing.T) {
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageChunk,
|
Stage: pipeline.StageChunk,
|
||||||
Provides: []string{"chunks"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
|
Provides: []string{"chunks"},
|
||||||
}
|
}
|
||||||
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ package appendorder
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
||||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Key = "appendorder"
|
const Key = "appendorder"
|
||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageMerge, Provides: []string{"merged"}}
|
return pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageMerge, ExecutionClass: contracts.ExecutionClassDeterministic, Provides: []string{"merged"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergerErrorf(format string, args ...any) error {
|
func mergerErrorf(format string, args ...any) error {
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ package noop
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
||||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Key = "noop"
|
const Key = "noop"
|
||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, Requires: []string{"merged"}, Provides: []string{"normalized"}}
|
return pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageNormalize, ExecutionClass: contracts.ExecutionClassDeterministic, Requires: []string{"merged"}, Provides: []string{"normalized"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizerErrorf(format string, args ...any) error {
|
func normalizerErrorf(format string, args ...any) error {
|
||||||
|
|||||||
@@ -80,10 +80,11 @@ func (e *Encoder) Encode(ctx context.Context, req contracts.OutputRequest) (cont
|
|||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageOutput,
|
Stage: pipeline.StageOutput,
|
||||||
Requires: []string{"normalized"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Provides: []string{"encoded"},
|
Requires: []string{"normalized"},
|
||||||
|
Provides: []string{"encoded"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ import (
|
|||||||
|
|
||||||
func TestModuleSpecAndRegister(t *testing.T) {
|
func TestModuleSpecAndRegister(t *testing.T) {
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageOutput,
|
Stage: pipeline.StageOutput,
|
||||||
Requires: []string{"normalized"},
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Provides: []string{"encoded"},
|
Requires: []string{"normalized"},
|
||||||
|
Provides: []string{"encoded"},
|
||||||
}
|
}
|
||||||
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
||||||
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
||||||
|
|||||||
@@ -94,9 +94,10 @@ func (a *Adapter) Parse(ctx context.Context, req contracts.ParseRequest) (*sourc
|
|||||||
|
|
||||||
func ModuleSpec() pipeline.ModuleSpec {
|
func ModuleSpec() pipeline.ModuleSpec {
|
||||||
return pipeline.ModuleSpec{
|
return pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageInput,
|
Stage: pipeline.StageInput,
|
||||||
Provides: append([]string(nil), providedCapabilities...),
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
|
Provides: append([]string(nil), providedCapabilities...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
|
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
|
||||||
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
||||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,8 +24,9 @@ func TestNewReturnsAdapterWithKey(t *testing.T) {
|
|||||||
func TestModuleSpec(t *testing.T) {
|
func TestModuleSpec(t *testing.T) {
|
||||||
got := ModuleSpec()
|
got := ModuleSpec()
|
||||||
want := pipeline.ModuleSpec{
|
want := pipeline.ModuleSpec{
|
||||||
Key: Key,
|
Key: Key,
|
||||||
Stage: pipeline.StageInput,
|
Stage: pipeline.StageInput,
|
||||||
|
ExecutionClass: contracts.ExecutionClassDeterministic,
|
||||||
Provides: []string{
|
Provides: []string{
|
||||||
"source.transcript",
|
"source.transcript",
|
||||||
"transcript.speaker",
|
"transcript.speaker",
|
||||||
|
|||||||
Reference in New Issue
Block a user