Plan resource inspection and typed configuration sources

This commit is contained in:
2026-11-06 15:03:30 +00:00
parent 951739eda0
commit 8563379216
2 changed files with 592 additions and 63 deletions

View File

@@ -0,0 +1,568 @@
# Resource Inspection And Typed Sources Implementation Plan
## Purpose And Sprint Model
Implement the accepted [resource inspection roadmap](inspect-backend.md). That
document owns intent, scope, and product decisions; this plan owns the concrete
steps and representation choices needed to deliver them.
Baseline: `951739e`. ConfigKit v1.1.0 composes and resolves definitions once.
Promptkit captures executable prompts and backend-completed profile targets.
`InspectPrompt` currently exposes limited metadata; `InspectProfile` exposes an
execution target. There is no `InspectBackend` or typed `PromptSource`, and
`BackendConfig` lacks `Extends`. Existing inspection values do not have the
selected generic JSON/YAML contract.
Each numbered stage is intended for one Luna implementation prompt, in order.
This is one end-to-end sprint: intermediate stages may fail to compile or leave
callers unmigrated. Do not build compatibility shims, optional capability probes,
dual public inspection modes, or temporary representations just to keep each
stage green. Run focused checks as their affected paths become buildable;
record deferred checks and resolve them before the final stage. There are no
intermediate human-review, publication, or downstream-release gates.
Follow [agent](../policy/agents.md), [architecture](../policy/architecture.md),
[testing](../policy/testing.md), and [documentation](../policy/documentation.md)
policies and the [configuration boundary ADR](../adr/0001-configuration-boundary.md).
Use the [development guide](../development.md) for toolchain selection and local
commits. Commit completed nonempty units and record stage completion here,
including checks run or deferred. Intermediate commits need not be releasable.
## Selected Implementation Decisions
### Resource Boundary And Internal Flow
All three public inspection operations return the selected resolved resource,
before execution completion. References remain references. Imported message
text comes from the already materialized prompt, not another file read.
Use a narrow, private resource-inspection interface on `internal/engine.Engine`,
implemented by the configuration snapshot, alongside its existing inspection
and listing collaborators. Its methods accept a context and exact full ID and
return configuration-owned internal resource views. The engine qualifies
caller IDs with the appropriate namespace and delegates. The root facade checks
engine validity, maps errors, and projects detached public values.
Keep configuration resource views under `internal/configuration`; they contain
no ConfigKit types in their engine-facing fields. Do not add these operations
to execution-profile, generation, capacity, or transport interfaces. Remove the
now-unused runner `InspectPrompt` and `InspectProfile` entry points when wiring
is switched. Retain execution selection helpers used by preparation and smoke
tests.
Requirement discovery still needs only the small existing prompt metadata
lookup and requirement snapshot. Keep `promptdef.Repository.GetPromptInspection`
and its narrow `domain.PromptInspection` for that purpose, with comments making
the distinction clear. Do not expand that internal value with message bodies.
The new configuration resource view is distinct from this lightweight execution
metadata. This avoids changing `InspectRequirements` into a full-resource copy.
Index resolved profile and backend configuration records by full ID once during
capture, reusing the already built indexed maps or references into the retained
result. Do not build full parallel configuration trees or query ConfigKit's
provenance during ordinary inspection. Prompt entries already retain captured
messages, templates, and hashes; use that capture and the selected prompt's
resolved values. Small presence metadata is appropriate where decoding has
already collapsed omission into a scalar default.
Internal views may borrow immutable captured values. Detach mutable data at the
public projection boundary, using existing trusted copy helpers for accepted
provider maps. Do not revalidate provider values merely to copy them. This is
an ownership strategy, not a new public allocation or complexity guarantee.
### Public Result Shapes
Keep the existing method signatures for prompt/profile inspection. Add:
```go
func (e *Engine) InspectBackend(ctx context.Context, backendID string) (*BackendInspection, error)
```
Declare the result types in `resource_inspection.go` at the module root. Move
the existing public `PromptInspection` and `ProfileInspection` declarations
there rather than leaving duplicate definitions. These are facade values, not
aliases of private types. Keep execution and extension type shapes unchanged.
The tables below specify Go fields, types, and serialized keys. Apply both
`json` and `yaml` tags with the same key. Required fields have no `omitempty`;
all pointer fields use `omitempty` and nil means absent. A non-nil pointer to
zero, false, an empty string, or an empty collection remains present.
| Result | Go fields and types | Serialized keys |
| --- | --- | --- |
| `ProfileInspection` | `ProfileID string` | `id` |
| | `Backend, Endpoint, Model *string` | `backend`, `endpoint`, `model` |
| | `Temperature, TopP *float64` | `temperature`, `top_p` |
| | `MaxTokens, TimeoutSeconds *int` | `max_tokens`, `timeout_seconds` |
| | `ServiceTier, ReasoningEffort *string` | `service_tier`, `reasoning_effort` |
| | `APIKeyEnv *string`, `APIKeyRequired *bool` | `api_key_env`, `api_key_required` |
| | `ExtraParams *map[string]any` | `extra_params` |
| `BackendInspection` | `BackendID string`, `Endpoint string` | `id`, `endpoint` |
| | `APIKeyEnv *string` | `api_key_env` |
| | `ConcurrencyLimit, QueueCapacity *int` | `concurrency_limit`, `queue_capacity` |
| | `ExtraParams *map[string]any` | `extra_params` |
| | `SmokeTests *BackendSmokeTestConfig` | `smoke_tests` |
| `PromptInspection` | `PromptID string`, `PromptHash string` | `id`, `prompt_hash` |
| | `DefaultProfileID, Description, SessionID *string` | `default_profile`, `description`, `session_id` |
| | `Inputs *[]PromptInputInspection` | `inputs` |
| | `Messages []PromptMessageInspection` | `messages` |
| | `OutputContract PromptOutputInspection` | `output` |
Remove `ProfileInspection.EffectiveModelParams`; do not retain a compatibility
copy of backend-completed settings. `APIKeyRequired` becomes an optional
profile resource field. Retain the familiar prompt field names `Inputs`,
`DefaultProfileID`, and `OutputContract`, but deliberately change their types
where needed for presence.
Nested prompt values are:
| Type | Go fields and types | Serialized keys |
| --- | --- | --- |
| `PromptInputInspection` | `Name string`, `Required *bool`, `ContentType, Description *string` | `name`, `required`, `content_type`, `description` |
| `PromptMessageInspection` | `Role string`, `Content string`, `CacheControl *PromptCacheControlInspection` | `role`, `content`, `cache_control` |
| `PromptCacheControlInspection` | `Type CacheControlType`, `TTL *string` | `type`, `ttl` |
| `PromptOutputInspection` | `Format OutputFormat`, `ValidationMode ValidationMode`, `SchemaPath *string`, `RepairAttempts *int` | `format`, `validation_mode`, `schema_path`, `repair_attempts` |
Required strings and enum values in these nested types are always encoded.
Imported and inline message bodies both use `content`; do not report a
`content_file` field or parsed template. Content is not rendered. A supplied
empty cache TTL stays present, unlike the existing execution cache-control
value's omission behavior. Keep `PromptInputDefinition`, `OutputContract`, and
execution `CacheControl` unchanged for their existing purposes.
Reuse `BackendSmokeTestConfig`, `ReachabilityProbeConfig`, and
`AuthenticationProbeConfig` for backend diagnostic metadata: their pointer
fields already fit the selected semantics. Add JSON/YAML tags to their fields
(`default_profile`, `reachability`, `authentication`, `endpoint`, `kind`), all
with `omitempty`. Preserve a configured empty reachability object as `{}`;
do not fill an omitted endpoint or invent a diagnostics block. This does not
make `BackendConfig` itself a serialization contract.
The supported generic encoding paths are `encoding/json` and the existing
`go.yaml.in/yaml/v4` dependency. Ordinary `Marshal`/`Encoder` calls must suffice.
Pointer-to-collection fields avoid needing public presence flags or custom
serializers to distinguish omitted collections from explicit `{}`/`[]`. Do not
add deserialization, source round-trip, output-order, or numeric precision
guarantees. Inspect values rather than inferring source syntax from zero values.
### Presence And Null Interpretation
Use resolved typed pointers and nil-versus-empty collections where they retain
presence. Capture only additional information needed for scalar fields such as
input `required` and output `repair_attempts` before they become execution
defaults. Inherited values count as present. For nullable resource fields,
resolved null and omission both produce nil in resource reports. Literal nulls
inside provider maps/arrays remain untouched.
Keep existing normalization and derived defaults recorded during the ConfigKit
resolution callback. In particular, positive backend concurrency with no queue
setting yields the already recorded queue default in inspection. Do not invent
an explicit zero concurrency value when the resolved field is absent, or add
the framework profile timeout merely because execution uses it.
Simplify `captureExecutionProfile` to use non-nil configured values rather than
profile-specific absent/null state. Endpoint, credential source, and whole-map
null now permit backend fallback. When `api_key_required` is true and the
profile's `APIKeyEnv` pointer is nil, suppress the backend credential source
just as for omission. An explicit empty endpoint or API-key source still clears
that value. A non-nil provider map still overlays backend values, including
an explicitly empty map that does not clear defaults. Nested provider nulls
remain literal data.
Remove the profile-only `state.profiles` presence map, `profileFields`, and
capture helpers made unused by this change. Retain helpers needed by other
metadata or validation; do not purge presence/null handling generically.
Preserve execution `ExecutionTargetPresence`, because provider control omission
and explicit zero still matter at dispatch. Do not change required-field or
non-nullable-field validation. ConfigKit's retained result and provenance are
not rewritten to erase nulls.
### Typed Prompt Source Shapes
Add `BackendConfig.Extends *string` and encode it exactly like the profile helper.
Add a root `prompts.go` containing these source-input types and helper:
```go
type PromptConfig struct {
ID string
Extends, DefaultProfile, Description, SessionID *string
Inputs []PromptInputConfig
Messages []PromptMessageConfig
Output *PromptOutputConfig
}
type PromptInputConfig struct {
Name string
Required *bool
ContentType, Description *string
}
type PromptMessageConfig struct {
Role, Content, ContentFile *string
CacheControl *PromptCacheControlConfig
}
type PromptCacheControlConfig struct {
Type, TTL *string
}
type PromptOutputConfig struct {
Format, ValidationMode, SchemaPath *string
RepairAttempts *int
}
func PromptSource(label string, prompts []PromptConfig) configkit.Source
```
These types are mapping-constructor inputs, not serialized result types. Match
`BackendSource`/`ProfileSource`: always write IDs/names, dereference supplied
pointers, omit nil optional fields, preserve non-nil empty slices/objects, and
return `configkit.Mapping(label, map[string]any{"prompts": records})`. Encode
`Extends` as `extends: {id: value}`. A nil top-level prompt slice supplies an
empty `prompts` sequence, matching the other source helpers.
Do not require a complete source record in the helper: higher layers or sibling
inheritance may complete it. Engine loading owns final validation, including
invalid content/content-file combinations. Raw mappings retain explicit-null
and generic ConfigKit operations. Do not add a Promptkit-specific content root,
filesystem adapter, recursive input converter, or inheritance resolver.
## Stage 1: Declare The Resource Result Contract
**Scope:** Public inspection values and their nested representation only.
1. Read `types.go`, `backends.go`, and the current inspection GoDoc in `engine.go`.
Create the public result types and tags specified above. Move only the two
existing inspection declarations; leave execution types alone.
2. Add tags to the reused backend diagnostic types. Document optional pointer
and collection semantics, caller ownership, captured content, references,
credential metadata, and the resource/execution distinction.
3. Remove outdated claims that these inspection results have no serialization
contract. Do not remove those claims from unrelated types.
**Check:** Review every field against the tables, particularly pointer maps,
input `required`, cache TTL, and output `repair_attempts`. Compilation of old
converters and callers may wait for later stages; do not add transitional fields.
## Stage 2: Simplify Execution's Post-Handoff Null Semantics
**Scope:** Profile capture and its targeted configuration tests.
1. In `internal/configuration/targets.go`, implement the pointer-based behavior
above. Continue applying backend defaults once, then the explicit profile
values, then ordinary request-time overrides through the existing path.
2. In `load.go`, remove only the now-unused profile tri-state capture machinery.
Preserve final effective validation and prompt metadata capture.
3. Update `targets_test.go` and relevant `load_test.go`/`interpretation_test.go`
cases. Compare null and omission for endpoint, API-key source, and whole
provider map; retain explicit-empty-string clearing, empty-map overlay,
nested provider nulls, and `api_key_required` behavior with both absent/null
and explicit profile sources.
4. Include real ConfigKit inheritance where a child's null displaces a parent's
endpoint/provider map: the inspected resource is unset and execution uses
the selected backend, not the displaced parent. Preserve the null in the
retained configuration inspection. Inspection assertions may be completed
after resource wiring exists.
**Check:** Run the focused adapter tests when buildable. Retain outbound-control
presence and timeout behavior; removing configuration null distinctions must
not collapse runtime explicit zero or broaden accepted configuration shapes.
## Stage 3: Project Resolved Backend And Profile Resources
**Scope:** Configuration-owned views and exact-ID resource lookup.
1. Add private-adapter result structs in `internal/configuration`, with fields
corresponding to the public profile/backend tables. Keep ConfigKit record
types and paths inside the adapter, and do not alias public root types.
2. Reuse the indexed resolved records built during `buildExecutionProfiles`
instead of discarding and recomputing those indexes for each inspection.
Values may reference the immutable retained config; avoid additional deep
retained copies of provider maps. Keep the execution registry/targets for
their current execution and smoke responsibilities.
3. Add adapter `InspectProfile(ctx, id)` and `InspectBackend(ctx, id)` lookups.
Build selected-resource views from the normalized resolved records, never
from `ExecutionProfile.ResolvedTarget` or the capacity manager. Use existing
internal not-found sentinels for absent IDs and preserve cancellation.
4. Include backend diagnostics only where configured after composition. Return
configured endpoint overrides, including inherited ones, and no derived URLs.
A missing diagnostic default profile does not prevent backend inspection.
5. Add focused adapter coverage using real ConfigKit loading: an inherited
partial profile, explicit zero/empty settings, backend defaults excluded
from that profile, and backend queue derivation and diagnostic metadata.
**Check:** Verify resource fields against the retained resolved config and
execution fields separately against the backend-completed target. Do not turn
backend/profile references into nested reports or require execution readiness.
## Stage 4: Capture Complete Prompt Resource Information
**Scope:** Prompt presence and resource projection, without changing execution
or requirement-discovery representations.
1. Extend the existing prompt metadata capture just enough to retain omission
versus explicit false for each input's `required`, and omission versus
explicit zero for `output.repair_attempts`. Use ConfigKit's effective entry
information during the existing callback, including inherited presence.
Keep non-nullable-field rejection intact; do not switch those scalars to
nullable fields as a shortcut.
2. Retain or reference the selected resolved prompt record for optional strings,
inputs-list presence, schema-path presence, and per-message cache TTL
presence. Do not create another copy of the whole configuration tree.
3. Add adapter `InspectPrompt(ctx, id)` returning its resource view. Use
captured `promptEntry.definition` message text/order and existing hash, plus
the resolved resource's presence. Do not reopen message files, render
templates, or load the referenced schema/default profile.
4. Leave `GetPromptInspection` and `domain.PromptInspection` lightweight for
`InspectRequirements`; keep requirement metadata, compiled templates, and
opaque definition hashing behavior independent of the expanded resource DTO.
5. Extend prompt adapter tests for inherited/imported captured content,
optional metadata, empty inline content, cache TTL absence versus empty,
and input/output scalar presence. Reuse existing content-origin fixtures.
**Check:** Inspect a prompt with an unresolved template variable and an absent
default profile/schema file successfully. Schema and template syntax validation
at construction remain as before. A later content-file change does not alter
the resource report or trigger a second read.
## Stage 5: Wire Resource Inspection Through The Engine And Facade
**Scope:** Selection, public conversion, backend entry point, and errors.
1. Add the three-method resource-inspection interface and captured collaborator
to `internal/engine.Engine`; initialize it from the configuration snapshot
and share it naturally through `WithNamespaces`.
2. Route internal prompt/profile inspection through this collaborator instead
of the runner, and add backend inspection. Reuse `qualifyResourceID` with
each kind's namespace. Do not qualify references stored inside definitions.
3. Replace root inspection conversion with explicit projections of the new
configuration views. Copy pointer scalars and mutable maps/slices/nested
diagnostics into caller-owned values; reuse immutable strings. Use trusted
detachment for accepted nested provider values, not a serialization round
trip or a new JSON compatibility conversion.
4. Add public `ErrBackendNotFound` and `Engine.InspectBackend`. Scope the mapping
of the registry's internal not-found sentinel to this new operation; do not
globally reclassify construction, smoke, or generation errors. Follow the
existing nil/uninitialized-engine guards and invalid-ID conventions.
Preserve cancellation causes without inventing a public backend-load category.
5. Update exact method/type GoDoc, including `Engine`'s concurrent-operation
list. All three calls return no partial result on error and expose neither
credential values nor runtime occupancy.
**Check:** A small assembled public-API test for each method builds. Missing
backend matches `ErrBackendNotFound` and not `ErrInvalidRequest`; malformed IDs
match `ErrInvalidRequest`, invalid engines match `ErrInvalidConfig`, and
cancellation remains detectable through `errors.Is`.
## Stage 6: Retire Superseded Inspection Paths And Migrate Existing Tests
**Scope:** Existing consumers and test ownership, without losing execution or
requirement coverage.
1. Remove the unused runner `InspectPrompt`/`InspectProfile` wrappers and their
wrapper-only tests. Preserve `resolvePromptInspection` for requirement
selection and profile identity/execution helpers used elsewhere.
2. Update root inspection, inheritance, namespace, bundled-configuration, and
source tests for the selected result shape. Preserve literal identity text
and exact stored-reference behavior. Dereference pointers only after
checking presence; an unset value is not a zero-valued setting.
3. Where an old `InspectProfile.EffectiveModelParams` assertion tested backend
completion or framework timeout, keep that protection on `Prepare`/execution
or the focused adapter target tests. Do not simply delete the assertion or
reproduce completed settings in the new inspection result.
4. Keep `InspectRequirements` tests using the narrow metadata/snapshot seam.
Retain protection against full definition/target lookups and source access;
do not replace that seam with the expanded resource report.
5. Migrate any in-repository examples or helper fixtures that actually consume
the changed inspection fields. Leave run/prepared-result, output validation,
appended-message, and extension-client contracts unchanged.
**Check:** Run the affected public, configuration, use-case, and example tests
when their dependency graph is coherent. Search for stale references to
`ProfileInspection.EffectiveModelParams` and old inspection scalar assumptions;
do not replace valid execution-result fields with the same name.
## Stage 7: Verify Generic JSON And YAML Rendering
**Scope:** One focused public serialization contract suite for resource results.
1. Inspect real configured resources, then encode the returned values directly
using `encoding/json` and `go.yaml.in/yaml/v4`. Consumers in the test must not
build substitute reports, register nested serializers, or switch on fields.
Use the existing YAML version; update `go.mod`/`go.sum` only as needed to
reflect its direct test import, without upgrading dependencies.
2. Decode both outputs into ordinary structures for semantic assertions. Assert
selected names/nesting and presence, not whitespace, key order, or a golden
byte snapshot. Use a small set of rich fixtures rather than one fixture per
field or duplicating configuration validation cases.
3. Cover absent versus explicit zero/false/empty strings, absent/null versus
empty collections, and provider-data nulls. Include profile provider maps,
prompt `inputs`, input `required`, output `repair_attempts`, empty message
content/cache TTL, and backend capacity/diagnostic fields.
4. Assert no `extends`, execution-completed profile fields, parsed templates,
or synthetic diagnostics/endpoints appear. A configured empty reachability
object remains present, and a recorded queue default is present even when
it was not originally written by the operator.
**Check:** The same semantic cases pass with both ordinary encoders. If tags
alone fail to preserve a selected case, correct the result representation or
add narrowly scoped encoding support; do not move adaptation into consumers.
## Stage 8: Verify Selection, Isolation, And Offline Boundaries
**Scope:** Public behavior risks not already covered by the migrated suite.
1. Extend existing namespace tests for backend inspection: scoped slashless ID,
qualified bypass, no fallback to another namespace, and full selected ID.
Include a bundled backend through the same API. Reuse existing profile/prompt
namespace coverage rather than duplicate every selection case three times.
2. Exercise independence: missing diagnostic default profiles do not prevent
backend reports; partial profiles do not require endpoints/models; prompt
reports do not resolve their default profile or schema reference.
3. Mutate representative returned pointer fields, nested diagnostics, provider
maps/arrays, and prompt input/message/cache values. Reinspection and later
preparation must retain the captured values. Include separate concurrent
inspections using caller-owned results under the race detector, reusing
existing ownership helpers where suitable.
4. Use offline boundary doubles or counting files only where needed to prove
that inspection does not render, read credentials/artifacts/schemas, or call
a provider. Preserve existing source-lifetime tests and avoid mocks of every
private call. No live diagnostic or inference requests belong in this suite.
5. Complete the resource-inspection assertions paired with Stage 2's null
inheritance case and verify that `InspectConfiguration` still shows the
retained null and provenance, separately from execution's backend fallback.
**Check:** Each test protects a distinct public risk; consolidate overlapping
new and old cases. Run focused tests and their race-enabled versions when useful.
Do not introduce benchmark thresholds or additional release gates.
## Stage 9: Add Typed Backend Inheritance And Prompt Sources
**Scope:** Public mapping-constructor implementation and GoDoc.
1. Add `Extends *string` to `BackendConfig` and encode it in `BackendSource`
using the existing profile helper pattern. Update its GoDoc accordingly.
2. Implement the source-input types and `PromptSource` specified above. Write
small explicit mapping construction for nested input, message, cache, and
output values. Preserve supplied order and nil-versus-empty collections.
3. Pass supported mapping values directly to ConfigKit so its snapshot behavior
applies. Preserve the other helpers' final-load validation and accepted-input
contracts. Do not copy through JSON/YAML or add reflection-based encoding.
4. Document nil/explicit values, sibling inheritance, deferred validation,
imported file context, and raw mapping escape hatches. Do not give these
source-input types the inspection result's serialization contract.
**Check:** Compare each mapping field with the format reference and the source
shape table. Incomplete layered records remain expressible, and constructing
the helper itself neither accesses files nor resolves inheritance.
## Stage 10: Verify Typed Sources Through Real Composition
**Scope:** Focused source-helper contract tests, not a second ConfigKit suite.
1. Extend existing backend-source tests with a real inherited child, preserving
the child's ID and endpoint/capacity overrides through `InspectBackend`.
2. Add prompt-source tests using real `NewEngine` composition. Exercise nested
input/message/output settings, sibling inheritance, source/layer completion,
explicit false/zero/empty values, nil versus empty lists, and message order.
Reuse the new resource APIs to observe resolved values and preparation where
execution behavior is the fact being tested.
3. Mutate original nested source slices, scalar pointees, and records after
creating the source. Loading should use ConfigKit's captured source values.
Keep this representative rather than reimplementing upstream snapshot tests.
4. Include a relative `content_file` from a typed source with ConfigKit's
ordinary explicit source context. Use the dependency's existing context
input setting: construct `filesystem := configkit.NewFilesystem("fixture", fsys)`
and set `configkit.Input.Filesystem` to
`&configkit.FilesystemContext{FS: &filesystem, Root: ".", BaseDir: "templates"}`.
Include an inherited relative message path. Confirm capture uses that context
without adding a new Promptkit path-setting API.
5. Confirm malformed final definitions fail at loading, not helper construction;
rely on existing generic null, inheritance-cycle, and schema validation
coverage instead of repeating every rejection for every typed helper.
**Check:** Run focused source/inspection tests. Existing `ProfileSource` and raw
mapping workflows remain usable; this stage is not a ConfigKit upgrade or an
authorization to edit another repository.
## Stage 11: Update Canonical Guidance And Migration Notes
**Scope:** Documentation of the implemented APIs and intentional changes.
1. Update `docs/consumers/pkg-promptkit.md` with the three resource views,
nullable pointer/collection usage, and minimal direct JSON/YAML rendering.
Distinguish them from `InspectConfiguration` provenance, requirement
discovery, `ValidateRequest`, and concrete-request preparation/details.
2. Document migration from `EffectiveModelParams` to the profile's resource
fields and from prompt scalar metadata to optional inspection values.
Consumers needing completed request settings use existing preparation APIs;
do not add a compatibility execution view to inspection.
3. Update `docs/formats.md`'s post-handoff profile table and map explanation.
Show a concrete null migration: a profile with null endpoint/API-key source/
provider map now permits backend defaults; explicit empty strings still clear
endpoint/key source, and backend provider maps can be edited through ordinary
composition. Do not imply a new whole-map suppression replacement exists.
4. Document typed prompt sources and backend inheritance through the source
helpers' GoDoc and consumer guidance. Keep exact field contracts in GoDoc
and the existing format owner rather than parallel exhaustive prose schemas.
5. Reconcile `docs/internal/sources.md`, `docs/internal/overview.md`, and affected
runner guidance with configuration-owned resource inspection, retained narrow
requirement metadata, and simplified execution capture. Adjust architecture
descriptions only where implemented structure changed; preserve policy and
the accepted configuration boundary ADR.
6. Prepare the next minor release note under the existing release procedure.
At this baseline `v0.19.0` is published, so use `docs/releases/v0.20.0.md`
unless another version has been published during the sprint. Explain the
inspection and configuration compatibility changes, link canonical guidance,
and include the required licensing footer. Update the README release link.
Do not edit published release notes, tag, push, or run publication commands.
7. Supply enough migration detail for CommandKit to adopt generic reporting
without per-field adapters. Changes or publication in CommandKit itself are
consumer follow-up, not prerequisites or work authorized by this sprint.
**Check:** Validate changed local links and terminology. Remove old claims that
profile inspection is backend-completed, resource results have no JSON contract,
or null suppresses profile backend fallbacks. Leave unrelated execution and
ConfigKit composition contracts intact.
## Stage 12: Validate And Close The Sprint
**Scope:** Combined verification and final cleanup of this feature only.
1. Confirm that all three inspection operations, every selected result field,
both generic encoders, helper inheritance, and post-handoff null migration
are implemented and covered at the appropriate owning boundary. Resolve any
checks deferred by intermediate compilation failures.
2. Check that resource lookup uses captured configuration without execution
completion or a second ConfigKit interpretation; requirement discovery still
uses its narrow metadata path. Remove obsolete converters/wrappers and
private fixtures that preserve the old report behavior, without sweeping
cleanup outside this feature.
3. Format changed Go files and tidy the module only where imports changed.
Using the newest locally available Go installation under the development
guide, run the complete offline suite and vet:
```sh
go test -race ./...
go vet ./...
git diff --check
```
Select that toolchain on `PATH`, with `GOTOOLCHAIN=local` and `GOWORK=off`.
The complete suite includes maintained example tests; do not impose another
standalone build/example/release-validation gate. No dependency or consumer
minimum upgrade is selected just to implement this feature.
4. Inspect all changes for unintended behavior and contracts. In particular,
preserve ConfigKit source ownership, literal provider nulls, existing request
overrides, output repair, provider-value support, credential handling, and
captured-state isolation. Do not add context limits, schema probes, health
promises, CLI policy, or source-round-trip guarantees.
5. Verify changed documentation links and review status/diffs under the agent
commit policy. Mark stages complete with actual validation evidence, commit
the finished unit, and report any remaining limitations accurately. Keep the
completed feature roadmap and this plan for the requested implementation
review; retirement can occur during later release preparation.
Completion requires the full selected end state, including generic rendering
and both deliberate compatibility changes. Passing only the new backend method
or preserving the old execution-oriented profile report is not completion.

View File

@@ -459,69 +459,30 @@ proposal to expose both declared and computed destinations is removed. This
avoids an additional representation and provider-specific derivation machinery
in resource inspection.
## Implementation And Verification
## Acceptance Criteria
1. Define typed results, serialization names/nesting, and consumer migration
selected in decision 4. Account for presence across prompt, profile, and
backend results. Source-input helpers, inspection results, and execution
values have distinct purposes; reuse types only where their semantics fit.
2. Implement and verify the post-handoff null change as a focused unit, separate
from inspection projection. Remove presence machinery made unnecessary by
that change while retaining omission versus explicit-value information.
Verify the changed execution behavior and document its migration example.
3. Expose expanded prompt content and resolved profile fields through existing
capture/lookup paths, before execution completion, without another composition
pass or changes to ConfigKit's retained result. Support generic encoding with
the selected omission rules and preserve explicit values.
4. Add backend inspection and the accepted public missing-backend error,
returning configured diagnostic metadata without endpoint derivation.
5. Add typed backend inheritance and the prompt source/helper types, delegating
both to the ordinary ConfigKit mapping and loading path.
6. Update GoDoc, formats, consumer/internal guidance, and release notes for the
selected behavior, inspection-result migrations, and null compatibility
change. Coordinate CommandKit's generic reporting adoption.
The companion [implementation plan](implementation.md) owns the staged work
and verification sequence. The target is complete when:
Use focused offline tests for actual boundary risks:
- Prompt, profile, and backend inspection expose the selected resolved resource
with the boundary and presence semantics above, using ordinary JSON/YAML
encoding without per-field consumer adapters.
- Inherited values, explicit zero/false/empty settings, and provider-data nulls
are represented accurately; nullable resource nulls and omission are absent.
- Profile inspection excludes backend-completed execution values, and backend
inspection reports configured diagnostics without synthesizing destinations
or requiring diagnostic readiness.
- Prompt inspection includes captured inline/imported message content and
metadata without rendering or loading related resources.
- Execution applies the selected post-handoff null behavior while preserving
explicit clearing, map overlay, and ConfigKit's retained result and provenance.
- Selection, errors, captured-state isolation, and credential handling follow
the selected contracts. Requirement discovery retains its lightweight path.
- All three resource kinds have typed source helpers, including inheritance,
using ordinary ConfigKit composition, context, and snapshot behavior.
- Canonical guidance and the next minor release note explain changed Go
inspection types, generic rendering, source helpers, and null migration.
- Directly encode each inspection result with ordinary JSON and YAML encoders,
without consumer-specific report structures. Verify semantic field names,
nesting, omitted settings, explicit zero/false/empty values, and nested
provider data. Include prompt input/output and backend capacity presence,
rather than testing only profile fields. Assert semantic output, not incidental
whitespace or mapping-key order.
- Child resources show the resolved inherited fields and overrides, not an
unresolved `extends` directive; explicit zero survives. Omitted/null nullable
settings use the same absent representation; provider-data nulls retain their
literal meaning.
- Null and omitted profile endpoint, credential-source, and provider-map fields
permit the same backend fallback. Explicit empty-string clearing and empty-map
overlay behavior remain intact. Include a ConfigKit inheritance case where
null clears a parent value before Promptkit applies backend defaults, and
verify that resource inspection does not rewrite the retained ConfigKit tree.
- Profile inspection excludes settings supplied only by a referenced backend,
framework execution defaults, or a request. Existing execution still applies
those settings through its ordinary resolution path.
- Prompt inspection exposes captured inline/imported content, metadata, and
order without rendering or adding related-resource lookup dependencies.
- Backend inspection reports configured/inherited diagnostic overrides while
leaving omitted overrides absent. It does not require diagnostic readiness.
- Resource selection, error classification, and mutable-result ownership follow
the selected contract; reuse existing namespace and ownership coverage.
- Typed backend and prompt inheritance work through real ConfigKit composition.
Prompt sources preserve nested message/input/output settings, omission and
explicit values, ordering, and source snapshot behavior. Include a representative
relative content-file case using ordinary source context. Reuse generic loading,
validation, and inheritance coverage rather than duplicating it for each helper.
Promptkit owns the inspection serialization checks; CommandKit owns presentation
and delivery tests for the migrated resource view. Follow the
[testing policy](../policy/testing.md), combine cases where useful, and reuse
existing coverage. No new benchmark threshold or release gate is selected.
Completion means operators can inspect the resolved selected prompt, profile,
or backend accurately through generic rendering, without per-field consumer
adapters, assembling execution settings, or navigating raw configuration paths.
All three resource kinds have typed source helpers, including inheritance
support, and consumers have migration guidance for changed inspection results
and post-handoff null semantics.
No engine-policy or prepared-request additions are part of completion.
Promptkit owns resource serialization checks; CommandKit owns presentation and
delivery. No engine-policy or prepared-request additions, benchmark threshold,
or new release gate is part of this feature.