Skip to content

Skip Claude models the user cannot call when picking defaults - #1161

Open
nachill-databricks wants to merge 5 commits into
databricks:mainfrom
nachill-databricks:achille/skip-uncallable-models
Open

nachill-databricks wants to merge 5 commits into
databricks:mainfrom
nachill-databricks:achille/skip-uncallable-models

Conversation

@nachill-databricks

Copy link
Copy Markdown
Contributor

Problem

The model-services listing does not say which services the caller may invoke, so ug claude could default to a model that returns 403 on every request.

Change

Probe the newest candidate per Claude family with a 1-token request. On a 403 permission denial, fall back to the next-newest model; families with no callable model are dropped. Results are cached per process. The probe is fail-open: any other outcome (success, OAuth-scope 403, 5xx, network error) keeps current behavior.

Before: the default Claude model could be one the user is denied. After: denied models are skipped.

Testing

  • Unit tests added in tests/test_databricks.py. uv run pytest -q tests/test_databricks.py: 410 passed.
  • uvx --from rust-just just lint: passes (ruff check, ruff format --check, ty check).
  • 8 tests in tests/test_agents_init.py and tests/test_e2e_user_agent.py fail on main too, independent of this change.
  • Live probe against a real workspace where all Claude models were callable picked the same defaults as main (no regression).
  • The deny path is covered only by unit tests.

Not yet verified

  • A workspace where a model actually returns 403. The probe is unverified against that case.

This pull request and its description were written by Isaac.

The model-services listing does not say which services the caller may
invoke, so `ug claude` could default to a model that 403s on every
request. Probe the newest candidate per Claude family with a
1-token request, fall back to the next-newest on a 403 permission denial,
and drop families with no callable model. Probe results are cached per
process; any other probe outcome keeps the current behavior.

Co-authored-by: Isaac <no-reply@databricks.com>
@nachill-databricks
nachill-databricks marked this pull request as ready for review October 16, 2026 17:59
@nachill-databricks

Copy link
Copy Markdown
Contributor Author

/ug-review

Comment thread src/ucode/databricks.py Outdated

# Per-process memo of `_claude_model_is_callable`, keyed by (workspace, model id). Only definite
# answers are stored; a probe that could not tell is never cached.
_CLAUDE_CALLABLE_CACHE: dict[tuple[str, str], bool] = {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · low
the key has no token or identity in it, so a profile/PAT switch on the same workspace in one process reuses stale answers. can we key on the profile/identity, or clear this when auth changes?

Comment thread src/ucode/databricks.py Outdated
)
if reason is None:
callable_ = True
elif _looks_like_permission_failure(reason) and not _looks_like_scope_failure(reason):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · medium
_looks_like_permission_failure matches any HTTP 403, so IP-ACL, budget or policy 403s can drop a family if another one passes. can we match the EXECUTE-denial wording?

Comment thread src/ucode/databricks.py Outdated
if candidates:
claude_models[family] = candidates[0]
claude_candidates[family] = candidates
claude_models = _drop_uncallable_claude_models(workspace, token, claude_candidates)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

performance · medium
this fires real billed inference calls on every configure/live refresh, even when only codex/gemini is wanted (want_claude False in cli.py). can we probe only when claude is requested?

@github-actions

Copy link
Copy Markdown

Polly AI Review

Blocking issues

  • [P1] src/ucode/databricks.py:2381 — can we preserve an all-denied result through callers? chosen or newest restores models whose probes returned permission-denied 403s.

    When every advertised Claude candidate is denied, this selects the same unusable defaults the PR intends to exclude. Inconclusive failures already fail open separately.

    Returning an empty mapping alone is insufficient: callers interpret emptiness as a reason to try legacy discovery. Preserve a distinct exhausted result, prevent legacy resurrection, and report an actionable permission error before default Claude launch.

    Replace tests/test_databricks.py::TestUncallableClaudeModels::test_all_denied_keeps_current_behavior. Extend existing CLI coverage to verify that exhausted candidates cannot return through legacy discovery or previously saved defaults.

Security vulnerabilities

No confirmed security vulnerabilities found. The probe cache does not grant access; the gateway still enforces authorization.

Non-blocking notes

  • src/ucode/databricks.py:2414 — can we limit probes to Claude selection? Shared discovery now sends inference requests during Codex/Gemini setup and ug status, adding usage and timeout waits.
  • tests/test_databricks.py::TestUncallableClaudeModels::test_probe_failure_keeps_current_behavior — can we add an OAuth-scope 403 case? The explicit fail-open guard currently has no regression assertion.

Approach

Probing candidates newest-first is a reasonable approach when listing cannot expose invocation permissions. Keep callable-model selection separate from shared inventory discovery, and distinguish definitive exhaustion from inconclusive probe failures.

Summary

Diff size (computed): 3 files; +142 / -2 lines (144 changed text lines); 0 binary files.

Category Files Added Deleted Share of changed text lines
Tests and test support 2 83 0 57.6%
Documentation 0 0 0 0.0%
Dependencies and lockfiles 0 0 0 0.0%
Implementation / other 1 59 2 42.4%

Shares use additions + deletions, including generated text and lockfiles. Binary files have no line count. Tests include fixtures/helpers under test paths and colocated test/spec files; categories are path-based, not coverage measurements.

Changes

The implementation adds cached invocation probes and filters Claude family defaults. The remaining changes add focused tests and an offline fixture guard. There are no documentation, dependency, or generated-file changes.

The implementation and support setup are proportional to the outcome; no concrete redundant scaffolding warrants removal. Restricting probing to Claude selection would reduce inference side effects without changing the intended behavior.

Tests

Test-by-test assessment

The following accounts for every added test and changed support element.

Test / case Behavior protected Layer Needed? Action / rationale
tests/conftest.py::_isolate_ucode_state Existing discovery tests do not issue inference requests Fixture keep The callable-probe stub preserves offline isolation; focused probe tests restore the real function.
tests/test_databricks.py::_REAL_CLAUDE_PROBE Probe tests can exercise the implementation despite the fixture stub Support keep Minimal opt-in to the real probe.
tests/test_databricks.py::_DENIED Tests use a consistent model-permission denial Support keep Shared response input avoids duplicated setup.
tests/test_databricks.py::TestUncallableClaudeModels::_listing Discovery receives controlled model candidates Helper keep Small transport-boundary stub using existing model-service setup.
tests/test_databricks.py::TestUncallableClaudeModels::_post, including nested fake Probe responses and requested models are observable Helper keep Shared HTTP-edge setup supports distinct selection cases without live requests.
tests/test_databricks.py::TestUncallableClaudeModels::test_denied_model_excluded_and_not_default A denied newest model falls back to an older candidate while another family remains available Unit/component keep Direct regression coverage for the principal selection change.
tests/test_databricks.py::TestUncallableClaudeModels::test_family_with_no_callable_model_is_dropped An exhausted family is omitted and another family supplies the default Unit/component keep Distinct from fallback within one family; checks downstream default selection.
tests/test_databricks.py::TestUncallableClaudeModels::test_accessible_models_unaffected_and_cached Successful candidates remain selected, older candidates are not probed, and repeated discovery reuses results Unit/component keep Protects compatibility and cache behavior.
tests/test_databricks.py::TestUncallableClaudeModels::test_probe_failure_keeps_current_behavior[HTTP 500 Internal Server Error], [network error: timed out], [HTTP 429 Too Many] Server, transport, and rate-limit failures preserve selection Unit/component keep The parameterized cases cover distinct operational failures with shared setup.
tests/test_databricks.py::TestUncallableClaudeModels::test_all_denied_keeps_current_behavior Currently restores denied defaults when every family is exhausted Unit/component uncertain The scenario is necessary, but its expectation enshrines the blocking issue; replace it with the exhausted-result contract.

Existing discovery, HTTP transport, cache, and CLI fallback tests provide useful surrounding coverage. The global probe stub means existing CLI tests do not establish the new selection-to-launch behavior. The missing boundaries are exhausted-result handling through configuration/status and the explicit OAuth-scope fail-open branch. Mocked-transport component tests are sufficient; a new live E2E is not required.

The PR reports 410 passing focused tests and passing lint. Those results were not independently reproduced. Network-free isolated checks reproduced denied-model restoration and downstream fallback behavior; repository tests were not executed. The frozen diff checksum was verified. Surrounding context came from the trusted default checkout because the supplied base/head objects were unavailable locally.

Scope

All changed files support permission-aware Claude default selection or its test isolation. No clearly unrelated changes were found. The broader inference side effects at src/ucode/databricks.py:2414 are an approach concern, not evidence of an independent outcome.


Automated review by Polly · workflow run

…y for Claude

Co-authored-by: Isaac <no-reply@databricks.com>
@nachill-databricks

Copy link
Copy Markdown
Contributor Author

/ug-review

Comment thread src/ucode/cli.py
return models[0] if models and tool in ("gemini", "opencode", "kilo", "copilot", "pi") else None


_CLAUDE_MODEL_CONSUMERS = ("claude", "opencode", "kilo", "copilot", "pi")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maintainability · low
can we reuse _tools_want_claude for want_claude in configure_shared_state? right now the consumer list lives in two places, so adding a Claude consumer in only one of them would leave configure and status disagreeing about whether to probe.

Comment thread src/ucode/databricks.py Outdated
Comment on lines +2386 to +2387
def pick(models: list[str]) -> str | None:
return next((m for m in models if _claude_model_is_callable(workspace, token, m)), None)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

performance · low
each family checks its candidates one at a time with a 10s timeout each. a slow gateway could stall configure for N×10s. can we cap the candidates per family, or use a shorter total deadline?

Comment thread src/ucode/databricks.py Outdated
Comment on lines +2391 to +2392
chosen = {family: model for family, model in picks.items() if model}
return chosen or newest

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · medium
inconclusive probes already return True, so chosen is empty only when every candidate got a definite EXECUTE denial. can we return {} (or warn) here rather than default to models we know the user can't call?

Comment thread src/ucode/databricks.py
Comment on lines 2395 to 2397
def discover_model_services(
workspace: str, token: str
workspace: str, token: str, *, probe_claude: bool = True
) -> tuple[dict[str, str], list[str], list[str], list[str], str | None]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other · medium
with probe_claude=True as the default, any caller that doesn't pass it (e.g. ug status with no tool filter) sends billed requests. can we make probing opt-in (default False)?

Comment thread tests/test_databricks.py
Comment on lines +608 to +610
assert db_mod._claude_model_is_callable(WS, "token-a", "system.ai.claude-opus-5-5")
assert db_mod._claude_model_is_callable(WS, "token-a", "system.ai.claude-opus-5-5")
assert len(calls) == 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test · low
is this necessary? the cache-hit check already exists in test_accessible_models_unaffected_and_cached; can we keep only the token-b re-probe part here?

@github-actions

Copy link
Copy Markdown

Polly AI Review

Blocking issues

  • P2 — src/ucode/databricks.py:2392: can we preserve an empty result after every candidate is definitively denied, without letting legacy discovery restore those models?

    return chosen or newest restores the denied defaults when no family survives. Inconclusive probes already return True, so this fallback only defeats definitive denials. This contradicts the promised omission of wholly denied families. Returning chosen also requires caller handling: configure and live status currently invoke legacy discovery for an empty Claude inventory. Update tests/test_databricks.py::TestUncallableClaudeModels.test_all_denied_keeps_current_behavior and cover that caller boundary.

Security vulnerabilities

None identified in the frozen diff. The probe cache separates identities using a token fingerprint, and requests use the existing workspace origin.

Non-blocking notes

  • tests/test_databricks.py::TestUncallableClaudeModels._post: can we assert the probe endpoint and max_tokens == 1? Recording only the model leaves the request contract unprotected.
  • tests/test_databricks.py::TestUncallableClaudeModels: can we assert that inconclusive results are retried and definitive denials are cached? Existing assertions cover successful caching.
  • tests/test_cli.py::TestConfigureSharedStateUsePat.test_codex_only_configure_persists_discovered_oss_models: can we assert probe_claude=False? The keyword-tolerant mock cannot catch incorrect forwarding.
  • src/ucode/cli.py:1218: should ug status skip inference probes? A fresh status process now sends potentially billed requests when a Claude consumer is configured.
  • src/ucode/databricks.py:2379: can we replace the fallback explanation with “Omit families whose candidates are all definitively denied”? Probe failures already retain candidates.

Approach

Probing at the HTTP boundary, reusing the existing request helper and OAuth-scope classifier, and caching per identity are consistent with existing patterns. Distinguish definitive exclusion from unavailable discovery so fail-open behavior does not undo a confirmed denial.

Summary

Diff size (computed): 6 files; +260 / -16 lines (276 changed text lines); 0 binary files.

Category Files Added Deleted Share of changed text lines
Tests and test support 4 154 11 59.8%
Documentation 0 0 0 0.0%
Dependencies and lockfiles 0 0 0 0.0%
Implementation / other 2 106 5 40.2%

Shares use additions + deletions, including generated text and lockfiles. Binary files have no line count. Tests include fixtures/helpers under test paths and colocated test/spec files; categories are path-based, not coverage measurements.

Changes

The change adds per-family Claude access probing, selection fallback, identity-scoped process caching, and CLI gating. The remaining changes adapt test setup and exercise selection and failure behavior. No documentation, dependency, or generated-file changes are included.

The size is proportionate to the intended outcome. One concrete simplification is to reuse _tools_want_claude in configure_shared_state instead of maintaining a second consumer-selection expression.

Tests

Test-by-test assessment
Test / case Behavior protected Layer Needed? Action / rationale
tests/conftest.py::_isolate_ucode_state Offline probing and cache isolation Fixture support consolidate Retain the offline stub; remove the extra callable-cache clear because clear_model_services_cache() already performs it.
tests/test_claude_search_discovery.py::search_setup Shared setup accepts the discovery keyword Fixture support keep Necessary signature adaptation; existing configuration assertions remain intact.
tests/test_claude_search_discovery.py::test_claude_only_setup_registers_search_without_prior_codex_setup — discovery="model_services", "legacy" Both discovery paths register search and preserve existing entries Component keep Distinct discovery paths; keyword adaptation preserves meaningful persistence and permission assertions.
tests/test_claude_search_discovery.py::test_claude_only_setup_without_search_models_preserves_existing_search Missing search models preserve prior configuration Component keep Distinct recovery boundary; preservation assertions are unchanged.
tests/test_cli.py::TestConfigureSharedStateUsePat._stub_deps Isolated configure dependencies remain compatible Helper support keep Generic setup needs the new keyword; targeted scenarios should assert its value.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_uc_models_used_without_legacy_fallback Successful discovery suppresses legacy fallback Component keep Existing inventory, persistence, and no-fallback assertions remain meaningful.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_codex_only_configure_persists_discovered_oss_models Codex-only configure preserves Codex and OSS inventory Component keep Extend this scenario to assert probe_claude=False; no separate scenario is needed.
tests/test_cli.py::TestConfigureSharedStateUsePat._stub_with_fable Fable discovery setup remains compatible Helper support keep Signature-only adaptation preserves existing consumer-inventory coverage.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_legacy_fable_toggle_is_discarded — legacy_enabled=False, True Stale toggle values do not suppress Fable Component keep Both persisted inputs matter; model and stale-state assertions remain unchanged.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_falls_back_to_legacy_when_uc_empty Unavailable UC inventory still permits legacy discovery Component keep Extend alongside the blocker fix to distinguish unavailable inventory from definitive denial.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_falls_back_to_legacy_when_uc_empty — legacy discovery mock signature Compatibility of an unchanged legacy-call signature Test support remove Adding arbitrary keywords to this legacy mock is unnecessary; that function’s signature did not change.
tests/test_cli.py::TestConfigureSharedStateMcpCleanup._stub_external_deps Workspace-cleanup scenarios remain isolated Helper support keep Keyword adaptation preserves existing cleanup assertions.
tests/test_cli.py::TestToolsWantClaude.test_only_claude_consumers_trigger_probe Tool selections gate Claude probing Unit keep Smallest reliable layer for the selection predicate; caller forwarding is a separate contract.
tests/test_cli.py::TestToolsWantClaude.test_live_refresh_skips_probe_for_codex_only Live status forwards the negative probe flag Component consolidate Add the case to existing TestStatusLiveModels.test_refreshes_models_with_the_saved_profile_without_persisting, preserving freshness, authentication, inventory, and no-write assertions.
tests/test_databricks.py::_REAL_CLAUDE_PROBE Probe tests bypass the global offline stub Support constant keep Restores production behavior without duplicating its implementation.
tests/test_databricks.py::_DENIED Representative model-service denial input Support constant keep Shared classifier fixture; it does not establish the wording of a live denial response.
tests/test_databricks.py::TestUncallableClaudeModels._listing Explicit discovery inventory Helper support keep Reuses existing model-service setup; remove its unused invocation from the direct identity-cache test.
tests/test_databricks.py::TestUncallableClaudeModels._post Controlled HTTP outcomes and request recording Helper support keep Appropriate boundary; add endpoint and minimal-payload assertions.
tests/test_databricks.py::TestUncallableClaudeModels.test_denied_model_excluded_and_not_default Denied newest candidate falls back to an older candidate Component keep Exact inventory assertions protect selection; asserting the request sequence would directly establish newest-first fallback.
tests/test_databricks.py::TestUncallableClaudeModels.test_family_with_no_callable_model_is_dropped A denied family disappears while another remains usable Component keep Distinct partial-denial boundary; also exercises the actual default-model consumer.
tests/test_databricks.py::TestUncallableClaudeModels.test_accessible_models_unaffected_and_cached Accessible newest candidates stop probing and cache success Component keep Exact calls detect unnecessary older-model probes; repeated lookup establishes positive caching.
tests/test_databricks.py::TestUncallableClaudeModels.test_probe_failure_keeps_current_behavior — HTTP 500, network timeout, HTTP 429, IP-ACL 403, budget 403, OAuth-scope 403 Inconclusive outcomes preserve the newest model Component keep These are meaningful failure categories. Repeat each lookup to establish that inconclusive results are not cached.
tests/test_databricks.py::TestUncallableClaudeModels.test_cache_is_scoped_to_identity Same-token reuse and different-token permission isolation Unit keep Distinct identity boundary; repeat the denied identity lookup to establish negative caching.
tests/test_databricks.py::TestUncallableClaudeModels.test_probe_skipped_when_claude_not_wanted Opt-out avoids POSTs and preserves unprobed inventory Component keep Protects discovery-level opt-out independently of CLI forwarding.
tests/test_databricks.py::TestUncallableClaudeModels.test_all_denied_keeps_current_behavior Currently requires restoration of denied families Component keep Correct its expectation to omission, and cover the caller boundary so legacy discovery cannot resurrect denied models.

No tests were removed. Existing coverage addresses family bucketing, discovery failures, HTTP timeout conversion, OAuth-scope classification, and live-status authentication and state preservation. It does not establish the new probe payload, negative/inconclusive cache behavior, or all-denied caller handling.

No PR code, tests, or lint were executed during this review. The reported passing tests and lint are author-provided evidence, not independently verified.

After the fix, run uv run pytest -q tests/test_databricks.py tests/test_cli.py tests/test_claude_search_discovery.py in an isolated checkout. The decisive regression input is a listing where every Claude candidate receives a model-service permission-denial 403: verify empty Claude inventory and no legacy resurrection. A credential-free mocked case is sufficient; a live denied workspace is not required for that assertion.

Scope

All changes support access-aware Claude default selection or the necessary test adaptations. No clearly unrelated work was found. The all-denied fallback is a correctness gap within the stated outcome, not a separate scope concern.


Automated review by Polly · workflow run

…fallback

Co-authored-by: Isaac <no-reply@databricks.com>
@nachill-databricks

Copy link
Copy Markdown
Contributor Author

/ug-review

Comment thread src/ucode/cli.py Outdated
discover_model_services(
workspace,
token,
probe_claude=_tools_want_claude(tools),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

performance · medium
is this necessary for status? every ug status with claude configured now sends up to 8 billed 1-token calls and can wait up to 15s. the cache only lasts one process. can we skip the probe here (probe_claude=False)?

Suggestion:

Suggested change
probe_claude=_tools_want_claude(tools),
probe_claude=False,

Comment thread src/ucode/databricks.py
):
return model
if len(models) > _CLAUDE_PROBE_MAX_CANDIDATES:
return models[_CLAUDE_PROBE_MAX_CANDIDATES] # beyond the probe cap: unprobed, keep

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · medium
if the first two models are definitely denied, the unprobed third one becomes the default, but with exactly two denied models the family is dropped. is that inconsistency intended? the third model is likely denied too

Comment thread src/ucode/databricks.py

with ThreadPoolExecutor(max_workers=len(candidates)) as pool:
picks = dict(zip(candidates, pool.map(pick, candidates.values()), strict=True))
return {family: model for family, model in picks.items() if model}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · high
what happens if every family is denied? {} with reason None makes configure_shared_state fall back to discover_claude_models, which lists the same denied models unprobed. can we return a reason so callers skip that fallback?

Comment thread tests/test_cli.py Outdated
assert not cli_mod._tools_want_claude({"codex"})
assert not cli_mod._tools_want_claude({"gemini", "codex"})

def test_live_refresh_skips_probe_for_codex_only(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test · low
can we also assert probe_claude in configure_shared_state? that's the main billed path, and every configure stub here swallows the kwarg with **_kw, so a codex-only configure that probes would still pass.

Comment thread tests/test_databricks.py
claude, *_ = db_mod.discover_model_services(WS, "token", probe_claude=True)
assert claude == {}

def test_probing_is_opt_in(self, monkeypatch):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test · low
is this needed? test_probe_skipped_when_claude_not_wanted already checks that no probes are sent and the unprobed pick is kept

…skip-uncallable-models

Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions

Copy link
Copy Markdown

Polly AI Review

Blocking issues

  • P1 — src/ucode/cli.py:663: can we distinguish permission-filtered empty results from unavailable discovery, so legacy fallback cannot restore denied defaults?

    When every candidate is denied, the new filtering returns {}. Configure then calls the existing, unprobed discover_claude_models fallback. If that catalog advertises the same denied models, they are saved and written back as Claude defaults. Live refresh has the same fallback.

    Preserve fallback for unavailable discovery, but distinguish intentional filtering. Add configure and live-refresh regressions where legacy discovery advertises the denied models.

Security vulnerabilities

None demonstrated. Fail-open selection does not bypass the gateway’s authorization checks.

Non-blocking notes

  • src/ucode/databricks.py:2405: can you clarify the two-probe cap? The third candidate is accepted without probing, so “families with no callable model are dropped” is not guaranteed.
  • src/ucode/cli.py:1214: should read-only live status issue billed model requests? Can it display inventory without probing, since it is not choosing persisted defaults?
  • tests/test_databricks.py: can _post check the request payload and timeout, and test_probe_failure_keeps_current_behavior retry to prove inconclusive answers are not cached?
  • tests/test_databricks.py: can test_probe_skipped_when_claude_not_wanted and test_probing_is_opt_in share omitted-keyword and explicit-False cases?
  • tests/test_cli.py: can test_live_refresh_skips_probe_for_codex_only extend the existing saved-profile refresh scenario, retaining its output and non-persistence assertions?

Approach

The bounded, fail-open probe fits the existing discovery helpers. The main correction is carrying an intentional-denial result through the caller boundary.

The separate clear_claude_callable_cache wrapper is unnecessary if clear_model_services_cache remains responsible for clearing both caches.

Summary

Diff size (computed): 6 files; +301 / -25 lines (326 changed text lines); 0 binary files.

Category Files Added Deleted Share of changed text lines
Tests and test support 4 174 11 56.7%
Documentation 0 0 0 0.0%
Dependencies and lockfiles 0 0 0 0.0%
Implementation / other 2 127 14 43.3%

Shares use additions + deletions, including generated text and lockfiles. Binary files have no line count. Tests include fixtures/helpers under test paths and colocated test/spec files; categories are path-based, not coverage measurements.

Changes

The implementation adds permission-aware Claude candidate selection, process-local caching, bounded probing, and caller opt-in. The remaining changes provide unit coverage and adapt existing discovery stubs. No dependencies, generated files, or documentation change.

The size is proportional to the outcome. Concrete reductions are the duplicate cache-clear interface/call and overlapping opt-in and live-refresh test setup; no broad restructuring is needed.

Tests

Test-by-test assessment

The frozen snapshot’s checksum matched, and both trusted policy files were read in full. Tests were not executed; the PR’s reported test, lint, and live results remain unverified. The supplied base/head commits were unavailable locally, so surrounding caller behavior was checked against the provided trusted default-branch checkout.

Test / case Behavior protected Layer Needed? Action / rationale
tests/conftest.py::_isolate_ucode_state Prevents ordinary tests from making probes; resets cache state Suite support consolidate Preserve the offline stub; remove the extra clear already performed by clear_model_services_cache.
tests/test_claude_search_discovery.py::search_setup Search setup accepts the new discovery keyword Component support keep Necessary signature adaptation; existing assertions remain unchanged.
tests/test_claude_search_discovery.py::test_claude_only_setup_registers_search_without_prior_codex_setup[model_services, legacy] Claude-only setup registers search through either discovery source Component keep Both source cases remain useful; only stub compatibility changes.
tests/test_claude_search_discovery.py::test_claude_only_setup_without_search_models_preserves_existing_search Discovery failure preserves search registration Component keep Existing preservation assertions cover a distinct failure boundary.
tests/test_cli.py::TestConfigureSharedStateUsePat._stub_deps Isolates configure scenarios from external discovery Component support keep Required keyword compatibility across existing scenarios.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_uc_models_used_without_legacy_fallback Successful discovery persists models without legacy fallback Component keep Protects the successful caller path, not permission-filtered emptiness.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_codex_only_configure_persists_discovered_oss_models Codex-only configure preserves discovered OSS models Component keep Existing persisted-state assertions remain relevant.
tests/test_cli.py::TestConfigureSharedStateUsePat._stub_with_fable Supplies Fable discovery to existing scenarios Component support keep Signature-only compatibility change; no additional setup introduced.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_legacy_fable_toggle_is_discarded[False, True] Historical toggle values are removed without losing discovery Component keep Both prior-state cases retain meaningful migration assertions.
tests/test_cli.py::TestConfigureSharedStateUsePat.test_falls_back_to_legacy_when_uc_empty Unavailable discovery still permits legacy fallback Component keep This legitimate fallback must survive the blocking fix.
tests/test_cli.py::TestConfigureSharedStateMcpCleanup._stub_external_deps Isolates workspace-cleanup scenarios Component support keep Necessary keyword adaptation; cleanup behavior is unchanged.
tests/test_cli.py::TestToolsWantClaude.test_only_claude_consumers_trigger_probe Tool selection gates Claude probing Unit keep Tests the extracted predicate at the smallest reliable layer.
tests/test_cli.py::TestToolsWantClaude.test_live_refresh_skips_probe_for_codex_only Codex-only live refresh disables Claude probing Component consolidate Extend TestStatusLiveModels.test_refreshes_models_with_the_saved_profile_without_persisting, preserving its stronger journey assertions.
tests/test_databricks.py::_REAL_CLAUDE_PROBE, tests/test_databricks.py::_DENIED Restores the real probe under the global stub; supplies denial input Unit support keep Small shared setup; the denial text is synthetic, not provider-contract evidence.
tests/test_databricks.py::TestUncallableClaudeModels._listing Supplies controlled discovery candidates Unit support keep Reuses the existing model-service primitive.
tests/test_databricks.py::TestUncallableClaudeModels._post / nested fake Simulates successful, denied, and inconclusive requests Unit support keep Appropriate seam; currently does not validate the complete probe request.
tests/test_databricks.py::TestUncallableClaudeModels.test_denied_model_excluded_and_not_default Denied newest candidate falls back within its family Unit keep Exact selection assertions protect the central regression.
tests/test_databricks.py::TestUncallableClaudeModels.test_family_with_no_callable_model_is_dropped One denied family disappears while another supplies the default Unit/component keep Includes a meaningful default-selection assertion.
tests/test_databricks.py::TestUncallableClaudeModels.test_accessible_models_unaffected_and_cached Accessible newest candidate stops probing and is cached Unit keep Result and call-list assertions cover the happy path.
tests/test_databricks.py::TestUncallableClaudeModels.test_probe_failure_keeps_current_behavior — 500, timeout, 429, IP-ACL 403, budget 403, OAuth-scope 403 Inconclusive failures preserve selection Unit keep Six distinct failure classifications; repeated-call behavior remains untested.
tests/test_databricks.py::TestUncallableClaudeModels.test_cache_is_scoped_to_identity Different tokens receive independent cached answers Unit keep Protects an important identity boundary.
tests/test_databricks.py::TestUncallableClaudeModels.test_probe_skipped_when_claude_not_wanted Explicit False avoids probes while preserving discovery Unit consolidate Combine with the omitted-keyword case below without losing either assertion.
tests/test_databricks.py::TestUncallableClaudeModels.test_all_denied_omits_families All probed families can produce an empty result Unit keep Valuable lower-layer boundary; cannot catch the caller’s legacy fallback.
tests/test_databricks.py::TestUncallableClaudeModels.test_probing_is_opt_in Omitting the keyword avoids probing Unit consolidate Share setup with the explicit-False case while preserving default-argument coverage.
tests/test_databricks.py::TestUncallableClaudeModels.test_probe_capped_per_family Two denials lead to an unprobed third candidate Unit uncertain Accurately asserts the implementation; resolve the stated-contract question before endorsing that outcome.
tests/test_databricks.py::TestUncallableClaudeModels.test_deadline_keeps_remaining_candidates An expired deadline prevents further probing Unit keep Protects the bounded-work fallback without real timing dependencies.

No tests are removed. Modified existing tests change stub signatures rather than weaken assertions.

Existing coverage protects discovery bucketing, pagination, request errors, live-status non-persistence, and search-registration preservation. It does not cover the demonstrated all-denied caller transition. Probe request shape and non-caching of inconclusive results also lack direct assertions. These gaps belong at unit/component seams; duplicate live/E2E coverage is unnecessary.

The real gateway’s denial wording remains unverified. Synthetic denial tests establish local classification behavior, not the provider response contract.

To verify the blocking fix offline, advertise the same denied candidates through both discovery sources, exercise configure and live refresh, and assert those candidates cannot reappear. Run the four changed test files in a credential-free, network-disabled checkout.

Scope

All changes support permission-aware defaults or the necessary adaptation of existing tests. No clearly unrelated outcome was found. Probing during live status is a related behavior expansion whose necessity needs clarification, not evidence of unrelated work.


Automated review by Polly · workflow run

Co-authored-by: Isaac <no-reply@databricks.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant