Vest: the bot activates a passed evaluation's funded account, and a passed one no longer holds the sync

A passed Vest evaluation sits at GOAL_PASSED (status 3) until someone presses
"Go to funded account", which sends POST /v3/capital/activate-funded
{eval_account_id} on the evaluation's own token (read from the Vest app's
bundle, 2026-10-29); Vest then opens the funded account and marks the
evaluation CLAIMED (6). The 5 evaluations that passed on 2026-10-29 waited
for a hand activation.

runActivations now asks for it, the way runClaims claims: from the
scheduler's tick (not awaited, so a slow ask doesn't hold the lane's entry)
and from the claim watcher while the scheduler is off, for evaluations with
an account type only, 15 minutes apart after a failure. Off with the
auto_activate setting at 'off' (dashboard: "Auto-activate funded"). The
client asks for an evaluation once at a time, never again after Vest
answered, and after a timeout not until a list read a minute on says either
way; a refusal frees it at once. The rule is the Vest app's own: an
evaluation at GOAL_PASSED, not blocked, on its plan's last step.

Vest's active balance list leaves a passed evaluation out, and a missing
balance made every sync short of good (15:31-15:34Z), which holds and then
quarantines the lane. Only a live account's missing balance does now. Log
lines name Vest's statuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-10-29 12:09:49 -05:00
co-authored by Claude Opus 5.5
parent 0eb56b3949
commit 8a5b2a64e7
8 changed files with 380 additions and 18 deletions
+8
View File
@@ -175,6 +175,14 @@ export interface PlatformClient {
/** A claim this client made that no good sync has read past yet: the
* balance on hand may not show it, so no claim may be judged on it. */
claimPending?(accountId: number): boolean;
/** Passed evaluations whose funded account the platform activates by
* API (Vest's "Go to funded account"), by account id — less any this
* client already asked for that no sync has read back yet. */
activatable?(): number[];
/** Activate the funded account of a passed evaluation. Resolves once the
* platform opened it, with its name when the answer gives one (the next
* sync lists it); rejects with the platform's reason otherwise. */
activateFunded?(accountId: number): Promise<{ funded: string | null }>;
/** Drop the account's history from memory (the wipe routes), so it reads
* unloaded until the next fetch rebuilds it. */
forgetHistory(accountId: number, accountName: string): void;