diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index c101f31..c9bedf1 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # ConfigKit v1.1.0 adoption implementation plan -Status: Stages 1–2 complete; Stages 3–6 are not started. +Status: Stages 1–3 complete; Stages 4–6 are not started. This plan is for a Luna coding agent implementing the selected [ConfigKit adoption target](configkit-v1.1.0.md). Follow Stage 1 through Stage 6 @@ -148,6 +148,10 @@ source inventory, explanation, diagnostic, and outcome semantics are retained. ## Stage 3: Update focused report and adapter coverage +**Completed.** Focused source tests cover the new text and YAML keys, native +main layer, ordered selections, empty lists, and nil/redacted evidence. The +offline `TestSources` suite passed with Go 1.27.0. + 1. Extend `TestSourcesProjectNativeEvidenceInTextAndYAML` in `sources_test.go` rather than building another report-test framework. Update fixtures and assertions to the new native fields and report keys. Check that legacy diff --git a/integrations/ckconfig/sources_test.go b/integrations/ckconfig/sources_test.go index 17dea6b..f13f40d 100644 --- a/integrations/ckconfig/sources_test.go +++ b/integrations/ckconfig/sources_test.go @@ -34,7 +34,11 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) { reader := &sourceInventory{values: []configkit.SourceInfo{ { ID: "root", Label: "root source", Path: "root.yml", - PlacementMode: configkit.PlacementModeMapping, + PlacementMode: configkit.PlacementModeMapping, Layer: configkit.LayerMain, + EmptyImportSelections: []configkit.EmptyImportSelection{ + {Path: configkit.Keys("imports", "first"), Location: configkit.Location{SourceID: "root.yml", Line: 3, Column: 4}, Selector: configkit.ImportSelectorGlob}, + {Path: configkit.Keys("imports", "second"), Location: configkit.Location{}, Selector: configkit.ImportSelectorPath}, + }, }, { ID: "item", Label: "sequence item", Path: "item.yml", @@ -70,11 +74,13 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) { var report struct { Scope string `yaml:"scope"` Sources []struct { - ID string `yaml:"id"` - Destination string `yaml:"destination"` - Placement string `yaml:"placement"` - DestinationUnresolved bool `yaml:"destination_unresolved"` - VersionCheck *struct { + ID string `yaml:"id"` + Destination string `yaml:"destination"` + Placement string `yaml:"placement"` + Layer string `yaml:"layer"` + EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"` + DestinationIsFallback bool `yaml:"destination_is_fallback"` + VersionEvidence *struct { Path string `yaml:"path"` Version struct { Present bool `yaml:"present"` @@ -87,7 +93,7 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) { Column int `yaml:"column"` } `yaml:"location"` Redacted bool `yaml:"redacted"` - } `yaml:"version_check"` + } `yaml:"version_evidence"` } `yaml:"sources"` } if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil { @@ -99,21 +105,31 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) { if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) { t.Fatalf("source order = %v", got) } - if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationUnresolved || root.VersionCheck != nil { + if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationIsFallback || root.VersionEvidence != nil || root.Layer != "main" { t.Errorf("root source projection = %#v", root) } + wantSelections := []emptyImportSelectionDTO{ + {Path: "/imports/first", Location: locationDTO{SourceID: "root.yml", Line: 3, Column: 4}, Selector: "glob"}, + {Path: "/imports/second", Location: locationDTO{}, Selector: "path"}, + } + if !reflect.DeepEqual(report.Sources[0].EmptyImportSelections, wantSelections) || report.Sources[1].EmptyImportSelections == nil || len(report.Sources[1].EmptyImportSelections) != 0 { + t.Fatalf("import selections: %#v", report.Sources) + } + if strings.Contains(yamlOutput.String(), "destination_unresolved:") || strings.Contains(yamlOutput.String(), "version_check:") { + t.Fatal("legacy YAML keys present") + } item := report.Sources[1] - if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationUnresolved { + if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationIsFallback { t.Errorf("sequence item projection = %#v", item) } - if check := item.VersionCheck; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted { + if check := item.VersionEvidence; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted { t.Errorf("text version evidence projection = %#v", check) } nullSource := report.Sources[2] - if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationUnresolved { + if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationIsFallback { t.Errorf("mapping projection = %#v", nullSource) } - if check := nullSource.VersionCheck; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted { + if check := nullSource.VersionEvidence; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted { t.Errorf("null/redacted version evidence projection = %#v", check) } @@ -122,9 +138,15 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) { if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 { t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls) } + if strings.Contains(textOutput.String(), "destination_unresolved:") || strings.Contains(textOutput.String(), "version_check:") { + t.Fatal("legacy text keys present") + } + if strings.Index(textOutput.String(), `path: "/imports/first"`) > strings.Index(textOutput.String(), `path: "/imports/second"`) { + t.Fatal("import selection order changed") + } for _, fragment := range []string{ - `id: "root"`, `destination: ""`, `placement: "mapping"`, "destination_unresolved: false", "version_check: null", - `destination: "/services"`, `placement: "sequence_item"`, "destination_unresolved: true", `path: "/version"`, `text: "v2"`, + `id: "root"`, `destination: ""`, `placement: "mapping"`, `layer: "main"`, "destination_is_fallback: false", "version_evidence: null", `path: "/imports/first"`, `location: {source_id: "root.yml", line: 3, column: 4}`, `selector: "glob"`, `path: "/imports/second"`, `location: {source_id: "", line: 0, column: 0}`, `selector: "path"`, "empty_import_selections: []", + `destination: "/services"`, `placement: "sequence_item"`, "destination_is_fallback: true", `path: "/version"`, `text: "v2"`, `destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true", } { if !strings.Contains(textOutput.String(), fragment) {