Repository navigation
R.5: remove D16 allowlist; keyless local runtimes send no Authorization (D16, D24; stacked on #22) - #23
Open
cunninghamcard-bit wants to merge 26 commits into
Open
R.5: remove D16 allowlist; keyless local runtimes send no Authorization (D16, D24; stacked on #22)#23cunninghamcard-bit wants to merge 26 commits into
cunninghamcard-bit wants to merge 26 commits into
Conversation
Drop ProviderOptions.body_overrides and both arcships#226 rejections in provider_handle.rs; ProviderOptions now denies unknown fields. Node ProviderConfig loses bodyOverrides and reports any unknown key as InvalidArgumentError 'unknown field `x`'. Python docs updated; Python already rejects unknown keys via serde. Tests in Rust/Python/Node. Adds docs/amendments/A6-remove-226-per-rfc.md verbatim.
…keys) Replace the hand-written key allowlist: the JS object is read as a raw JSON map (undefined values skipped), maxRetries is rejected first with the call-level message, then the map deserializes into ProviderConfig with #[serde(deny_unknown_fields, rename_all = "camelCase")]. The max_retries struct field is gone (index.d.ts loses maxRetries?). Tests: maxRetries gets the call-level message, undefined keys are absent.
…ies only (A6 item 2) Drop RetryConfig and prepare_retries_with_config from aimux-core, DecisionModel::retry_config, the retry fields/overrides in jev, openai/decision (with_retry_config), runtime_decision and decision_support (snapshot no longer records max_retries), and the handle-level ProviderOptions.max_retries default in provider_handle. decide() uses retry::prepare_retries(options.max_retries, ...). New mock test: max_retries = 0/1/3/None makes exactly 1/2/4/3 requests.
…n jev_test Retry counting moves into aimux-core decision_model::retry_tests, using a crate-internal #[cfg(test)] PreparedRetries::with_initial_delay(ZERO); asserts attempts = max_retries + 1 and RetryErrorReason::MaxRetriesExceeded with the last 503/429/529 error. jev_test keeps status classification at max_retries = 0 plus one max_retries = 1 run on 503 asserting 2 requests and retry exhaustion. No public API, feature or binding change.
…st time (A6 item 4, D23)
provider_handle no longer reads the generic format!("{}_API_KEY") for local
runtimes (arcships#226). openai with api_key None keeps the package default
OPENAI_API_KEY, now read at request time (arcships#200:538); Some("") is used as
given (RFC-0040:67); a changed base URL without a key sends no credential and
reads no env. Tests inject env as a plain-data map (crate-internal
EnvSource::Vars), never std::env::set_var: generic key not read, env set after
construction is used, Some("") no fallback, replay/auth=none/changed base URL
read nothing. api_key_source field stays for R.4; placeholder key for R.5.
…eep identity only (A6 item 1, D3) decide() records ProviderRecord::from_model(provider, model_id). Removed DecisionModel::config_snapshot and its jev/openai/runtime/handle overrides, DecisionEndpoint::snapshot, ProviderHandle's api_key_source and HandleDecisionModel, and ProviderRecord.api_key_source (ts-rs regenerated). Recording tests now assert no apiKeySource / baseUrl / providerOptions in the provider record; config_snapshot() callers rewritten to the recorded identity.
…only) Nothing writes them since config_snapshot is gone. Also removes the arcships#226-only ProviderRecord::redacted and redact_provider_options. ProviderRecord is not deny_unknown_fields; a new test shows an old record carrying baseUrl / apiKeySource / profile / providerOptions still deserializes (and re-serializes as identity only). ts-rs regenerated.
…tion (D16, D24/D15) check_provider_boundaries.sh has no d16_allow or per-file D16 exceptions left (rule 1 provider_handle max_retries, rule 2 removed names, rule 5 PLACEHOLDER_API_KEY, rule 9 RetryConfig) and exits 0. PLACEHOLDER_API_KEY is deleted: a local runtime with no key is auth = none and the mock test asserts the Authorization header is absent. The R.3 env tests rely on the fixtures' max_retries: 0 instead of writing options.max_retries in src.
This was referenced Oct 11, 2026
… the struct Drop #[napi(skip)] invalid: Option<String>; from_napi_value now returns the InvalidArgumentError directly. The constructors' 3rd arg becomes ConfigArg (dispatch on JS type) because napi's Either swallowed the member error.
… from env_tests Prod compiles no Handles / fetch / env plumbing. The env is injected, so the tests need no serialization; the replay test keeps only its own recording (unique state) since the recorder is process-global.
…") sends no Authorization
Constructors accept the config argument as serde_json::Value (d.ts unchanged), so conversion never throws synchronously; maxRetries, unknown keys and wrong types are refused inside the async body as InvalidArgumentError. ConfigArg and the custom ProviderConfig FromNapiValue are gone.
…ve-config-snapshot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1R unit R.5 (D16, D24/D15; A6 item 5). Stacked on #22 (R.4 @ f5e72b0), #21, #20 and #19, so this diff includes them until they merge. The R.5-only change is commit 18b31ea.
Changes
scripts/check_provider_boundaries.sh: the D16 allowlist is gone entirely.d16_allow()function and its use in rule 2 (fn config_snapshot/fn retry_config/RetryConfig/api_key_source).provider_handle.rs ... options.max_retries.provider_handle.rs ... PLACEHOLDER_API_KEY.RetryConfigin the decision files. This one wasn't in the plan's line list; it's at:256on this stack.grep -ni d16 scripts/check_provider_boundaries.shfinds nothing.provider_handle.rs:PLACEHOLDER_API_KEY("not-needed") is deleted. A local runtime (ollama/llamacpp/localai/vllm/sglang/laya) with no key passesapi_key: Nonetocreate_openai_compatible. That isauth = none, so noAuthorizationheader is sent (D24, RFC-0040:155/:192; matches AI SDKopenai-compatible-provider.ts:156).env_testshelper wroteoptions.max_retries = Some(0)insidesrc/, which rule 1 now catches. It no longer writes it, because both fixtures already contain"max_retries": 0.Tests
decision_handle_test::keyless_local_runtime_sends_placeholder_beareris renamed tokeyless_local_runtime_sends_no_authorization_header. It asserts!headers.contains_key("authorization"), i.e. the header is absent, not empty. The recording-leak check for "not-needed" is dropped because the value no longer exists anywhere.Boundary script
bash scripts/check_provider_boundaries.sh; echo $?printsprovider boundaries: okand0.// probe: fn config_snapshottojev.rs(decision file)const PLACEHOLDER_API_KEYtoprovider_handle.rs(decision file)// probe: options.timeouttogroq/mod.rs(non-decision file)// probe: api_key_sourcetoaimux-core/src/recording.rsfn config_snapshotin jev,api_key_sourcein recording.rs) and rule 5 (PLACEHOLDER_API_KEY). Decision files and non-decision files both fail now. After restoring the files it exits 0 again.Results vs R.0 (local linux x64; new and renamed test names confirmed in the log)
Go/Java/Kotlin/Swift/Flutter were not run locally.
Review follow-up