Phase 3 of identity-deregistry. BuildEffectiveCommandRegistry now builds the EffectiveCommandRegistry from CollectIdentitySpecs(root) instead of the embedded reviewed registry, and the registry source is removed atomically: - delete internal/cli/schema_command_registry/ (registry.json + products/), schema_command_registry.schema.json, the three //go:embed directives, and the registry-only loaders/validators (loadReviewedCommandRegistry, decodeCommandRegistry, ValidateCommandRegistrySource, shard assemble/merge helpers, ReviewedCommandRegistryMergedJSON/SourceHash, ReviewedCommandSpecs) - keep CommandSpec/CommandRegistry/EffectiveCommandRegistry, newEffectiveCommandRegistry/indexCommandSpecs, and SourceHash; the collector-built effective hash is byte-identical to the reviewed one, so catalog surface_hash/source_hash are unchanged - convert the Phase 2 dual-run gate into TestCollectedIdentityIsValidSingleSource: collected specs non-empty, no missing primaries, effective build succeeds, SourceHash stable across repeated collection walks - generators: catalog -surface and agent-metadata -registry/-surface become fail-closed retired valves; outputguard no longer protects the registry paths; fetch_mcp_metadata derives interface refs from collected identity instead of the merged registry JSON - retire scripts/policy/check-schema-command-registry.sh and its Makefile invocation; generate-schema/check-generated-drift now fail closed if schema_command_registry/ reappears - update AGENTS.md, docs/reference.md, and in-code reviewed-input notes
423 lines
17 KiB
Go
423 lines
17 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
package cli
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func TestDeliveryRuntimeSchemaExclusionsAreReviewedExact(t *testing.T) {
|
|
exclusions, err := ReviewedRuntimeSchemaExclusions()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(exclusions) == 0 {
|
|
t.Fatal("reviewed runtime schema exclusions must not be empty")
|
|
}
|
|
seen := map[string]bool{}
|
|
for _, exclusion := range exclusions {
|
|
if !exclusion.Reviewed || strings.TrimSpace(exclusion.Reason) == "" {
|
|
t.Fatalf("unreviewed exclusion: %#v", exclusion)
|
|
}
|
|
path := normalizeSchemaCLIPath(exclusion.CLIPath)
|
|
if path == "" || path != exclusion.CLIPath {
|
|
t.Fatalf("exclusion path must be normalized and non-empty: %#v", exclusion)
|
|
}
|
|
if seen[path] {
|
|
t.Fatalf("duplicate exclusion %q", path)
|
|
}
|
|
seen[path] = true
|
|
}
|
|
for _, group := range reviewedRuntimeSchemaExclusionGroups {
|
|
if strings.TrimSpace(group.ID) == "" || !group.Reviewed || strings.TrimSpace(group.Reason) == "" {
|
|
t.Fatalf("invalid exclusion group: %#v", group)
|
|
}
|
|
if len(group.Commands) == 0 {
|
|
t.Fatalf("exclusion group %q has no commands", group.ID)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRuntimeSchemaCompletenessRequiresCoverageOrReviewedExclusion(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
covered := &cobra.Command{Use: "covered", Run: func(*cobra.Command, []string) {}}
|
|
missing := &cobra.Command{Use: "missing", Run: func(*cobra.Command, []string) {}}
|
|
excluded := &cobra.Command{Use: "excluded", Run: func(*cobra.Command, []string) {}}
|
|
hidden := &cobra.Command{Use: "hidden", Hidden: true, Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(covered, "sample", "covered", "test")
|
|
root.AddCommand(covered, missing, excluded, hidden)
|
|
|
|
report := runtimeSchemaCompletenessForTest(root, []RuntimeSchemaExclusion{{
|
|
CLIPath: "excluded", Reason: "reviewed test exclusion", Reviewed: true,
|
|
}})
|
|
if !reflect.DeepEqual(report.Covered, []string{"covered"}) {
|
|
t.Fatalf("covered = %v", report.Covered)
|
|
}
|
|
if !reflect.DeepEqual(report.Excluded, []string{"excluded"}) {
|
|
t.Fatalf("excluded = %v", report.Excluded)
|
|
}
|
|
if !reflect.DeepEqual(report.Missing, []string{"missing"}) {
|
|
t.Fatalf("missing = %v", report.Missing)
|
|
}
|
|
if len(report.InvalidExclusions) != 0 || len(report.StaleExclusions) != 0 {
|
|
t.Fatalf("invalid=%v stale=%v", report.InvalidExclusions, report.StaleExclusions)
|
|
}
|
|
}
|
|
|
|
func TestRuntimeSchemaCompletenessRejectsInvalidAndStaleExclusions(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
current := &cobra.Command{Use: "current", Run: func(*cobra.Command, []string) {}}
|
|
covered := &cobra.Command{Use: "covered", Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(covered, "sample", "covered", "test")
|
|
root.AddCommand(current, covered)
|
|
report := runtimeSchemaCompletenessForTest(root, []RuntimeSchemaExclusion{
|
|
{CLIPath: "current", Reason: "", Reviewed: true},
|
|
{CLIPath: "stale", Reason: "reviewed but obsolete", Reviewed: true},
|
|
{CLIPath: "covered", Reason: "no longer needed", Reviewed: true},
|
|
})
|
|
if !reflect.DeepEqual(report.InvalidExclusions, []string{"current"}) {
|
|
t.Fatalf("invalid = %v", report.InvalidExclusions)
|
|
}
|
|
if !reflect.DeepEqual(report.StaleExclusions, []string{"covered", "stale"}) {
|
|
t.Fatalf("stale = %v", report.StaleExclusions)
|
|
}
|
|
if !reflect.DeepEqual(report.Missing, []string{"current"}) {
|
|
t.Fatalf("missing = %v", report.Missing)
|
|
}
|
|
}
|
|
|
|
func TestEffectiveCommandRegistryOwnsIdentityWithoutNativeAnnotation(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
product := &cobra.Command{Use: "aisearch"}
|
|
leaf := &cobra.Command{Use: "person", Run: func(*cobra.Command, []string) {}}
|
|
product.AddCommand(leaf)
|
|
root.AddCommand(product)
|
|
|
|
spec := CommandSpec{
|
|
CanonicalPath: "aisearch.enterprise_person_search",
|
|
PrimaryCLIPath: "aisearch person",
|
|
}
|
|
effective, err := newEffectiveCommandRegistry([]CommandSpec{spec})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bound, err := BindEffectiveCommandRegistry(root, effective)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
entries, err := collectRuntimeSchemaEntriesFromBound(bound)
|
|
if err != nil || len(entries) != 1 || entries[0].ProductID+"."+entries[0].ToolName != spec.CanonicalPath {
|
|
t.Fatalf("registry-owned entries = %#v, err=%v", entries, err)
|
|
}
|
|
|
|
AttachRuntimeSchema(leaf, "aisearch", "wrong_identity", "test")
|
|
if _, err := BindEffectiveCommandRegistry(root, effective); err == nil || !strings.Contains(err.Error(), "conflicts with native annotation") {
|
|
t.Fatalf("native mismatch error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsAnnotatedLeafOutsideSurface(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
product := &cobra.Command{Use: "sample"}
|
|
covered := &cobra.Command{Use: "covered", Run: func(*cobra.Command, []string) {}}
|
|
omitted := &cobra.Command{Use: "omitted", Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(covered, "sample", "covered", "test")
|
|
AttachRuntimeSchema(omitted, "sample", "omitted", "test")
|
|
product.AddCommand(covered, omitted)
|
|
root.AddCommand(product)
|
|
|
|
annotationReport := runtimeSchemaCompletenessForTest(root, nil)
|
|
if !reflect.DeepEqual(annotationReport.Covered, []string{"sample covered", "sample omitted"}) || len(annotationReport.Missing) != 0 {
|
|
t.Fatalf("annotation report = %#v", annotationReport)
|
|
}
|
|
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{
|
|
Canonical: "sample.covered", CLIPath: "sample covered",
|
|
})
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, snapshot, nil)
|
|
if !reflect.DeepEqual(report.Covered, []string{"sample covered"}) {
|
|
t.Fatalf("covered = %v", report.Covered)
|
|
}
|
|
if !reflect.DeepEqual(report.Missing, []string{"sample omitted"}) {
|
|
t.Fatalf("missing = %v", report.Missing)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessAcceptsExactReviewedExclusion(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
product := &cobra.Command{Use: "sample"}
|
|
covered := &cobra.Command{Use: "covered", Run: func(*cobra.Command, []string) {}}
|
|
excluded := &cobra.Command{Use: "excluded", Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(covered, "sample", "covered", "test")
|
|
product.AddCommand(covered, excluded)
|
|
root.AddCommand(product)
|
|
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{
|
|
Canonical: "sample.covered", CLIPath: "sample covered",
|
|
})
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, snapshot, []RuntimeSchemaExclusion{{
|
|
CLIPath: "sample excluded", Reason: "reviewed test exclusion", Reviewed: true,
|
|
}})
|
|
if !reflect.DeepEqual(report.Covered, []string{"sample covered"}) ||
|
|
!reflect.DeepEqual(report.Excluded, []string{"sample excluded"}) ||
|
|
len(report.Missing) != 0 || len(report.StaleExclusions) != 0 {
|
|
t.Fatalf("delivery report = %#v", report)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessAcceptsDeliveredAlias(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
product := &cobra.Command{Use: "sample"}
|
|
current := &cobra.Command{Use: "current", Hidden: true, Run: func(*cobra.Command, []string) {}}
|
|
legacy := &cobra.Command{Use: "legacy", Run: func(*cobra.Command, []string) {}}
|
|
annotateTestCompatibilityPair(current, legacy)
|
|
AttachRuntimeSchema(current, "sample", "current", "test")
|
|
AttachRuntimeSchema(legacy, "sample", "current", "test")
|
|
product.AddCommand(current, legacy)
|
|
root.AddCommand(product)
|
|
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{
|
|
Canonical: "sample.current", CLIPath: "sample current", Aliases: []string{"sample legacy"},
|
|
})
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, snapshot, nil)
|
|
if !reflect.DeepEqual(report.Covered, []string{"sample legacy"}) || len(report.Missing) != 0 {
|
|
t.Fatalf("delivery report = %#v", report)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsWrongCanonical(t *testing.T) {
|
|
root := schemaDeliveryTestRoot(
|
|
schemaDeliveryTestTool{Canonical: "sample.expected", CLIPath: "sample run"},
|
|
)
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{
|
|
Canonical: "sample.wrong", CLIPath: "sample run",
|
|
})
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, snapshot, nil)
|
|
if !reflect.DeepEqual(report.Missing, []string{"sample run"}) {
|
|
t.Fatalf("missing = %v", report.Missing)
|
|
}
|
|
if len(report.DeliveryErrors) == 0 {
|
|
t.Fatal("wrong canonical passed final delivery validation")
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsMissingFinalLookup(t *testing.T) {
|
|
root := schemaDeliveryTestRoot(
|
|
schemaDeliveryTestTool{Canonical: "sample.delivered", CLIPath: "sample delivered"},
|
|
schemaDeliveryTestTool{Canonical: "sample.missing", CLIPath: "sample missing"},
|
|
)
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{
|
|
Canonical: "sample.delivered", CLIPath: "sample delivered",
|
|
})
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, snapshot, nil)
|
|
if !reflect.DeepEqual(report.Covered, []string{"sample delivered"}) || !reflect.DeepEqual(report.Missing, []string{"sample missing"}) {
|
|
t.Fatalf("delivery report = %#v", report)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsAliasCollision(t *testing.T) {
|
|
root := schemaDeliveryTestRoot(
|
|
schemaDeliveryTestTool{Canonical: "sample.one", CLIPath: "sample one"},
|
|
schemaDeliveryTestTool{Canonical: "sample.two", CLIPath: "sample two"},
|
|
)
|
|
snapshot := schemaDeliveryTestSnapshot(
|
|
schemaDeliveryTestTool{Canonical: "sample.one", CLIPath: "sample one", Aliases: []string{"sample shared"}},
|
|
schemaDeliveryTestTool{Canonical: "sample.two", CLIPath: "sample two"},
|
|
)
|
|
// Corrupt the serialized delivery boundary after building a valid typed
|
|
// registry. SchemaRegistry itself rejects this state at construction time;
|
|
// the production loader must reject the same collision after decoding.
|
|
snapshot.Tools["sample.two"]["aliases"] = []string{"sample shared"}
|
|
for _, product := range snapshot.Catalog["products"].([]map[string]any) {
|
|
for _, tool := range product["tools"].([]map[string]any) {
|
|
if schemaString(tool["canonical_path"]) == "sample.two" {
|
|
tool["aliases"] = []string{"sample shared"}
|
|
}
|
|
}
|
|
}
|
|
snapshot.SourceHash = schemaCatalogSnapshotHash(snapshot)
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, snapshot, nil)
|
|
if len(report.DeliveryErrors) != 1 || (!strings.Contains(report.DeliveryErrors[0], "resolves to both") && !strings.Contains(report.DeliveryErrors[0], "claimed by both")) {
|
|
t.Fatalf("delivery errors = %v", report.DeliveryErrors)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsPhantomAlias(t *testing.T) {
|
|
tool := schemaDeliveryTestTool{Canonical: "sample.run", CLIPath: "sample run", Aliases: []string{"sample ghost"}}
|
|
root := schemaDeliveryTestRoot(schemaDeliveryTestTool{Canonical: tool.Canonical, CLIPath: tool.CLIPath})
|
|
report := schemaCatalogDeliveryCompletenessForTest(root, schemaDeliveryTestSnapshot(tool), nil)
|
|
if len(report.DeliveryErrors) != 1 || !strings.Contains(report.DeliveryErrors[0], "non-executable Schema path") {
|
|
t.Fatalf("delivery errors = %v", report.DeliveryErrors)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsSummaryLeafDrift(t *testing.T) {
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{Canonical: "sample.run", CLIPath: "sample run"})
|
|
snapshot.Catalog["products"].([]map[string]any)[0]["tools"].([]map[string]any)[0]["primary_cli_path"] = "sample drift"
|
|
snapshot.SourceHash = schemaCatalogSnapshotHash(snapshot)
|
|
report := schemaCatalogDeliveryCompletenessForTest(schemaDeliveryTestRoot(schemaDeliveryTestTool{Canonical: "sample.run", CLIPath: "sample run"}), snapshot, nil)
|
|
if len(report.DeliveryErrors) != 1 || (!strings.Contains(report.DeliveryErrors[0], "disagrees with full leaf") && !strings.Contains(report.DeliveryErrors[0], "changed product/tool summaries")) {
|
|
t.Fatalf("delivery errors = %v", report.DeliveryErrors)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRejectsProvenanceDrift(t *testing.T) {
|
|
snapshot := schemaDeliveryTestSnapshot(schemaDeliveryTestTool{Canonical: "sample.run", CLIPath: "sample run"})
|
|
provenance := snapshot.Tools["sample.run"]["field_provenance"].(map[string]any)
|
|
canonical := provenance["canonical_path"].(map[string]any)
|
|
canonical["value"] = "sample.wrong"
|
|
snapshot.SourceHash = schemaCatalogSnapshotHash(snapshot)
|
|
|
|
report := schemaCatalogDeliveryCompletenessForTest(schemaDeliveryTestRoot(schemaDeliveryTestTool{
|
|
Canonical: "sample.run", CLIPath: "sample run",
|
|
}), snapshot, nil)
|
|
if len(report.DeliveryErrors) != 1 || !strings.Contains(report.DeliveryErrors[0], "provenance winner does not equal final value") {
|
|
t.Fatalf("delivery errors = %v", report.DeliveryErrors)
|
|
}
|
|
}
|
|
|
|
func TestSchemaCatalogDeliveryCompletenessRoundTripsThroughProductionLoader(t *testing.T) {
|
|
tool := schemaDeliveryTestTool{Canonical: "sample.run", CLIPath: "sample run"}
|
|
if err := validateSchemaCatalogDeliveryCompletenessForTest(schemaDeliveryTestRoot(tool), schemaDeliveryTestSnapshot(tool), nil); err != nil {
|
|
t.Fatalf("valid final delivery: %v", err)
|
|
}
|
|
}
|
|
|
|
type schemaDeliveryTestTool struct {
|
|
Canonical string
|
|
CLIPath string
|
|
Aliases []string
|
|
Parameters []ParameterSpec
|
|
Selection contract.SelectionSpec
|
|
}
|
|
|
|
func schemaDeliveryTestRoot(tools ...schemaDeliveryTestTool) *cobra.Command {
|
|
root := &cobra.Command{Use: "dws"}
|
|
products := map[string]*cobra.Command{}
|
|
for _, tool := range tools {
|
|
parts := strings.SplitN(tool.Canonical, ".", 2)
|
|
product := products[parts[0]]
|
|
if product == nil {
|
|
product = &cobra.Command{Use: parts[0]}
|
|
products[parts[0]] = product
|
|
root.AddCommand(product)
|
|
}
|
|
pathParts := strings.Fields(tool.CLIPath)
|
|
leaf := &cobra.Command{Use: pathParts[len(pathParts)-1], Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(leaf, parts[0], parts[1], "test")
|
|
product.AddCommand(leaf)
|
|
}
|
|
return root
|
|
}
|
|
|
|
func schemaDeliveryTestSnapshot(tools ...schemaDeliveryTestTool) SchemaCatalogSnapshot {
|
|
registry := schemaDeliveryTestRegistry(tools...)
|
|
payload, err := registry.ToSnapshotPayload()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
snapshot := SchemaCatalogSnapshot{
|
|
Version: SchemaCatalogSnapshotVersion,
|
|
Catalog: payload.Catalog,
|
|
Tools: payload.Tools,
|
|
}
|
|
snapshot.SourceHash = schemaCatalogSnapshotHash(snapshot)
|
|
return snapshot
|
|
}
|
|
|
|
func schemaDeliveryTestRegistry(tools ...schemaDeliveryTestTool) SchemaRegistry {
|
|
products := map[string][]ToolSpec{}
|
|
for _, tool := range tools {
|
|
parts := strings.SplitN(tool.Canonical, ".", 2)
|
|
interfaceReason := "synthetic delivery fixture"
|
|
provenanceValues := map[string]any{
|
|
"canonical_path": tool.Canonical,
|
|
"effect": "",
|
|
"risk": "",
|
|
"confirmation": "",
|
|
"idempotency": "",
|
|
"interface_ref": nil,
|
|
"interface_mode": "local",
|
|
"availability": "available",
|
|
"interface_reason": interfaceReason,
|
|
"agent_summary": tool.Selection.AgentSummary,
|
|
}
|
|
for field, values := range map[string][]string{
|
|
"use_when": tool.Selection.UseWhen,
|
|
"avoid_when": tool.Selection.AvoidWhen,
|
|
"prerequisites": tool.Selection.Prerequisites,
|
|
"tips": tool.Selection.Tips,
|
|
"workflow_refs": tool.Selection.WorkflowRefs,
|
|
"examples": tool.Selection.Examples,
|
|
} {
|
|
if values != nil {
|
|
provenanceValues[field] = values
|
|
}
|
|
}
|
|
if tool.Selection.Reviewed != nil {
|
|
provenanceValues["reviewed"] = *tool.Selection.Reviewed
|
|
}
|
|
spec, err := ToolSpecFromRuntime(RuntimeToolSpecInput{
|
|
Identity: contract.ToolIdentitySpec{
|
|
ProductID: parts[0],
|
|
Name: parts[1],
|
|
CLIName: strings.Fields(tool.CLIPath)[len(strings.Fields(tool.CLIPath))-1],
|
|
CanonicalPath: tool.Canonical,
|
|
CLIPath: tool.CLIPath,
|
|
PrimaryCLIPath: tool.CLIPath,
|
|
Aliases: append([]string(nil), tool.Aliases...),
|
|
Source: "test",
|
|
},
|
|
Parameters: append([]ParameterSpec(nil), tool.Parameters...),
|
|
Interface: contract.InterfaceSpec{Mode: "local", Availability: "available", Reason: interfaceReason},
|
|
Selection: tool.Selection,
|
|
FieldProvenance: schemaDeliveryTestProvenance(provenanceValues),
|
|
})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
products[parts[0]] = append(products[parts[0]], spec)
|
|
}
|
|
productIDs := make([]string, 0, len(products))
|
|
for productID := range products {
|
|
productIDs = append(productIDs, productID)
|
|
}
|
|
sort.Strings(productIDs)
|
|
typedProducts := make([]ProductSpec, 0, len(productIDs))
|
|
for _, productID := range productIDs {
|
|
typedProducts = append(typedProducts, ProductSpec{ID: productID, Tools: products[productID]})
|
|
}
|
|
registry, err := SchemaRegistryFromRuntime("", typedProducts)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return registry
|
|
}
|
|
|
|
func schemaDeliveryTestProvenance(fields map[string]any) map[string]contract.FieldProvenance {
|
|
provenance := make(map[string]contract.FieldProvenance, len(fields))
|
|
for field, value := range fields {
|
|
encoded, err := json.Marshal(value)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
selected := true
|
|
provenance[field] = contract.FieldProvenance{
|
|
Value: encoded,
|
|
Source: "test",
|
|
Precedence: "test",
|
|
Resolution: "test",
|
|
Candidates: []contract.FieldCandidateProvenance{{Value: append(json.RawMessage(nil), encoded...), Source: "test", Precedence: "test", Selected: &selected}},
|
|
}
|
|
}
|
|
return provenance
|
|
}
|