# Profile And Prompt Listing Implementation Plan Implement the [listing roadmap](listing.md) in the numbered order below. Each stage is scoped for one Luna coding-agent prompt and should leave a compiling, tested unit. All four stages are pending. This replaces the completed performance plan, preserved in [Git history](https://gitea.maximumdirect.net/eric/promptkit/src/commit/7325a34c070c77c4784ab76c916fc8a4d79b5c46/docs/roadmap/implementation.md). For older inspection-roadmap references to this pathname, the completed [inspection plan](https://gitea.maximumdirect.net/eric/promptkit/src/commit/481e2d494c5a4e8b7f3a2a6f1cceaeb3f7c71d05/docs/roadmap/implementation.md) is also preserved. These historical plans are not work for this sprint. ## Baseline And Working Rules Planning baseline: `7325a34c070c77c4784ab76c916fc8a4d79b5c46`. There are no listing methods yet. Configuration already captures profiles in `loaded.indexedProfiles` and prompts in `loaded.prompts`, after the final ConfigKit handoff. `internal/engine.Engine` currently retains the runner and the operator inspection view. Start with [development](../development.md), then read the applicable [agent](../policy/agents.md), [architecture](../policy/architecture.md), [testing](../policy/testing.md), and [documentation](../policy/documentation.md) policies. Reuse unchanged documents already read. Consult [internal sources](../internal/sources.md), the [component overview](../internal/overview.md), the [consumer guide](../consumers/pkg-promptkit.md), existing inspection GoDoc, and the [configuration ADR](../adr/0001-configuration-boundary.md). For each stage: inspect the current worktree, preserve unrelated edits, implement only its scope, format changed Go files, run focused verification, review the diff, update this plan's stage status with brief evidence, and commit the nonempty completed unit with a plain-English message. Report any blocked validation honestly. Publication and release preparation are separate tasks. Use the existing module versions. No dependency upgrade, configuration-format change, execution refactor, new public package, or release-tool change is needed. The storage and wiring choices below are implementation decisions, not permanent consumer invariants. Tests protect outcomes, not private helper names, clone counts, allocation counts, or timing thresholds. ## Selected Public Contract Use these root-package declarations: ```go type PromptIdentity struct { ID string Version string } func (e *Engine) ListProfiles(ctx context.Context) ([]string, error) func (e *Engine) ListPrompts(ctx context.Context) ([]PromptIdentity, error) ``` - List final effective captured identities, including maintained and consumer profiles. Inherited profiles keep their own keys. Return each profile ID and each prompt ID/version pair once; omit historical-only contributions. - Preserve literal spelling. Sort profiles lexically by ID; sort prompts lexically by ID, then version. Do not interpret versions as SemVer or select a preferred version. Existing omitted-version inspection remains unchanged. - Results are caller-owned. Concurrent listing and other supported engine operations cannot mutate the captured inventory through these results. - Empty inventories succeed. Nil and zero-value public engines return an error matching `ErrInvalidConfig`, consistent with existing facade checks. - For a valid engine, context cancellation/deadline errors retain their standard identity. Return no partial inventory on error. Follow existing inspection precedence: validate the public engine before delegating context handling. Check context before and after the synchronous copy/conversion work; do not promise immediate interruption or deterministic precedence in a cancel/return race. No new nil-context behavior is selected. - `PromptIdentity` follows other inspection values: no stable JSON representation is promised. Do not add custom serialization or pin nil versus nonnil empty slices in GoDoc or tests. - Membership is not execution readiness. Listing performs no per-item full inspection, target validation, credential resolution, resource reads, rendering, admission, generation, or ConfigKit provenance traversal. The roadmap owns scope and intent; implemented GoDoc will own the exact API. Do not add backend listing, filters, pagination, reloads, runtime mutation, provider discovery, new caller limits, or stronger catalog availability promises. ## Stage 1 — Capture And Read Identity Inventories **Status: Complete (2026-10-09).** Verified with `go test ./internal/configuration ./internal/domain` and `go vet ./internal/configuration ./internal/domain`. Adapter tests cover effective sorted identities, literal keys, partial profiles, empty loads, caller-owned results, and canceled contexts. **Scope:** `internal/domain`, `internal/configuration`, and focused adapter tests. 1. Add an internal `domain.PromptIdentity` with only `ID` and `Version` strings. Keep it separate from the eventual public declaration; no public type alias. 2. Add private profile-ID and prompt-identity slices to `loaded`. Populate them once at the end of `load`, after both `materializePrompts` and `buildExecutionProfiles` have succeeded. Enumerate the finished `indexedProfiles` keys and the finished `prompts` ID/version keys, not ConfigKit metadata or raw contributions. 3. Build the ordered slices with existing `sortedKeys` or standard-library sorting. Flatten actual prompt versions; an ID with no versions contributes no prompt identity. Store only strings, not targets, definitions, or histories. 4. Add `ListProfiles(context.Context) ([]string, error)` and `ListPrompts(context.Context) ([]domain.PromptIdentity, error)` on `loaded`, in a focused `internal/configuration/listing.go`. Check context, copy the captured slice, check context again, and return the independent result. Ordinary slice copying suffices because elements contain only strings. Reads are linear in returned inventory size and require no repeated sorting. 5. Add adapter tests using the real `Load` and existing mapping helpers. Cover a small unsorted profile/prompt fixture, multiple versions such as `"10"` and `"2"`, literal whitespace/slash keys, a partial profile, and an empty load. Mutate returned entries and verify subsequent lists are unchanged. Cover an already-canceled context for each method without timing assertions. Do not change existing lookup methods or add inventory mutation. Keep construction complexity proportionate; there is no benchmark gate. **Verify:** format changed files; run `go test ./internal/configuration ./internal/domain` and `go vet ./internal/configuration ./internal/domain`. **Done when:** successful loads retain sorted identity-only inventories and return owned lists without rereading ConfigKit or requiring runnable targets. ## Stage 2 — Wire The Public Facade And Its Basic Contract **Status: Pending.** Depends on Stage 1. **Scope:** `internal/engine`, root API/conversion, and focused facade tests. 1. Add a private, consumer-owned inventory interface in `internal/engine` containing just the two listing methods from Stage 1. Store the loaded snapshot through this interface during `New`, alongside the existing operator inspection view. Delegate new internal engine methods to it. There is no need to extend execution repository interfaces or the use-case runner, add optional capabilities, or provide a full-inspection fallback. 2. Add `listing.go` at the module root, containing public `PromptIdentity` and the two methods. Apply the same `e == nil || e.internal == nil` check as existing inspection methods, returning `ErrInvalidConfig` with useful context. Map delegated errors through `mapPublicError`. 3. Return the already-owned profile slice. Convert internal prompt identities into a separate public slice by copying their two strings. Check context after conversion so a detected cancellation yields no partial result. Do not export an internal type in any public signature. 4. Write concise GoDoc covering effective membership, exact lexical ordering, all prompt versions, captured-state behavior, caller ownership, concurrent use, empty success, nil-engine and context errors, and absence of readiness checks or external work. Identifiers may be sensitive application data; do not describe these lists as automatically safe for disclosure. 5. Add external-package basic tests in `listing_contract_test.go`: a usable public engine lists a configured profile and two exact prompt versions; returned identities can be inspected; nil/zero engines match `ErrInvalidConfig`; canceled and expired contexts preserve context identity with no partial inventory. Use real constructors and synthetic configuration. **Verify:** format changed files; run `go test ./internal/engine .` and `go vet ./internal/engine .`. Existing root boundary tests must continue to pass; do not weaken them. **Done when:** consumers can call both methods through the root facade and receive independent public values with the selected error behavior. ## Stage 3 — Verify Effective Membership, Ownership, And Concurrent Use **Status: Pending.** Depends on Stage 2. **Scope:** focused additions to the external-package listing contract tests. Production edits are limited to defects those tests reveal. 1. Build one representative layered engine with a consumer base profile, an inherited child, an overlay of the same profile ID, and multiple prompt versions. Verify effective identities, no duplicate overlay entry, and child/base identities remaining distinct. Inspect one listed identity to confirm it resolves to the effective captured definition. 2. Verify maintained profiles are included without asserting a complete catalog inventory or a specific upstream model. The two PromptKit-owned standard profile names may serve as stable membership examples under the existing release policy; other expectations should use fixture-controlled identities. 3. Exercise empty effective inventories through a public engine: a final main mapping with `profiles: null` and `prompts: null` clears the sections above the catalog underlays. Assert successful zero-length lists, not a particular nil/empty representation. This also checks that lower-layer historical profile paths are not returned. Use existing ConfigKit semantics; add no source-validation pass or special listing-only removal rule. 4. Mutate elements in both public results and relist to verify independent storage across calls. Add one bounded concurrent test that lists and mutates independent results while other goroutines list/inspect the same captured engine. Coordinate deterministically; avoid sleeps or shared test-owned mutable result slices. 5. Cover snapshot/no-execution behavior with a compact fixture: construct from an application filesystem, then remove/change its content after construction and verify listing still reports the captured identities. Inject existing model-client and artifact-reader stubs that fail if invoked. Include a partial profile or a named but unavailable API-key environment variable; listing succeeds without provider readiness. Do not add new extension points or exact private-call-count assertions solely for these tests. Place effective-loading/ordering mechanics in Stage 1's adapter tests and public assembled outcomes here. Avoid duplicating every loader, inheritance, or existing inspection case. No execution/network call is required to prove identity discovery. **Verify:** `go test -race ./internal/configuration ./internal/engine .`. **Done when:** public tests demonstrate effective—not historical—membership, independent results, concurrent safety, and listing without execution work. ## Stage 4 — Document And Verify The Completed Feature **Status: Pending.** Depends on Stage 3. **Scope:** owning documentation, final review, and complete offline verification. 1. Update `doc.go` to include listing in its operation and concurrent-use summaries, and `PromptIdentity` among values without stable JSON contracts. Keep exact behavior in the method/type GoDoc from Stage 2. 2. Add a short consumer-guide discovery example listing identities and then inspecting a selected entry. Distinguish listing from configuration history and from execution readiness; link to the exact GoDoc. A new runnable example project or CLI is unnecessary. 3. Update `docs/internal/sources.md` and `docs/internal/overview.md` for captured inventories and direct internal-engine delegation. The execution runner has not acquired a listing responsibility. Add a brief format-reference link to the listing guidance where it currently introduces inspection, without changing configuration semantics. 4. Repair old `implementation.md` links in the completed `performance.md`, `inspection.md`, and historical sections of `remediation.md` to their respective history links at the top of this plan. Preserve finding statuses and recorded evidence; do not retire unrelated roadmaps or imply their work remains pending. This is navigation repair, not another feature. 5. Review the entire feature diff against the listing roadmap and selected contract. Confirm only effective indexes are used; no runtime imports of ConfigKit, provenance traversal, readiness checks, resource reads, new limits, or stable serialization promises have been introduced. 6. Run the complete offline race suite and full vet, plus maintained examples if changed or affected. Validate changed documentation links and `git diff --check`. Reuse successful focused checks for unchanged content. 7. Mark the listing roadmap and this plan complete with concise verification evidence. Commit the completed unit. Leave release notes, roadmap retirement, tags, and publication for the later release-preparation task. Use the existing local Go installation and prepared module cache. Suggested final commands (not new release gates): ```sh GOTOOLCHAIN=local GOWORK=off GOPROXY=off GONOPROXY=none GOSUMDB=off \ go test -race -vet=off -mod=readonly -count=1 ./... GOTOOLCHAIN=local GOWORK=off GOPROXY=off go vet -mod=readonly ./... git diff --check ``` **Done when:** all four stages are verified, listing is documented by its canonical owners, and the feature is ready for ordinary release preparation. ## Open Questions None. The selected signatures, result shape, ordering, ownership, error behavior, implementation boundary, and verification scope are specified above.