Unstick a project row whose lifecycle command was refused
Two more pieces of drift from the same merges, both invisible to `tsc`. **A refused Start/Stop/Reset strands the row.** `start`, `stop` and `rebuild` paint an optimistic "starting"/"stopping" so a click moves the row at once. That was safe while the only way these could fail was after the backend had begun changing things. `fix/sec`'s per-project lock ended that: all three now take the lock and are refused *before* any state changes, and `stop` could not fail this way at all before — it took no exclusion. So the optimistic paint has nothing to become, `isTransitioning` disables both Start and Stop, and the only thing that clears it is `reconcileProjectStatuses`, which runs once from `App.tsx` when Docker first appears. Clicking Stop during a compaction left the project unusable until the app was restarted. `withOptimisticStatus` re-reads the authoritative list when the command throws, and falls back to the status that was on screen if even that call fails — two failures in a row must not land on the one state there is no way out of. The error is rethrown unchanged, so the toast is unaffected. Five of the six new tests fail against the previous code; the sixth pins that the optimistic paint still happens on the way in. **Six secrets are typed as if they arrive, and they never do.** `git_token`, the four Bedrock credentials and `OpenAiCompatibleConfig .api_key` are `#[serde(skip_serializing)]` in Rust, so the key is absent from every project the backend returns — reading one gives `undefined`, not the `null` the type promised. Every current reader happens to use `?? ""`, so nothing is broken today; a single `=== null` would have been a branch that silently never ran. They are optional now, which makes that a compile error, and documented as write-only, which is what they are. 669 frontend tests pass, `tsc --noEmit` clean, `npm run build` green. Nothing under `src-tauri/` touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBq2rGum6GX7xXgsas1fDc
This commit is contained in:
+30
-6
@@ -52,7 +52,13 @@ export interface Project {
|
||||
* certificate file or a directory of them). null falls back to
|
||||
* `AppSettings.ca_cert_path`. Changing it recreates the container. */
|
||||
ca_cert_path: string | null;
|
||||
git_token: string | null;
|
||||
/** **Write-only.** Rust marks this `#[serde(skip_serializing)]`, so it is
|
||||
* absent from every project the backend hands back — reading it gives
|
||||
* `undefined`, never `null`. Optional here so that is the type, and so a
|
||||
* `=== null` test against it is a compile error rather than a branch that
|
||||
* silently never runs. Still sent on the way *in*: this is how the secret
|
||||
* is set. */
|
||||
git_token?: string | null;
|
||||
git_user_name: string | null;
|
||||
git_user_email: string | null;
|
||||
custom_env_vars: EnvVar[];
|
||||
@@ -96,11 +102,23 @@ export type BedrockAuthMethod = "static_credentials" | "profile" | "bearer_token
|
||||
export interface BedrockConfig {
|
||||
auth_method: BedrockAuthMethod;
|
||||
aws_region: string;
|
||||
aws_access_key_id: string | null;
|
||||
aws_secret_access_key: string | null;
|
||||
aws_session_token: string | null;
|
||||
/** **Write-only.** Rust marks this `#[serde(skip_serializing)]`, so it is
|
||||
* absent from every project the backend hands back — reading it gives
|
||||
* `undefined`, never `null`. Optional here so that is the type, and so a
|
||||
* `=== null` test against it is a compile error rather than a branch that
|
||||
* silently never runs. Still sent on the way *in*: this is how the secret
|
||||
* is set. */
|
||||
aws_access_key_id?: string | null;
|
||||
aws_secret_access_key?: string | null;
|
||||
aws_session_token?: string | null;
|
||||
aws_profile: string | null;
|
||||
aws_bearer_token: string | null;
|
||||
/** **Write-only.** Rust marks this `#[serde(skip_serializing)]`, so it is
|
||||
* absent from every project the backend hands back — reading it gives
|
||||
* `undefined`, never `null`. Optional here so that is the type, and so a
|
||||
* `=== null` test against it is a compile error rather than a branch that
|
||||
* silently never runs. Still sent on the way *in*: this is how the secret
|
||||
* is set. */
|
||||
aws_bearer_token?: string | null;
|
||||
model_id: string | null;
|
||||
disable_prompt_caching: boolean;
|
||||
service_tier: string | null;
|
||||
@@ -127,7 +145,13 @@ export interface LlamaCppConfig {
|
||||
* implement the **Anthropic** Messages API — e.g. LiteLLM. */
|
||||
export interface OpenAiCompatibleConfig {
|
||||
base_url: string;
|
||||
api_key: string | null;
|
||||
/** **Write-only.** Rust marks this `#[serde(skip_serializing)]`, so it is
|
||||
* absent from every project the backend hands back — reading it gives
|
||||
* `undefined`, never `null`. Optional here so that is the type, and so a
|
||||
* `=== null` test against it is a compile error rather than a branch that
|
||||
* silently never runs. Still sent on the way *in*: this is how the secret
|
||||
* is set. */
|
||||
api_key?: string | null;
|
||||
model_id: string | null;
|
||||
/** See `OllamaConfig.haiku_model_id`. */
|
||||
haiku_model_id: string | null;
|
||||
|
||||
Reference in New Issue
Block a user