Update the architecture plan to standardize on input -> chunk -> extract -> merge -> normalize -> output naming conventions
This commit is contained in:
@@ -107,7 +107,7 @@ func (extractor compositionExtractor) Extract(ctx context.Context, req contracts
|
||||
}
|
||||
|
||||
return contracts.ExtractionResult{
|
||||
Candidates: []artifacts.Candidate{
|
||||
Candidates: []artifacts.ArtifactCandidate{
|
||||
{
|
||||
Index: 0,
|
||||
ExtractorKey: extractor.Key(),
|
||||
|
||||
@@ -53,8 +53,8 @@ type ExtractionRequest struct {
|
||||
}
|
||||
|
||||
type ExtractionResult struct {
|
||||
Candidates []artifacts.Candidate `json:"candidates,omitempty"`
|
||||
Warnings []Warning `json:"warnings,omitempty"`
|
||||
Candidates []artifacts.ArtifactCandidate `json:"candidates,omitempty"`
|
||||
Warnings []Warning `json:"warnings,omitempty"`
|
||||
}
|
||||
|
||||
type Extractor interface {
|
||||
@@ -66,9 +66,9 @@ type Extractor interface {
|
||||
}
|
||||
|
||||
type ValidationRequest struct {
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
Candidates []artifacts.Candidate `json:"candidates"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
Candidates []artifacts.ArtifactCandidate `json:"candidates"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ValidationDecision struct {
|
||||
|
||||
@@ -58,19 +58,19 @@ func TestFakeExtractorReturnsCandidateAndValidator(t *testing.T) {
|
||||
|
||||
candidate := result.Candidates[0]
|
||||
if candidate.Index != 0 {
|
||||
t.Fatalf("Candidate.Index = %d, want 0", candidate.Index)
|
||||
t.Fatalf("ArtifactCandidate.Index = %d, want 0", candidate.Index)
|
||||
}
|
||||
if candidate.ExtractorKey != extractor.Key() {
|
||||
t.Fatalf("Candidate.ExtractorKey = %q, want %q", candidate.ExtractorKey, extractor.Key())
|
||||
t.Fatalf("ArtifactCandidate.ExtractorKey = %q, want %q", candidate.ExtractorKey, extractor.Key())
|
||||
}
|
||||
if candidate.ArtifactType != extractor.ArtifactType() {
|
||||
t.Fatalf("Candidate.ArtifactType = %q, want %q", candidate.ArtifactType, extractor.ArtifactType())
|
||||
t.Fatalf("ArtifactCandidate.ArtifactType = %q, want %q", candidate.ArtifactType, extractor.ArtifactType())
|
||||
}
|
||||
if candidate.SchemaVersion != extractor.SchemaVersion() {
|
||||
t.Fatalf("Candidate.SchemaVersion = %q, want %q", candidate.SchemaVersion, extractor.SchemaVersion())
|
||||
t.Fatalf("ArtifactCandidate.SchemaVersion = %q, want %q", candidate.SchemaVersion, extractor.SchemaVersion())
|
||||
}
|
||||
if string(candidate.Payload) != `{"value":"example"}` {
|
||||
t.Fatalf("Candidate.Payload = %s, want example payload", candidate.Payload)
|
||||
t.Fatalf("ArtifactCandidate.Payload = %s, want example payload", candidate.Payload)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (extractor fakeExtractor) Validators() []Validator {
|
||||
|
||||
func (extractor fakeExtractor) Extract(ctx context.Context, req ExtractionRequest) (ExtractionResult, error) {
|
||||
return ExtractionResult{
|
||||
Candidates: []artifacts.Candidate{
|
||||
Candidates: []artifacts.ArtifactCandidate{
|
||||
{
|
||||
Index: 0,
|
||||
ExtractorKey: extractor.key,
|
||||
|
||||
@@ -82,7 +82,7 @@ func (extractor integrationExtractor) Validators() []contracts.Validator {
|
||||
func (extractor integrationExtractor) Extract(ctx context.Context, req contracts.ExtractionRequest) (contracts.ExtractionResult, error) {
|
||||
*extractor.executedKeys = append(*extractor.executedKeys, extractor.key)
|
||||
return contracts.ExtractionResult{
|
||||
Candidates: []artifacts.Candidate{
|
||||
Candidates: []artifacts.ArtifactCandidate{
|
||||
{Payload: []byte(`{"value":true}`)},
|
||||
},
|
||||
}, nil
|
||||
|
||||
@@ -90,8 +90,8 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (RunOutput, error) {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func normalizeCandidates(extractor contracts.Extractor, candidates []artifacts.Candidate, nextIndex *int) ([]artifacts.Candidate, error) {
|
||||
normalized := make([]artifacts.Candidate, 0, len(candidates))
|
||||
func normalizeCandidates(extractor contracts.Extractor, candidates []artifacts.ArtifactCandidate, nextIndex *int) ([]artifacts.ArtifactCandidate, error) {
|
||||
normalized := make([]artifacts.ArtifactCandidate, 0, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
candidate.Index = *nextIndex
|
||||
*nextIndex = *nextIndex + 1
|
||||
@@ -119,7 +119,7 @@ func normalizeCandidates(extractor contracts.Extractor, candidates []artifacts.C
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
func runValidators(ctx context.Context, extractor contracts.Extractor, doc *source.SourceDocument, candidates []artifacts.Candidate, metadata map[string]any) ([]artifacts.Candidate, []artifacts.RejectedArtifact, []contracts.Warning, error) {
|
||||
func runValidators(ctx context.Context, extractor contracts.Extractor, doc *source.SourceDocument, candidates []artifacts.ArtifactCandidate, metadata map[string]any) ([]artifacts.ArtifactCandidate, []artifacts.RejectedArtifact, []contracts.Warning, error) {
|
||||
eligible := candidates
|
||||
var rejected []artifacts.RejectedArtifact
|
||||
var warnings []contracts.Warning
|
||||
@@ -149,7 +149,7 @@ func runValidators(ctx context.Context, extractor contracts.Extractor, doc *sour
|
||||
decisions[decision.CandidateIndex] = decision
|
||||
}
|
||||
|
||||
nextEligible := make([]artifacts.Candidate, 0, len(eligible))
|
||||
nextEligible := make([]artifacts.ArtifactCandidate, 0, len(eligible))
|
||||
for _, candidate := range eligible {
|
||||
decision := decisions[candidate.Index]
|
||||
if decision.Approved {
|
||||
|
||||
@@ -99,7 +99,7 @@ func TestRunRejectsNilExtractorFromFactory(t *testing.T) {
|
||||
func TestRunUsesConfiguredExtractorOrderAndAssignsGlobalIndices(t *testing.T) {
|
||||
var order []string
|
||||
var seenIndices []int
|
||||
recordIndices := func(candidates []artifacts.Candidate) []contracts.ValidationDecision {
|
||||
recordIndices := func(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
decisions := make([]contracts.ValidationDecision, 0, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
seenIndices = append(seenIndices, candidate.Index)
|
||||
@@ -133,7 +133,7 @@ func TestRunUsesConfiguredExtractorOrderAndAssignsGlobalIndices(t *testing.T) {
|
||||
|
||||
func TestRunFillsEmptyCandidateExtractorMetadata(t *testing.T) {
|
||||
factory := fakeFactory{extractors: map[string]contracts.Extractor{
|
||||
"generic-extractor": fakeExtractor{key: "generic-extractor", artifactType: "generic-artifact", schemaVersion: "v1", candidates: []artifacts.Candidate{{Payload: []byte(`{"value":true}`)}}},
|
||||
"generic-extractor": fakeExtractor{key: "generic-extractor", artifactType: "generic-artifact", schemaVersion: "v1", candidates: []artifacts.ArtifactCandidate{{Payload: []byte(`{"value":true}`)}}},
|
||||
}}
|
||||
|
||||
output, err := New(factory).Run(context.Background(), RunInput{Source: validSourceDocument(), ExtractorKeys: []string{"generic-extractor"}})
|
||||
@@ -150,18 +150,18 @@ func TestRunFillsEmptyCandidateExtractorMetadata(t *testing.T) {
|
||||
func TestRunRejectsCandidateMetadataMismatches(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
candidate artifacts.Candidate
|
||||
candidate artifacts.ArtifactCandidate
|
||||
error string
|
||||
}{
|
||||
{name: "extractor key", candidate: artifacts.Candidate{ExtractorKey: "other"}, error: "extractor_key"},
|
||||
{name: "artifact type", candidate: artifacts.Candidate{ArtifactType: "other"}, error: "artifact_type"},
|
||||
{name: "schema version", candidate: artifacts.Candidate{SchemaVersion: "other"}, error: "schema_version"},
|
||||
{name: "extractor key", candidate: artifacts.ArtifactCandidate{ExtractorKey: "other"}, error: "extractor_key"},
|
||||
{name: "artifact type", candidate: artifacts.ArtifactCandidate{ArtifactType: "other"}, error: "artifact_type"},
|
||||
{name: "schema version", candidate: artifacts.ArtifactCandidate{SchemaVersion: "other"}, error: "schema_version"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
factory := fakeFactory{extractors: map[string]contracts.Extractor{
|
||||
"generic-extractor": fakeExtractor{key: "generic-extractor", artifactType: "generic-artifact", schemaVersion: "v1", candidates: []artifacts.Candidate{tt.candidate}},
|
||||
"generic-extractor": fakeExtractor{key: "generic-extractor", artifactType: "generic-artifact", schemaVersion: "v1", candidates: []artifacts.ArtifactCandidate{tt.candidate}},
|
||||
}}
|
||||
|
||||
_, err := New(factory).Run(context.Background(), RunInput{Source: validSourceDocument(), ExtractorKeys: []string{"generic-extractor"}})
|
||||
@@ -194,7 +194,7 @@ func TestRunApprovesCandidatesWithoutValidators(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunValidatorApprovalProducesApprovedArtifacts(t *testing.T) {
|
||||
validator := fakeValidator{name: "generic-validator", decisions: func(candidates []artifacts.Candidate) []contracts.ValidationDecision {
|
||||
validator := fakeValidator{name: "generic-validator", decisions: func(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
return []contracts.ValidationDecision{validationhelpers.Approved(candidates[0].Index)}
|
||||
}}
|
||||
factory := fakeFactory{extractors: map[string]contracts.Extractor{
|
||||
@@ -212,13 +212,13 @@ func TestRunValidatorApprovalProducesApprovedArtifacts(t *testing.T) {
|
||||
|
||||
func TestRunValidatorRejectionRemovesCandidateFromLaterValidators(t *testing.T) {
|
||||
var laterSeen int
|
||||
rejectFirst := fakeValidator{name: "reject-first", decisions: func(candidates []artifacts.Candidate) []contracts.ValidationDecision {
|
||||
rejectFirst := fakeValidator{name: "reject-first", decisions: func(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
return []contracts.ValidationDecision{
|
||||
validationhelpers.Rejected(candidates[0].Index, "invalid", "not accepted"),
|
||||
validationhelpers.Approved(candidates[1].Index),
|
||||
}
|
||||
}}
|
||||
approveRemaining := fakeValidator{name: "approve-remaining", decisions: func(candidates []artifacts.Candidate) []contracts.ValidationDecision {
|
||||
approveRemaining := fakeValidator{name: "approve-remaining", decisions: func(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
laterSeen = len(candidates)
|
||||
return []contracts.ValidationDecision{validationhelpers.Approved(candidates[0].Index)}
|
||||
}}
|
||||
@@ -254,7 +254,7 @@ func TestRunSurfacesValidatorNameMismatch(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunSurfacesValidatorCardinalityError(t *testing.T) {
|
||||
validator := fakeValidator{name: "generic-validator", decisions: func(candidates []artifacts.Candidate) []contracts.ValidationDecision {
|
||||
validator := fakeValidator{name: "generic-validator", decisions: func(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
return nil
|
||||
}}
|
||||
factory := factoryWithValidator(validator)
|
||||
@@ -359,7 +359,7 @@ type fakeExtractor struct {
|
||||
artifactType string
|
||||
schemaVersion string
|
||||
candidateCount int
|
||||
candidates []artifacts.Candidate
|
||||
candidates []artifacts.ArtifactCandidate
|
||||
validators []contracts.Validator
|
||||
warnings []contracts.Warning
|
||||
err error
|
||||
@@ -386,9 +386,9 @@ func (extractor fakeExtractor) Extract(ctx context.Context, req contracts.Extrac
|
||||
if extractor.order != nil {
|
||||
*extractor.order = append(*extractor.order, extractor.key)
|
||||
}
|
||||
candidates := append([]artifacts.Candidate(nil), extractor.candidates...)
|
||||
candidates := append([]artifacts.ArtifactCandidate(nil), extractor.candidates...)
|
||||
for len(candidates) < extractor.candidateCount {
|
||||
candidates = append(candidates, artifacts.Candidate{Payload: []byte(`{"value":true}`)})
|
||||
candidates = append(candidates, artifacts.ArtifactCandidate{Payload: []byte(`{"value":true}`)})
|
||||
}
|
||||
return contracts.ExtractionResult{
|
||||
Candidates: candidates,
|
||||
@@ -399,7 +399,7 @@ func (extractor fakeExtractor) Extract(ctx context.Context, req contracts.Extrac
|
||||
type fakeValidator struct {
|
||||
name string
|
||||
resultName string
|
||||
decisions func([]artifacts.Candidate) []contracts.ValidationDecision
|
||||
decisions func([]artifacts.ArtifactCandidate) []contracts.ValidationDecision
|
||||
warnings []contracts.Warning
|
||||
err error
|
||||
}
|
||||
@@ -436,7 +436,7 @@ func factoryWithValidator(validator contracts.Validator) fakeFactory {
|
||||
}}
|
||||
}
|
||||
|
||||
func approveAll(candidates []artifacts.Candidate) []contracts.ValidationDecision {
|
||||
func approveAll(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
decisions := make([]contracts.ValidationDecision, 0, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
decisions = append(decisions, validationhelpers.Approved(candidate.Index))
|
||||
|
||||
@@ -30,7 +30,7 @@ func Rejected(candidateIndex int, reasonCode string, message string) contracts.V
|
||||
}
|
||||
}
|
||||
|
||||
func EnforceDecisionCardinality(candidates []artifacts.Candidate, decisions []contracts.ValidationDecision) error {
|
||||
func EnforceDecisionCardinality(candidates []artifacts.ArtifactCandidate, decisions []contracts.ValidationDecision) error {
|
||||
if len(candidates) != len(decisions) {
|
||||
return fmt.Errorf("validator returned %d decisions for %d candidates", len(decisions), len(candidates))
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestRejectedTrimsReasonAndMessage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnforceDecisionCardinalityAllowsNonZeroCandidateIndices(t *testing.T) {
|
||||
candidates := []artifacts.Candidate{{Index: 4}, {Index: 8}}
|
||||
candidates := []artifacts.ArtifactCandidate{{Index: 4}, {Index: 8}}
|
||||
decisions := []contracts.ValidationDecision{Approved(8), Approved(4)}
|
||||
|
||||
if err := EnforceDecisionCardinality(candidates, decisions); err != nil {
|
||||
@@ -59,7 +59,7 @@ func TestEnforceDecisionCardinalityAllowsEmptyInputs(t *testing.T) {
|
||||
|
||||
func TestEnforceDecisionCardinalityRejectsUnknownDecisionIndex(t *testing.T) {
|
||||
err := EnforceDecisionCardinality(
|
||||
[]artifacts.Candidate{{Index: 1}},
|
||||
[]artifacts.ArtifactCandidate{{Index: 1}},
|
||||
[]contracts.ValidationDecision{Approved(2)},
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestEnforceDecisionCardinalityRejectsUnknownDecisionIndex(t *testing.T) {
|
||||
|
||||
func TestEnforceDecisionCardinalityRejectsDuplicateDecisionIndex(t *testing.T) {
|
||||
err := EnforceDecisionCardinality(
|
||||
[]artifacts.Candidate{{Index: 1}, {Index: 2}},
|
||||
[]artifacts.ArtifactCandidate{{Index: 1}, {Index: 2}},
|
||||
[]contracts.ValidationDecision{Approved(1), Approved(1)},
|
||||
)
|
||||
|
||||
@@ -77,7 +77,7 @@ func TestEnforceDecisionCardinalityRejectsDuplicateDecisionIndex(t *testing.T) {
|
||||
|
||||
func TestEnforceDecisionCardinalityRejectsMissingDecisionIndex(t *testing.T) {
|
||||
err := EnforceDecisionCardinality(
|
||||
[]artifacts.Candidate{{Index: 1}, {Index: 2}},
|
||||
[]artifacts.ArtifactCandidate{{Index: 1}, {Index: 2}},
|
||||
[]contracts.ValidationDecision{Approved(1)},
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ func TestEnforceDecisionCardinalityRejectsMissingDecisionIndex(t *testing.T) {
|
||||
|
||||
func TestEnforceDecisionCardinalityRejectsDuplicateCandidateIndex(t *testing.T) {
|
||||
err := EnforceDecisionCardinality(
|
||||
[]artifacts.Candidate{{Index: 1}, {Index: 1}},
|
||||
[]artifacts.ArtifactCandidate{{Index: 1}, {Index: 1}},
|
||||
[]contracts.ValidationDecision{Approved(1), Approved(1)},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user