Replace generic resolution recording with intent methods
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Pre-v1 Public API Cleanup Implementation Plan
|
# Pre-v1 Public API Cleanup Implementation Plan
|
||||||
|
|
||||||
Status: in progress; Stages 1–5 are complete and Stages 6–11 are pending.
|
Status: in progress; Stages 1–6 are complete and Stages 7–11 are pending.
|
||||||
Baseline: `07e4ae5d9236935389e81b207d4a8f00543fafce`.
|
Baseline: `07e4ae5d9236935389e81b207d4a8f00543fafce`.
|
||||||
Audience: a Luna coding agent executing the stages sequentially.
|
Audience: a Luna coding agent executing the stages sequentially.
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ bootstrap behavior remain unchanged.
|
|||||||
|
|
||||||
## Stage 6 — Replace Kind-Selecting Recording With Intent Methods
|
## Stage 6 — Replace Kind-Selecting Recording With Intent Methods
|
||||||
|
|
||||||
Status: pending. Implements D6 and N4.
|
Status: complete. Implements D6 and N4.
|
||||||
|
|
||||||
1. Replace root and engine `Resolution.Record` with:
|
1. Replace root and engine `Resolution.Record` with:
|
||||||
|
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ func resolveCollectionResources(configuration *CollectionBundleConfig, resolutio
|
|||||||
}
|
}
|
||||||
prompt.ResourceText = string(data)
|
prompt.ResourceText = string(data)
|
||||||
collection.Prompts[promptID] = prompt
|
collection.Prompts[promptID] = prompt
|
||||||
resolution.Record(
|
resolution.RecordNormalization(
|
||||||
configkit.Keys("collections", collectionID, "prompts", promptID, "resource_text"),
|
configkit.Keys("collections", collectionID, "prompts", promptID, "resource_text"),
|
||||||
configkit.ChangeNormalization, "read source-relative prompt content", contentPath,
|
"read source-relative prompt content", contentPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
configuration.Collections[collectionID] = collection
|
configuration.Collections[collectionID] = collection
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ func resolveRollout(configuration *RolloutConfig, resolution *configkit.Resoluti
|
|||||||
url := fmt.Sprintf("https://%s:%d", endpoint.Host, endpoint.Port)
|
url := fmt.Sprintf("https://%s:%d", endpoint.Host, endpoint.Port)
|
||||||
if endpoint.URL != url {
|
if endpoint.URL != url {
|
||||||
endpoint.URL = url
|
endpoint.URL = url
|
||||||
resolution.Record(configkit.Keys("service", "endpoint", "url"),
|
resolution.RecordNormalization(configkit.Keys("service", "endpoint", "url"),
|
||||||
configkit.ChangeNormalization, "derived endpoint URL",
|
"derived endpoint URL",
|
||||||
configkit.Keys("service", "endpoint", "host"),
|
configkit.Keys("service", "endpoint", "host"),
|
||||||
configkit.Keys("service", "endpoint", "port"))
|
configkit.Keys("service", "endpoint", "port"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func LoadSequenceCatalog(mainPath, overlayName, runLabel string) (*configkit.Res
|
|||||||
},
|
},
|
||||||
Resolve: func(configuration *SequenceCatalogConfig, resolution *configkit.Resolution) error {
|
Resolve: func(configuration *SequenceCatalogConfig, resolution *configkit.Resolution) error {
|
||||||
configuration.ResolvedLabel = "for:" + configuration.RunLabel
|
configuration.ResolvedLabel = "for:" + configuration.RunLabel
|
||||||
resolution.Record(configkit.Keys("resolved_label"), configkit.ChangeNormalization,
|
resolution.RecordNormalization(configkit.Keys("resolved_label"),
|
||||||
"derive the resolved label from the selected run label", configkit.Keys("run_label"))
|
"derive the resolved label from the selected run label", configkit.Keys("run_label"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -245,6 +245,8 @@ func TestFacadeLoadBridgesLifecycleCallbacks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, context := range []func(){
|
for _, context := range []func(){
|
||||||
func() { retainedResolution.IsExplicit(configkit.Keys("input")) },
|
func() { retainedResolution.IsExplicit(configkit.Keys("input")) },
|
||||||
|
func() { retainedResolution.RecordDerivedDefault(configkit.Keys("input"), "too late") },
|
||||||
|
func() { retainedResolution.RecordNormalization(configkit.Keys("input"), "too late") },
|
||||||
func() { retainedValidation.Warning(configkit.Keys("input"), "too late") },
|
func() { retainedValidation.Warning(configkit.Keys("input"), "too late") },
|
||||||
} {
|
} {
|
||||||
func() {
|
func() {
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ func TestFacadeInactiveContextsPreserveClosedFailure(t *testing.T) {
|
|||||||
{"EntryInfo", func() { state.resolution.EntryInfo(path) }},
|
{"EntryInfo", func() { state.resolution.EntryInfo(path) }},
|
||||||
{"Source", func() { state.resolution.Source("source") }},
|
{"Source", func() { state.resolution.Source("source") }},
|
||||||
{"SourceContext", func() { state.resolution.SourceContext("source") }},
|
{"SourceContext", func() { state.resolution.SourceContext("source") }},
|
||||||
{"Record", func() { state.resolution.Record(path, configkit.ChangeNormalization, "reason") }},
|
{"RecordDerivedDefault", func() { state.resolution.RecordDerivedDefault(path, "reason") }},
|
||||||
|
{"RecordNormalization", func() { state.resolution.RecordNormalization(path, "reason") }},
|
||||||
{"Resolution.Error", func() { state.resolution.Error(path, "message") }},
|
{"Resolution.Error", func() { state.resolution.Error(path, "message") }},
|
||||||
{"Resolution.Warning", func() { state.resolution.Warning(path, "message") }},
|
{"Resolution.Warning", func() { state.resolution.Warning(path, "message") }},
|
||||||
{"Default", func() { configkit.Default(state.resolution, path, &target, 1, "reason") }},
|
{"Default", func() { configkit.Default(state.resolution, path, &target, 1, "reason") }},
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ func TestFacadeMountedMainAndUnderlayInspectionResourcesAndDiff(t *testing.T) {
|
|||||||
}
|
}
|
||||||
entry := facadeDestinationMap(t, facadeDestinationMap(t, facadeDestinationMap(t, *configuration, "catalog"), "entries"), "item")
|
entry := facadeDestinationMap(t, facadeDestinationMap(t, facadeDestinationMap(t, *configuration, "catalog"), "entries"), "item")
|
||||||
entry["resource_text"] = string(data)
|
entry["resource_text"] = string(data)
|
||||||
resolution.Record(configkit.Keys("catalog", "entries", "item", "resource_text"), configkit.ChangeNormalization, "read source-relative summary", resourcePath)
|
resolution.RecordNormalization(configkit.Keys("catalog", "entries", "item", "resource_text"), "read source-relative summary", resourcePath)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Validate: func(*map[string]any, *configkit.Validation) { callbacks.validate++ },
|
Validate: func(*map[string]any, *configkit.Validation) { callbacks.validate++ },
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestFacadeDiffKeepsPublicSequenceChangesWithHistoricalDescendants(t *testin
|
|||||||
Sensitive: func(path configkit.Path) bool { return path.String() == "/items/0/secret" },
|
Sensitive: func(path configkit.Path) bool { return path.String() == "/items/0/secret" },
|
||||||
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
|
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
|
||||||
current.Items[0] = "public scalar"
|
current.Items[0] = "public scalar"
|
||||||
resolution.Record(configkit.Keys("items"), configkit.ChangeNormalization, "normalize first item")
|
resolution.RecordNormalization(configkit.Keys("items"), "normalize first item")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}})
|
}})
|
||||||
@@ -74,7 +74,7 @@ func TestFacadeDiffKeepsPublicScalarAcrossHistoricalAbsence(t *testing.T) {
|
|||||||
Sensitive: func(path configkit.Path) bool { return path.String() == "/dynamic/entry/token" },
|
Sensitive: func(path configkit.Path) bool { return path.String() == "/dynamic/entry/token" },
|
||||||
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
|
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
|
||||||
delete(current.Dynamic, "entry")
|
delete(current.Dynamic, "entry")
|
||||||
resolution.Record(configkit.Keys("dynamic", "entry"), configkit.ChangeNormalization, "remove entry")
|
resolution.RecordNormalization(configkit.Keys("dynamic", "entry"), "remove entry")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -221,7 +221,7 @@ func TestFacadeDiffIgnoresSourceAndResolutionHistory(t *testing.T) {
|
|||||||
resolve := func(value string) configkit.Options[config] {
|
resolve := func(value string) configkit.Options[config] {
|
||||||
return configkit.Options[config]{Definition: configkit.Definition[config]{Resolve: func(current *config, resolution *configkit.Resolution) error {
|
return configkit.Options[config]{Definition: configkit.Definition[config]{Resolve: func(current *config, resolution *configkit.Resolution) error {
|
||||||
current.Count = len(value) + 8
|
current.Count = len(value) + 8
|
||||||
resolution.Record(configkit.Keys("count"), configkit.ChangeNormalization, "set effective count")
|
resolution.RecordNormalization(configkit.Keys("count"), "set effective count")
|
||||||
return nil
|
return nil
|
||||||
}}}
|
}}}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ func TestFacadeSearchRunsCallbacksOnceAndKeepsInspectionWithSelectedFile(t *test
|
|||||||
Resolve: func(configuration *facadeDiscoveryLifecycleConfig, resolution *Resolution) error {
|
Resolve: func(configuration *facadeDiscoveryLifecycleConfig, resolution *Resolution) error {
|
||||||
resolveCalls++
|
resolveCalls++
|
||||||
configuration.Resolved = "from:" + configuration.Value
|
configuration.Resolved = "from:" + configuration.Value
|
||||||
resolution.Record(Keys("resolved"), ChangeNormalization, "derive from selected value", Keys("value"))
|
resolution.RecordNormalization(Keys("resolved"), "derive from selected value", Keys("value"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Validate: func(_ *facadeDiscoveryLifecycleConfig, _ *Validation) { validateCalls++ },
|
Validate: func(_ *facadeDiscoveryLifecycleConfig, _ *Validation) { validateCalls++ },
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestFinalSequenceIdentityTreatsLateExtendsFieldsAsPayload(t *testing.T) {
|
|||||||
if phase == "resolution" {
|
if phase == "resolution" {
|
||||||
definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error {
|
definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error {
|
||||||
(*value)["items"] = items
|
(*value)["items"] = items
|
||||||
resolution.Record(configkit.Keys("items"), configkit.ChangeNormalization, "supply application payload")
|
resolution.RecordNormalization(configkit.Keys("items"), "supply application payload")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ func TestFinalSequenceIdentityValidatesLateValues(t *testing.T) {
|
|||||||
case "resolution":
|
case "resolution":
|
||||||
options.Definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error {
|
options.Definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error {
|
||||||
(*value)["items"] = items
|
(*value)["items"] = items
|
||||||
resolution.Record(configkit.Keys("items"), configkit.ChangeNormalization, "create effective records")
|
resolution.RecordNormalization(configkit.Keys("items"), "create effective records")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ func TestFinalSequenceIdentityMatchesLateDynamicNamespaces(t *testing.T) {
|
|||||||
case "resolution":
|
case "resolution":
|
||||||
options.Definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error {
|
options.Definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error {
|
||||||
(*value)["collections"] = map[string]any{name: map[string]any{"items": items}}
|
(*value)["collections"] = map[string]any{name: map[string]any{"items": items}}
|
||||||
resolution.Record(configkit.Keys("collections"), configkit.ChangeNormalization, "create namespaced records")
|
resolution.RecordNormalization(configkit.Keys("collections"), "create namespaced records")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func TestPublicHistoryUsesResolutionShapeAttribution(t *testing.T) {
|
|||||||
Definition: configkit.Definition[map[string]any]{
|
Definition: configkit.Definition[map[string]any]{
|
||||||
Resolve: func(configuration *map[string]any, resolution *configkit.Resolution) error {
|
Resolve: func(configuration *map[string]any, resolution *configkit.Resolution) error {
|
||||||
(*configuration)["shape"] = []any{"replacement"}
|
(*configuration)["shape"] = []any{"replacement"}
|
||||||
resolution.Record(configkit.Keys("shape"), configkit.ChangeNormalization, "replace numeric mapping key")
|
resolution.RecordNormalization(configkit.Keys("shape"), "replace numeric mapping key")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
43
facade_resolution_recording_test.go
Normal file
43
facade_resolution_recording_test.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package configkit
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestFacadeResolutionRecordingIntents(t *testing.T) {
|
||||||
|
type configuration struct {
|
||||||
|
Derived string `yaml:"derived"`
|
||||||
|
Normalized string `yaml:"normalized"`
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := Load(Bytes("recording.yml", []byte("derived: explicit\nnormalized: before\n")), Options[configuration]{
|
||||||
|
Definition: Definition[configuration]{Resolve: func(value *configuration, resolution *Resolution) error {
|
||||||
|
value.Derived = "changed explicit input"
|
||||||
|
resolution.RecordDerivedDefault(Keys("derived"), "derive explicit input")
|
||||||
|
value.Normalized = "after"
|
||||||
|
resolution.RecordNormalization(Keys("normalized"), "normalize configured input")
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []struct {
|
||||||
|
path Path
|
||||||
|
kind ChangeKind
|
||||||
|
}{
|
||||||
|
{path: Keys("derived"), kind: ChangeDerivedDefault},
|
||||||
|
{path: Keys("normalized"), kind: ChangeNormalization},
|
||||||
|
} {
|
||||||
|
info, ok := result.Metadata().Lookup(test.path)
|
||||||
|
if !ok || info.Origin.Operation != test.kind {
|
||||||
|
t.Errorf("metadata %s = %#v, %v; want operation %q", test.path, info, ok, test.kind)
|
||||||
|
}
|
||||||
|
history := result.Metadata().History(test.path)
|
||||||
|
if len(history) == 0 || history[len(history)-1].Origin.Operation != test.kind {
|
||||||
|
t.Errorf("history %s = %#v; want final operation %q", test.path, history, test.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !result.Metadata().IsExplicit(Keys("derived")) {
|
||||||
|
t.Fatal("recording a derived default suppressed explicit-input provenance")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -807,7 +807,7 @@ func TestFacadeSourceVersionLifecycleKeepsConsumedHeadersOutOfPayloadHistory(t *
|
|||||||
},
|
},
|
||||||
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
|
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
|
||||||
current.Service.Resolved = "resolved once"
|
current.Service.Resolved = "resolved once"
|
||||||
resolution.Record(configkit.Keys("service", "resolved"), configkit.ChangeNormalization, "derive resolved value")
|
resolution.RecordNormalization(configkit.Keys("service", "resolved"), "derive resolved value")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Validate: func(current *configuration, validation *configkit.Validation) {
|
Validate: func(current *configuration, validation *configkit.Validation) {
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ func TestCallbackAssignmentsAreDetachedAcrossLoads(t *testing.T) {
|
|||||||
definition := Definition[cfg]{Resolve: func(c *cfg, r *Resolution) error {
|
definition := Definition[cfg]{Resolve: func(c *cfg, r *Resolution) error {
|
||||||
Normalize(r, Keys("map"), &c.Map, shared, "populate")
|
Normalize(r, Keys("map"), &c.Map, shared, "populate")
|
||||||
c.Pointer = external
|
c.Pointer = external
|
||||||
r.Record(Keys("pointer"), ChangeNormalization, "populate")
|
r.RecordNormalization(Keys("pointer"), "populate")
|
||||||
c.Secret = SecretEnv("CONFIGKIT_CALLBACK_SECRET")
|
c.Secret = SecretEnv("CONFIGKIT_CALLBACK_SECRET")
|
||||||
r.Record(Keys("secret"), ChangeNormalization, "reference")
|
r.RecordNormalization(Keys("secret"), "reference")
|
||||||
return nil
|
return nil
|
||||||
}}
|
}}
|
||||||
if validatorAssignment {
|
if validatorAssignment {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func TestRelativeImportsFeedFinalInheritanceAndInspectionLifecycle(t *testing.T)
|
|||||||
child := config.Catalog.Entries["child"]
|
child := config.Catalog.Entries["child"]
|
||||||
child.Derived = child.Label + ":" + child.Dynamic + ":" + fmt.Sprint(child.Height)
|
child.Derived = child.Label + ":" + child.Dynamic + ":" + fmt.Sprint(child.Height)
|
||||||
config.Catalog.Entries["child"] = child
|
config.Catalog.Entries["child"] = child
|
||||||
resolution.Record(Keys("catalog", "entries", "child", "derived"), ChangeNormalization, "derive final child summary", Keys("catalog", "entries", "child", "label"), Keys("catalog", "entries", "child", "dynamic"), Keys("catalog", "entries", "child", "height"))
|
resolution.RecordNormalization(Keys("catalog", "entries", "child", "derived"), "derive final child summary", Keys("catalog", "entries", "child", "label"), Keys("catalog", "entries", "child", "dynamic"), Keys("catalog", "entries", "child", "height"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Validate: func(config *configuration, validation *Validation) {
|
Validate: func(config *configuration, validation *Validation) {
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ func TestLayeredDestinationLifecycleAndSensitiveInspectionUseFinalShape(t *testi
|
|||||||
Resolve: func(configuration *destinationLifecycleConfig, resolution *Resolution) error {
|
Resolve: func(configuration *destinationLifecycleConfig, resolution *Resolution) error {
|
||||||
observed.resolve++
|
observed.resolve++
|
||||||
configuration.Tenant.Derived = configuration.Tenant.Dynamic
|
configuration.Tenant.Derived = configuration.Tenant.Dynamic
|
||||||
resolution.Record(Keys("tenant", "derived"), ChangeNormalization, "derive from mounted input", Keys("tenant", "dynamic"))
|
resolution.RecordNormalization(Keys("tenant", "derived"), "derive from mounted input", Keys("tenant", "dynamic"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Validate: func(configuration *destinationLifecycleConfig, _ *Validation) {
|
Validate: func(configuration *destinationLifecycleConfig, _ *Validation) {
|
||||||
@@ -425,7 +425,7 @@ func TestLayeredDestinationDiffUsesBilateralSensitivity(t *testing.T) {
|
|||||||
definition: Definition[config]{
|
definition: Definition[config]{
|
||||||
Resolve: func(configuration *config, resolution *Resolution) error {
|
Resolve: func(configuration *config, resolution *Resolution) error {
|
||||||
configuration.Tenant.Derived = configuration.Tenant.Dynamic
|
configuration.Tenant.Derived = configuration.Tenant.Dynamic
|
||||||
resolution.Record(Keys("tenant", "derived"), ChangeNormalization, "derive from dynamic input", Keys("tenant", "dynamic"))
|
resolution.RecordNormalization(Keys("tenant", "derived"), "derive from dynamic input", Keys("tenant", "dynamic"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Secret: func(path Path) bool { return classify && path.String() == "/tenant/dynamic" },
|
Secret: func(path Path) bool { return classify && path.String() == "/tenant/dynamic" },
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestDiffUsesFinalValuesAndDependencyDerivedSensitivity(t *testing.T) {
|
|||||||
Resolve: func(configuration *diffIntegrationConfig, resolution *Resolution) error {
|
Resolve: func(configuration *diffIntegrationConfig, resolution *Resolution) error {
|
||||||
resolveCalls++
|
resolveCalls++
|
||||||
configuration.Derived = configuration.Dynamic["visible"].(string)
|
configuration.Derived = configuration.Dynamic["visible"].(string)
|
||||||
resolution.Record(Keys("derived"), ChangeNormalization, "derive from effective values", Keys("credential"))
|
resolution.RecordNormalization(Keys("derived"), "derive from effective values", Keys("credential"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -203,7 +203,7 @@ func TestDiffProtectsHistoricalSensitiveRemovalAndReplacement(t *testing.T) {
|
|||||||
t.Run("removed historical value", func(t *testing.T) {
|
t.Run("removed historical value", func(t *testing.T) {
|
||||||
left := load("dynamic: {token: removed-canary}\n", func(configuration *configuration, resolution *Resolution) error {
|
left := load("dynamic: {token: removed-canary}\n", func(configuration *configuration, resolution *Resolution) error {
|
||||||
delete(configuration.Dynamic, "token")
|
delete(configuration.Dynamic, "token")
|
||||||
resolution.Record(secretPath, ChangeNormalization, "remove token")
|
resolution.RecordNormalization(secretPath, "remove token")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
right := load("dynamic: {token: current-canary}\n", nil)
|
right := load("dynamic: {token: current-canary}\n", nil)
|
||||||
@@ -228,7 +228,7 @@ func TestDiffProtectsHistoricalSensitiveRemovalAndReplacement(t *testing.T) {
|
|||||||
t.Run("replaced historical value", func(t *testing.T) {
|
t.Run("replaced historical value", func(t *testing.T) {
|
||||||
left := load("dynamic: {token: original-canary}\n", func(configuration *configuration, resolution *Resolution) error {
|
left := load("dynamic: {token: original-canary}\n", func(configuration *configuration, resolution *Resolution) error {
|
||||||
configuration.Dynamic["token"] = "replacement-canary"
|
configuration.Dynamic["token"] = "replacement-canary"
|
||||||
resolution.Record(secretPath, ChangeNormalization, "replace token")
|
resolution.RecordNormalization(secretPath, "replace token")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
right := load("dynamic: {token: other-canary}\n", nil)
|
right := load("dynamic: {token: other-canary}\n", nil)
|
||||||
|
|||||||
@@ -525,10 +525,10 @@ func TestExplanationReplaysResolutionAdditionsAndOverlappingIntent(t *testing.T)
|
|||||||
result, err := testLoad(Bytes("base", []byte("m: {old: 1}\n")), Options[cfg]{Definition: Definition[cfg]{Resolve: func(c *cfg, r *Resolution) error {
|
result, err := testLoad(Bytes("base", []byte("m: {old: 1}\n")), Options[cfg]{Definition: Definition[cfg]{Resolve: func(c *cfg, r *Resolution) error {
|
||||||
c.M["new"] = map[string]any{"child": int64(7)}
|
c.M["new"] = map[string]any{"child": int64(7)}
|
||||||
delete(c.M, "old")
|
delete(c.M, "old")
|
||||||
r.Record(Keys("m", "new"), ChangeDerivedDefault, "add nested", Keys("m", "old"))
|
r.RecordDerivedDefault(Keys("m", "new"), "add nested", Keys("m", "old"))
|
||||||
r.Record(Keys("m", "old"), ChangeNormalization, "remove old")
|
r.RecordNormalization(Keys("m", "old"), "remove old")
|
||||||
if overlap {
|
if overlap {
|
||||||
r.Record(Keys("m"), ChangeNormalization, "update container")
|
r.RecordNormalization(Keys("m"), "update container")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}}})
|
}}})
|
||||||
@@ -587,7 +587,7 @@ func TestExplanationReplayDescriptorsRemainDetachedAcrossQueries(t *testing.T) {
|
|||||||
result, err := testLoad(Bytes("resolution-explanation.yml", []byte("count: 1\n")), Options[config]{
|
result, err := testLoad(Bytes("resolution-explanation.yml", []byte("count: 1\n")), Options[config]{
|
||||||
Definition: Definition[config]{Resolve: func(value *config, resolution *Resolution) error {
|
Definition: Definition[config]{Resolve: func(value *config, resolution *Resolution) error {
|
||||||
value.Count = 2
|
value.Count = 2
|
||||||
resolution.Record(Keys("count"), ChangeNormalization, "normalized", Keys("count"))
|
resolution.RecordNormalization(Keys("count"), "normalized", Keys("count"))
|
||||||
return nil
|
return nil
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
@@ -635,7 +635,7 @@ func TestConcurrentReadOnlyInspectionQueries(t *testing.T) {
|
|||||||
result, err := testLoad(Bytes("concurrent-inspection.yml", []byte("group: {value: input}\n")), Options[config]{
|
result, err := testLoad(Bytes("concurrent-inspection.yml", []byte("group: {value: input}\n")), Options[config]{
|
||||||
Definition: Definition[config]{Resolve: func(value *config, resolution *Resolution) error {
|
Definition: Definition[config]{Resolve: func(value *config, resolution *Resolution) error {
|
||||||
value.Group.Value = "resolved"
|
value.Group.Value = "resolved"
|
||||||
resolution.Record(Keys("group", "value"), ChangeNormalization, "normalized", Keys("group", "value"))
|
resolution.RecordNormalization(Keys("group", "value"), "normalized", Keys("group", "value"))
|
||||||
return nil
|
return nil
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -149,8 +149,8 @@ func TestLayeredHistoryBudgetRejectsBeforeSecretsAndValidation(t *testing.T) {
|
|||||||
definition: Definition[historyBudgetLayeredConfig]{
|
definition: Definition[historyBudgetLayeredConfig]{
|
||||||
Resolve: func(configuration *historyBudgetLayeredConfig, resolution *Resolution) error {
|
Resolve: func(configuration *historyBudgetLayeredConfig, resolution *Resolution) error {
|
||||||
configuration.Child.Value += "-resolved"
|
configuration.Child.Value += "-resolved"
|
||||||
resolution.Record(Keys("child", "value"), ChangeNormalization, "normalize child")
|
resolution.RecordNormalization(Keys("child", "value"), "normalize child")
|
||||||
resolution.Record(Keys("child"), ChangeDerivedDefault, "record enclosing child state")
|
resolution.RecordDerivedDefault(Keys("child"), "record enclosing child state")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Validate: func(*historyBudgetLayeredConfig, *Validation) { counts.validations++ },
|
Validate: func(*historyBudgetLayeredConfig, *Validation) { counts.validations++ },
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ func TestResolutionInputKeepsDetachedEntryMetadata(t *testing.T) {
|
|||||||
configurationAtEntry := decoded.value.Interface().(configuration)
|
configurationAtEntry := decoded.value.Interface().(configuration)
|
||||||
resolved := runResolution(&configurationAtEntry, func(value *configuration, resolution *Resolution) error {
|
resolved := runResolution(&configurationAtEntry, func(value *configuration, resolution *Resolution) error {
|
||||||
value.Items[0] = "normalized"
|
value.Items[0] = "normalized"
|
||||||
resolution.Record(Keys("items"), ChangeNormalization, "normalized item")
|
resolution.RecordNormalization(Keys("items"), "normalized item")
|
||||||
return nil
|
return nil
|
||||||
}, schema, decoded, document, input)
|
}, schema, decoded, document, input)
|
||||||
if len(resolved.diagnostics) != 0 {
|
if len(resolved.diagnostics) != 0 {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func TestPostDecodeOverrideContextOrdersDecodeCLIAndResolutionEvidence(t *testin
|
|||||||
|
|
||||||
resolvedContext, resolveDiagnostics := resolveLoadInput(schema, Definition[config]{Resolve: func(value *config, resolution *Resolution) error {
|
resolvedContext, resolveDiagnostics := resolveLoadInput(schema, Definition[config]{Resolve: func(value *config, resolution *Resolution) error {
|
||||||
value.Count = 6
|
value.Count = 6
|
||||||
resolution.Record(Keys("count"), ChangeNormalization, "normalize count")
|
resolution.RecordNormalization(Keys("count"), "normalize count")
|
||||||
return nil
|
return nil
|
||||||
}}, input, preparePostDecodeOverrideContext(input, decoded, assigned))
|
}}, input, preparePostDecodeOverrideContext(input, decoded, assigned))
|
||||||
if len(resolveDiagnostics) != 0 {
|
if len(resolveDiagnostics) != 0 {
|
||||||
@@ -130,7 +130,7 @@ func TestPostDecodeOverrideContextOrdersDecodeCLIAndResolutionEvidence(t *testin
|
|||||||
Default(resolution, Keys("count"), &value.Count, 99, "fill missing count")
|
Default(resolution, Keys("count"), &value.Count, 99, "fill missing count")
|
||||||
Default(resolution, Keys("derived"), &value.Derived, 42, "derive default")
|
Default(resolution, Keys("derived"), &value.Derived, 42, "derive default")
|
||||||
value.APIKey = SecretEnv("RESOLVED_SECRET")
|
value.APIKey = SecretEnv("RESOLVED_SECRET")
|
||||||
resolution.Record(Keys("api_key"), ChangeNormalization, "select effective secret reference")
|
resolution.RecordNormalization(Keys("api_key"), "select effective secret reference")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
resolved := runResolution(&configuration, resolver, schema, prepared.decoded, prepared.referenceInput, prepared.resolution)
|
resolved := runResolution(&configuration, resolver, schema, prepared.decoded, prepared.referenceInput, prepared.resolution)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func TestCLIHistoryFollowsInheritanceAndPrecedesResolution(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
(*value)["child"].(map[string]any)["value"] = "resolved"
|
(*value)["child"].(map[string]any)["value"] = "resolved"
|
||||||
}
|
}
|
||||||
resolution.Record(recorded, ChangeNormalization, "normalize after CLI", parent)
|
resolution.RecordNormalization(recorded, "normalize after CLI", parent)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ empty: {}
|
|||||||
Normalize(resolution, Keys("values"), &configuration.Values, []int{5},
|
Normalize(resolution, Keys("values"), &configuration.Values, []int{5},
|
||||||
"bounded values", Keys("shared", "imported"))
|
"bounded values", Keys("shared", "imported"))
|
||||||
delete(configuration.Items, "remove")
|
delete(configuration.Items, "remove")
|
||||||
resolution.Record(Keys("items"), ChangeNormalization, "removed disabled items")
|
resolution.RecordNormalization(Keys("items"), "removed disabled items")
|
||||||
Default(resolution, Keys("derived"), &configuration.Derived, 7,
|
Default(resolution, Keys("derived"), &configuration.Derived, 7,
|
||||||
"derived from equal", Keys("shared", "equal"), Keys("shared", "equal"))
|
"derived from equal", Keys("shared", "equal"), Keys("shared", "equal"))
|
||||||
resolution.Warning(Keys("values"), "values were bounded", Keys("shared", "imported"))
|
resolution.Warning(Keys("values"), "values were bounded", Keys("shared", "imported"))
|
||||||
@@ -434,7 +434,7 @@ func TestResolutionInputRemainsFixedAcrossRecordedMutations(t *testing.T) {
|
|||||||
Normalize(resolution, Keys("existing"), &value.Existing, "normalized", "normalized existing value")
|
Normalize(resolution, Keys("existing"), &value.Existing, "normalized", "normalized existing value")
|
||||||
value.Values["destination"] = value.Values["original"]
|
value.Values["destination"] = value.Values["original"]
|
||||||
delete(value.Values, "original")
|
delete(value.Values, "original")
|
||||||
resolution.Record(Keys("values"), ChangeNormalization, "moved configured value")
|
resolution.RecordNormalization(Keys("values"), "moved configured value")
|
||||||
againOriginal, againOriginalFound := resolution.InputInfo(Keys("values", "original"))
|
againOriginal, againOriginalFound := resolution.InputInfo(Keys("values", "original"))
|
||||||
againDestination, againDestinationFound := resolution.InputInfo(Keys("values", "destination"))
|
againDestination, againDestinationFound := resolution.InputInfo(Keys("values", "destination"))
|
||||||
againExisting, againExistingFound := resolution.InputInfo(Keys("existing"))
|
againExisting, againExistingFound := resolution.InputInfo(Keys("existing"))
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ const (
|
|||||||
CodeResolveWarning Code = "resolve.warning"
|
CodeResolveWarning Code = "resolve.warning"
|
||||||
CodeResolveHookFailed Code = "resolve.hook_failed"
|
CodeResolveHookFailed Code = "resolve.hook_failed"
|
||||||
CodeResolveInvalidPath Code = "resolve.invalid_path"
|
CodeResolveInvalidPath Code = "resolve.invalid_path"
|
||||||
CodeResolveInvalidKind Code = "resolve.invalid_kind"
|
|
||||||
CodeResolveInvalidRecord Code = "resolve.invalid_record"
|
CodeResolveInvalidRecord Code = "resolve.invalid_record"
|
||||||
CodeResolveInvalidTarget Code = "resolve.invalid_target"
|
CodeResolveInvalidTarget Code = "resolve.invalid_target"
|
||||||
CodeResolveInvalidValue Code = "resolve.invalid_value"
|
CodeResolveInvalidValue Code = "resolve.invalid_value"
|
||||||
|
|||||||
@@ -112,11 +112,21 @@ func (r *Resolution) SourceContext(id string) (ResourceContext, bool) {
|
|||||||
return r.activeState().input.sourceContext(id)
|
return r.activeState().input.sourceContext(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record declares the intent for a resolver mutation. A container path covers
|
// RecordDerivedDefault declares a derived-default intent for a resolver
|
||||||
// mutations to its descendants.
|
// mutation already performed by application code. A container path covers
|
||||||
func (r *Resolution) Record(path Path, kind ChangeKind, reason string, dependencies ...Path) {
|
// mutations to its descendants. This does not assign a value or suppress work
|
||||||
|
// for explicit input.
|
||||||
|
func (r *Resolution) RecordDerivedDefault(path Path, reason string, dependencies ...Path) {
|
||||||
state := r.activeState()
|
state := r.activeState()
|
||||||
state.addRecord(path, kind, reason, dependencies, nil)
|
state.addRecord(path, ChangeDerivedDefault, reason, dependencies, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordNormalization declares a normalization intent for a resolver mutation
|
||||||
|
// already performed by application code. A container path covers mutations to
|
||||||
|
// its descendants. This does not assign a value.
|
||||||
|
func (r *Resolution) RecordNormalization(path Path, reason string, dependencies ...Path) {
|
||||||
|
state := r.activeState()
|
||||||
|
state.addRecord(path, ChangeNormalization, reason, dependencies, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error reports a safe, value-free resolution error at path.
|
// Error reports a safe, value-free resolution error at path.
|
||||||
@@ -219,10 +229,6 @@ func (state *resolutionState) addRecord(path Path, kind ChangeKind, reason strin
|
|||||||
if !state.validPath(path) {
|
if !state.validPath(path) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if kind != ChangeDerivedDefault && kind != ChangeNormalization {
|
|
||||||
state.addDiagnostic(CodeResolveInvalidKind, path, "resolution record has an invalid change kind")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if reason == "" {
|
if reason == "" {
|
||||||
state.addDiagnostic(CodeResolveInvalidRecord, path, "resolution record requires a safe reason")
|
state.addDiagnostic(CodeResolveInvalidRecord, path, "resolution record requires a safe reason")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ func TestResolutionContainerRecordCoversSubtreeRemovalAndSnapshotsAreDetached(t
|
|||||||
result, err := testLoad(Bytes("remove.yml", []byte("items:\n keep: {value: 'yes'}\n remove: {value: 'no'}\n")), Options[config]{Definition: Definition[config]{
|
result, err := testLoad(Bytes("remove.yml", []byte("items:\n keep: {value: 'yes'}\n remove: {value: 'no'}\n")), Options[config]{Definition: Definition[config]{
|
||||||
Resolve: func(configuration *config, resolution *Resolution) error {
|
Resolve: func(configuration *config, resolution *Resolution) error {
|
||||||
delete(configuration.Items, "remove")
|
delete(configuration.Items, "remove")
|
||||||
resolution.Record(Keys("items"), ChangeNormalization, "removed disabled entries")
|
resolution.RecordNormalization(Keys("items"), "removed disabled entries")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}})
|
}})
|
||||||
@@ -259,12 +259,8 @@ func TestResolutionRejectsUnrecordedAndMismatchedMutations(t *testing.T) {
|
|||||||
Normalize(resolution, Keys("value"), &unrelated, 2, "changed value")
|
Normalize(resolution, Keys("value"), &unrelated, 2, "changed value")
|
||||||
return nil
|
return nil
|
||||||
}, code: CodeResolveInvalidTarget},
|
}, code: CodeResolveInvalidTarget},
|
||||||
{name: "invalid record kind", resolve: func(_ *config, resolution *Resolution) error {
|
|
||||||
resolution.Record(Keys("value"), ChangeKind("other"), "invalid kind")
|
|
||||||
return nil
|
|
||||||
}, code: CodeResolveInvalidKind},
|
|
||||||
{name: "invalid path", resolve: func(_ *config, resolution *Resolution) error {
|
{name: "invalid path", resolve: func(_ *config, resolution *Resolution) error {
|
||||||
resolution.Record(Keys("unknown"), ChangeNormalization, "unknown field")
|
resolution.RecordNormalization(Keys("unknown"), "unknown field")
|
||||||
return nil
|
return nil
|
||||||
}, code: CodeResolveInvalidPath},
|
}, code: CodeResolveInvalidPath},
|
||||||
}
|
}
|
||||||
@@ -361,7 +357,7 @@ func TestResolutionPresenceUsesEntryShapeAcrossDynamicChanges(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolution.Record(Keys("dynamic"), ChangeNormalization, "change dynamic shape")
|
resolution.RecordNormalization(Keys("dynamic"), "change dynamic shape")
|
||||||
child := ""
|
child := ""
|
||||||
if test.keyPresent {
|
if test.keyPresent {
|
||||||
configuration.Dynamic = []any{}
|
configuration.Dynamic = []any{}
|
||||||
@@ -466,7 +462,7 @@ func TestResolutionMetadataExplicitnessUsesEntryShape(t *testing.T) {
|
|||||||
callbackErr = err
|
callbackErr = err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resolution.Record(Keys("shape"), ChangeNormalization, "normalize shape")
|
resolution.RecordNormalization(Keys("shape"), "normalize shape")
|
||||||
test.mutate(configuration)
|
test.mutate(configuration)
|
||||||
if err := checkEntry(); err != nil {
|
if err := checkEntry(); err != nil {
|
||||||
callbackErr = err
|
callbackErr = err
|
||||||
@@ -605,6 +601,8 @@ func TestResolutionEntryQueriesRequireAnActiveCallback(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
call()
|
call()
|
||||||
}
|
}
|
||||||
|
requireClosed(t, func() { (*Resolution)(nil).RecordDerivedDefault(Keys("value"), "late") })
|
||||||
|
requireClosed(t, func() { (*Resolution)(nil).RecordNormalization(Keys("value"), "late") })
|
||||||
requireClosed(t, func() { (*Resolution)(nil).InputInfo(Keys("value")) })
|
requireClosed(t, func() { (*Resolution)(nil).InputInfo(Keys("value")) })
|
||||||
requireClosed(t, func() { (&Resolution{}).Source("source-1") })
|
requireClosed(t, func() { (&Resolution{}).Source("source-1") })
|
||||||
|
|
||||||
@@ -617,6 +615,8 @@ func TestResolutionEntryQueriesRequireAnActiveCallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
requireClosed(t, func() { successful.InputInfo(Keys("value")) })
|
requireClosed(t, func() { successful.InputInfo(Keys("value")) })
|
||||||
requireClosed(t, func() { successful.Source("source-1") })
|
requireClosed(t, func() { successful.Source("source-1") })
|
||||||
|
requireClosed(t, func() { successful.RecordDerivedDefault(Keys("value"), "late") })
|
||||||
|
requireClosed(t, func() { successful.RecordNormalization(Keys("value"), "late") })
|
||||||
|
|
||||||
var failed *Resolution
|
var failed *Resolution
|
||||||
if _, err := testLoad(NoSource(), Options[config]{Definition: Definition[config]{Resolve: func(_ *config, resolution *Resolution) error {
|
if _, err := testLoad(NoSource(), Options[config]{Definition: Definition[config]{Resolve: func(_ *config, resolution *Resolution) error {
|
||||||
@@ -627,6 +627,8 @@ func TestResolutionEntryQueriesRequireAnActiveCallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
requireClosed(t, func() { failed.InputInfo(Keys("value")) })
|
requireClosed(t, func() { failed.InputInfo(Keys("value")) })
|
||||||
requireClosed(t, func() { failed.Source("source-1") })
|
requireClosed(t, func() { failed.Source("source-1") })
|
||||||
|
requireClosed(t, func() { failed.RecordDerivedDefault(Keys("value"), "late") })
|
||||||
|
requireClosed(t, func() { failed.RecordNormalization(Keys("value"), "late") })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidationContextPanicsAfterVersionCallback(t *testing.T) {
|
func TestValidationContextPanicsAfterVersionCallback(t *testing.T) {
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ func TestRegisteredSequencePolicyAcrossLoadingLifecycle(t *testing.T) {
|
|||||||
resolved := definition
|
resolved := definition
|
||||||
resolved.Resolve = func(value *config, resolution *Resolution) error {
|
resolved.Resolve = func(value *config, resolution *Resolution) error {
|
||||||
value.Items[1].ID = value.Items[0].ID
|
value.Items[1].ID = value.Items[0].ID
|
||||||
resolution.Record(Keys("items"), ChangeNormalization, "registered identities collide")
|
resolution.RecordNormalization(Keys("items"), "registered identities collide")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
result, err = testLoad[config](Bytes("main", []byte("items: [{id: first}, {id: second}]\n")), Options[config]{Definition: resolved})
|
result, err = testLoad[config](Bytes("main", []byte("items: [{id: first}, {id: second}]\n")), Options[config]{Definition: resolved})
|
||||||
|
|||||||
@@ -1252,7 +1252,7 @@ func TestSourceVersionEvidencePropagatesThroughRecordedResolutionDependency(t *t
|
|||||||
},
|
},
|
||||||
Resolve: func(value *configuration, resolution *Resolution) error {
|
Resolve: func(value *configuration, resolution *Resolution) error {
|
||||||
value.Derived = value.Credentials.Password
|
value.Derived = value.Credentials.Password
|
||||||
resolution.Record(Keys("derived"), ChangeNormalization, "derive from credentials", Keys("credentials"))
|
resolution.RecordNormalization(Keys("derived"), "derive from credentials", Keys("credentials"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
17
lifecycle.go
17
lifecycle.go
@@ -259,10 +259,19 @@ func (r *Resolution) Source(id string) (SourceInfo, bool) {
|
|||||||
return fromEngineSourceInfo(value), ok
|
return fromEngineSourceInfo(value), ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record declares the intent for a resolver mutation. A container path covers
|
// RecordDerivedDefault records a derived-default intent for a resolver mutation
|
||||||
// mutations to its descendants.
|
// already performed by application code. A container path covers mutations to
|
||||||
func (r *Resolution) Record(path Path, kind ChangeKind, reason string, dependencies ...Path) {
|
// its descendants. This does not assign a value or suppress work for explicit
|
||||||
r.engineContext().Record(toEnginePath(path), engine.ChangeKind(kind), reason, toEnginePaths(dependencies)...)
|
// input.
|
||||||
|
func (r *Resolution) RecordDerivedDefault(path Path, reason string, dependencies ...Path) {
|
||||||
|
r.engineContext().RecordDerivedDefault(toEnginePath(path), reason, toEnginePaths(dependencies)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordNormalization records a normalization intent for a resolver mutation
|
||||||
|
// already performed by application code. A container path covers mutations to
|
||||||
|
// its descendants. This does not assign a value.
|
||||||
|
func (r *Resolution) RecordNormalization(path Path, reason string, dependencies ...Path) {
|
||||||
|
r.engineContext().RecordNormalization(toEnginePath(path), reason, toEnginePaths(dependencies)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error reports a safe, value-free resolution error at path.
|
// Error reports a safe, value-free resolution error at path.
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ const (
|
|||||||
CodeResolveWarning Code = "resolve.warning"
|
CodeResolveWarning Code = "resolve.warning"
|
||||||
CodeResolveHookFailed Code = "resolve.hook_failed"
|
CodeResolveHookFailed Code = "resolve.hook_failed"
|
||||||
CodeResolveInvalidPath Code = "resolve.invalid_path"
|
CodeResolveInvalidPath Code = "resolve.invalid_path"
|
||||||
CodeResolveInvalidKind Code = "resolve.invalid_kind"
|
|
||||||
CodeResolveInvalidRecord Code = "resolve.invalid_record"
|
CodeResolveInvalidRecord Code = "resolve.invalid_record"
|
||||||
CodeResolveInvalidTarget Code = "resolve.invalid_target"
|
CodeResolveInvalidTarget Code = "resolve.invalid_target"
|
||||||
CodeResolveInvalidValue Code = "resolve.invalid_value"
|
CodeResolveInvalidValue Code = "resolve.invalid_value"
|
||||||
|
|||||||
Reference in New Issue
Block a user