Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,30 @@ not using an Opskit registry. It follows the manager's core readiness policy.

Operational routes can expose metadata, revisions, checksums, redacted values, and error strings. Protect them with Servekit endpoint options appropriate for the deployment.

## Opskit reload command

Configkit exposes reload as an Opskit command handler in the root package:

```go
reload := configkit.ReloadCommand(manager, source, pipeline,
configkit.WithReloadCommandName("config/reload"),
configkit.WithReloadCommandDescription("reloads Configkit configuration from source"),
)

ops.MustRegister(reload, opskit.Informational())
```

The command descriptor defaults to `config/reload`. Completed reload failures
are returned as completed Opskit command results with failure metadata because
Configkit preserves last-known-good state. Context cancellation and deadline
failures are returned as failed command results with no result payload.

The result payload is `configkit.ReloadCommandResult`. It does not include typed
config values or redacted inspection output. It may include attempt status,
manager state, revision, checksum, and error strings. Normal returned errors
are caller-owned operational output and should be safe for the command audience.
Recovered panic payloads are sanitized into safe stage-specific messages.

## Workerkit reload command adapter

Configkit core does not poll, watch files, schedule reloads, or expose HTTP reload routes.
Expand Down Expand Up @@ -381,7 +405,9 @@ and deadline failures are returned as command errors.

The payload does not include typed config values or redacted inspection output.
It may include attempt status, manager state, revision, checksum, and error
strings, so those values should be safe for the command audience.
strings. Normal returned errors are caller-owned operational output and should
be safe for the command audience. Recovered panic payloads are sanitized into
safe stage-specific messages.

## Observability

Expand Down
1 change: 1 addition & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
// packages that need current configuration state or safe lifecycle inspection
// without mutating configuration lifecycle state. Manager also directly
// implements Opskit's Component, ReadinessContributor, and Inspector contracts.
// ReloadCommand exposes reload as an Opskit CommandHandler and CommandDescriber.
// Operational views do not expose the typed configuration value, but they can
// include caller-provided metadata, revisions, redacted values, and error
// strings.
Expand Down
71 changes: 65 additions & 6 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,12 +398,16 @@ configuration into a framework.

- `WithIdentity(name string)`

Sets the manager's Opskit component name. The default is `config`.
Sets the manager's Opskit component name. The default is `config`. Non-empty
names should satisfy Opskit component-name rules; invalid names may fail when
the manager is registered with an Opskit registry.

- `WithComponentInfo(info opskit.ComponentInfo)`

Sets the manager's Opskit component identity. Empty fields fall back to
Configkit defaults.
Configkit defaults. Non-empty component names should satisfy Opskit
component-name rules; invalid names may fail when the manager is registered
with an Opskit registry.

- `WithDegradedReady(ready bool)`

Expand Down Expand Up @@ -832,6 +836,60 @@ this repository's `go.mod`.
degraded lifecycle state not ready. The default is `true` because
degraded means the last-known-good snapshot remains active.

### Opskit reload command

- `ReloadCommand[T](manager, source, pipeline, opts...)`

Creates an Opskit component that implements `opskit.CommandHandler` and
`opskit.CommandDescriber` for Configkit reload.

Default component name: `config-reload`

Default command name: `config/reload`

The command calls
`manager.LoadFromSource(ctx, configkit.AttemptKindReload, source, pipeline)`.
Completed reload failures are returned as completed Opskit command results
with failure metadata. Context cancellation and deadline failures are returned
as failed command results with no result payload.

- `ReloadCommandResult`

Safe operational result payload for reload commands.

Fields:

- `attempt_id`
- `attempt_status`
- `manager_state`
- `published`
- `changed`
- `current_checksum`
- `current_revision`
- `error`

The payload does not expose typed config values or redacted inspection output.
Revisions, checksums, and normal returned error strings are still
operationally visible and should be safe for the command audience. Recovered
panic payloads are sanitized into safe stage-specific messages.

- `ReloadCommandOption`

Reload command configuration hook.

- `WithReloadCommandName(name string)`

Sets the Opskit command name. Empty names preserve the default.

- `WithReloadCommandDescription(description string)`

Sets the command discovery description.

- `WithReloadCommandComponentInfo(info opskit.ComponentInfo)`

Sets the Opskit component identity for the reload command handler. Empty
fields fall back to Configkit defaults.

## Package `worker`

The `worker` package adapts Configkit reloads into Workerkit commands. It is
Expand All @@ -846,8 +904,8 @@ the Workerkit runtime itself in Opskit for readiness and generic inspection;

- `ReloadCommand[T](manager, source, pipeline, opts...)`

Creates a Workerkit command spec that calls
`manager.LoadFromSource(ctx, configkit.AttemptKindReload, source, pipeline)`.
Creates a Workerkit command spec backed by the root Configkit Opskit reload
command.

Default command name: `config/reload`

Expand All @@ -863,8 +921,9 @@ the Workerkit runtime itself in Opskit for readiness and generic inspection;
- `error`

The payload does not expose typed config values or redacted inspection output.
Revisions, checksums, and error strings are still operationally visible and
should be safe for the command audience.
Revisions, checksums, and normal returned error strings are still
operationally visible and should be safe for the command audience. Recovered
panic payloads are sanitized into safe stage-specific messages.

- `ReloadCommandOption`

Expand Down
24 changes: 17 additions & 7 deletions docs/composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,17 @@ server := servekit.New(
)
```

## Reload Commands with Workerkit
## Reload Commands

Use `configkit/worker` when reload should be exposed as a Workerkit command:
Root Configkit exposes reload as an Opskit command handler:

```go
reload := configkit.ReloadCommand(manager, source, pipeline)
ops.MustRegister(reload, opskit.Informational())
```

Use `configkit/worker` when that reload command should be dispatched through a
Workerkit runtime today:

```go
err := runtime.Register(workerkit.WorkerSpec{
Expand All @@ -137,7 +145,8 @@ err := runtime.Register(workerkit.WorkerSpec{

Workerkit v0.2.0 runtimes implement Opskit component, readiness, and inspection
contracts directly. Register the runtime in the same Opskit registry as the
Configkit manager, then keep `configkit/worker` focused on the reload command.
Configkit manager and reload command handler, then keep `configkit/worker`
focused on Workerkit dispatch.

Default command name:

Expand All @@ -151,9 +160,9 @@ The command calls:
manager.LoadFromSource(ctx, configkit.AttemptKindReload, source, pipeline)
```

Failed reloads return a successful Workerkit command result containing failure
metadata. That preserves the command payload and lets Configkit report degraded
state without treating every failed reload as a Workerkit dispatch failure.
Failed reloads return a completed command result containing failure metadata.
That preserves the command payload and lets Configkit report degraded state
without treating every failed reload as a dispatch failure.

## Full Production Shape

Expand All @@ -165,7 +174,8 @@ A typical composed service has:
- Workerkit runtime for operational commands
- `servekit.WithOps` for shared readiness and generic component inspection
- optional `opshttp.Mount` for read-only Configkit-specific inspection
- `worker.ReloadCommand` for reload
- `configkit.ReloadCommand` for the Opskit reload command
- optional `worker.ReloadCommand` for Workerkit dispatch
- app routes that read current config through `manager.Value()`

This keeps the ownership clear:
Expand Down
19 changes: 12 additions & 7 deletions docs/operational-safety.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,12 @@ Use `EmptyRedactor[T]()` until a field is explicitly safe to expose.

## Error Strings

Validation errors, source read errors, and recovered panic strings may be
recorded in attempts, status, logs, telemetry, ops HTTP responses, and reload
command payloads.
Validation errors and source read errors may be recorded in attempts, status,
logs, telemetry, ops HTTP responses, and reload command payloads. Normal
returned errors are caller-owned operational output.

Recovered panic payloads are not exposed; Configkit records safe
stage-specific panic messages instead.

Do not include raw secret values in errors.

Expand Down Expand Up @@ -141,9 +144,10 @@ opshttp.Mount(server, manager,
)
```

## Worker Reload Command
## Reload Command

`configkit/worker.ReloadCommand` returns operational reload metadata:
`configkit.ReloadCommand` and `configkit/worker.ReloadCommand` return
operational reload metadata:

- attempt ID
- attempt status
Expand All @@ -155,8 +159,9 @@ opshttp.Mount(server, manager,
- error string

The payload does not include typed config values or redacted inspection output.
Revisions, checksums, and errors are still visible to whoever can dispatch or
inspect the command result.
Revisions, checksums, and normal returned error strings are still visible to
whoever can dispatch or inspect the command result. Recovered panic payloads are
sanitized into safe stage-specific messages.

## Future Operational Endpoints

Expand Down
8 changes: 5 additions & 3 deletions docs/reloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,15 @@ routes, or rebuild clients.
Common trigger owners:

- application startup code for initial load
- Workerkit commands for operator-triggered reload
- Opskit commands for operator-triggered reload
- Workerkit command dispatch for runtime execution
- application-specific signal handlers
- deployment hooks
- custom source watchers outside Configkit core

Use `configkit/worker` when Workerkit should expose reload as an operational
command.
Use root `configkit.ReloadCommand` to expose reload through Opskit's command
contracts. Use `configkit/worker` when Workerkit should dispatch that reload as
an operational command.

## Examples

Expand Down
8 changes: 6 additions & 2 deletions manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ func WithAttemptHistoryLimit(limit int) ManagerOption {

// WithIdentity sets the Opskit component name for the manager.
//
// The default name is "config". Empty names are ignored.
// The default name is "config". Empty names are ignored. Non-empty names should
// satisfy Opskit component-name rules; invalid names may fail when the manager
// is registered with an Opskit registry.
func WithIdentity(name string) ManagerOption {
return func(options *managerOptions) {
if name == "" {
Expand All @@ -90,7 +92,9 @@ func WithIdentity(name string) ManagerOption {
// WithComponentInfo sets the Opskit component identity for the manager.
//
// Empty fields fall back to Configkit defaults. Labels are appended to stable
// Configkit labels; the kit=configkit label is always preserved.
// Configkit labels; the kit=configkit label is always preserved. Non-empty
// component names should satisfy Opskit component-name rules; invalid names may
// fail when the manager is registered with an Opskit registry.
func WithComponentInfo(info opskit.ComponentInfo) ManagerOption {
return func(options *managerOptions) {
options.componentInfo = info
Expand Down
5 changes: 4 additions & 1 deletion opshttp/opshttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ type ReadinessProvider interface {

// ReadinessCheck adapts Configkit readiness into a Servekit readiness check.
//
// Readiness follows the provider's core Configkit readiness policy.
// For composed Kit Series services, prefer registering Manager with an Opskit
// registry and passing that registry to Servekit with servekit.WithOps.
// ReadinessCheck remains useful for standalone Servekit services that are not
// using Opskit.
func ReadinessCheck(provider ReadinessProvider) servekit.ReadinessCheck {
return func(ctx context.Context) error {
if err := ctx.Err(); err != nil {
Expand Down
Loading