Refocus internal component documentation

This commit is contained in:
2026-07-26 14:20:06 +00:00
parent c927b7819d
commit ff31f8daf8
6 changed files with 297 additions and 384 deletions

View File

@@ -2,145 +2,118 @@
## Purpose
`internal/usecase.Runner` is the core prompt-execution orchestrator. It prepares prompt requests, calls the configured LLM client for `Run`, validates generated output, and returns domain results.
`internal/usecase.Runner` is the prompt-execution orchestrator. It prepares
domain requests, invokes an injected LLM client, validates output, and returns
domain results. Transport parsing, response mapping, and public type conversion
remain outside this package.
Transport parsing, DTOs, CLI output, HTTP status mapping, and public package type conversion belong outside the runner.
The [configuration reference](../config.md) owns prompt, profile, schema, and
runtime-setting definitions. Public error behavior is defined by the
[HTTP API](../api.md) and [Go package](../consumers/pkg-scriptorium.md)
contracts.
## Inputs And Outputs
## Dependencies And Construction
Primary inputs:
`Runner` receives these collaborators:
- `domain.RunRequest`
- repositories/readers/renderers/validators injected at construction
- `context.Context` for cancellation
- `promptdef.Repository`;
- `profile.Repository`;
- `artifact.Reader`;
- `prompt.Renderer`;
- `llm.Client`;
- `validate.Validator`; and
- an optional `OutputRepairer`.
Primary outputs:
- `domain.PreparedRun` from `Prepare`
- `domain.RunResult` from `Run`
- wrapped sentinel errors for adapter mapping
LLM boundary types:
- `domain.GenerateRequest`
- `domain.GenerateResponse`
## Dependencies
`Runner` depends on package interfaces instead of concrete adapter types:
- `promptdef.Repository`
- `profile.Repository`
- `artifact.Reader`
- `prompt.Renderer`
- `llm.Client`
- `validate.Validator`
- optional `usecase.OutputRepairer`
The CLI, HTTP adapter, and public Go package construct these dependencies and pass them in.
## Config Fields
`Runner` does not read app config files. Effective behavior is determined by injected dependencies and the `domain.RunRequest`.
Adapter wiring commonly reflects these app config fields:
- `prompt_dir`
- `profile_dir`
- `schema_dir`
- `server.artifact_root`
- HTTP request/artifact/response size limits
Runtime model settings are resolved from the selected profile plus request overrides.
`NewRunner` constructs a runner without a repairer. `NewRunnerWithRepairer`
accepts one explicitly. Adapters and the public engine choose concrete
repositories and readers; the runner does not load application configuration.
## Prepare Flow
`Prepare`:
`Prepare` performs one deterministic preparation pass for a request:
1. requires a non-empty prompt ID.
2. loads the prompt definition and computes its hash.
3. selects the profile from request `profile_id`, then prompt `default_profile`.
4. loads the selected execution profile.
5. merges built-in execution defaults, profile values, and request overrides.
6. applies request-scoped direct API key values for public Go callers.
7. validates endpoint, model, and credential requirements.
8. resolves the output contract and JSON Schema document when required.
9. reads input artifacts.
10. renders prompt messages and hashes the rendered prompt.
11. returns a prepared run without calling the LLM.
1. validate the prompt ID and load the prompt definition;
2. hash the definition and select the explicit or default profile;
3. load the profile and resolve effective execution settings;
4. validate endpoint, model, and credential availability;
5. resolve the output contract and, for JSON Schema output, load a structured
schema document before model execution;
6. read and hash input artifacts;
7. render messages and the session ID; and
8. return a `PreparedRun` containing the effective state and rendered-prompt
hash.
Numeric request overrides are presence-aware: omitted values preserve the current effective value, while explicit zero values are real overrides.
Execution settings merge defaults, profile values, and a request override.
Numeric override presence is retained so explicit zero values are not confused
with omissions.
## Run Flow
## Run And Validation Flow
`Run`:
`Run` creates a run ID and timestamps, then calls `Prepare` rather than
duplicating preparation. It sends the prepared prompt, effective target,
target-presence state, and optional structured-output specification to the LLM
client. It converts the returned content to an output artifact, validates it,
and returns the artifact, validation, hashes, usage, and timing metadata.
1. creates a run ID and start timestamp.
2. calls `Prepare`.
3. calls the injected LLM client with rendered messages, effective target, target presence, and structured-output settings.
4. builds the output artifact.
5. validates the output.
6. optionally attempts bounded repair when a repairer is injected and the contract permits repair.
7. returns the run result with artifact, raw output, validation, hashes, selected profile/model metadata, usage, and timing.
A validator can return a content result or an operational error. Content
failures stay in the result; schema loading, compilation, and validator
operational failures are returned as `ErrValidation`. The canonical distinction
for callers is documented by the public contracts.
`Run` must reuse `Prepare`; prepare logic should not be duplicated elsewhere.
## Repair Boundary
## Validation And Repair
Repair is an internal optional loop. It starts only when a repairer is present,
the output contract permits one or more attempts, validation failed, and the
validation mode is JSON or JSON Schema. Each repair receives the previous
output, validation errors, effective target, structured-output specification,
and attempt metadata; every repaired result is validated again.
Validation content failures are returned as successful run results with `Validation.Status == failed`. They are not runtime errors.
`NewDefaultOutputRepairer` delegates to the injected LLM client. CLI, HTTP, and
the public engine use `NewRunner` and therefore do not inject this repairer.
Validation runtime failures, such as schema load or compile errors, return `ErrValidation`.
## Error Translation
Repair attempts occur only when all conditions are true:
- a repairer is injected
- `repair_attempts` is greater than zero
- validation status is `failed`
- validation mode is `json` or `json_schema`
CLI and HTTP wiring call `usecase.NewRunner(...)`, which does not inject a repairer. Normal CLI and HTTP execution therefore does not repair invalid output.
## Failure Behavior
Stable runner sentinels include:
Runner sentinels identify failure categories for adapters:
- `ErrInvalidRequest`
- `ErrProfileRequired`
- `ErrAPIKeyEnvMissing`
- `ErrAPIKeyRequired`
- `ErrPromptLoad`
- `ErrProfileLoad`
- `ErrArtifactLoad`
- `ErrAPIKeyEnvMissing` and `ErrAPIKeyRequired`
- `ErrPromptLoad`, `ErrProfileLoad`, and `ErrArtifactLoad`
- `ErrPromptRender`
- `ErrLLMGenerate`
- `ErrValidation`
Adapters should use `errors.Is` against sentinels and lower-level repository errors instead of matching message text.
Wrap errors with those sentinels and preserve their identities through
`errors.Is`; adapters must not classify errors by message text. The runner
passes direct keys only to the LLM boundary and never includes resolved key
values in prepared or run results.
Secret values must not appear in prepared output, run results, logs, HTTP responses, or serialized public package results. The effective API-key environment-variable name may appear.
## Package-Local Guarantees
## State And Manifests
- `Run` always reuses `Prepare`.
- Schema documents are loaded before the initial LLM call when structured output
is required.
- Output validation records attempts used, including repair attempts.
- Runner state is per request; the package does not create a durable run store
or manifest.
- Source, renderer, validator, and LLM implementations remain injected
boundaries.
The runner is stateless across requests.
## Verification And Change Recipe
- No durable run store.
- No manifest files.
- No checkpoint, skip, or resume behavior.
- Recovery is a new request after correcting inputs, config, or environment.
## Tests To Inspect
Inspect:
- `internal/usecase/runner_test.go`
- `internal/usecase/integration_test.go`
- `engine_test.go`
- `internal/adapter/cli/run_test.go`
- `internal/adapter/http/handler_test.go`
## Architectural Invariants
When changing orchestration:
- Use-case decisions stay in `internal/usecase`.
- `Run` reuses `Prepare`.
- Prompt/profile/artifact/schema loading remains behind injected boundaries.
- Validation content failures are result state; validation runtime failures are errors.
- Repair loops are bounded by `repair_attempts` and repairer presence.
- Resolved secret values are never serialized or emitted.
1. identify the collaborator boundary and the affected `Prepare` or `Run` state;
2. preserve the `Run`-through-`Prepare` path and error identity;
3. add focused runner or integration tests for changed state transitions,
validation, or repair behavior; and
4. update the owning external contract and any affected source or LLM internal
document.
The [testing policy](../policy/testing.md) owns global test sufficiency.