17 KiB
Optional Request-Parameter Omission Implementation Plan
Status: Complete.
Purpose
This document is the decision-complete implementation plan for
omitting unset optional request parameters.
It is written for a gpt-5.6-terra coding agent that will implement each stage
in order.
The feature roadmap owns the motivation, policy choices, compatibility boundary, non-goals, and target end state. This document owns the concrete design, file-level work, test ownership, documentation updates, validation, and completion gates.
The separate application fallback profiles roadmap is not part of this implementation plan. Preserve it unchanged for its own later planning and implementation cycle.
Implementation Rules
- Complete the stages in order. Stage 1 must leave code, tests, GoDoc, and current-state documentation mutually accurate; Stage 2 performs the final audit and repository-wide acceptance.
- Preserve unrelated working-tree changes. In particular, do not edit,
implement, retire, or reclassify
fallback-profiles.md. - Follow every policy under
docs/policy/, the task-specific reading guide indocs/development.md, and the accepted behavior inoptional-request-parameters.md. - Keep the existing package boundaries. Framework defaults remain in
internal/defaults, resolution remains ininternal/usecase, and outbound OpenAI-compatible serialization remains ininternal/llm. - Do not add an exported type, field, option, method, error, or public package. This feature changes default and wire semantics within existing contracts.
- Do not replace numeric profile fields with pointers or add profile presence tracking. File and in-memory profile zero values retain their existing inheritance semantics; runtime pointer overrides remain the only supported way to select an explicit numeric zero.
- Preserve required request fields, session IDs, structured output, credentials, extra-parameter validation, reasoning clearing, deadlines, capacity management, and all existing precedence rules.
- Do not query a provider for defaults or capabilities and do not add backend- or model-specific serialization branches.
- Keep tests lean and behavioral. Use the existing root precedence test to own resolved public/injected-client metadata and the existing model-client tests to own wire inclusion and omission. Do not duplicate those matrices in a new end-to-end fixture.
- Update exact exported semantics in GoDoc, profile/default semantics in
docs/formats.md, and provider request-body semantics indocs/integrations/openai-compatible-chat.mdin the same stage as the code. - Do not add release notes, change a module version, commit, tag, push, or publish a release as part of this plan.
Fixed Design
Framework Defaults
In internal/defaults/defaults.go, remove these constants:
ExecutionDefaultTemperature
ExecutionDefaultMaxTokens
ExecutionDefaultTopP
They currently encode zero for temperature and max_tokens and one for
top_p. Optional provider controls are no longer framework defaults, so
retaining zero-valued constants under default-oriented names would obscure the
new contract.
Keep ExecutionDefaultTimeoutSeconds at its current positive value. Timeout is
a Promptkit-owned generation deadline and is not an OpenAI-compatible request
body field.
Keep ExecutionTargetDefault as the common resolution baseline, but have it
initialize only TimeoutSeconds. The zero Go values for Temperature,
MaxTokens, and TopP then represent unspecified provider controls. Do not
rename this internal function or add a second defaults constructor.
Resolution And Public Metadata
Do not change the merge functions or precedence in
internal/usecase/runner.go:
- the baseline target supplies only the Promptkit timeout;
- nonzero profile numeric fields replace the baseline;
- non-nil runtime numeric overrides replace profile values; and
ExecutionTargetPresencerecords runtime overrides, including explicit zero values.
Consequently, when a profile omits the optional provider controls, resolved
ExecutionTarget values contain zero for Temperature, MaxTokens, and
TopP. That zero is stable metadata for “unspecified” unless the accompanying
GenerateRequest.TargetPresence bit reports an explicit runtime zero.
Do not expose target presence in PreparedRun, RunResult, or
ProfileInspection, and do not change their stable JSON shapes. As already
true for max_tokens, those metadata values report the resolved numeric value
rather than provenance. A prepared result containing top_p: 0 therefore does
not distinguish an unspecified value from an explicit runtime zero; injected
clients receive the separate presence value when the distinction affects
execution.
Update root GoDoc in types.go so it no longer calls an unspecified optional
provider control an effective provider value:
ExecutionTarget.Temperature,MaxTokens, andTopPmust each state that zero leaves the field unspecified to compatible providers unless the correspondingExecutionTargetPresencebit is true;ExecutionTarget.TimeoutSecondsretains its existing deadline semantics;ProfileandExecutionTargetOverridedocumentation must describe zero or nil as inheriting a lower-precedence value and otherwise leaving the provider control unspecified, rather than implying that every field receives a concrete framework value; andPreparedRun,ProfileInspection, and other effective-target summaries may continue to describe precedence, but must not imply that Promptkit knows a provider's omitted default.
Do not change field types, field order, JSON tags, conversion functions, string formatting, or copying behavior.
Outbound Request Semantics
The current built-in client already has the required mechanism:
openAIChatRequestFromGenerateRequest includes temperature, max_tokens, or
top_p when the resolved value is nonzero or the corresponding target-presence
bit is true, and openAIChatRequestPayload omits nil fields. Preserve that
logic.
No production change should be needed in
internal/llm/openai_compatible_client.go. Change it only if a focused failing
test demonstrates that the existing implementation does not meet this plan;
do not special-case top_p, inspect profile provenance, or move framework
default policy into the transport.
The resulting behavior is:
- an omitted profile
top_presolves to zero and is absent from the body; - a nonzero profile or runtime
top_pis included; - an explicit runtime
top_pof zero is included because presence is true; - the same rules continue to apply to
temperatureandmax_tokens; - empty
service_tierand effectivereasoning_effortremain absent; - configured
extra_paramsremain present after validation; and model,messages, conditionalsession_id, and conditionalresponse_formatremain unchanged.
Profile Formats And Built-In Profiles
Do not change YAML or public Profile field shapes. Numeric zero in a file or
in-memory profile continues to mean “do not replace the lower layer.” With no
lower provider value, zero therefore resolves to unspecified. An explicit
profile-level numeric zero remains unsupported; consumers use a runtime
pointer override when zero itself must be sent.
Do not edit files under internal/profile/builtin/assets/. Values declared in
those files are explicit profile policy and remain effective. Existing
nonzero-profile tests are sufficient to protect explicit inclusion; do not add
one test per built-in asset or parameter.
Test Ownership
Use these existing boundaries:
- In
engine_test.go, update the “framework defaults” row ofTestEngineExecutionSettingPrecedenceso the zero-valued profile expectsTopP: 0while retainingTemperature: 0,MaxTokens: 0, and the positive timeout. Rename that row to describe unspecified provider controls plus the framework timeout. Keep the rows proving nonzero profile precedence and explicit runtime-zero presence unchanged. - Remove
TestRunnerRunBuiltInDefaultsUsedWhenProfileOmitsOptionalFieldsfrominternal/usecase/runner_test.go. Its literal-default assertions duplicate the stronger assembled root precedence test and depend on the internal constants being removed. Do not replace it with another internal default-value test. - Keep
TestOpenAICompatibleClientOmitsImplicitZeroNumericFieldsandTestOpenAICompatibleClientSerializesExplicitZeroNumericOverridesininternal/llm/openai_compatible_client_test.go. Together they own the wire distinction and should pass without weakening their assertions. - Keep the existing nonzero request serialization and profile-precedence tests passing. They prove that explicitly configured values continue to be sent and selected.
Do not add snapshots, golden files, provider calls, or a broad duplicate integration test. Add a new test only if the implementation exposes a distinct contract risk not covered by the tests above, and record that reason in the test name or nearby test structure rather than in a new planning document.
Canonical Documentation
Update current-state documentation in Stage 1:
- In
docs/formats.md, replace the optional provider-control entries in the framework-default table with clear unspecified/omitted semantics, while retaining the positivetimeout_secondsframework default. Explain that profile numeric zero inherits a lower layer and otherwise remains unspecified; an explicit runtime pointer zero is retained. - In
docs/integrations/openai-compatible-chat.md, state thattemperature,max_tokens, andtop_pare included only when selected by a profile or runtime override, including explicit runtime zero, and are absent when unspecified. Keep the existing ownership of required fields,session_id, structured output, extra parameters, and timeout behavior. - In
types.go, apply the GoDoc changes described above; these declarations own the exact public value semantics.
Do not add a README or release-document note. The consumer guide already routes exact field behavior to GoDoc and profile/default behavior to the format reference, so do not duplicate the new contract there. The internal LLM document describes flow rather than exact field omission and does not require a change unless its current text is found to contradict the implementation.
Stage 1: Implement Omission Semantics And Canonical Contracts
Objective
Remove optional provider controls from the framework baseline, preserve explicit profile and runtime values, update the canonical contracts, and prove the behavior at the existing resolution and wire boundaries.
Implementation Prompt
Implement only Stage 1 of docs/roadmap/implementation.md. Read the complete
feature roadmap, implementation rules, and fixed design above before editing.
- In
internal/defaults/defaults.go, remove the three provider-control constants and makeExecutionTargetDefaultinitialize onlyTimeoutSeconds. - In
engine_test.go, update and rename the default-precedence table row exactly as described under Test Ownership. - Remove the redundant literal-default test from
internal/usecase/runner_test.go; do not weaken other precedence, profile-value, or runtime-zero tests. - Update the affected exported GoDoc in
types.gowithout changing any declaration, JSON tag, or serialization shape. - Update
docs/formats.mdanddocs/integrations/openai-compatible-chat.mdaccording to Canonical Documentation. - Run the focused validation below. Repair regressions in scope, but do not broaden the feature or change the established serializer merely to make a mistaken expectation pass.
Do not edit built-in profile assets, fallback-profile work, backend registration, profile parsing, target merge logic, public value shapes, prepared-execution lifecycle, capacity management, or release material.
Focused Validation
Run from the repository root:
gofmt -w internal/defaults/defaults.go types.go engine_test.go \
internal/usecase/runner_test.go
go test . -run 'TestEngineExecutionSettingPrecedence'
go test ./internal/llm -run \
'TestOpenAICompatibleClient(GenerateSuccess|OmitsImplicitZeroNumericFields|SerializesExplicitZeroNumericOverrides)'
go test ./internal/usecase -run \
'Test(ResolveExecutionTarget|RunnerPrepareRequestNumericOverridePresence|RunnerPrepareSelectedProfileBeatsBuiltInDefault|RunnerRunSelectedProfileBeatsBuiltInDefault)'
go test . ./internal/defaults ./internal/usecase ./internal/llm
go vet . ./internal/defaults ./internal/usecase ./internal/llm
git diff --check
If a focused regular expression does not match an existing test name, inspect the current names and run the narrowest equivalent set; do not silently skip the intended resolution, explicit-profile, explicit-zero, and wire-omission coverage.
Completion Gate
Stage 1 is complete only when:
- the resolution baseline contains no provider tuning value and retains the Promptkit timeout;
- an omitted
top_presolves to zero and the built-in client omits it; - nonzero profile and runtime values remain effective and serialized;
- explicit runtime zero values remain distinguishable and serialized through
ExecutionTargetPresence; - no public type or stable JSON shape changed;
- required fields, structured output, session IDs, extra parameters, reasoning, credentials, and deadlines retain their existing behavior;
- GoDoc, format documentation, and the integration contract describe the implemented behavior without conflicting ownership; and
- all focused tests, vet, formatting, and whitespace checks pass.
Stage 2: Audit Compatibility And Validate The Repository
Objective
Confirm that the narrow semantic change is complete across all public, injected-client, built-in-profile, documentation, and repository surfaces, then mark the temporary planning documents complete.
Implementation Prompt
Implement only Stage 2 of docs/roadmap/implementation.md after Stage 1
satisfies its completion gate.
- Search tracked Go and Markdown files for the removed constant names,
framework
top_pdefaults, claims that all effective provider controls have concrete framework values, and request-body inclusion rules. Correct only stale statements or tests owned by this feature. - Confirm that
internal/profile/builtin/assets/has no feature-related diff and that its explicit nonzero optional controls still pass ordinary profile validation and resolution tests. - Confirm that
internal/llm/openai_compatible_client.goeither has no diff or contains only a change required by a focused failing contract test. The default policy must remain outside the transport. - Follow every changed Markdown link and confirm its target exists. Verify that current-state documents describe implemented behavior and that exact contracts remain with GoDoc, the format reference, and the integration contract.
- Run the complete validation sequence below and repair only in-scope failures.
- After all checks pass, change the status of
optional-request-parameters.mdand this document toComplete. Do not change the status or contents offallback-profiles.md. - Re-run
git diff --checkand inspect the final working tree and diff.
Do not delete temporary roadmaps in this stage; retirement is a separate maintainer action. Do not add release notes, change versions, or create a commit, tag, push, or release.
Full Validation
Run from the repository root:
gofmt -w internal/defaults/defaults.go types.go engine_test.go \
internal/usecase/runner_test.go
gofmt -l $(git ls-files '*.go')
go test ./...
go test -race ./...
go vet ./...
go build ./...
go run ./examples/go-library/prepare
git diff --check
git status --short
The gofmt -l command must print no paths. The maintained example must remain
offline and require no real credential or provider.
Inspect the final diff and confirm:
- only this feature's files and pre-existing user changes are present;
- no built-in profile asset, public declaration shape, stable JSON tag, credential rule, workspace file, local module replacement, generated binary, or unrelated formatting changed;
- the removed provider-default constants have no remaining references;
- the provider omission policy is implemented by resolution plus the existing
generic serializer, not by a
top_ptransport special case; - the optional-parameter roadmap and this plan are complete while the fallback roadmap remains selected; and
- no commit, tag, push, or release was created.
Completion Gate
The implementation is complete only when:
- every Stage 1 gate remains satisfied;
- the ordinary and race-enabled suites pass;
- vet, build, formatting, the maintained offline example, Markdown links, and whitespace checks pass;
- public metadata, injected-client presence, profile inheritance, and outbound omission semantics are mutually consistent;
- explicit built-in and consumer profile values retain their behavior;
- both feature-specific roadmap statuses are
Complete; fallback-profiles.mdremains unchanged and selected for later work; and- the repository is ready for maintainer review without a commit or release having been created by this plan.
Open Questions
None. The feature roadmap and fixed design above fully specify the behavior, compatibility boundary, implementation, documentation ownership, and test strategy.