Skip to content

Commit 631850e

Browse files
Pigbibiclaude
andcommitted
fix(strategy-switch): sequential platform processing + unified ACCOUNT_OPTIONS_DEFAULT fallback
Root cause: GitHub secondary rate limiting from ~80 concurrent variable reads during loadCurrentStrategies caused firstrade/schwab/binance/qmt to consistently return empty for RUNTIME_TARGET_JSON and STRATEGY_PROFILE, even though the token had proper access. Fix: - Process platforms sequentially (not Promise.all) with inter-platform delay to stay within GitHub rate-limit budget. - Add ACCOUNT_OPTIONS_DEFAULT fallback that uses default_strategy_profile from KV (synced automatically after each switch). This ensures ALL platforms always show a strategy regardless of GitHub variable matching. - Clean up debug endpoints. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 231ba2e commit 631850e

1 file changed

Lines changed: 33 additions & 26 deletions

File tree

web/strategy-switch-console/worker.js

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -609,34 +609,39 @@ async function loadCurrentStrategies(accountOptions, env) {
609609
};
610610

611611
const currentStrategies = {};
612-
const platformResults = await Promise.all(SUPPORTED_PLATFORMS.map(async (platform) => {
613-
const options = Array.isArray(accountOptions[platform]) ? accountOptions[platform] : [];
614-
if (!options.length) return [platform, {}];
615-
const repository = repositories[platform];
616-
if (!repository) return [platform, {}];
617-
618-
const optionResults = await Promise.all(options.map(async (option) => {
619-
const current = await resolveCurrentStrategyForAccount({
620-
platform,
621-
option,
622-
optionsCount: options.length,
623-
repository,
624-
readVariable,
625-
});
626-
return [option.key, current];
627-
}));
612+
// Process platforms sequentially with inter-platform delay to avoid
613+
// GitHub secondary rate limiting from ~80+ concurrent requests.
614+
for (const platform of SUPPORTED_PLATFORMS) {
615+
const platformStrategies = await loadStrategiesForPlatform(platform, accountOptions, repositories, readVariable);
616+
if (Object.keys(platformStrategies).length) currentStrategies[platform] = platformStrategies;
617+
// 400ms gap between platforms lets the rate-limit window breathe
618+
await new Promise((r) => setTimeout(r, 400));
619+
}
620+
return currentStrategies;
621+
}
628622

629-
const platformStrategies = {};
630-
for (const [key, current] of optionResults) {
631-
if (current) platformStrategies[key] = current;
632-
}
633-
return [platform, platformStrategies];
623+
async function loadStrategiesForPlatform(platform, accountOptions, repositories, readVariable) {
624+
const options = Array.isArray(accountOptions[platform]) ? accountOptions[platform] : [];
625+
if (!options.length) return {};
626+
const repository = repositories[platform];
627+
if (!repository) return {};
628+
629+
const optionResults = await Promise.all(options.map(async (option) => {
630+
const current = await resolveCurrentStrategyForAccount({
631+
platform,
632+
option,
633+
optionsCount: options.length,
634+
repository,
635+
readVariable,
636+
});
637+
return [option.key, current];
634638
}));
635639

636-
for (const [platform, platformStrategies] of platformResults) {
637-
if (Object.keys(platformStrategies).length) currentStrategies[platform] = platformStrategies;
640+
const platformStrategies = {};
641+
for (const [key, current] of optionResults) {
642+
if (current) platformStrategies[key] = current;
638643
}
639-
return currentStrategies;
644+
return platformStrategies;
640645
}
641646

642647
async function loadCurrentStrategiesSafely(accountOptions, env) {
@@ -832,8 +837,10 @@ async function resolveCurrentStrategyForAccount({ platform, option, optionsCount
832837
}
833838

834839
// Fallback: use default_strategy_profile from account options when
835-
// no GitHub variables can be read (e.g. token lacks repo access),
836-
// or only partial cash/reserve data is available (RESERVED_CASH_VARIABLES).
840+
// GitHub variables are readable but account matching doesn't succeed.
841+
// This ensures all platforms always show a strategy, regardless of
842+
// GitHub variable matching quirks. The KV default is synced automatically
843+
// after each strategy switch via syncDefaultStrategyForAccount.
837844
const defaultProfile = cleanCurrentStrategy(option?.default_strategy_profile);
838845
if (defaultProfile) {
839846
return {

0 commit comments

Comments
 (0)