Verify ConfigKit integration and record release handoff

This commit is contained in:
2026-09-26 18:21:38 +00:00
parent 41304e4eea
commit 47c2a711f0
6 changed files with 124 additions and 11 deletions

View File

@@ -53,6 +53,11 @@ preparation or generation.
formats a safe application-owned effective profile view. It intentionally does formats a safe application-owned effective profile view. It intentionally does
not require prompt, schema, or artifact sources. not require prompt, schema, or artifact sources.
The `config` family loads the same application ConfigKit result once and uses
its validation, effective-output, source, and explanation views directly. It
does not construct a Promptkit engine. The CLI maps source records into a small
JSON DTO for `sources`; `show` and `explain` use ConfigKit's own writers.
`serve` constructs Scriptorium's restricted HTTP artifact reader, injects it `serve` constructs Scriptorium's restricted HTTP artifact reader, injects it
with `promptkit.WithArtifactReader`, passes the engine through the HTTP with `promptkit.WithArtifactReader`, passes the engine through the HTTP
adapter's consumer-owned `Runner` interface, and starts the server. adapter's consumer-owned `Runner` interface, and starts the server.

View File

@@ -49,6 +49,10 @@ Every configuration-loading command uses this boundary. The CLI maps only
explicitly visited application flags to ConfigKit overrides and prints explicitly visited application flags to ConfigKit overrides and prints
structured load diagnostics before engine construction. The old application structured load diagnostics before engine construction. The old application
YAML decoder and merge path have been removed. YAML decoder and merge path have been removed.
Application `config` inspection reuses the result's frozen effective,
provenance, and history views without constructing an engine or reloading
sources. It does not resolve API-key environment values; ordinary backend
parameters remain visible by the selected inspection policy.
## Restricted HTTP Artifact Reader ## Restricted HTTP Artifact Reader

View File

@@ -77,6 +77,13 @@ Do not add tests merely because a function, branch, or line exists. Do not add a
Test through the narrowest stable boundary that expresses the behavior clearly. Test through the narrowest stable boundary that expresses the behavior clearly.
For application configuration, ConfigKit owns exhaustive YAML grammar,
source traversal, import/overlay composition, provenance, and inspection
renderer tests. Scriptorium tests its selected definition, source discovery,
CLI override presence, command prerequisites, runtime conversion, credential
boundary, and representative execution/inspection workflows with the tagged
library. Do not copy the upstream parser test matrix into this repository.
This is often the package API, but it may instead be: This is often the package API, but it may instead be:
- a smaller pure function when dense domain logic is most clearly isolated there; - a smaller pure function when dense domain logic is most clearly isolated there;

View File

@@ -2,11 +2,10 @@
## Status And Intent ## Status And Intent
Accepted feature direction, drafted on 2026-09-26; not implemented. This Implemented feature direction, drafted on 2026-09-26 and delivered through the
roadmap defines the target behavior and changes from the reviewed baseline. [implementation plan](implementation.md). This roadmap records the target
The [implementation plan](implementation.md) owns sequencing, concrete interfaces, behavior and changes from the reviewed baseline; the implementation plan owns
verification steps, and implementation status. This document owns the desired sequencing, concrete interfaces, and verification evidence.
end state and the policy choices behind it.
The user is adopting ConfigKit across an application suite to standardize The user is adopting ConfigKit across an application suite to standardize
configuration semantics. Scriptorium will make a clean cutover to ConfigKit's configuration semantics. Scriptorium will make a clean cutover to ConfigKit's
@@ -20,7 +19,7 @@ application-specific reason or a genuine ownership boundary, not backward
compatibility alone. The [architecture policy](../policy/architecture.md) and compatibility alone. The [architecture policy](../policy/architecture.md) and
[ADR 0004](../adr/0004-definition-boundary.md) remain the scope boundaries. [ADR 0004](../adr/0004-definition-boundary.md) remain the scope boundaries.
## Reviewed Baseline ## Reviewed Baseline (Historical)
Scriptorium consumes Promptkit v0.11.0. Its `internal/config` package uses Scriptorium consumes Promptkit v0.11.0. Its `internal/config` package uses
yaml.v3 directly and manually applies defaults, file settings, and CLI overrides. yaml.v3 directly and manually applies defaults, file settings, and CLI overrides.
@@ -225,3 +224,8 @@ the relevant secret to the API key. Inspection therefore preserves parameter
values and environment-reference names, while actual API-key values remain values and environment-reference names, while actual API-key values remain
outside the application configuration pipeline. Visibility is intentional; outside the application configuration pipeline. Visibility is intentional;
this is not a promise to detect secrets placed inside arbitrary parameter values. this is not a promise to detect secrets placed inside arbitrary parameter values.
The delivered `config show` and `config explain` commands use ConfigKit's
inspection writers without secret tags or a second redaction path. Both
effective and historical parameter values remain visible; `api_key_env` names
remain visible while Promptkit alone resolves selected credential values.

View File

@@ -3,10 +3,9 @@
## Status, Authority, And Historical Plans ## Status, Authority, And Historical Plans
Planned on 2026-09-26 against Scriptorium commit Planned on 2026-09-26 against Scriptorium commit
`43eea5c7c41d2a8134b3dece60f3af5c98b8fd1c`. No stage is implemented by this `43eea5c7c41d2a8134b3dece60f3af5c98b8fd1c`. This document records the
planning change. Execute Stage 1 through Stage 7 in order. Each stage is sized ordered implementation and its completion evidence. The maintainer resolved
as one focused gpt-5.6-terra implementation task, including tests and current the inspection-policy question:
documentation. The maintainer has resolved the inspection-policy question:
`extra_params` remain visible; only API-key values require secret protection. `extra_params` remain visible; only API-key values require secret protection.
The [feature roadmap](configkit.md) owns scope, target behavior, and user intent. The [feature roadmap](configkit.md) owns scope, target behavior, and user intent.
@@ -429,7 +428,12 @@ visible, and explanation neither resolves nor discloses API-key values.
## Stage 7: Verify Integration, Finish Documentation, And Record Release Handoff ## Stage 7: Verify Integration, Finish Documentation, And Record Release Handoff
**Status: Not started.** **Status: Complete.** The feature roadmap, command paths, dependency boundary,
documentation, and attribution were audited. Maintained single-file and
composed examples passed configuration inspection and no-provider rendering;
the optional-credential/integer-parameter backend path passed with a local
provider. The full test, race, vet, build, formatting, link, and diff checks
passed. Release preparation is recorded below; no tag or publication occurred.
1. Review the feature roadmap against actual code. Confirm all five original 1. Review the feature roadmap against actual code. Confirm all five original
command modes and all four new configuration subcommands use one definition command modes and all four new configuration subcommands use one definition
@@ -488,6 +492,37 @@ is not guaranteed reloadable. Include dependency/attribution changes and the
existing LICENSE | ATTRIBUTION footer. Preserve the still-relevant Promptkit existing LICENSE | ATTRIBUTION footer. Preserve the still-relevant Promptkit
v0.11 release handoff identified above when preparing a combined next release. v0.11 release handoff identified above when preparing a combined next release.
### Implementation And Release Preparation Record
The ConfigKit v0.4.0 adoption is implemented in committed source. The next
breaking release still needs version selection, version-matched release notes,
candidate validation, tagging, and publication under the release policy; none
has occurred as part of this work. Keep the earlier Promptkit v0.11 handoff
linked above when preparing a combined release.
The release note should summarize the deliberate configuration migration:
empty files now fail and `{}` means an empty mapping; explicitly empty strings
and zero values override lower values; `null` follows declared nullable types;
strict YAML rejects additional documents, anchors/aliases, unsupported scalar
forms, and unknown fields; `configkit` is reserved and ConfigKit's source and
resource limits apply. Explicit `--config ''` is invalid. Imports are opt-in
per file directive, while `--config-overlay` selects one named overlay under
the selected file's canonical directory; application path *values* remain
process-working-directory-relative. Only explicitly supplied application CLI
flags override configuration. An explicit empty server address is passed to
the standard HTTP server and does not restore Scriptorium's default.
Document the four application-inspection modes and the selected policy:
`extra_params`, including history, and `api_key_env` reference names remain
visible, but actual API-key bytes are never resolved by ConfigKit. Inspection
output can be sensitive and is not guaranteed reloadable. Application
validation neither probes a provider nor completely validates Promptkit
definitions. Keep request retry overrides and Promptkit's credential rules
separate from application settings. Include the new dependency and attribution
notices, and retain the existing LICENSE | ATTRIBUTION footer. Deferred
secrets bootstrap, schema versioning, reload, and remote acquisition remain
deferred; do not imply source or binary publication has happened.
## Open Questions ## Open Questions
None remain for this scope. On 2026-09-26 the maintainer selected no redaction None remain for this scope. On 2026-09-26 the maintainer selected no redaction

View File

@@ -1148,6 +1148,64 @@ backends:
} }
} }
func TestConfiguredBackendPreservesIntegerParameterAndOptionalCredential(t *testing.T) {
lib := newCLITestLibrary(t)
writePromptDefinition(t, lib.promptDir, "custom.yaml", `id: custom
version: "1"
default_profile: local-gpu
messages:
- role: user
content: "hello"
output:
format: text
validation_mode: none
`)
if err := os.WriteFile(filepath.Join(lib.profileDir, "local-gpu.yaml"), []byte("id: local-gpu\nbackend: local-gpu\nmodel: local-model\n"), 0o644); err != nil {
t.Fatal(err)
}
const credentialName = "SCRIPTORIUM_OPTIONAL_BACKEND_KEY"
t.Setenv(credentialName, "")
type observedRequest struct {
number json.Number
authorization string
}
observed := make(chan observedRequest, 1)
provider := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
request := observedRequest{authorization: r.Header.Get("Authorization")}
var body map[string]any
decoder := json.NewDecoder(r.Body)
decoder.UseNumber()
if err := decoder.Decode(&body); err == nil {
request.number, _ = body["synthetic_count"].(json.Number)
}
observed <- request
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"choices":[{"message":{"role":"assistant","content":"generated"}}]}`))
}))
defer provider.Close()
configPath := writeAppConfigFile(t, fmt.Sprintf(`prompt_dir: %q
profile_dir: %q
backends:
local-gpu:
endpoint: %q
api_key_env: %s
extra_params:
synthetic_count: 7
`, lib.promptDir, lib.profileDir, provider.URL+"/v1", credentialName))
cfg, err := parseRunArgs([]string{"--config", configPath, "--prompt", "custom"})
if err != nil || len(cfg.backends) != 1 || cfg.backends[0].ExtraParams["synthetic_count"] != int64(7) {
t.Fatalf("ConfigKit integer did not reach runtime settings: cfg=%+v err=%v", cfg, err)
}
code, stdout, stderr := runCLICommand(t, runCommand, []string{"--config", configPath, "--prompt", "custom"})
if code != ExitOK {
t.Fatalf("backend run failed: code=%d out=%q err=%q", code, stdout, stderr)
}
request := <-observed
if !strings.Contains(stdout, "generated") || request.number != "7" || request.authorization != "" {
t.Fatalf("backend request changed: code=%d out=%q err=%q count=%q auth=%q", code, stdout, stderr, request.number, request.authorization)
}
}
func TestRenderCommandMapsReasoningEffortAndSessionID(t *testing.T) { func TestRenderCommandMapsReasoningEffortAndSessionID(t *testing.T) {
lib := newCLITestLibrary(t) lib := newCLITestLibrary(t)
writePromptDefinition(t, lib.promptDir, "session.yaml", `id: session writePromptDefinition(t, lib.promptDir, "session.yaml", `id: session