mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-09 01:49:49 -10:00
catalog: keep the load path fail-closed and clear the three clippy errors
The hosted Lint and Safety jobs both pinned this tree at `d05d883bc4` and both failed inside `codewhale-tui`, so one slice closes them together. Clippy, three errors under `-D warnings`, taken verbatim from the job log: - `client/provider_native_search.rs:700` called `filter(..).next_back()` on a `DoubleEndedIterator` -> `rfind(..)`, same last non-empty segment in one pass. - `models_dev_live.rs:350` and `:435` redundant closure -> pass `note_persistence_error` directly. Safety gate: `provider_catalog_live::tests:: durable_provider_catalog_cannot_claim_cloud_or_override_price_authority` panicked at `:3243` with `forged scope must be dropped`. `f173c4829f` made the loader keep a scope and drain unusable rows one at a time, which also kept a scope whose *every* row failed validation — exactly the forged-scope shape the test exists to refuse. A scope that arrives with rows and loses all of them is dropped again, gated on `rows_before > 0` so a genuine empty-on-write scope still loads. CHANGELOG gains the bullet `f173c4829f` earned and never got: the OrcaRouter refresh that reported `failed / cache_write_failed / model_count 0` against a 468-row endpoint lands 449 rows now, and a failed refresh names its typed reason instead of flattening it. Checks on this tree: - `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings -A clippy::uninlined_format_args -A clippy::too_many_arguments -A clippy::unnecessary_map_or` (the CI invocation verbatim) -> exit 0, zero `error:` lines, 9m05s. - `nextest run -p codewhale-tui --lib -E 'test(provider_catalog_live::tests) | test(models_dev_live::tests)'` -> 35 run, 35 passed, 15352 skipped, including the previously failing forged-scope case and the OrcaRouter neighbour `disk_reload_rehydrates_and_exposes_six_hundred_openrouter_models`. Not verified: hosted CI, which runs once at the release gate.
This commit is contained in:
1 parent
d7674aa3b2
commit
6467fc28ee
4 files changed
+22
-3
No files matched your search
@@ -117,6 +117,17 @@ and independent workflow steps can continue after another child fails.
|
||||
snapshot, and an unfresh one still contributes its own ids as an offline
|
||||
tail so a withdrawn model does not vanish by omission.
|
||||
|
||||
- One catalog row without a price no longer costs you every model in its
|
||||
provider. `models --update` reported `failed / cache_write_failed` with
|
||||
`model_count 0` for OrcaRouter while the endpoint answered 468 rows, because
|
||||
a row whose price was dropped still carried a live cost stamp and one such
|
||||
row rejected the whole refresh as `invalid_response`; the same all-or-nothing
|
||||
rule also discarded an entire cached scope on the next read. Rows are now
|
||||
judged one at a time, a refresh fails only when rows arrived and none
|
||||
survived, and a cached scope that loses every row to validation is still
|
||||
dropped rather than loaded. A failed refresh names its typed reason instead
|
||||
of `cache_write_failed` and still reports the rows you have left.
|
||||
|
||||
- A new OrcaRouter session with no saved wire model defaults to
|
||||
`deepseek/deepseek-v4.1-flash-1017`. Every OrcaRouter catalog row has
|
||||
`default_for_provider` false, so the descriptor was the only thing deciding
|
||||
|
||||
@@ -697,7 +697,7 @@ fn fallback_title(url: &str) -> String {
|
||||
};
|
||||
let slug = parsed
|
||||
.path_segments()
|
||||
.and_then(|segments| segments.filter(|segment| !segment.is_empty()).next_back());
|
||||
.and_then(|mut segments| segments.rfind(|segment| !segment.is_empty()));
|
||||
let Some(slug) = slug else {
|
||||
return format!("{host} (home page)");
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ pub async fn refresh(force_network: bool) -> Result<usize, ModelsDevRefreshError
|
||||
body,
|
||||
},
|
||||
)
|
||||
.inspect_err(|error| note_persistence_error(error))?;
|
||||
.inspect_err(note_persistence_error)?;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
@@ -432,7 +432,7 @@ async fn refresh_from_path(path: &Path) -> Result<usize, ModelsDevRefreshError>
|
||||
body,
|
||||
},
|
||||
)
|
||||
.inspect_err(|error| note_persistence_error(error))?;
|
||||
.inspect_err(note_persistence_error)?;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
@@ -869,6 +869,14 @@ fn load_from_disk_unlocked_with_limit(path: &Path, max_bytes: u64) -> Option<Pro
|
||||
"dropped unusable rows from a cached provider catalog"
|
||||
);
|
||||
}
|
||||
if rows_before > 0 && entry.offerings.is_empty() {
|
||||
tracing::debug!(
|
||||
target: "provider_catalog",
|
||||
scope = %entry.provider,
|
||||
"dropping provider catalog scope whose every row was unusable"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
});
|
||||
if cache.entries.len() != scopes_before {
|
||||
|
||||
Reference in new issue
Block a user