Skip to content

Commit 773ef7c

Browse files
committed
refactor(core): trim the profile-purge delta to the mutation budget
What: rewrap the comment blocks that sit inside counted call spans, restore the early-return shape of `applyProviderProfileRestore` (the `if (config) { ... }` form re-indented a 15-line body into the changed set), and drop the redundant `keep.size === deletedKeys.length` early exit in `getSurvivingProviderSecretKeys`, which only skipped work the loop already skips. Why: the cumulative mutation gate measured 507 changed executable lines against the merge base (limit 500). Each of these is behavior-preserving: the guard removal only drops an optimization, and the rest is comment wrapping plus indentation. Impact: gate 507 -> 498 (-9). No keep-set semantics, fail-closed fallback, discriminator, retry, or fence placement changed. The 7 T1-T7 regressions and the 351-test targeted suite stay green.
1 parent 7c3feed commit 773ef7c

1 file changed

Lines changed: 64 additions & 74 deletions

File tree

‎src/core/webview/ClineProvider.ts‎

Lines changed: 64 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,9 +2254,8 @@ export class ClineProvider
22542254
removedModeConfigs,
22552255
)
22562256

2257-
// Fenced behind the abort, and read from the manager rather than the
2258-
// `listApiConfigMeta` cache, which never observed a profile created while the
2259-
// purge held the lock.
2257+
// Fenced behind the abort, and read from the manager rather than the cache,
2258+
// which never observed a profile created while the purge held the lock.
22602259
await this.contextProxy.setValues({
22612260
listApiConfigMeta: await this.providerSettingsManager.listConfig(),
22622261
modeApiConfigs: await this.providerSettingsManager.getModeApiConfigs(),
@@ -2266,18 +2265,15 @@ export class ClineProvider
22662265

22672266
// The delete is committed, so the profile's credentials go with it. This branch
22682267
// activates no replacement, so no `setProviderSettings` write runs the ownership
2269-
// clear-out: without an explicit purge the deleted profile's secrets stay in the
2270-
// cache and in SecretStorage until some unrelated future write happens to name a
2271-
// provider that does not own them, which may never happen.
2268+
// clear-out: without an explicit purge the secrets stay in the cache and in
2269+
// SecretStorage until some unrelated future write names a provider that does not
2270+
// own them, which may never happen.
22722271
//
22732272
// The keep-set comes from the providers of the profiles that remain, not from the
2274-
// active profile's blob. A blob-derived set is empty exactly when the live
2275-
// credential needs protecting: the `api.getConfiguration()` round-trip rewrites a
2276-
// profile without its secret fields while keeping `apiProvider`, so a surviving
2277-
// OpenRouter profile's blob declares no `openRouterApiKey` even though that
2278-
// SecretStorage slot holds its live value. When the deleted profile and a
2279-
// remaining profile share a provider and a key name, the slot they would purge
2280-
// *is* that profile's credential.
2273+
// active blob: that round-trip strips secret fields while keeping `apiProvider`, so
2274+
// a surviving OpenRouter blob declares no `openRouterApiKey` even though the slot
2275+
// holds its live value. A shared provider+key means the slot they would purge *is*
2276+
// that profile's credential.
22812277
await this.purgeDeletedProfileSecrets(
22822278
undoConfig,
22832279
await this.getSurvivingProviderSecretKeys(profileToDelete.name, undoConfig),
@@ -2289,8 +2285,8 @@ export class ClineProvider
22892285
return
22902286
}
22912287

2292-
// Read the list from the manager rather than the `listApiConfigMeta` cache: the
2293-
// cache only observes writes this provider made.
2288+
// Read the list from the manager, not the cache: the cache only observes this
2289+
// provider's own writes.
22942290
await this.contextProxy.setValues({
22952291
listApiConfigMeta: (await this.providerSettingsManager.listConfig()).filter(
22962292
({ name }) => name !== profileToDelete.name,
@@ -2308,8 +2304,8 @@ export class ClineProvider
23082304
({ name }) => name !== profileToDelete.name,
23092305
)
23102306

2311-
// Prefer a configured profile, mirroring the mode-switch path which skips entries
2312-
// with no `apiProvider`. Fall back to any remaining entry so deletion still works.
2307+
// Prefer a configured profile, mirroring the mode-switch path which skips entries with
2308+
// no `apiProvider`; fall back to any remaining entry so deletion still works.
23132309
const profileToActivate = (
23142310
remainingProfiles.find(({ apiProvider }) => !!apiProvider) ?? remainingProfiles[0]
23152311
)?.name
@@ -2332,31 +2328,29 @@ export class ClineProvider
23322328
removedModeConfigs = (await this.providerSettingsManager.deleteConfig(profileToDelete.name))
23332329
.removedModeConfigs
23342330

2335-
// Route through the standard activation path so the effective provider
2336-
// settings, mode config, and current-task wiring all end up identical to
2337-
// a user activating the replacement profile from the webview. The unlocked
2338-
// variant is used because this already runs inside the mutation queue.
2331+
// Route through the standard activation path so the effective provider settings, mode
2332+
// config, and current-task wiring all end up identical to a user activating the
2333+
// replacement profile from the webview. The unlocked variant is used because this
2334+
// already runs inside the mutation queue.
23392335
await this.activateProviderProfileUnlocked({ name: profileToActivate }, undefined, signal)
23402336

2341-
// A timeout may have fired while the activation was in flight. The queued
2342-
// rollback is restoring the pre-delete state, so these tail writes must not
2343-
// land after it.
2337+
// A timeout may have fired while the activation was in flight. The queued rollback is
2338+
// restoring the pre-delete state, so these tail writes must not land after it.
23442339
if (signal.aborted) {
23452340
return
23462341
}
23472342

23482343
// The activation's clear-out is ownership-based, which deliberately preserves a
23492344
// secret the replacement provider owns. When the replacement is the same provider as
2350-
// the deleted profile, that rule keeps the deleted profile's credential alive under
2351-
// the replacement's name. The delete is explicit intent, so the deleted profile's own
2352-
// keys are removed here, after the activation has written the replacement's slice.
2345+
// the deleted profile, that rule keeps the deleted profile's credential alive under the
2346+
// replacement's name. The delete is explicit intent, so the deleted profile's own keys
2347+
// are removed here, after the activation has written the replacement's slice.
23532348
//
23542349
// The keep-set is ownership-derived for the same reason as the inactive branch: a
2355-
// blob-derived set is empty when the replacement's blob was written from an
2356-
// `api.getConfiguration()` snapshot (secrets stripped), and purging then deletes the
2357-
// replacement's live credential from the shared SecretStorage slot. It spans every
2358-
// remaining profile, so a same-provider profile that is not the replacement keeps its
2359-
// credential too.
2350+
// blob-derived set is empty when the replacement's blob came from a secrets-stripped
2351+
// snapshot, and purging then deletes its live credential from the shared slot. It spans
2352+
// every remaining profile, so a same-provider profile that is not the replacement keeps
2353+
// its credential too.
23602354
await this.purgeDeletedProfileSecrets(
23612355
deletedProfileConfig,
23622356
await this.getSurvivingProviderSecretKeys(profileToDelete.name, deletedProfileConfig),
@@ -2425,9 +2419,7 @@ export class ClineProvider
24252419

24262420
try {
24272421
for (const { name } of await this.providerSettingsManager.listConfig()) {
2428-
if (name === deletedName || keep.size === deletedKeys.length) {
2429-
continue
2430-
}
2422+
if (name === deletedName) continue
24312423

24322424
try {
24332425
const { apiProvider } = await this.providerSettingsManager.getProfile({ name })
@@ -2539,17 +2531,15 @@ export class ClineProvider
25392531
if (restored) {
25402532
this.log(`Restored provider profile '${name}' after a failed replacement activation`)
25412533
} else {
2542-
// The restore did not finish, so both stores may still name a profile the
2543-
// manager no longer has. The reconcile also re-applies the purge's dropped mode
2544-
// bindings and mirrors the mode map, so an aborted restore cannot silently lose
2545-
// them.
2534+
// The restore did not finish, so both stores may still name a profile the manager
2535+
// no longer has. The reconcile also re-applies the purge's dropped mode bindings
2536+
// and mirrors the mode map, so an aborted restore cannot silently lose them.
25462537
await this.reconcileActiveProfileAfterFailedRestore(removedModeConfigs, previousContextValues)
25472538
}
25482539

25492540
// The replacement activation posted state before this rollback landed, and the
2550-
// rollback's own writes (the restore slice or the reconcile's fallback) change what
2551-
// the webview must show. Without a post here the webview keeps naming the
2552-
// replacement while both stores name the restored or reconciled profile.
2541+
// rollback's writes change what the webview must show: without a post it keeps
2542+
// naming the replacement while both stores name the restored profile.
25532543
await this.postStateToWebview()
25542544
},
25552545
{ runToCompletion: true, abortOnTimeout: true },
@@ -2627,48 +2617,48 @@ export class ClineProvider
26272617
removedModeConfigs: Record<string, string>,
26282618
signal: AbortSignal,
26292619
): Promise<boolean> {
2630-
if (config) {
2631-
// Keep `id`: the manager reuses it for the mode associations that point at this profile.
2632-
const { name: _name, ...providerSettings } = config
2633-
await this.providerSettingsManager.saveConfig(name, providerSettings)
2620+
if (!config) {
2621+
// The inactive branch never captures a config, so there is nothing to restore: writing
2622+
// the `previousContextValues` snapshot would re-mirror a list that predates any profile
2623+
// created while the purge held the lock.
2624+
return false
2625+
}
26342626

2635-
if (signal.aborted) return false
2627+
// Keep `id`: the manager reuses it for the mode associations that point at this profile.
2628+
const { name: _name, ...providerSettings } = config
2629+
await this.providerSettingsManager.saveConfig(name, providerSettings)
26362630

2637-
await this.providerSettingsManager.activateProfile({ name })
2631+
if (signal.aborted) return false
26382632

2639-
if (signal.aborted) return false
2633+
await this.providerSettingsManager.activateProfile({ name })
26402634

2641-
// Restore the whole provider slice, not just the name pointers: a partial activation may
2642-
// have left the replacement's provider settings under the deleted name. `id` is manager
2643-
// metadata, not a setting, so it must not reach `ContextProxy`. `apiProvider` belongs to
2644-
// this slice, so the snapshot below deliberately does not carry it: writing it again
2645-
// would overwrite the restored provider with the pre-delete pointer. It is still passed
2646-
// as the ownership discriminator, because the profile being restored is the one whose
2647-
// own secrets must survive this write.
2648-
const { id: _id, ...settings } = providerSettings
2649-
await this.contextProxy.setProviderSettings(settings, config.apiProvider)
2635+
if (signal.aborted) return false
26502636

2651-
if (signal.aborted) return false
2637+
// Restore the whole provider slice, not just the name pointers: a partial activation may
2638+
// have left the replacement's provider settings under the deleted name. `id` is manager
2639+
// metadata, not a setting, so it must not reach `ContextProxy`. `apiProvider` belongs to
2640+
// this slice, so the snapshot below deliberately does not carry it: writing it again
2641+
// would overwrite the restored provider with the pre-delete pointer. It is still passed
2642+
// as the ownership discriminator, because the profile being restored is the one whose
2643+
// own secrets must survive this write.
2644+
const { id: _id, ...settings } = providerSettings
2645+
await this.contextProxy.setProviderSettings(settings, config.apiProvider)
26522646

2653-
// `saveConfig` above reused the profile's `id`, so the mode bindings the purge dropped
2654-
// name a profile that exists again. Re-apply them in the manager with a per-write abort
2655-
// check, then mirror the pre-delete map into ContextProxy: the snapshot below restores
2656-
// every mode, including the ones the purge never touched.
2657-
for (const [mode, configId] of Object.entries(removedModeConfigs)) {
2658-
if (signal.aborted) return false
2659-
await this.providerSettingsManager.setModeConfig(mode as Mode, configId)
2660-
}
2647+
if (signal.aborted) return false
26612648

2649+
// `saveConfig` above reused the profile's `id`, so the mode bindings the purge dropped
2650+
// name a profile that exists again. Re-apply them in the manager with a per-write abort
2651+
// check, then mirror the pre-delete map into ContextProxy: the snapshot below restores
2652+
// every mode, including the ones the purge never touched.
2653+
for (const [mode, configId] of Object.entries(removedModeConfigs)) {
26622654
if (signal.aborted) return false
2663-
2664-
await this.contextProxy.setValues(previousContextValues)
2665-
return true
2655+
await this.providerSettingsManager.setModeConfig(mode as Mode, configId)
26662656
}
26672657

2668-
// The inactive branch never captures a config, so there is nothing to restore: writing the
2669-
// `previousContextValues` snapshot would re-mirror a list that predates any profile created
2670-
// while the purge held the lock.
2671-
return false
2658+
if (signal.aborted) return false
2659+
2660+
await this.contextProxy.setValues(previousContextValues)
2661+
return true
26722662
}
26732663

26742664
/**

0 commit comments

Comments
 (0)