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
@@ -240,6 +240,7 @@ describe('account runtime isolation', () => {
|
||||
conversationAutomation: { hasActionableReplies },
|
||||
chatService: { getInvitationCooldown: () => null },
|
||||
rateLimiter: { getTimers: () => ({ nextMessageAvailableAt: null }) },
|
||||
establishmentService: { isSendable: () => true },
|
||||
} as unknown as RedditAccountRuntimeResources,
|
||||
{ start: vi.fn(), stop: vi.fn() },
|
||||
);
|
||||
@@ -250,6 +251,37 @@ describe('account runtime isolation', () => {
|
||||
expect(await runtime.canAcceptPost()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not accept new outreach while the account is not established yet', async () => {
|
||||
const stored = account('too_new');
|
||||
const isSendable = vi.fn().mockReturnValue(false);
|
||||
const runtime = new RedditAccountRuntime(
|
||||
{
|
||||
accountId: stored.accountId,
|
||||
redditUsername: stored.redditUsername,
|
||||
matrixUserId: stored.matrixUserId!,
|
||||
cookies: [],
|
||||
matrixCredentials: JSON.parse(stored.matrixCredentialsJson),
|
||||
updatedAt: stored.updatedAt,
|
||||
},
|
||||
{
|
||||
accountAuth: {
|
||||
isFullyAuthenticated: () => true,
|
||||
ensureFullyAuthenticated: async () => true,
|
||||
},
|
||||
conversationAutomation: { hasActionableReplies: vi.fn().mockResolvedValue(false) },
|
||||
chatService: { getInvitationCooldown: () => null },
|
||||
rateLimiter: { getTimers: () => ({ nextMessageAvailableAt: null }) },
|
||||
establishmentService: { isSendable },
|
||||
} as unknown as RedditAccountRuntimeResources,
|
||||
{ start: vi.fn(), stop: vi.fn() },
|
||||
);
|
||||
await runtime.start();
|
||||
|
||||
expect(await runtime.canAcceptPost()).toBe(false);
|
||||
isSendable.mockReturnValue(true);
|
||||
expect(await runtime.canAcceptPost()).toBe(true);
|
||||
});
|
||||
|
||||
it('uses the Reddit fullname for auth while retaining the Matrix runtime owner', () => {
|
||||
expect(runtimeAuthenticatedAccount(
|
||||
{ matrixUserId: '@t2_1u57iqxxbv:reddit.com' },
|
||||
|
||||
Reference in new issue
Block a user