feat: flag accounts Reddit considers unestablished and re-test them
New accounts cannot start chats until Reddit considers them established. Until now the bot would burn a candidate on every invitation Reddit was always going to reject, with nothing in the dashboard explaining why the account looked idle. Two signals feed the verdict. A periodic profile check reads the account's own age, karma and email verification from about.json and compares them against configurable thresholds — that is what flags a brand new account before it wastes anything. A rejected invitation is authoritative: Reddit has told us directly, so the account is held out of sending with a backoff that doubles per rejection, and a delivered invitation clears the flag outright. An unestablished account takes no new posts (canAcceptPost), raises an attention item, reports an `unestablished` sending state, and shows its age/karma evidence on the Accounts page. An unchecked account is always allowed through, so a first run is never blocked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c43e534cf1
commit
89eb4583f8
25 files changed
+1425
-11
No files matched your search
@@ -6,6 +6,24 @@ export const RedditSessionStateSchema = z.union([
|
||||
z.literal('login-required'),
|
||||
z.literal('unreachable'),
|
||||
]);
|
||||
export const AccountEstablishmentStateSchema = z.union([
|
||||
z.literal('unknown'),
|
||||
z.literal('established'),
|
||||
z.literal('unestablished'),
|
||||
]);
|
||||
export const AccountEstablishmentSummarySchema = z.strictObject({
|
||||
state: AccountEstablishmentStateSchema,
|
||||
reasons: z.array(z.string()),
|
||||
accountAgeDays: z.number().nullable(),
|
||||
linkKarma: z.number().nullable(),
|
||||
commentKarma: z.number().nullable(),
|
||||
totalKarma: z.number().nullable(),
|
||||
hasVerifiedEmail: z.boolean().nullable(),
|
||||
profileCheckedAt: z.number().nullable(),
|
||||
lastProbeAt: z.number().nullable(),
|
||||
lastProbeFailure: z.string().nullable(),
|
||||
retryAt: z.number().nullable(),
|
||||
});
|
||||
export const RedditAccountSummarySchema = z.strictObject({
|
||||
accountId: z.string().min(1),
|
||||
redditUsername: z.string().min(1),
|
||||
@@ -15,6 +33,8 @@ export const RedditAccountSummarySchema = z.strictObject({
|
||||
createdAt: z.number(),
|
||||
updatedAt: z.number(),
|
||||
lastImportedAt: z.number(),
|
||||
/** Absent on responses from a build that predates establishment tracking. */
|
||||
establishment: AccountEstablishmentSummarySchema.nullable().optional(),
|
||||
});
|
||||
export const RedditAccountOwnerSchema = RedditAccountSummarySchema.pick({
|
||||
accountId: true,
|
||||
@@ -71,4 +91,6 @@ export type RedditSessionState = z.infer<typeof RedditSessionStateSchema>;
|
||||
export type LoginStatusResponse = z.infer<typeof LoginStatusResponseSchema>;
|
||||
export type RedditCookieImportRequest = z.infer<typeof RedditCookieImportRequestSchema>;
|
||||
export type RedditAccountSummary = z.infer<typeof RedditAccountSummarySchema>;
|
||||
export type AccountEstablishmentState = z.infer<typeof AccountEstablishmentStateSchema>;
|
||||
export type AccountEstablishmentSummary = z.infer<typeof AccountEstablishmentSummarySchema>;
|
||||
export type RedditAccountOwner = z.infer<typeof RedditAccountOwnerSchema>;
|
||||
Reference in new issue
Block a user