diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 7f0b585..abdb6d7 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # Implementation Plan: Sequence Placement and Composition -Status: implementation in progress; stages 1–13 completed. +Status: implementation complete; all 14 stages completed. ## Purpose and authority @@ -796,3 +796,20 @@ No environmental limitation affected validation; checks ran on Linux/amd64. Completion: the repository is clean, the feature and its evidence agree, and no known in-scope implementation work remains. No product decisions remain open; private helper names and equivalent mechanics are ordinary implementation work. + +Completion evidence: final review covered the complete implementation diff from +baseline `2051177` against the settled behavior and public-contract boundaries. +It found one malformed-record diagnostic using a contribution-local rather than +assigned sequence index. The composer now reports the effective assigned item +path, with a regression for a malformed record in the second contribution at +`/records/1`. Review also confirmed registered identity checks remain limited to +strict composition, precedence still replaces complete sequences, both opt-ins +are explicit, and source ownership, physical locations, contexts, and detached +evidence remain intact. Final checks passed with Go `go1.26.9 linux/amd64`: + +- `GOTOOLCHAIN=local GOPROXY=off go test ./internal/engine -run 'ComposeDocuments(ReportsAssignedPathForMalformedRegisteredSequenceContribution|ValidatesRegisteredSequenceSingletons|RejectsRegisteredSequence)' -count=1` +- `GOTOOLCHAIN=local GOPROXY=off go test -race ./...` +- `GOTOOLCHAIN=local GOPROXY=off ./scripts/check.sh` +- `git diff --check 2051177` + +No environmental limitation affected validation; checks ran on Linux/amd64. diff --git a/internal/engine/compose.go b/internal/engine/compose.go index 29ba829..31f6c83 100644 --- a/internal/engine/compose.go +++ b/internal/engine/compose.go @@ -239,7 +239,7 @@ func validateRegisteredSequences(inputs []*document.Node, claims []compositionCl start := lengthsByPath[pathKey] contribution := validatedSequence{items: node.Sequence} for itemIndex, item := range node.Sequence { - itemPath := claim.path.Index(itemIndex) + itemPath := claim.path.Index(start + itemIndex) if item == nil || item.Kind != document.Mapping { location := (*Location)(nil) if item != nil { diff --git a/internal/engine/compose_test.go b/internal/engine/compose_test.go index e635636..b6c5ac4 100644 --- a/internal/engine/compose_test.go +++ b/internal/engine/compose_test.go @@ -339,6 +339,20 @@ func TestComposeDocumentsValidatesRegisteredSequenceSingletons(t *testing.T) { } } +func TestComposeDocumentsReportsAssignedPathForMalformedRegisteredSequenceContribution(t *testing.T) { + _, diagnostics := composeDocumentsWithPolicy( + sequencePolicy{identityFields: map[string]string{"/records": "id"}}, + parseCompositionDocument(t, "source-1", "records: [{id: first}]\n"), + parseCompositionDocument(t, "source-2", "records: [{name: malformed}]\n"), + ) + if len(diagnostics) != 1 || diagnostics[0].Code != CodeComposeInvalid || diagnostics[0].Path.String() != "/records/1" { + t.Fatalf("diagnostics = %#v, want invalid item at /records/1", diagnostics) + } + if diagnostics[0].Primary == nil || diagnostics[0].Primary.SourceID != "source-2" { + t.Fatalf("malformed item location = %#v, want source-2", diagnostics[0].Primary) + } +} + func TestComposeDocumentsRejectsRegisteredDuplicateIdentities(t *testing.T) { tests := []struct { name string