From dbba1485a7db564df114246b0e9a42f1e2054474 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Thu, 5 Nov 2026 14:11:41 +0000 Subject: [PATCH] Select inventory namespaces before copying --- docs/roadmap/implementation.md | 14 ++++ internal/configuration/listing.go | 77 +++++++++++++-------- internal/configuration/listing_test.go | 94 +++++++++++++++++++------- internal/engine/engine.go | 63 +++++------------ 4 files changed, 151 insertions(+), 97 deletions(-) diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 9b5d864..8b37580 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -543,6 +543,20 @@ IDs, All/default/views, missing matches, mutation, and cancellation. Repeat the baseline through the new select-before-copy path. No persistent buckets/cache, new public signature, or unqualified-query complexity promise is required. +Completion: namespace selection now precedes copying for all three inventories; +focused listing and ownership tests pass on Go 1.27.3. The documented 100-iteration, +three-run engine workload measured the following bytes/op, in All / sparse / +dense / absent order (one allocation except absent, which used none): + +| Total IDs | Bytes/op | +| --- | --- | +| 32 | 512 / 16 / 256 / 0 | +| 1,024 | 18,432 / 16 / 9,472 / 0 | +| 4,096 | 65,536 / 16 / 32,768 / 0 | + +The baseline included full-inventory copying and subsequent filtering; these +measurements are observations, not performance guarantees. + ## Stage 21: Put Authentication Protocol Mechanics In The Outbound Adapter **Catalog:** 26. **Files:** llm authentication adapter, selection, assembly and tests. diff --git a/internal/configuration/listing.go b/internal/configuration/listing.go index fd7242f..b8dc421 100644 --- a/internal/configuration/listing.go +++ b/internal/configuration/listing.go @@ -2,36 +2,66 @@ package configuration import ( "context" + "sort" + "strings" "go.maximumdirect.net/promptkit/internal/domain" ) +// IdentityFilter selects all identities, one namespace, or unqualified IDs. +type IdentityFilter struct { + All bool + Namespace string +} + +func selectIdentities[T any](ctx context.Context, entries []T, filter IdentityFilter, id func(T) string) ([]T, error) { + if err := ctx.Err(); err != nil { + return nil, err + } + if filter.All { + result := append([]T(nil), entries...) + if err := ctx.Err(); err != nil { + return nil, err + } + return result, nil + } + if filter.Namespace != "" { + prefix := filter.Namespace + "/" + start := sort.Search(len(entries), func(i int) bool { return id(entries[i]) >= prefix }) + end := start + sort.Search(len(entries)-start, func(i int) bool { return !strings.HasPrefix(id(entries[start+i]), prefix) }) + result := append([]T(nil), entries[start:end]...) + if err := ctx.Err(); err != nil { + return nil, err + } + return result, nil + } + var result []T + for _, entry := range entries { + if err := ctx.Err(); err != nil { + return nil, err + } + if !strings.Contains(id(entry), "/") { + result = append(result, entry) + } + } + if err := ctx.Err(); err != nil { + return nil, err + } + return result, nil +} + // CollectionIdentity is the captured metadata for one final collection entry. type CollectionIdentity struct { Namespace string ReleaseVersion *string } -func (state *loaded) ListProfiles(ctx context.Context) ([]string, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - profiles := append([]string(nil), state.profileIDs...) - if err := ctx.Err(); err != nil { - return nil, err - } - return profiles, nil +func (state *loaded) ListProfiles(ctx context.Context, filter IdentityFilter) ([]string, error) { + return selectIdentities(ctx, state.profileIDs, filter, func(id string) string { return id }) } -func (state *loaded) ListBackends(ctx context.Context) ([]string, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - backends := append([]string(nil), state.backendIDs...) - if err := ctx.Err(); err != nil { - return nil, err - } - return backends, nil +func (state *loaded) ListBackends(ctx context.Context, filter IdentityFilter) ([]string, error) { + return selectIdentities(ctx, state.backendIDs, filter, func(id string) string { return id }) } func (state *loaded) ListNamespaces(ctx context.Context, kinds []string) ([]string, error) { @@ -72,13 +102,6 @@ func (state *loaded) ListCollections(ctx context.Context) ([]CollectionIdentity, return collections, nil } -func (state *loaded) ListPrompts(ctx context.Context) ([]domain.PromptIdentity, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - prompts := append([]domain.PromptIdentity(nil), state.promptIDs...) - if err := ctx.Err(); err != nil { - return nil, err - } - return prompts, nil +func (state *loaded) ListPrompts(ctx context.Context, filter IdentityFilter) ([]domain.PromptIdentity, error) { + return selectIdentities(ctx, state.promptIDs, filter, func(entry domain.PromptIdentity) string { return entry.ID }) } diff --git a/internal/configuration/listing_test.go b/internal/configuration/listing_test.go index 3d624ed..98b6346 100644 --- a/internal/configuration/listing_test.go +++ b/internal/configuration/listing_test.go @@ -23,7 +23,7 @@ func TestLoadedListsSortedEffectiveIdentities(t *testing.T) { if err != nil { t.Fatal(err) } - backends, err := state.ListBackends(context.Background()) + backends, err := state.ListBackends(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } @@ -32,7 +32,7 @@ func TestLoadedListsSortedEffectiveIdentities(t *testing.T) { t.Fatalf("backend IDs = %#v, want %#v", backends, wantBackends) } - profiles, err := state.ListProfiles(context.Background()) + profiles, err := state.ListProfiles(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } @@ -41,7 +41,7 @@ func TestLoadedListsSortedEffectiveIdentities(t *testing.T) { t.Fatalf("profile IDs = %#v, want %#v", profiles, wantProfiles) } - prompts, err := state.ListPrompts(context.Background()) + prompts, err := state.ListPrompts(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } @@ -65,36 +65,36 @@ func TestLoadedListsAreIndependent(t *testing.T) { t.Fatal(err) } - profiles, err := state.ListProfiles(context.Background()) + profiles, err := state.ListProfiles(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } profiles = append(profiles, "caller profile") profiles[0] = "changed profile" - backends, err := state.ListBackends(context.Background()) + backends, err := state.ListBackends(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } backends[0] = "changed backend" - prompts, err := state.ListPrompts(context.Background()) + prompts, err := state.ListPrompts(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } prompts[0].ID = "changed prompt" - profiles, err = state.ListProfiles(context.Background()) + profiles, err = state.ListProfiles(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(profiles, []string{"profile"}) { t.Fatalf("caller mutation changed profile inventory: %#v", profiles) } - backends, err = state.ListBackends(context.Background()) + backends, err = state.ListBackends(context.Background(), IdentityFilter{All: true}) if err != nil || !reflect.DeepEqual(backends, []string{"backend"}) { t.Fatalf("caller mutation changed backend inventory: %#v, %v", backends, err) } - prompts, err = state.ListPrompts(context.Background()) + prompts, err = state.ListPrompts(context.Background(), IdentityFilter{All: true}) if err != nil { t.Fatal(err) } @@ -104,20 +104,66 @@ func TestLoadedListsAreIndependent(t *testing.T) { } } +func TestLoadedListsSelectNamespaces(t *testing.T) { + ids := []string{"a", "a-b/one", "a/one", "a/two", "b", "z/one"} + state := &loaded{profileIDs: append([]string(nil), ids...), backendIDs: append([]string(nil), ids...)} + for _, id := range ids { + state.promptIDs = append(state.promptIDs, domain.PromptIdentity{ID: id}) + } + cases := []struct { + name string + filter IdentityFilter + want []string + }{ + {"all", IdentityFilter{All: true}, ids}, + {"unqualified", IdentityFilter{}, []string{"a", "b"}}, + {"namespace", IdentityFilter{Namespace: "a"}, []string{"a/one", "a/two"}}, + {"prefix sharing", IdentityFilter{Namespace: "a-b"}, []string{"a-b/one"}}, + {"missing", IdentityFilter{Namespace: "absent"}, nil}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + profiles, err := state.ListProfiles(context.Background(), tc.filter) + if err != nil || !reflect.DeepEqual(profiles, tc.want) { + t.Fatalf("profiles = %v, %v; want %v", profiles, err, tc.want) + } + backends, err := state.ListBackends(context.Background(), tc.filter) + if err != nil || !reflect.DeepEqual(backends, tc.want) { + t.Fatalf("backends = %v, %v; want %v", backends, err, tc.want) + } + prompts, err := state.ListPrompts(context.Background(), tc.filter) + if err != nil || len(prompts) != len(tc.want) { + t.Fatalf("prompts = %v, %v; want %v", prompts, err, tc.want) + } + for i := range prompts { + if prompts[i].ID != tc.want[i] { + t.Fatalf("prompt ID = %q; want %q", prompts[i].ID, tc.want[i]) + } + } + if len(profiles) > 0 { + profiles[0], backends[0], prompts[0].ID = "changed", "changed", "changed" + } + }) + } + if !reflect.DeepEqual(state.profileIDs, ids) || !reflect.DeepEqual(state.backendIDs, ids) || state.promptIDs[0].ID != ids[0] { + t.Fatal("caller mutation changed captured identities") + } +} + func TestLoadedListsEmptyInventory(t *testing.T) { state, err := Load(configkit.Input{Source: configkit.NoSource()}, nil) if err != nil { t.Fatal(err) } - profiles, err := state.ListProfiles(context.Background()) + profiles, err := state.ListProfiles(context.Background(), IdentityFilter{All: true}) if err != nil || len(profiles) != 0 { t.Fatalf("empty profile listing = %#v, %v", profiles, err) } - backends, err := state.ListBackends(context.Background()) + backends, err := state.ListBackends(context.Background(), IdentityFilter{All: true}) if err != nil || len(backends) != 0 { t.Fatalf("empty backend listing = %#v, %v", backends, err) } - prompts, err := state.ListPrompts(context.Background()) + prompts, err := state.ListPrompts(context.Background(), IdentityFilter{All: true}) if err != nil || len(prompts) != 0 { t.Fatalf("empty prompt listing = %#v, %v", prompts, err) } @@ -134,17 +180,19 @@ func TestLoadedListsHonorCanceledContext(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() - profiles, err := state.ListProfiles(ctx) - if !errors.Is(err, context.Canceled) || len(profiles) != 0 { - t.Fatalf("canceled profile listing = %#v, %v", profiles, err) - } - backends, err := state.ListBackends(ctx) - if !errors.Is(err, context.Canceled) || len(backends) != 0 { - t.Fatalf("canceled backend listing = %#v, %v", backends, err) - } - prompts, err := state.ListPrompts(ctx) - if !errors.Is(err, context.Canceled) || len(prompts) != 0 { - t.Fatalf("canceled prompt listing = %#v, %v", prompts, err) + for _, filter := range []IdentityFilter{{All: true}, {}, {Namespace: "example"}} { + profiles, err := state.ListProfiles(ctx, filter) + if !errors.Is(err, context.Canceled) || len(profiles) != 0 { + t.Fatalf("canceled profile listing = %#v, %v", profiles, err) + } + backends, err := state.ListBackends(ctx, filter) + if !errors.Is(err, context.Canceled) || len(backends) != 0 { + t.Fatalf("canceled backend listing = %#v, %v", backends, err) + } + prompts, err := state.ListPrompts(ctx, filter) + if !errors.Is(err, context.Canceled) || len(prompts) != 0 { + t.Fatalf("canceled prompt listing = %#v, %v", prompts, err) + } } } diff --git a/internal/engine/engine.go b/internal/engine/engine.go index a6e2a70..6b65f36 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -98,9 +98,9 @@ type resourceNamespaces struct { } type identityInventory interface { - ListBackends(context.Context) ([]string, error) - ListProfiles(context.Context) ([]string, error) - ListPrompts(context.Context) ([]domain.PromptIdentity, error) + ListBackends(context.Context, configuration.IdentityFilter) ([]string, error) + ListProfiles(context.Context, configuration.IdentityFilter) ([]string, error) + ListPrompts(context.Context, configuration.IdentityFilter) ([]domain.PromptIdentity, error) ListNamespaces(context.Context, []string) ([]string, error) ListCollections(context.Context) ([]configuration.CollectionIdentity, error) } @@ -268,24 +268,11 @@ func (e *Engine) ListProfiles(ctx context.Context, filters ...ListingFilter) ([] } func (e *Engine) ListPrompts(ctx context.Context, filters ...ListingFilter) ([]domain.PromptIdentity, error) { - mode, namespace, err := resolveListingFilter(filters, e.namespaces.prompt) + filter, err := inventoryFilter(filters, e.namespaces.prompt) if err != nil { return nil, err } - prompts, err := e.listing.ListPrompts(ctx) - if err != nil { - return nil, err - } - var filtered []domain.PromptIdentity - for _, prompt := range prompts { - if matchesListingNamespace(prompt.ID, mode, namespace) { - filtered = append(filtered, prompt) - } - } - if err := ctx.Err(); err != nil { - return nil, err - } - return filtered, nil + return e.listing.ListPrompts(ctx, filter) } func (e *Engine) ListNamespaces(ctx context.Context, kinds []string) ([]string, error) { @@ -307,26 +294,21 @@ func filterIdentityList( ctx context.Context, filters []ListingFilter, scope string, - list func(context.Context) ([]string, error), + list func(context.Context, configuration.IdentityFilter) ([]string, error), ) ([]string, error) { + filter, err := inventoryFilter(filters, scope) + if err != nil { + return nil, err + } + return list(ctx, filter) +} + +func inventoryFilter(filters []ListingFilter, scope string) (configuration.IdentityFilter, error) { mode, namespace, err := resolveListingFilter(filters, scope) if err != nil { - return nil, err + return configuration.IdentityFilter{}, err } - ids, err := list(ctx) - if err != nil { - return nil, err - } - var filtered []string - for _, id := range ids { - if matchesListingNamespace(id, mode, namespace) { - filtered = append(filtered, id) - } - } - if err := ctx.Err(); err != nil { - return nil, err - } - return filtered, nil + return configuration.IdentityFilter{All: mode == ListingAll, Namespace: namespace}, nil } func resolveListingFilter(filters []ListingFilter, scope string) (ListingFilterMode, string, error) { @@ -355,19 +337,6 @@ func resolveListingFilter(filters []ListingFilter, scope string) (ListingFilterM } } -func matchesListingNamespace(id string, mode ListingFilterMode, namespace string) bool { - switch mode { - case ListingNamed: - idNamespace, _, qualified := strings.Cut(id, "/") - return qualified && idNamespace == namespace - case ListingUnqualified: - return !strings.Contains(id, "/") - case ListingAll: - return true - default: - return false - } -} func (e *Engine) Prepare(ctx context.Context, request domain.RunRequest) (*domain.PreparedRun, error) { request, err := e.qualifyRunRequest(request) if err != nil {