roast findings: arm ordering, composer deps, follow-all fallthrough, createdAt clobber
Adversarial review (roast) of the branch, 9 path-scoped passes: - cross-tab rebuild armed the new session's hooks before the deferred bundle dispatch, so an 'expired' event fired in that async window would be dropped by the reducer's bundle-identity check; arm now happens in the same callback as the dispatch, and the dispatched account is re-read from the live session (mirrors snapshot-after- prep). - Composer onPressPublish's dep array omitted appviewClient and resolveClients (stale-client hazard after cross-tab rebuild). - follow-all catch blocks (onboarding starter-pack card, starter pack screen) showed the error toast but fell through to dereference the undefined followUris map, throwing and showing a bogus success toast. - contacts createProfileRecord unconditionally overwrote the profile's createdAt on every run; now preserved when already set, matching StepFinished. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -347,7 +347,9 @@ async function createProfileRecord(
|
||||
|
||||
next.displayName = ''
|
||||
|
||||
next.createdAt = toDatetimeString(new Date())
|
||||
if (!next.createdAt) {
|
||||
next.createdAt = toDatetimeString(new Date())
|
||||
}
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ export function StarterPackCard({
|
||||
type: 'error',
|
||||
})
|
||||
logger.error('Failed to follow all accounts', {safeMessage: e})
|
||||
return
|
||||
}
|
||||
|
||||
setIsFollowingAll(true)
|
||||
|
||||
@@ -385,6 +385,7 @@ function Header({
|
||||
type: 'error',
|
||||
})
|
||||
logger.error('Failed to follow all accounts', {safeMessage: e})
|
||||
return
|
||||
}
|
||||
|
||||
setIsProcessing(false)
|
||||
|
||||
@@ -452,7 +452,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
)
|
||||
newBundle = buildBundle(newSession)
|
||||
registerBundleKillSwitch(newBundle, hooks.kill)
|
||||
hooks.arm()
|
||||
/*
|
||||
* Reapply this account's subscribed labelers to the freshly built
|
||||
* appview client - buildBundle starts with an empty per-instance
|
||||
@@ -465,6 +464,15 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
* preserving this branch's no-network intent), and the OLD bundle's
|
||||
* access token stays valid throughout the deferral, so nothing
|
||||
* regresses by waiting.
|
||||
*
|
||||
* arm() happens inside the same callback as the dispatch (not
|
||||
* before the deferral) so there is no async window where the new
|
||||
* session is armed but the reducer still holds the old bundle -
|
||||
* an 'expired' event fired in such a window would be dropped by
|
||||
* the reducer's bundle-identity check. Mirroring the factories'
|
||||
* snapshot-after-prep, the dispatched account is re-read from the
|
||||
* live session, so a token refresh during the (unarmed) deferral
|
||||
* still persists fresh tokens.
|
||||
*/
|
||||
void configureModerationForAccount(newBundle, syncedAccount)
|
||||
.catch(() => {})
|
||||
@@ -478,10 +486,17 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
: undefined,
|
||||
nextSession: newBundle.session.session,
|
||||
})
|
||||
const newAccount = newBundle.session.destroyed
|
||||
? syncedAccount
|
||||
: (sessionDataToSessionAccount(
|
||||
newBundle.session.session,
|
||||
newBundle.session.session.service,
|
||||
) ?? syncedAccount)
|
||||
hooks.arm()
|
||||
store.dispatch({
|
||||
type: 'replaced-current-bundle',
|
||||
newAgent: newBundle,
|
||||
newAccount: syncedAccount,
|
||||
newAccount,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1271,6 +1271,8 @@ export const ComposePost = ({
|
||||
l,
|
||||
ax,
|
||||
pdsClient,
|
||||
appviewClient,
|
||||
resolveClients,
|
||||
canPost,
|
||||
isPublishing,
|
||||
currentLanguages,
|
||||
|
||||
Reference in New Issue
Block a user