fix(browser): stop reporting an unhydratable profile as a retired choice

A profile that fails validation for a reason unrelated to identity — a non-UUID
id, a mismatched partition — armed both the notice and its degraded flag. Since
hydrateFromPersisted skips such entries silently and nothing ever repairs them,
the user got "an old browser identity choice could not be inspected" forever,
about a profile that never carried one.

Key the notice on the presence of userAgentMode instead, and use validation only
to decide whether the choice that was found is inspectable. Refusing to hydrate
an entry and finding a retired choice are now separate facts.

The old case table asserted the defect for null, 42 and 'broken', so it is
replaced by two tables stating the new contract rather than adapted to pass.
This commit is contained in:
Brennan Benson
2026-09-14 21:02:45 -07:00
parent e414942ba8
commit b4e7d024eb
2 changed files with 61 additions and 23 deletions
@@ -30,17 +30,20 @@ export function inspectRetiredBrowserSessionProfileUserAgentModes(
let noticePending = false
let degraded = false
for (const profile of profiles) {
if (!isValidPersistedBrowserSessionProfile(profile, activeOrcaProfileId)) {
noticePending = true
degraded = true
continue
}
if (!Object.hasOwn(profile, 'userAgentMode')) {
// Refusing to hydrate an entry is not the same as finding a retired choice: hydrateFromPersisted
// already skips it silently, and a notice here would claim an old choice could not be inspected
// for a profile that never carried one.
if (!profile || typeof profile !== 'object' || !Object.hasOwn(profile, 'userAgentMode')) {
continue
}
noticePending = true
const mode = Reflect.get(profile, 'userAgentMode')
if (mode !== 'clean' && mode !== 'native') {
// Degraded covers both ways the choice is uninspectable: an unreadable mode, and a mode sitting
// on an entry we refuse to hydrate, where we cannot say which profile it belonged to.
if (
(mode !== 'clean' && mode !== 'native') ||
!isValidPersistedBrowserSessionProfile(profile, activeOrcaProfileId)
) {
degraded = true
}
}
@@ -3,38 +3,73 @@ import { getOrcaProfileBrowserSessionPartition } from '../../shared/orca-profile
import { inspectRetiredBrowserSessionProfileUserAgentModes } from './browser-session-persisted-profile-validation'
const ORCA_PROFILE_ID = 'local-default'
const PROFILE_ID = '11111111-1111-4111-8111-111111111111'
function profileWithMode(mode: unknown): Record<string, unknown> {
const id = '11111111-1111-4111-8111-111111111111'
return {
id,
id: PROFILE_ID,
scope: 'isolated',
partition: getOrcaProfileBrowserSessionPartition(ORCA_PROFILE_ID, id),
partition: getOrcaProfileBrowserSessionPartition(ORCA_PROFILE_ID, PROFILE_ID),
label: 'Existing',
source: null,
userAgentMode: mode
}
}
/** Fails `isValidPersistedBrowserSessionProfile` on its id, for reasons unrelated to identity. */
function unhydratableProfile(extra: Record<string, unknown> = {}): Record<string, unknown> {
return {
id: 'not-a-uuid',
scope: 'isolated',
partition: 'persist:orca-browser-session-not-a-uuid',
label: 'Unhydratable',
source: null,
...extra
}
}
describe('retired browser profile identity inspection', () => {
it('detects an inspectable old choice without removing its bytes', () => {
const profile = profileWithMode('native')
expect(
inspectRetiredBrowserSessionProfileUserAgentModes([profile], ORCA_PROFILE_ID)
).toEqual({ noticePending: true, degraded: false })
expect(inspectRetiredBrowserSessionProfileUserAgentModes([profile], ORCA_PROFILE_ID)).toEqual({
noticePending: true,
degraded: false
})
expect(profile.userAgentMode).toBe('native')
})
it.each([[null], [42], ['broken'], [profileWithMode('unexpected')]])(
'turns malformed metadata into a degraded notice without throwing',
(entry) => {
expect(() =>
inspectRetiredBrowserSessionProfileUserAgentModes([entry], ORCA_PROFILE_ID)
).not.toThrow()
expect(
inspectRetiredBrowserSessionProfileUserAgentModes([entry], ORCA_PROFILE_ID)
).toEqual({ noticePending: true, degraded: true })
// "I refuse to hydrate this" is not "a retired identity choice was found". hydrateFromPersisted
// skips these entries silently, and the notice text claims an old choice could not be inspected —
// which would be a lie about a profile that never carried one, repeated on every launch.
it.each([
{ scenario: 'null', entry: null },
{ scenario: 'a number', entry: 42 },
{ scenario: 'a string', entry: 'broken' },
{
scenario: 'a profile that fails validation for an unrelated reason',
entry: unhydratableProfile()
}
)
])('stays silent about $scenario, which carries no identity choice', ({ entry }) => {
expect(inspectRetiredBrowserSessionProfileUserAgentModes([entry], ORCA_PROFILE_ID)).toEqual({
noticePending: false,
degraded: false
})
})
it.each([
{ scenario: 'an unreadable mode', entry: profileWithMode('unexpected') },
{
scenario: 'a mode on an entry that cannot be hydrated',
entry: unhydratableProfile({ userAgentMode: 'native' })
}
])('turns $scenario into a degraded notice without throwing', ({ entry }) => {
expect(() =>
inspectRetiredBrowserSessionProfileUserAgentModes([entry], ORCA_PROFILE_ID)
).not.toThrow()
expect(inspectRetiredBrowserSessionProfileUserAgentModes([entry], ORCA_PROFILE_ID)).toEqual({
noticePending: true,
degraded: true
})
})
})