diff --git a/tests/account_diagnosis_targets_validation.mjs b/tests/account_diagnosis_targets_validation.mjs
index 2a0fbf80..72448782 100644
--- a/tests/account_diagnosis_targets_validation.mjs
+++ b/tests/account_diagnosis_targets_validation.mjs
@@ -1,10 +1,13 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
-const workerSource = readFileSync(new URL("../web/strategy-switch-console/worker.js", import.meta.url), "utf8");
-assert.match(workerSource, /"schwab\.primary": Object\.freeze\(/);
-assert.match(workerSource, /"firstrade\.primary": Object\.freeze\(/);
-assert.match(workerSource, /recheckRepository: "QuantStrategyLab\/CharlesSchwabPlatform"/);
-assert.match(workerSource, /recheckRepository: "QuantStrategyLab\/FirstradePlatform"/);
-assert.match(workerSource, /recheckWorkflow: "runtime-target-lifecycle\.yml"/);
+const diagnosisTargetsSource = [
+ readFileSync(new URL("../web/strategy-switch-console/worker.js", import.meta.url), "utf8"),
+ readFileSync(new URL("../web/strategy-switch-console/application/account_diagnosis/constants.js", import.meta.url), "utf8"),
+].join("\n");
+assert.match(diagnosisTargetsSource, /"schwab\.primary": Object\.freeze\(/);
+assert.match(diagnosisTargetsSource, /"firstrade\.primary": Object\.freeze\(/);
+assert.match(diagnosisTargetsSource, /recheckRepository: "QuantStrategyLab\/CharlesSchwabPlatform"/);
+assert.match(diagnosisTargetsSource, /recheckRepository: "QuantStrategyLab\/FirstradePlatform"/);
+assert.match(diagnosisTargetsSource, /recheckWorkflow: "runtime-target-lifecycle\.yml"/);
console.log("account_diagnosis_targets_validation: PASS (schwab.primary + firstrade.primary admitted)");
diff --git a/tests/account_facts_readonly_extract_validation.mjs b/tests/account_facts_readonly_extract_validation.mjs
index 5f09c66c..64bc5c6c 100644
--- a/tests/account_facts_readonly_extract_validation.mjs
+++ b/tests/account_facts_readonly_extract_validation.mjs
@@ -11,20 +11,26 @@ const workerSource = await readFile(
new URL("../web/strategy-switch-console/worker.js", import.meta.url),
"utf8",
);
+const supportSource = await readFile(
+ new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url),
+ "utf8",
+);
const readSource = await readFile(
new URL("../web/strategy-switch-console/application/account_facts/read.js", import.meta.url),
"utf8",
);
+const wiredSource = `${workerSource}\n${supportSource}`;
assert.equal(
- workerSource.includes('from "./application/account_facts/read.js"'),
+ workerSource.includes('from "./application/account_facts/read.js"')
+ || supportSource.includes('from "../account_facts/read.js"')
+ || supportSource.includes("from '../account_facts/read.js'"),
true,
- "Worker imports the B10-a account-facts read module",
+ "Worker stack imports the B10-a account-facts read module",
);
-assert.match(workerSource, /\/api\/account-facts"/);
-assert.match(workerSource, /\/api\/account-facts\/history"/);
-assert.match(workerSource, /async function syncAccountFactsResponse/);
-assert.equal(
+assert.match(wiredSource, /\/api\/account-facts"/);
+assert.match(wiredSource, /\/api\/account-facts\/history"/);
+assert.match(supportSource, /async function syncAccountFactsResponse/);assert.equal(
/transactionSync/.test(readSource),
false,
"read module must not open Durable Object transactions",
diff --git a/tests/account_facts_sync_extract_validation.mjs b/tests/account_facts_sync_extract_validation.mjs
index f1cb96a1..82cfc391 100644
--- a/tests/account_facts_sync_extract_validation.mjs
+++ b/tests/account_facts_sync_extract_validation.mjs
@@ -6,19 +6,26 @@ const workerSource = await readFile(
new URL("../web/strategy-switch-console/worker.js", import.meta.url),
"utf8",
);
+const supportSource = await readFile(
+ new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url),
+ "utf8",
+);
const syncSource = await readFile(
new URL("../web/strategy-switch-console/application/account_facts/sync.js", import.meta.url),
"utf8",
);
+const wiredSource = `${workerSource}\n${supportSource}`;
assert.equal(
- workerSource.includes('from "./application/account_facts/sync.js"'),
+ workerSource.includes('from "./application/account_facts/sync.js"')
+ || supportSource.includes('from "../account_facts/sync.js"')
+ || supportSource.includes("from '../account_facts/sync.js'"),
true,
- "Worker imports the B10-b account-facts sync module",
+ "Worker stack imports the B10-b account-facts sync module",
);
-assert.match(workerSource, /\/api\/account-facts\/sync"/);
-assert.match(workerSource, /async function syncAccountFactsResponse/);
-assert.match(workerSource, /syncAccountFactsResponseImpl/);
+assert.match(wiredSource, /\/api\/account-facts\/sync"/);
+assert.match(supportSource, /async function syncAccountFactsResponse/);
+assert.match(wiredSource, /syncAccountFactsResponseImpl/);
const syncSourceNoComments = syncSource.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
assert.equal(
/transactionSync/.test(syncSourceNoComments),
@@ -40,11 +47,11 @@ assert.equal(
true,
"sync still issues account_facts_put via injected repository",
);
-assert.match(workerSource, /async function syncAccountPeriodReturnResponse/);
+assert.match(wiredSource, /async function syncAccountPeriodReturnResponse|syncAccountPeriodReturnResponse/);
assert.equal(
/syncAccountPeriodReturnResponse/.test(syncSource),
false,
- "B10-b smallest slice: period-return sync stays in worker",
+ "B10-b smallest slice: period-return sync stays outside sync.js",
);
function json(payload, status = 200) {
diff --git a/tests/account_facts_validation.mjs b/tests/account_facts_validation.mjs
index 14f18d3a..4e506654 100644
--- a/tests/account_facts_validation.mjs
+++ b/tests/account_facts_validation.mjs
@@ -1960,12 +1960,15 @@ for (const platform of ["longbridge", "ibkr", "schwab", "firstrade"]) {
}
const workerSource = readFileSync(join(root, "web/strategy-switch-console/worker.js"), "utf8");
-assert.match(workerSource, /account_facts_put/);
-assert.match(workerSource, /account_facts_history_read|account_facts_daily/);
-assert.match(workerSource, /account_facts_stale_write|decideAccountFactsPut/);
-assert.doesNotMatch(workerSource, /writeConfigJson\(env, accountFactsStorageKey/);
-assert.doesNotMatch(workerSource, /account_facts:\$\{platform\}/);
-assert.match(workerSource, /\/api\/account-facts\/history/);
+const supportSource = readFileSync(join(root, "web/strategy-switch-console/application/worker/runtime_support.js"), "utf8");
+const durableSource = readFileSync(join(root, "web/strategy-switch-console/application/runtime_instances/durable_object.js"), "utf8");
+const wiredSource = `${workerSource}\n${supportSource}\n${durableSource}`;
+assert.match(wiredSource, /account_facts_put/);
+assert.match(wiredSource, /account_facts_history_read|account_facts_daily/);
+assert.match(wiredSource, /account_facts_stale_write|decideAccountFactsPut/);
+assert.doesNotMatch(wiredSource, /writeConfigJson\(env, accountFactsStorageKey/);
+assert.doesNotMatch(wiredSource, /account_facts:\$\{platform\}/);
+assert.match(wiredSource, /\/api\/account-facts\/history/);
await mf.dispose();
console.log("account_facts_validation ok");
diff --git a/tests/console_gap_contract_validation.mjs b/tests/console_gap_contract_validation.mjs
index 4cde582e..172dbe2f 100644
--- a/tests/console_gap_contract_validation.mjs
+++ b/tests/console_gap_contract_validation.mjs
@@ -130,7 +130,14 @@ for (const reason of controlReasons.filter(r => r !== "available")) {
}
const controlSource = readFileSync(new URL("../web/strategy-switch-console/application/console_api/run_controls.js", import.meta.url), "utf8");
const workerSource = readFileSync(new URL("../web/strategy-switch-console/worker.js", import.meta.url), "utf8");
+const supportSource = readFileSync(new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url), "utf8");
+const profileStateSources = [workerSource, supportSource]
+ .map((source) => {
+ const start = source.indexOf(" profileState: async () => {");
+ return start < 0 ? "" : source.slice(start).split("\n });")[0];
+ })
+ .join("\n");
const reasons = [...controlSource.matchAll(/(?:blocked\(|reason: )"([a-z_]+)"/g),
- ...workerSource.slice(workerSource.indexOf(" profileState: async () => {")).split("\n });")[0].matchAll(/reason: "([a-z_]+)"/g)].map(m => m[1]);
+ ...profileStateSources.matchAll(/reason: "([a-z_]+)"/g)].map(m => m[1]);
assert.deepEqual([...new Set(reasons)].sort(), [...controlReasons].sort(), "handoff reasons cover every current control gate");
console.log("console_gap_contract_validation: PASS (M0 12, currency 7, ten identities, failure/unknown/control semantics)");
diff --git a/tests/overview_fx_proxy_validation.mjs b/tests/overview_fx_proxy_validation.mjs
index e839856e..5fda7a90 100644
--- a/tests/overview_fx_proxy_validation.mjs
+++ b/tests/overview_fx_proxy_validation.mjs
@@ -14,14 +14,24 @@ const workerSource = await fs.readFile(
new URL("../web/strategy-switch-console/worker.js", import.meta.url),
"utf8",
);
+const supportSource = await fs.readFile(
+ new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url),
+ "utf8",
+);
const fxSource = await fs.readFile(
new URL("../web/strategy-switch-console/infrastructure/fx/overview_fx.js", import.meta.url),
"utf8",
);
-assert.match(workerSource, /connect-src 'self'/, "CSP stays same-origin; Frankfurter is not widened into connect-src");
+assert.match(supportSource, /connect-src 'self'/, "CSP stays same-origin; Frankfurter is not widened into connect-src");
assert.equal(fxSource.includes("api.frankfurter.dev"), true, "FX module retains the fixed Frankfurter upstream");
-assert.equal(workerSource.includes("infrastructure/fx/overview_fx.js"), true, "Worker imports the FX module");
-assert.equal(/connect-src[^;]*frankfurter/.test(workerSource), false, "browser CSP must not allow frankfurter");
+assert.equal(
+ workerSource.includes("infrastructure/fx/overview_fx.js")
+ || supportSource.includes("infrastructure/fx/overview_fx.js"),
+ true,
+ "Worker stack imports the FX module",
+);
+assert.equal(/connect-src[^;]*frankfurter/.test(supportSource), false, "browser CSP must not allow frankfurter");
+assert.equal(/connect-src[^;]*frankfurter/.test(workerSource), false, "facade CSP must not allow frankfurter");
__test.resetOverviewFxCache();
const frankfurterBody = JSON.stringify({
diff --git a/tests/owner_decision_extract_validation.mjs b/tests/owner_decision_extract_validation.mjs
index 2b5884fe..9a831ead 100644
--- a/tests/owner_decision_extract_validation.mjs
+++ b/tests/owner_decision_extract_validation.mjs
@@ -9,21 +9,28 @@ const workerSource = await readFile(
new URL("../web/strategy-switch-console/worker.js", import.meta.url),
"utf8",
);
+const supportSource = await readFile(
+ new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url),
+ "utf8",
+);
const moduleSource = await readFile(
new URL("../web/strategy-switch-console/application/approval/owner_decisions.js", import.meta.url),
"utf8",
);
+const wiredSource = `${workerSource}\n${supportSource}`;
assert.equal(
- workerSource.includes('from "./application/approval/owner_decisions.js"'),
+ workerSource.includes('from "./application/approval/owner_decisions.js"')
+ || supportSource.includes('from "../approval/owner_decisions.js"')
+ || supportSource.includes("from '../approval/owner_decisions.js'"),
true,
- "Worker imports the B10-c owner-decision module",
+ "Worker stack imports the B10-c owner-decision module",
);
-assert.match(workerSource, /\/api\/owner-decisions"/);
-assert.match(workerSource, /ownerDecisionQueueResponseImpl/);
-assert.match(workerSource, /recordOwnerDecisionResponseImpl/);
-assert.match(workerSource, /async function ownerDecisionQueueResponse/);
-assert.match(workerSource, /async function recordOwnerDecisionResponse/);
+assert.match(wiredSource, /\/api\/owner-decisions"/);
+assert.match(wiredSource, /ownerDecisionQueueResponseImpl/);
+assert.match(wiredSource, /recordOwnerDecisionResponseImpl/);
+assert.match(supportSource, /async function ownerDecisionQueueResponse/);
+assert.match(supportSource, /async function recordOwnerDecisionResponse/);
const moduleNoComments = moduleSource.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
assert.equal(
diff --git a/tests/reconciliation_material_presentation_validation.mjs b/tests/reconciliation_material_presentation_validation.mjs
index e4005310..b8d568df 100644
--- a/tests/reconciliation_material_presentation_validation.mjs
+++ b/tests/reconciliation_material_presentation_validation.mjs
@@ -16,10 +16,20 @@ import { recoveryMaterialPresentation, currentReconciliationObservationPresentat
// Exercise the production aggregation/freshness functions with in-memory inputs.
// No Worker, storage adapter, KV, server, or network is instantiated.
const workerText = readFileSync(new URL("../web/strategy-switch-console/worker.js", import.meta.url), "utf8");
+const runtimeSupportText = readFileSync(
+ new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url),
+ "utf8",
+);
function productionFunction(name, dependencies = {}) {
- const start = workerText.search(new RegExp(`(?:async )?function ${name}\\(`));
+ const pattern = new RegExp(`(?:export )?(?:async )?function ${name}\\(`);
+ let source = workerText;
+ let start = source.search(pattern);
+ if (start < 0) {
+ source = runtimeSupportText;
+ start = source.search(pattern);
+ }
assert.ok(start >= 0, name);
- const code = workerText.slice(start, workerText.indexOf("\n}", start) + 2);
+ const code = source.slice(start, source.indexOf("\n}", start) + 2).replace(/^export\s+/, "");
return new Function(...Object.keys(dependencies), `return (${code});`)(...Object.values(dependencies));
}
const now = Date.parse("2001-10-17T04:05:00Z");
diff --git a/tests/research_promotion_application_extract_validation.mjs b/tests/research_promotion_application_extract_validation.mjs
index ae5a25c3..da4f2609 100644
--- a/tests/research_promotion_application_extract_validation.mjs
+++ b/tests/research_promotion_application_extract_validation.mjs
@@ -9,26 +9,36 @@ const workerSource = await readFile(
new URL("../web/strategy-switch-console/worker.js", import.meta.url),
"utf8",
);
+const supportSource = await readFile(
+ new URL("../web/strategy-switch-console/application/worker/runtime_support.js", import.meta.url),
+ "utf8",
+);
+const durableSource = await readFile(
+ new URL("../web/strategy-switch-console/application/runtime_instances/durable_object.js", import.meta.url),
+ "utf8",
+);
const moduleSource = await readFile(
new URL("../web/strategy-switch-console/application/research_promotion/applications.js", import.meta.url),
"utf8",
);
+const wiredSource = `${workerSource}\n${supportSource}`;
assert.equal(
- workerSource.includes('from "./application/research_promotion/applications.js"'),
+ workerSource.includes('from "./application/research_promotion/applications.js"')
+ || supportSource.includes('from "../research_promotion/applications.js"')
+ || supportSource.includes("from '../research_promotion/applications.js'"),
true,
- "Worker imports the B10-d research-promotion applications module",
+ "Worker stack imports the B10-d research-promotion applications module",
);
-assert.match(workerSource, /\/api\/research-promotion-applications"/);
-assert.match(workerSource, /\/api\/internal\/research-promotion-application\//);
-assert.match(workerSource, /researchPromotionApplicationResponseImpl/);
-assert.match(workerSource, /researchPromotionApplicationInternalResponseImpl/);
-assert.match(workerSource, /async function researchPromotionApplicationResponse/);
-assert.match(workerSource, /async function researchPromotionApplicationInternalResponse/);
-assert.match(workerSource, /function applicationIdFromPath/);
-assert.match(workerSource, /function validateV7PaperApplicationReadback/);
-assert.match(workerSource, /CREATE TABLE IF NOT EXISTS research_promotion_applications/);
-
+assert.match(wiredSource, /\/api\/research-promotion-applications"/);
+assert.match(wiredSource, /\/api\/internal\/research-promotion-application\//);
+assert.match(wiredSource, /researchPromotionApplicationResponseImpl/);
+assert.match(wiredSource, /researchPromotionApplicationInternalResponseImpl/);
+assert.match(supportSource, /async function researchPromotionApplicationResponse/);
+assert.match(supportSource, /async function researchPromotionApplicationInternalResponse/);
+assert.match(supportSource, /function applicationIdFromPath|applicationIdFromPath/);
+assert.match(supportSource, /function validateV7PaperApplicationReadback|validateV7PaperApplicationReadback/);
+assert.match(durableSource, /CREATE TABLE IF NOT EXISTS research_promotion_applications/);
const moduleNoComments = moduleSource.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
assert.equal(
/transactionSync/.test(moduleNoComments),
diff --git a/tests/runtime_instances_worker_validation.mjs b/tests/runtime_instances_worker_validation.mjs
index f76ae151..ade8e349 100644
--- a/tests/runtime_instances_worker_validation.mjs
+++ b/tests/runtime_instances_worker_validation.mjs
@@ -147,7 +147,10 @@ try {
mf = new Miniflare({ ...options, durableObjectsPersist: false,
durableObjects: { STRATEGY_SWITCH_RUNTIME_INSTANCES: { className: "FailingRuntimeInstances", useSQLite: true } },
script: source + `\nexport class FailingRuntimeInstances extends RuntimeInstances {
- constructor(ctx) { super(ctx); this.sql.exec("CREATE TRIGGER IF NOT EXISTS fail_history BEFORE INSERT ON instance_history WHEN NEW.revision = 2 BEGIN SELECT RAISE(ABORT, 'fixture rollback'); END"); }
+ constructor(ctx, env) {
+ super(ctx, env);
+ this.sql.exec("CREATE TRIGGER IF NOT EXISTS fail_history BEFORE INSERT ON instance_history WHEN NEW.revision = 2 BEGIN SELECT RAISE(ABORT, 'fixture rollback'); END");
+ }
}`,
});
assert.equal((await call({ action: "initialize", expected_revision: 0, confirm: "IMPORT_EXISTING_CONFIG" })).status, 200);
diff --git a/tests/ux1_research_worker_validation.mjs b/tests/ux1_research_worker_validation.mjs
index f8fc4ad6..b096dbbb 100644
--- a/tests/ux1_research_worker_validation.mjs
+++ b/tests/ux1_research_worker_validation.mjs
@@ -569,8 +569,15 @@ try {
assert.equal(__test.ux1CalculatorDeadlineMs, 30000);
assert.equal(__test.ux1CalculatorMaxBytes, 65536);
- const workerSource = await readFile(new URL("../web/strategy-switch-console/worker.js", import.meta.url), "utf8");
- const previewFn = workerSource.slice(workerSource.indexOf("async function ux1PreviewPost"), workerSource.indexOf("async function ux1IntentPost"));
+ // Implementation lives in application/ux1/research.js; worker.js only imports and routes.
+ const ux1ResearchSource = await readFile(
+ new URL("../web/strategy-switch-console/application/ux1/research.js", import.meta.url),
+ "utf8",
+ );
+ const previewStart = ux1ResearchSource.indexOf("async function ux1PreviewPost");
+ const intentStart = ux1ResearchSource.indexOf("async function ux1IntentPost");
+ assert.equal(previewStart >= 0 && intentStart > previewStart, true);
+ const previewFn = ux1ResearchSource.slice(previewStart, intentStart);
assert.equal(previewFn.includes("readUx1CalculatorExchange(binding, canonicalJson(calculatorRequest))"), true);
assert.equal(previewFn.includes("deadlineMs"), false);
assert.equal(previewFn.includes("maxBytes"), false);
diff --git a/web/strategy-switch-console/application/account_diagnosis/constants.js b/web/strategy-switch-console/application/account_diagnosis/constants.js
new file mode 100644
index 00000000..b784fb3c
--- /dev/null
+++ b/web/strategy-switch-console/application/account_diagnosis/constants.js
@@ -0,0 +1,62 @@
+export const ACCOUNT_DIAGNOSIS_REQUEST_PATH = "/api/account-diagnosis";
+export const ACCOUNT_DIAGNOSIS_INTERNAL_PREFIX = "/api/internal/account-diagnosis/";
+export const ACCOUNT_DIAGNOSIS_TARGET_ID = "binance.crypto_live_pool_rotation";
+export const ACCOUNT_DIAGNOSIS_TARGETS = Object.freeze({
+ [ACCOUNT_DIAGNOSIS_TARGET_ID]: Object.freeze({
+ platform: "binance",
+ recheckRepository: "QuantStrategyLab/BinancePlatform",
+ recheckWorkflow: "runtime-target-lifecycle.yml",
+ }),
+ "longbridge.paper": Object.freeze({
+ platform: "longbridge",
+ recheckRepository: "QuantStrategyLab/LongBridgePlatform",
+ recheckWorkflow: "runtime-target-lifecycle.yml",
+ }),
+ "longbridge.hk": Object.freeze({
+ platform: "longbridge",
+ recheckRepository: "QuantStrategyLab/LongBridgePlatform",
+ recheckWorkflow: "runtime-target-lifecycle.yml",
+ }),
+ "longbridge.sg": Object.freeze({
+ platform: "longbridge",
+ recheckRepository: "QuantStrategyLab/LongBridgePlatform",
+ recheckWorkflow: "runtime-target-lifecycle.yml",
+ }),
+ "schwab.primary": Object.freeze({
+ platform: "schwab",
+ recheckRepository: "QuantStrategyLab/CharlesSchwabPlatform",
+ recheckWorkflow: "runtime-target-lifecycle.yml",
+ }),
+ "firstrade.primary": Object.freeze({
+ platform: "firstrade",
+ recheckRepository: "QuantStrategyLab/FirstradePlatform",
+ recheckWorkflow: "runtime-target-lifecycle.yml",
+ }),
+});
+export const ACCOUNT_DIAGNOSIS_TRIGGERS = ["incident", "manual_check"];
+export const ACCOUNT_DIAGNOSIS_STATUSES = ["queued", "running", "succeeded", "failed", "unknown"];
+export const ACCOUNT_DIAGNOSIS_REASON_CODES = ["diagnosis_ready", "capacity_unavailable", "codex_unavailable", "invalid_response"];
+export const ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES = 16 * 1024;
+export const ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS = 600;
+export const ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS = 24 * 60 * 60 * 1000;
+export const ACCOUNT_DIAGNOSIS_AUTO_ENABLED_ENV = "ACCOUNT_DIAGNOSIS_AUTO_ENABLED";
+export const ACCOUNT_DIAGNOSIS_DO_ACTIONS = new Set([
+ "diagnosis_create", "diagnosis_latest", "diagnosis_read", "diagnosis_mark_dispatch", "diagnosis_claim", "diagnosis_result", "diagnosis_mark_recheck", "diagnosis_native_intent", "diagnosis_native_save", "diagnosis_native_cancel",
+]);
+/** Stable 409/qualification reason codes for /api/account-diagnosis (P0-08). */
+export const ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT = Object.freeze({
+ account_diagnosis_config_unavailable: "账户选项配置不可用,无法绑定诊断身份。",
+ account_diagnosis_account_not_found: "未找到匹配的账户选项。",
+ account_diagnosis_account_not_unique: "账户选项不唯一,无法安全绑定诊断身份。",
+ account_diagnosis_target_not_admitted: "该 target 未纳入账户诊断准入清单。",
+ account_diagnosis_identity_conflict: "target 与账户身份冲突或不唯一。",
+ account_diagnosis_lifecycle_store_unavailable: "生命周期配置存储不可用。",
+ account_diagnosis_lifecycle_match_missing: "缺少匹配的生命周期观测来源。",
+ account_diagnosis_lifecycle_match_ambiguous: "生命周期观测来源不唯一。",
+ account_diagnosis_source_unavailable: "生命周期来源不可用(非 ready/stale)。",
+ account_diagnosis_observation_missing: "缺少观测时间,无法确认诊断资格。",
+ account_diagnosis_incident_requires_attention: "incident 触发需要已确认的监测关注项。",
+ account_diagnosis_native_binding_conflict: "诊断原生任务身份或材料绑定冲突。",
+ account_diagnosis_workflow_binding_conflict: "诊断工作流运行绑定冲突。",
+ account_diagnosis_schema_incompatible: "诊断上下文 schema 不兼容。",
+});
diff --git a/web/strategy-switch-console/application/account_diagnosis/helpers.js b/web/strategy-switch-console/application/account_diagnosis/helpers.js
new file mode 100644
index 00000000..e88aea1f
--- /dev/null
+++ b/web/strategy-switch-console/application/account_diagnosis/helpers.js
@@ -0,0 +1,40 @@
+import { HttpError } from "../http_error.js";
+import { ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT } from "./constants.js";
+
+export function accountDiagnosisConflict(reasonCode, status = 409) {
+ const reason = ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT[reasonCode] || "";
+ return new HttpError(reasonCode, status, { reason_code: reasonCode, reason });
+}
+export function accountDiagnosisErrorPayload(error) {
+ const reason_code = String(error?.reason_code || error?.message || "account_diagnosis_unavailable");
+ const payload = { ok: false, error: reason_code, reason_code };
+ const reason = String(error?.reason || ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT[reason_code] || "").trim();
+ if (reason) payload.reason = reason;
+ return payload;
+}
+export function accountDiagnosisTaskFromRow(row) {
+ if (!row) return null;
+ return {
+ request_id: row.request_id,
+ platform: row.platform,
+ key: row.account_key,
+ target_id: row.target_id,
+ trigger: row.trigger,
+ observed_at: row.observed_at,
+ checks: JSON.parse(row.checks_json),
+ state_fingerprint: row.state_fingerprint,
+ status: row.status,
+ native: row.native_json ? JSON.parse(row.native_json) : null,
+ backend_kind: row.native_json ? "native" : "legacy",
+ workflow_run_id: row.workflow_run_id || null,
+ workflow_run_attempt: row.workflow_run_attempt || null,
+ job_id: row.job_id || null,
+ summary: row.summary || "",
+ reason_code: row.reason_code || "",
+ dispatch_state: row.dispatch_state,
+ recheck_dispatch_state: row.recheck_dispatch_state,
+ auto_source: row.auto_source || "manual",
+ created_at: row.created_at,
+ updated_at: row.updated_at,
+ };
+}
diff --git a/web/strategy-switch-console/application/auth/constants.js b/web/strategy-switch-console/application/auth/constants.js
new file mode 100644
index 00000000..c9476bba
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/constants.js
@@ -0,0 +1,6 @@
+export const SESSION_COOKIE = "qsl_switch_session";
+export const OAUTH_STATE_COOKIE = "qsl_switch_oauth_state";
+export const SESSION_TTL_SECONDS = 8 * 60 * 60;
+export const AUTH_CONFIG_KEY = "auth_config";
+export const GITHUB_LOGIN_REQUEST_TIMEOUT_MS = 20000;
+export const GITHUB_API_TIMEOUT_MS = 8000;
diff --git a/web/strategy-switch-console/application/auth/cookies.js b/web/strategy-switch-console/application/auth/cookies.js
new file mode 100644
index 00000000..de4a7f56
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/cookies.js
@@ -0,0 +1,47 @@
+import { OAUTH_STATE_COOKIE } from "./constants.js";
+
+export function randomToken() {
+ const bytes = new Uint8Array(24);
+ crypto.getRandomValues(bytes);
+ return base64UrlEncodeBytes(bytes);
+}
+
+export function base64UrlEncodeJson(value) {
+ return base64UrlEncodeBytes(new TextEncoder().encode(JSON.stringify(value)));
+}
+
+export function base64UrlEncodeBytes(bytes) {
+ let binary = "";
+ for (const byte of bytes) binary += String.fromCharCode(byte);
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
+}
+
+export function base64UrlDecode(value) {
+ const base64 = value.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
+ const binary = atob(base64);
+ const bytes = new Uint8Array(binary.length);
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
+ return new TextDecoder().decode(bytes);
+}
+
+export function parseCookies(header) {
+ const result = {};
+ for (const part of header.split(";")) {
+ const [name, ...rest] = part.trim().split("=");
+ if (!name) continue;
+ result[name] = decodeURIComponent(rest.join("="));
+ }
+ return result;
+}
+
+export function cookie(name, value, maxAge) {
+ return `${name}=${encodeURIComponent(value)}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=${maxAge}`;
+}
+
+export function clearCookie(name) {
+ return `${name}=; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=0`;
+}
+
+export function clearOAuthCookie() {
+ return { "Set-Cookie": clearCookie(OAUTH_STATE_COOKIE) };
+}
diff --git a/web/strategy-switch-console/application/auth/fetch.js b/web/strategy-switch-console/application/auth/fetch.js
new file mode 100644
index 00000000..b1802e22
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/fetch.js
@@ -0,0 +1,14 @@
+import { GITHUB_API_TIMEOUT_MS } from "./constants.js";
+
+export async function fetchWithTimeout(resource, init = {}, timeoutMs = GITHUB_API_TIMEOUT_MS, fetchImpl = fetch) {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
+ try {
+ return await fetchImpl(resource, { ...init, signal: controller.signal });
+ } catch (error) {
+ if (error?.name === "AbortError") throw new Error("GitHub request timed out");
+ throw error;
+ } finally {
+ clearTimeout(timeoutId);
+ }
+}
diff --git a/web/strategy-switch-console/application/auth/github.js b/web/strategy-switch-console/application/auth/github.js
new file mode 100644
index 00000000..f991d80b
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/github.js
@@ -0,0 +1,31 @@
+import { fetchWithTimeout } from "./fetch.js";
+import { GITHUB_API_TIMEOUT_MS } from "./constants.js";
+import { cleanGithubOrg, uniqueStrings } from "./identity_lists.js";
+
+export function githubHeaders(token) {
+ return {
+ Authorization: `Bearer ${token}`,
+ Accept: "application/vnd.github+json",
+ "Content-Type": "application/json",
+ "User-Agent": "QuantRuntimeSettings-StrategySwitchConsole",
+ "X-GitHub-Api-Version": "2022-11-28",
+ };
+}
+
+export async function fetchGithubOrgLogins(token, timeoutMs = GITHUB_API_TIMEOUT_MS) {
+ const orgs = [];
+ for (let page = 1; page <= 5; page += 1) {
+ const response = await fetchWithTimeout(`https://api.github.com/user/orgs?per_page=100&page=${page}`, {
+ headers: githubHeaders(token),
+ }, timeoutMs);
+ if (!response.ok) return orgs;
+ const payload = await response.json();
+ if (!Array.isArray(payload) || !payload.length) break;
+ for (const org of payload) {
+ const login = cleanGithubOrg(org?.login || "", "github org");
+ if (login) orgs.push(login);
+ }
+ if (payload.length < 100) break;
+ }
+ return uniqueStrings(orgs);
+}
diff --git a/web/strategy-switch-console/application/auth/identity_lists.js b/web/strategy-switch-console/application/auth/identity_lists.js
new file mode 100644
index 00000000..77e3e6df
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/identity_lists.js
@@ -0,0 +1,48 @@
+export function parseLoginList(value, fieldName) {
+ return normalizeLoginList(value, fieldName);
+}
+
+export function normalizeLoginList(value, fieldName) {
+ const items = Array.isArray(value) ? value : String(value || "").split(/[\s,]+/);
+ if (items.length > 80) throw new Error(`${fieldName} supports at most 80 logins`);
+ return uniqueStrings(items.map((item) => cleanGithubLogin(item, fieldName)).filter(Boolean));
+}
+
+export function parseOrgList(value, fieldName) {
+ return normalizeOrgList(value, fieldName);
+}
+
+export function normalizeOrgList(value, fieldName) {
+ const items = Array.isArray(value) ? value : String(value || "").split(/[\s,]+/);
+ if (items.length > 80) throw new Error(`${fieldName} supports at most 80 orgs`);
+ return uniqueStrings(items.map((item) => cleanGithubOrg(item, fieldName)).filter(Boolean));
+}
+
+export function cleanGithubLogin(value, fieldName) {
+ const login = String(value || "").trim().toLowerCase();
+ if (!login) return "";
+ if (
+ login.length > 39 ||
+ !/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(login) ||
+ login.includes("--")
+ ) {
+ throw new Error(`${fieldName} contains an invalid GitHub login`);
+ }
+ return login;
+}
+
+export function cleanGithubOrg(value, fieldName) {
+ return cleanGithubLogin(value, fieldName);
+}
+
+export function uniqueStrings(items) {
+ const result = [];
+ const seen = new Set();
+ for (const item of items) {
+ const text = String(item || "").trim().toLowerCase();
+ if (!text || seen.has(text)) continue;
+ seen.add(text);
+ result.push(text);
+ }
+ return result;
+}
diff --git a/web/strategy-switch-console/application/auth/login.js b/web/strategy-switch-console/application/auth/login.js
new file mode 100644
index 00000000..4d862453
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/login.js
@@ -0,0 +1,137 @@
+import { SESSION_COOKIE, OAUTH_STATE_COOKIE, GITHUB_LOGIN_REQUEST_TIMEOUT_MS, SESSION_TTL_SECONDS } from "./constants.js";
+import { requireEnv } from "./require_env.js";
+import { randomToken, cookie, clearOAuthCookie, parseCookies, clearCookie } from "./cookies.js";
+import { redirect, html } from "../http_response.js";
+import { renderMessage, escapeHtml } from "../html_message.js";
+import { fetchWithTimeout } from "./fetch.js";
+import { githubHeaders, fetchGithubOrgLogins } from "./github.js";
+import { loadAuthConfig, isAllowedPrincipal, authorizedOrgLogins } from "./principals.js";
+import { makeSession } from "./session.js";
+
+export async function startLogin(request, env) {
+ requireEnv(env, "GITHUB_CLIENT_ID");
+ const url = new URL(request.url);
+ const state = randomToken();
+ const authorizeUrl = new URL("https://github.com/login/oauth/authorize");
+ authorizeUrl.searchParams.set("client_id", env.GITHUB_CLIENT_ID);
+ authorizeUrl.searchParams.set("redirect_uri", `${url.origin}/callback`);
+ authorizeUrl.searchParams.set("scope", "read:user read:org");
+ authorizeUrl.searchParams.set("state", state);
+ return redirect(authorizeUrl.toString(), {
+ "Set-Cookie": cookie(OAUTH_STATE_COOKIE, state, 600),
+ });
+}
+
+export async function finishLogin(request, env) {
+ requireEnv(env, "GITHUB_CLIENT_ID");
+ requireEnv(env, "GITHUB_CLIENT_SECRET");
+ requireEnv(env, "SESSION_SECRET");
+
+ const url = new URL(request.url);
+ const code = url.searchParams.get("code") || "";
+ const state = url.searchParams.get("state") || "";
+ const cookies = parseCookies(request.headers.get("Cookie") || "");
+ if (!code || !state || cookies[OAUTH_STATE_COOKIE] !== state) {
+ return html(renderMessage("登录失败", "OAuth state 校验失败,请重新登录。"), 400, clearOAuthCookie());
+ }
+
+ const tokenStage = await runLoginGithubStage("token_exchange", () => fetchWithTimeout("https://github.com/login/oauth/access_token", {
+ method: "POST",
+ headers: {
+ Accept: "application/json",
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ client_id: env.GITHUB_CLIENT_ID,
+ client_secret: env.GITHUB_CLIENT_SECRET,
+ code,
+ redirect_uri: `${url.origin}/callback`,
+ }),
+ }, GITHUB_LOGIN_REQUEST_TIMEOUT_MS));
+ if (tokenStage.timedOut) return loginTimeoutResponse("token_exchange");
+ const tokenResponse = tokenStage.value;
+ const tokenPayload = await tokenResponse.json();
+ const tokenPayloadIsObject = tokenPayload !== null && typeof tokenPayload === "object";
+ if (!tokenResponse.ok || !tokenPayloadIsObject || !tokenPayload.access_token) {
+ const status = Number.isSafeInteger(tokenResponse?.status) ? tokenResponse.status : null;
+ const allowedOauthErrors = new Set([
+ "incorrect_client_credentials",
+ "redirect_uri_mismatch",
+ "bad_verification_code",
+ "unverified_user_email",
+ ]);
+ const errorCategory = tokenPayloadIsObject && typeof tokenPayload.error === "string"
+ && allowedOauthErrors.has(tokenPayload.error)
+ ? tokenPayload.error
+ : "unknown";
+ console.warn("github_token_exchange_failed", {
+ http_status: status,
+ error_category: errorCategory,
+ });
+ const statusLabel = status === null ? "不可用" : String(status);
+ return html(
+ renderMessage("登录失败", `GitHub 凭证交换未成功(HTTP ${statusLabel},类别:${errorCategory})。请从登录入口重新开始。`),
+ 502,
+ clearOAuthCookie(),
+ );
+ }
+
+ const userStage = await runLoginGithubStage("user_lookup", () => fetchWithTimeout("https://api.github.com/user", {
+ headers: githubHeaders(tokenPayload.access_token),
+ }, GITHUB_LOGIN_REQUEST_TIMEOUT_MS));
+ if (userStage.timedOut) return loginTimeoutResponse("user_lookup");
+ const userResponse = userStage.value;
+ const user = await userResponse.json();
+ const login = String(user.login || "").toLowerCase();
+ if (!userResponse.ok || !login) {
+ return html(renderMessage("登录失败", "无法读取 GitHub 用户。"), 502, clearOAuthCookie());
+ }
+
+ const authConfig = await loadAuthConfig(env);
+ const orgStage = await runLoginGithubStage("organization_lookup", () => fetchGithubOrgLogins(
+ tokenPayload.access_token,
+ GITHUB_LOGIN_REQUEST_TIMEOUT_MS,
+ ));
+ if (orgStage.timedOut) return loginTimeoutResponse("organization_lookup");
+ const orgLogins = orgStage.value;
+ if (!isAllowedPrincipal(login, orgLogins, authConfig)) {
+ return html(renderMessage("没有权限", `${login} 不在允许登录名单或组织中。`), 403, clearOAuthCookie());
+ }
+
+ const session = await makeSession(login, authorizedOrgLogins(orgLogins, authConfig), env);
+ return redirect("/", {
+ "Set-Cookie": [
+ cookie(SESSION_COOKIE, session, SESSION_TTL_SECONDS),
+ clearCookie(OAUTH_STATE_COOKIE),
+ ],
+ });
+}
+
+export async function runLoginGithubStage(stage, operation) {
+ const startedAt = Date.now();
+ try {
+ return { timedOut: false, value: await operation() };
+ } catch (error) {
+ if (error?.message !== "GitHub request timed out") throw error;
+ console.warn("github_login_request_timed_out", {
+ stage,
+ timeout_ms: GITHUB_LOGIN_REQUEST_TIMEOUT_MS,
+ elapsed_ms: Math.max(0, Date.now() - startedAt),
+ });
+ return { timedOut: true };
+ }
+}
+
+export function loginTimeoutResponse(stage) {
+ const stageLabels = {
+ token_exchange: "登录凭证交换",
+ user_lookup: "读取用户身份",
+ organization_lookup: "核对组织权限",
+ };
+ const stageLabel = stageLabels[stage] || "登录请求处理";
+ return html(
+ renderMessage("登录超时", `${stageLabel}超时,请从登录入口重新开始。此回调链接已失效,请勿复用。`),
+ 504,
+ clearOAuthCookie(),
+ );
+}
diff --git a/web/strategy-switch-console/application/auth/principals.js b/web/strategy-switch-console/application/auth/principals.js
new file mode 100644
index 00000000..ccdf4bbd
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/principals.js
@@ -0,0 +1,88 @@
+import {
+ AUTH_CONFIG_KEY,
+} from "./constants.js";
+import { hasConfigStore, readConfigJson } from "../config_kv.js";
+import { uniqueStrings, parseLoginList, parseOrgList, normalizeLoginList, normalizeOrgList, cleanGithubLogin, cleanGithubOrg } from "./identity_lists.js";
+
+export async function loadAuthConfig(env) {
+ const bootstrapAdmins = parseLoginList(env.STRATEGY_SWITCH_ADMIN_LOGINS || "", "STRATEGY_SWITCH_ADMIN_LOGINS");
+ const bootstrapAdminOrgs = parseOrgList(env.STRATEGY_SWITCH_ADMIN_ORGS || "", "STRATEGY_SWITCH_ADMIN_ORGS");
+ const envAllowed = parseLoginList(
+ env.ALLOWED_GITHUB_LOGINS || env.ALLOWED_GITHUB_LOGIN || "",
+ "ALLOWED_GITHUB_LOGINS",
+ );
+ const envAllowedOrgs = parseOrgList(
+ env.ALLOWED_GITHUB_ORGS || env.ALLOWED_GITHUB_ORG || "",
+ "ALLOWED_GITHUB_ORGS",
+ );
+ let storedAllowed = [];
+ let storedAllowedOrgs = [];
+ let storedAdmins = [];
+ let storedAdminOrgs = [];
+ let source = "secret";
+ if (hasConfigStore(env)) {
+ const stored = await readConfigJson(env, AUTH_CONFIG_KEY);
+ if (stored) {
+ const normalized = normalizeAuthConfigPayload(stored, AUTH_CONFIG_KEY);
+ storedAllowed = normalized.allowed_logins;
+ storedAllowedOrgs = normalized.allowed_orgs;
+ storedAdmins = normalized.admin_logins;
+ storedAdminOrgs = normalized.admin_orgs;
+ source = "kv";
+ }
+ }
+ const adminLogins = uniqueStrings([...bootstrapAdmins, ...storedAdmins]);
+ const adminOrgs = uniqueStrings([...bootstrapAdminOrgs, ...storedAdminOrgs]);
+ const allowedLogins = uniqueStrings([...envAllowed, ...storedAllowed, ...adminLogins]);
+ const allowedOrgs = uniqueStrings([...envAllowedOrgs, ...storedAllowedOrgs]);
+ return {
+ allowed_logins: allowedLogins,
+ allowed_orgs: allowedOrgs,
+ admin_logins: adminLogins,
+ admin_orgs: adminOrgs,
+ bootstrap_admin_logins: bootstrapAdmins,
+ bootstrap_admin_orgs: bootstrapAdminOrgs,
+ env_allowed_logins: envAllowed,
+ env_allowed_orgs: envAllowedOrgs,
+ source,
+ kv_available: hasConfigStore(env),
+ };
+}
+
+export function normalizeAuthConfigPayload(payload, fieldName) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ return {
+ allowed_logins: normalizeLoginList(payload.allowed_logins || [], `${fieldName}.allowed_logins`),
+ allowed_orgs: normalizeOrgList(payload.allowed_orgs || [], `${fieldName}.allowed_orgs`),
+ admin_logins: normalizeLoginList(payload.admin_logins || [], `${fieldName}.admin_logins`),
+ admin_orgs: normalizeOrgList(payload.admin_orgs || [], `${fieldName}.admin_orgs`),
+ };
+}
+export function isAdminLogin(login, orgLogins, authConfig) {
+ return authConfig.admin_logins.includes(String(login || "").toLowerCase());
+}
+
+export function isAdminPrincipal(login, orgLogins, authConfig) {
+ return isAdminLogin(login, orgLogins, authConfig) || hasOrgMatch(orgLogins, authConfig.admin_orgs);
+}
+
+export function isAllowedPrincipal(login, orgLogins, authConfig) {
+ const normalizedLogin = String(login || "").toLowerCase();
+ return (
+ authConfig.allowed_logins.includes(normalizedLogin) ||
+ hasOrgMatch(orgLogins, authConfig.allowed_orgs) ||
+ isAdminPrincipal(normalizedLogin, orgLogins, authConfig)
+ );
+}
+
+export function authorizedOrgLogins(orgLogins, authConfig) {
+ const authorized = new Set([...authConfig.allowed_orgs, ...authConfig.admin_orgs]);
+ return uniqueStrings(orgLogins).filter((org) => authorized.has(org));
+}
+
+export function hasOrgMatch(orgLogins, configuredOrgs) {
+ const orgs = new Set(uniqueStrings(orgLogins));
+ return configuredOrgs.some((org) => orgs.has(String(org || "").toLowerCase()));
+}
diff --git a/web/strategy-switch-console/application/auth/require_env.js b/web/strategy-switch-console/application/auth/require_env.js
new file mode 100644
index 00000000..0d580969
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/require_env.js
@@ -0,0 +1,3 @@
+export function requireEnv(env, name) {
+ if (!env[name]) throw new Error(`${name} is not configured`);
+}
diff --git a/web/strategy-switch-console/application/auth/session.js b/web/strategy-switch-console/application/auth/session.js
new file mode 100644
index 00000000..a5404099
--- /dev/null
+++ b/web/strategy-switch-console/application/auth/session.js
@@ -0,0 +1,47 @@
+import { HttpError } from "../http_error.js";
+import {
+ SESSION_COOKIE,
+ SESSION_TTL_SECONDS,
+ AUTH_CONFIG_KEY,
+} from "./constants.js";
+import { parseCookies, base64UrlEncodeJson, base64UrlEncodeBytes, base64UrlDecode } from "./cookies.js";
+import { loadAuthConfig, isAllowedPrincipal, isAdminPrincipal } from "./principals.js";
+import { normalizeOrgList, uniqueStrings } from "./identity_lists.js";
+
+export async function makeSession(login, orgs, env) {
+ const payload = base64UrlEncodeJson({
+ login,
+ orgs: uniqueStrings(orgs),
+ exp: Math.floor(Date.now() / 1000) + SESSION_TTL_SECONDS,
+ });
+ const signature = await hmac(payload, env.SESSION_SECRET);
+ return `${payload}.${signature}`;
+}
+
+export async function readSession(request, env) {
+ if (!env.SESSION_SECRET) return null;
+ const cookies = parseCookies(request.headers.get("Cookie") || "");
+ const token = cookies[SESSION_COOKIE];
+ if (!token || !token.includes(".")) return null;
+ const [payload, signature] = token.split(".", 2);
+ const expected = await hmac(payload, env.SESSION_SECRET);
+ if (signature !== expected) return null;
+ const session = JSON.parse(base64UrlDecode(payload));
+ if (!session.exp || session.exp < Math.floor(Date.now() / 1000)) return null;
+ const login = String(session.login || "").toLowerCase();
+ const orgs = normalizeOrgList(session.orgs || [], "session.orgs");
+ const authConfig = await loadAuthConfig(env);
+ const admin = isAdminPrincipal(login, orgs, authConfig);
+ return { login, orgs, allowed: isAllowedPrincipal(login, orgs, authConfig), admin };
+}
+export async function hmac(value, secret) {
+ const key = await crypto.subtle.importKey(
+ "raw",
+ new TextEncoder().encode(secret),
+ { name: "HMAC", hash: "SHA-256" },
+ false,
+ ["sign"],
+ );
+ const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(value));
+ return base64UrlEncodeBytes(new Uint8Array(signature));
+}
diff --git a/web/strategy-switch-console/application/config_kv.js b/web/strategy-switch-console/application/config_kv.js
new file mode 100644
index 00000000..2d1ac53a
--- /dev/null
+++ b/web/strategy-switch-console/application/config_kv.js
@@ -0,0 +1,31 @@
+import { indexedKey, directoryCommand } from "../kv_directory.js";
+
+export function configStore(env) {
+ const store = env.STRATEGY_SWITCH_CONFIG;
+ if (!store || typeof store.get !== "function" || typeof store.put !== "function") return null;
+ return store;
+}
+
+export function hasConfigStore(env) {
+ return Boolean(configStore(env));
+}
+
+export async function readConfigJson(env, key) {
+ const store = configStore(env);
+ if (!store) return null;
+ const text = await store.get(key);
+ if (!text) return null;
+ try {
+ return JSON.parse(text);
+ } catch (error) {
+ throw new Error(`STRATEGY_SWITCH_CONFIG.${key} must be valid JSON`);
+ }
+}
+
+export async function writeConfigJson(env, key, value) {
+ const store = configStore(env);
+ if (!store) throw new Error("STRATEGY_SWITCH_CONFIG KV binding is required");
+ const text = JSON.stringify(value, null, 2);
+ if (indexedKey(key)) await directoryCommand(env, { action: "put", key, value: text });
+ else await store.put(key, text);
+}
diff --git a/web/strategy-switch-console/application/html_message.js b/web/strategy-switch-console/application/html_message.js
new file mode 100644
index 00000000..b31c30f7
--- /dev/null
+++ b/web/strategy-switch-console/application/html_message.js
@@ -0,0 +1,13 @@
+export function renderMessage(title, message) {
+ return `
${escapeHtml(title)}
+
+${escapeHtml(title)}
${escapeHtml(message)}
返回控制台
`;
+}
+
+export function escapeHtml(value) {
+ return String(value)
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """);
+}
diff --git a/web/strategy-switch-console/application/http_error.js b/web/strategy-switch-console/application/http_error.js
new file mode 100644
index 00000000..85f572f1
--- /dev/null
+++ b/web/strategy-switch-console/application/http_error.js
@@ -0,0 +1,8 @@
+export class HttpError extends Error {
+ constructor(message, status, details = null) {
+ super(message);
+ this.status = status;
+ this.reason_code = (details && details.reason_code) || message;
+ this.reason = (details && details.reason) || "";
+ }
+}
diff --git a/web/strategy-switch-console/application/http_request.js b/web/strategy-switch-console/application/http_request.js
new file mode 100644
index 00000000..07f1d765
--- /dev/null
+++ b/web/strategy-switch-console/application/http_request.js
@@ -0,0 +1,10 @@
+import { HttpError } from "./http_error.js";
+
+export function requireSameOrigin(request, options = {}) {
+ const origin = request.headers.get("Origin");
+ if (!origin) {
+ if (options.requireOrigin) throw new HttpError("Origin header is required", 403);
+ return;
+ }
+ if (origin !== new URL(request.url).origin) throw new HttpError("cross-origin request rejected", 403);
+}
diff --git a/web/strategy-switch-console/application/http_response.js b/web/strategy-switch-console/application/http_response.js
new file mode 100644
index 00000000..9d579811
--- /dev/null
+++ b/web/strategy-switch-console/application/http_response.js
@@ -0,0 +1,45 @@
+import { SECURITY_HEADERS } from "./security_headers.js";
+
+export function json(payload, status = 200, headers = {}) {
+ return new Response(JSON.stringify(payload, null, 2), {
+ status,
+ headers: responseHeaders({
+ "Content-Type": "application/json; charset=utf-8",
+ "Cache-Control": "no-store",
+ }, headers),
+ });
+}
+
+export function html(body, status = 200, headers = {}) {
+ return new Response(body, {
+ status,
+ headers: responseHeaders({
+ "Content-Type": "text/html; charset=utf-8",
+ "Cache-Control": "no-store",
+ }, headers),
+ });
+}
+
+export function redirect(location, headers = {}) {
+ return new Response(null, {
+ status: 302,
+ headers: responseHeaders({ Location: location }, headers),
+ });
+}
+
+export function responseHeaders(base = {}, extra = {}) {
+ const headers = new Headers(SECURITY_HEADERS);
+ appendHeaderEntries(headers, base);
+ appendHeaderEntries(headers, extra);
+ return headers;
+}
+
+export function appendHeaderEntries(headers, values) {
+ for (const [name, value] of Object.entries(values)) {
+ if (Array.isArray(value)) {
+ for (const item of value) headers.append(name, item);
+ } else {
+ headers.set(name, value);
+ }
+ }
+}
diff --git a/web/strategy-switch-console/application/risk_envelope.js b/web/strategy-switch-console/application/risk_envelope.js
new file mode 100644
index 00000000..0ed58c96
--- /dev/null
+++ b/web/strategy-switch-console/application/risk_envelope.js
@@ -0,0 +1,90 @@
+import { RESEARCH_PROMOTION_RISK_PROFILES } from "./risk_envelope_profiles.js";
+
+export const RISK_ENVELOPE_PREFERENCE_META = {
+ CAPITAL_PRESERVATION: {
+ short_zh: "保全",
+ short_en: "Preserve",
+ composer_mdd_multiple: 1.0,
+ promotion_size_scale: 0.5,
+ },
+ BALANCED_COMPOUNDING: {
+ short_zh: "均衡",
+ short_en: "Balance",
+ composer_mdd_multiple: 1.25,
+ promotion_size_scale: 0.75,
+ },
+ GROWTH_COMPOUNDING: {
+ short_zh: "增长",
+ short_en: "Growth",
+ composer_mdd_multiple: 1.5,
+ promotion_size_scale: 1.0,
+ },
+};
+
+/** Read-only console view: preference / capital band / status lamp. No KV writes. */
+export function buildRiskEnvelopeView({ riskPreference = null, equityUsd = null, status = null } = {}) {
+ const preferenceRaw = String(riskPreference || "").trim().toUpperCase();
+ const preference = RESEARCH_PROMOTION_RISK_PROFILES.includes(preferenceRaw) ? preferenceRaw : null;
+ const meta = preference ? RISK_ENVELOPE_PREFERENCE_META[preference] : null;
+ const hasEquity = equityUsd != null && Number.isFinite(Number(equityUsd));
+ // Equity injection is not wired yet — band/status/capital_scale stay unknown.
+ const source = hasEquity ? "reconciled_equity" : "design_preview";
+ const statusId = hasEquity && status ? String(status) : "unknown";
+ const statusLabels = {
+ normal: { zh: "正常", en: "Normal" },
+ stepped_down: { zh: "已降档", en: "Stepped down" },
+ new_risk_blocked: { zh: "禁止新增风险", en: "New risk blocked" },
+ unknown: { zh: "待对账权益注入", en: "Awaiting reconciled equity" },
+ };
+ const statusLabel = statusLabels[statusId] || statusLabels.unknown;
+ return {
+ schema: "qsl.risk_envelope_view.v1",
+ source,
+ preference: preference
+ ? {
+ id: preference,
+ label_zh: meta.short_zh,
+ label_en: meta.short_en,
+ }
+ : {
+ id: "unknown",
+ label_zh: "未设定",
+ label_en: "Unset",
+ },
+ capital_band: {
+ id: "unknown",
+ label_zh: "待对账权益注入",
+ label_en: "Awaiting reconciled equity",
+ },
+ status: {
+ id: statusId,
+ label_zh: statusLabel.zh,
+ label_en: statusLabel.en,
+ },
+ scales: {
+ composer_mdd_multiple: meta ? meta.composer_mdd_multiple : null,
+ promotion_size_scale: meta ? meta.promotion_size_scale : null,
+ capital_scale: null,
+ vol_scale: null,
+ dd_scale: null,
+ },
+ detail: {
+ dual_scale_note_zh:
+ "双口径:Composer 相对无杠杆基准 MDD 天花板为 1.00 / 1.25 / 1.50;晋级仓位缩放为 0.50 / 0.75 / 1.00(仅新晋级/材料变更)。资金信封 combined_scale = capital_scale × vol_scale × dd_scale(各因子 ≤1),由系统按权益/波动/回撤计算,禁止自动升档。",
+ dual_scale_note_en:
+ "Dual scale: Composer unlevered-benchmark MDD caps are 1.00 / 1.25 / 1.50; promotion size scales are 0.50 / 0.75 / 1.00 (new promotion / material change only). Envelope combined_scale = capital_scale × vol_scale × dd_scale (each ≤1), system-computed from equity/vol/drawdown; auto step-up is forbidden.",
+ },
+ live_authority_granted: false,
+ };
+}
+
+export function attachRiskEnvelopeView(ticket) {
+ if (!ticket || typeof ticket !== "object") return ticket;
+ return {
+ ...ticket,
+ risk_envelope_view: buildRiskEnvelopeView({
+ riskPreference: ticket.suggested_risk_profile,
+ equityUsd: null,
+ }),
+ };
+}
diff --git a/web/strategy-switch-console/application/risk_envelope_profiles.js b/web/strategy-switch-console/application/risk_envelope_profiles.js
new file mode 100644
index 00000000..b26c4030
--- /dev/null
+++ b/web/strategy-switch-console/application/risk_envelope_profiles.js
@@ -0,0 +1,5 @@
+export const RESEARCH_PROMOTION_RISK_PROFILES = [
+ "CAPITAL_PRESERVATION",
+ "BALANCED_COMPOUNDING",
+ "GROWTH_COMPOUNDING",
+];
diff --git a/web/strategy-switch-console/application/runtime_instances/command.js b/web/strategy-switch-console/application/runtime_instances/command.js
new file mode 100644
index 00000000..8488a552
--- /dev/null
+++ b/web/strategy-switch-console/application/runtime_instances/command.js
@@ -0,0 +1,58 @@
+import { HttpError } from "../http_error.js";
+
+export function hasRuntimeInstanceStore(env) {
+ return env.STRATEGY_SWITCH_RUNTIME_INSTANCES !== undefined && env.STRATEGY_SWITCH_RUNTIME_INSTANCES !== null;
+}
+
+export async function runtimeInstanceCommand(env, command) {
+ const namespace = env.STRATEGY_SWITCH_RUNTIME_INSTANCES;
+ if (!namespace?.idFromName || !namespace?.get) throw new HttpError("runtime_instances_not_bound", 503);
+ try {
+ const stub = namespace.get(namespace.idFromName("runtime-instances"));
+ const response = await stub.fetch("https://runtime-instances/", command ? {
+ method: "POST", body: JSON.stringify(command),
+ } : {});
+ let result;
+ try {
+ result = await response.json();
+ } catch {
+ throw new HttpError("runtime_instances_unavailable", response.status || 503);
+ }
+ if (!response.ok) throw new HttpError(result.error || "runtime_instances_unavailable", response.status);
+ return result;
+ } catch (error) {
+ if (error instanceof HttpError) throw error;
+ if (error && typeof error.status === "number") {
+ throw new HttpError(error.message || "runtime_instances_unavailable", error.status);
+ }
+ throw new HttpError("runtime_instances_unavailable", 503);
+ }
+}
+
+export function runtimeInstanceAccountOptions(instances) {
+ const options = {};
+ for (const instance of instances) {
+ if (instance.kind !== "existing") continue;
+ (options[instance.platform] ||= []).push(instance.config);
+ }
+ return options;
+}
+
+export function runtimeInstanceConflict(instances, platform, config, exceptKey = null) {
+ const selectors = (value) => String(value || "").split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
+ for (const item of instances) {
+ if (item.platform !== platform || item.key === exceptKey) continue;
+ const other = item.config;
+ if (item.key === config.key || other.target_name === config.target_name ||
+ (other.service_name && other.service_name === config.service_name) ||
+ selectors(other.account_selector).some((value) => selectors(config.account_selector).includes(value))) {
+ throw new HttpError("runtime_instance_identity_conflict", 409);
+ }
+ }
+}
+
+export function runtimeInstanceFields(raw, allowed) {
+ if (!raw || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).some((key) => !allowed.includes(key))) {
+ throw new HttpError("invalid_runtime_instance_fields", 400);
+ }
+}
diff --git a/web/strategy-switch-console/application/runtime_instances/durable_object.js b/web/strategy-switch-console/application/runtime_instances/durable_object.js
new file mode 100644
index 00000000..50312870
--- /dev/null
+++ b/web/strategy-switch-console/application/runtime_instances/durable_object.js
@@ -0,0 +1,3171 @@
+import { dateOnlyExternalFlow, externalFlowEnabled, initializeExternalFlow, normalizeExternalFlow, putExternalFlow, readExternalFlow, readExternalFlowCoverage } from "../account_facts/external_flow.js";
+import { initializeExecutions, normalizeExecutions, putExecutions, readExecutions } from "../account_facts/executions.js";
+import { DeskError } from "../desk/http.js";
+import { DeskReadbackStore, readbackTargets } from "../desk/readback.js";
+import { HttpError } from "../http_error.js";
+import { KvDirectory, DIRECTORY_PATH } from "../../kv_directory.js";
+import { initializeSecretRotation, durableRotationCommand } from "../../secretRotation.js";
+import { initializeCredentialMaintenance } from "../../credentialMaintenance.js";
+import { runtimeInstanceAccountOptions } from "./command.js";
+import { ux1MutateJob, ux1SelectSlot, ux1SlotPayload } from "../ux1/research.js";
+import {
+ ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS,
+ ACCOUNT_DIAGNOSIS_DO_ACTIONS,
+ ACCOUNT_DIAGNOSIS_STATUSES,
+} from "../account_diagnosis/constants.js";
+import { accountDiagnosisConflict, accountDiagnosisTaskFromRow } from "../account_diagnosis/helpers.js";
+import { researchPromotionApplicationFromRow } from "./promotion_application_row.js";
+import {
+ CycleHealthError,
+ canonicalCycleJson, compareCycleInstants, cycleCoverageComplete,
+ cycleHealthAttemptKey, cycleHealthFaultCategory, cycleHealthFaultTime, normalizeCycleInstant,
+} from "../../runtime_cycle_health.js";
+import { CredentialMaintenanceError, credentialMaintenanceCommand } from "../../credentialMaintenance.js";
+import { RotationError } from "../../secretRotationStepUp.js";
+
+import { accountFactsIdentityDates } from "../account_facts/read.js";
+import { runtimeInstanceConflict } from "./command.js";
+import { deskErrorResponse } from "../desk/http.js";
+import { binanceDetailCommand } from "../../binance_detail_archive.js";
+import {
+ ACCOUNT_FACTS_FUTURE_SKEW_MS,
+ ACCOUNT_FACTS_HISTORY_MAX_DAYS,
+ ACCOUNT_FACTS_RETURN_UNAVAILABLE,
+ ACCOUNT_FACTS_STALE_MS,
+ ACCOUNT_FACTS_SUPPORTED_PLATFORMS,
+ AccountFactsError,
+ FIRSTRADE_ACCOUNT_FACTS_PLATFORM,
+ IBKR_ACCOUNT_FACTS_PLATFORM,
+ SCHWAB_ACCOUNT_FACTS_PLATFORM,
+ canonicalizeAccountFactsHistory,
+ decideAccountFactsDailyUpsert,
+ decideAccountFactsPut,
+ historyRetentionCutoff,
+ normalizeAccountFactsHistoricalPayload,
+ normalizeAccountFactsHistoryPayload,
+ normalizeIbkrPeriodReturn,
+ publicIbkrPeriodReturn,
+ validFirstradeAccountId,
+} from "../../account_facts.js";
+import {
+ BINANCE_WALLET_HISTORY_MAX_DAYS,
+ normalizeBinanceWalletHistoryEntry,
+} from "../../binance_account_facts.js";
+import {
+ MARKET_BENCHMARK_SCHEMA,
+ MarketBenchmarkError,
+ normalizeMarketBenchmarkSyncPayload,
+ publicMarketBenchmarkReadModel,
+} from "../../infrastructure/market_benchmark/market_benchmark.js";
+import { BROKER_ENVIRONMENTS } from "../../account_options_schema.js";
+import { RISK_TIER_POLICY_BINDINGS } from "../console_api/risk_tiers.js";
+import {
+ ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY,
+ AUDIT_EVENTS_MAX_ROWS,
+ HK_STOP_REQUEST_ID,
+ HK_STOP_TARGET_ID,
+ RISK_PROFILE_PREFERENCES,
+ SUPPORTED_PLATFORMS,
+ accountSettingsIdentity,
+ accountSettingsIdentityIsComplete,
+ accountSettingsProfileName,
+ applyAccountSettingOverrides,
+ canonicalResearchTaskJson,
+ deskTargetReadback,
+ hkStopDigestOrEmpty,
+ hkStopIdentityComplete,
+ hkStopSourceIdentity,
+ isDcaProfile,
+ json,
+ normalizeControlPlaneIdentifier,
+ promotionMaterialReviewBinding,
+ promotionReviewBindingsMatch,
+ readRiskProfileLegacy,
+ riskProfileBindingTargets,
+ riskProfileScopeId,
+ runtimeControlIdentityIsComplete,
+ runtimeDailyCalendarDate,
+ supportedBrokerEnvironmentsForPlatform,
+ updateAccountOptionsDefaultStrategy,
+ HUMAN_DECISION_DO_ACTIONS,
+ ACCOUNT_SETTINGS_DO_ACTIONS,
+ ACCOUNT_FACTS_DO_ACTIONS,
+ MARKET_BENCHMARK_DO_ACTIONS,
+ V7_PAPER_APPLICATION_DO_ACTIONS,
+ RUNTIME_CONTROL_DO_ACTIONS,
+ HK_STOP_DO_ACTIONS,
+ CYCLE_HEALTH_HISTORY_PAGE_SIZE,
+ CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION,
+} from '../worker/runtime_support.js';
+
+export class RuntimeInstances {
+ constructor(ctx, env) {
+ this.directory = new KvDirectory(ctx.storage, env?.STRATEGY_SWITCH_CONFIG, env);
+ this.storage = ctx.storage;
+ this.sql = ctx.storage.sql;
+ initializeExecutions(this.sql);
+ this.externalFlowEnabled = externalFlowEnabled(env);
+ initializeExternalFlow(this.sql);
+ initializeCredentialMaintenance(this.sql);
+ initializeSecretRotation(this.sql);
+ this.rotationEnv = env;
+ this.deskReadbacks = new DeskReadbackStore(ctx.storage, async (id, actor) => {
+ const state = this.read();
+ const target = readbackTargets({ options: runtimeInstanceAccountOptions(state.instances), revision: state.revision }).find(target => target.id === id);
+ if (!target) throw new DeskError("not_found", 404);
+ let observed = null;
+ try { observed = this.readAccountSettings({ platform: target.platform, key: target.key, legacy: await readRiskProfileLegacy(env) }); } catch { /* Degrade saved independently. */ }
+ return deskTargetReadback(env, target, actor, observed);
+ });
+ // Native intervals remain in the existing private account read-model store.
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_period_return (
+ account_key TEXT PRIMARY KEY, payload_json TEXT NOT NULL
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_daily_native_return (
+ account_key TEXT NOT NULL, source_binding_id TEXT NOT NULL, currency TEXT NOT NULL,
+ observation_date TEXT NOT NULL, payload_json TEXT NOT NULL,
+ PRIMARY KEY(account_key, source_binding_id, currency, observation_date)
+ )`);
+ // Dormant: only an independent protected provisioning step may seed admission.
+ // There is deliberately no ingress/admin command that writes an admission.
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_source (
+ source_id TEXT PRIMARY KEY, target_id TEXT NOT NULL UNIQUE, binding_fingerprint TEXT NOT NULL,
+ configuration_sha256 TEXT NOT NULL, authority_revision INTEGER NOT NULL,
+ required_from TEXT NOT NULL, observed_at TEXT, observation_json TEXT,
+ observation_sha256 TEXT, received_at TEXT, checkpoint_revision INTEGER
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_checkpoint (
+ target_id TEXT NOT NULL, binding_fingerprint TEXT NOT NULL, source_id TEXT NOT NULL,
+ revision INTEGER NOT NULL, payload_json TEXT NOT NULL,
+ PRIMARY KEY (target_id, binding_fingerprint)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_incident (
+ target_id TEXT NOT NULL, binding_fingerprint TEXT NOT NULL, source_id TEXT NOT NULL,
+ cycle_id TEXT NOT NULL, cycle_json TEXT NOT NULL, category TEXT NOT NULL,
+ active_category TEXT, latest_fault_at TEXT NOT NULL, attempt_count INTEGER NOT NULL,
+ resolution_history_json TEXT NOT NULL,
+ PRIMARY KEY (target_id, binding_fingerprint, source_id, cycle_id)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_attempt (
+ history_id INTEGER PRIMARY KEY AUTOINCREMENT,
+ target_id TEXT NOT NULL, binding_fingerprint TEXT NOT NULL, source_id TEXT NOT NULL,
+ cycle_id TEXT NOT NULL, attempt_key TEXT NOT NULL, fault_at TEXT NOT NULL,
+ category TEXT NOT NULL, configuration_sha256 TEXT NOT NULL, cycle_json TEXT NOT NULL,
+ resolution_ref TEXT,
+ UNIQUE (target_id, binding_fingerprint, source_id, attempt_key)
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS runtime_cycle_health_history_page ON runtime_cycle_health_attempt (target_id, source_id, history_id)");
+ this.sql.exec("CREATE TABLE IF NOT EXISTS instance_state (id INTEGER PRIMARY KEY CHECK (id = 1), revision INTEGER NOT NULL, payload TEXT NOT NULL)");
+ this.sql.exec("CREATE TABLE IF NOT EXISTS instance_history (revision INTEGER PRIMARY KEY, entry TEXT NOT NULL)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_diagnosis_tasks (
+ request_id TEXT PRIMARY KEY,
+ platform TEXT NOT NULL,
+ account_key TEXT NOT NULL,
+ target_id TEXT NOT NULL,
+ trigger TEXT NOT NULL,
+ observed_at TEXT NOT NULL,
+ checks_json TEXT NOT NULL,
+ state_fingerprint TEXT NOT NULL,
+ status TEXT NOT NULL,
+ workflow_run_id TEXT,
+ workflow_run_attempt TEXT,
+ job_id TEXT,
+ summary TEXT NOT NULL,
+ reason_code TEXT NOT NULL,
+ dispatch_state TEXT NOT NULL,
+ recheck_dispatch_state TEXT NOT NULL,
+ created_at TEXT NOT NULL,
+ updated_at TEXT NOT NULL
+ )`);
+ try { this.sql.exec("ALTER TABLE account_diagnosis_tasks ADD COLUMN auto_source TEXT NOT NULL DEFAULT 'manual'"); } catch { /* already present */ }
+ try { this.sql.exec("ALTER TABLE account_diagnosis_tasks ADD COLUMN native_json TEXT"); } catch { /* already present */ }
+ this.sql.exec("CREATE INDEX IF NOT EXISTS account_diagnosis_tasks_fingerprint ON account_diagnosis_tasks (target_id, state_fingerprint, updated_at)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS research_promotion_applications (
+ application_id TEXT PRIMARY KEY,
+ ticket_id TEXT NOT NULL,
+ status TEXT NOT NULL,
+ dispatch_state TEXT NOT NULL,
+ claim_token TEXT NOT NULL,
+ platform_id TEXT NOT NULL,
+ account_key TEXT NOT NULL,
+ account_scope TEXT NOT NULL,
+ account_selector TEXT NOT NULL,
+ service_name TEXT NOT NULL,
+ broker_environment TEXT NOT NULL,
+ expected_revision INTEGER NOT NULL,
+ expected_strategy_profile TEXT NOT NULL,
+ strategy_profile TEXT NOT NULL,
+ candidate_id TEXT NOT NULL,
+ config_sha256 TEXT NOT NULL,
+ source_commit TEXT NOT NULL,
+ approved_ues_revision TEXT NOT NULL,
+ desired_state TEXT NOT NULL,
+ workflow_run_id TEXT,
+ workflow_run_attempt TEXT,
+ reason_code TEXT NOT NULL,
+ readback_json TEXT,
+ created_at TEXT NOT NULL,
+ updated_at TEXT NOT NULL
+ )`);
+ // A rejected application is a terminal record, but an explicitly
+ // re-qualified user request may create a new attempt. Keep history while
+ // deduplicating all still-active/uncertain attempts.
+ this.sql.exec("DROP INDEX IF EXISTS research_promotion_applications_ticket_account");
+ this.sql.exec("CREATE INDEX IF NOT EXISTS research_promotion_applications_ticket_account_idx ON research_promotion_applications (ticket_id, platform_id, account_key, status)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS ux1_research_slot (
+ login TEXT PRIMARY KEY,
+ revision INTEGER NOT NULL,
+ draft_json TEXT NOT NULL,
+ fingerprint TEXT NOT NULL,
+ preview_json TEXT,
+ intent_json TEXT,
+ job_json TEXT
+ )`);
+ try {
+ this.sql.exec("ALTER TABLE ux1_research_slot ADD COLUMN job_json TEXT");
+ } catch {
+ /* already migrated */
+ }
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS human_decision_material (
+ kind TEXT NOT NULL,
+ subject_id TEXT NOT NULL,
+ source_id TEXT NOT NULL,
+ material_key TEXT NOT NULL,
+ summary_json TEXT NOT NULL,
+ eligible INTEGER NOT NULL,
+ expires_at_ms INTEGER,
+ legacy_state TEXT NOT NULL,
+ legacy_block TEXT NOT NULL,
+ updated_at TEXT NOT NULL,
+ PRIMARY KEY (kind, subject_id)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS human_decision_record (
+ request_key TEXT PRIMARY KEY,
+ kind TEXT NOT NULL,
+ subject_id TEXT NOT NULL,
+ material_key TEXT NOT NULL,
+ action TEXT NOT NULL,
+ actor TEXT NOT NULL,
+ decided_at TEXT NOT NULL,
+ target_json TEXT NOT NULL,
+ payload_json TEXT NOT NULL
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS human_decision_record_subject ON human_decision_record (kind, subject_id, material_key)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS human_decision_source_material (
+ kind TEXT NOT NULL,
+ subject_id TEXT NOT NULL,
+ source_id TEXT NOT NULL,
+ material_key TEXT NOT NULL,
+ summary_json TEXT NOT NULL,
+ eligible INTEGER NOT NULL,
+ expires_at_ms INTEGER,
+ updated_at TEXT NOT NULL,
+ PRIMARY KEY (kind, subject_id, source_id)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS risk_profile_authority (
+ id INTEGER PRIMARY KEY CHECK (id = 1),
+ revision INTEGER NOT NULL,
+ imported INTEGER NOT NULL,
+ bindings_json TEXT NOT NULL
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_setting_draft (
+ platform TEXT NOT NULL,
+ account_key TEXT NOT NULL,
+ revision INTEGER NOT NULL,
+ identity_json TEXT NOT NULL,
+ overrides_json TEXT NOT NULL,
+ updated_at TEXT NOT NULL,
+ PRIMARY KEY (platform, account_key)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_setting_declaration (
+ platform TEXT NOT NULL, account_key TEXT NOT NULL, revision INTEGER NOT NULL,
+ identity_json TEXT NOT NULL, declaration_json TEXT NOT NULL,
+ PRIMARY KEY (platform, account_key)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_setting_profile_application (
+ request_key TEXT PRIMARY KEY,
+ platform TEXT NOT NULL,
+ account_key TEXT NOT NULL,
+ identity_json TEXT NOT NULL,
+ instance_revision INTEGER NOT NULL,
+ draft_revision INTEGER NOT NULL,
+ old_profile TEXT NOT NULL,
+ new_profile TEXT NOT NULL,
+ approved_by TEXT NOT NULL,
+ approved_at TEXT NOT NULL,
+ status TEXT NOT NULL,
+ workflow_run_id TEXT,
+ workflow_run_attempt TEXT,
+ claimed_at TEXT
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS account_setting_profile_application_target ON account_setting_profile_application (platform, account_key, status)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_facts_observation (
+ platform TEXT NOT NULL,
+ account_key TEXT NOT NULL,
+ payload_json TEXT NOT NULL,
+ observed_finished_at TEXT NOT NULL,
+ observation_date TEXT NOT NULL,
+ target_id TEXT NOT NULL,
+ source_binding_id TEXT NOT NULL,
+ account_scope TEXT NOT NULL,
+ updated_at TEXT NOT NULL,
+ PRIMARY KEY (platform, account_key)
+ )`);
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS account_facts_daily (
+ platform TEXT NOT NULL,
+ account_key TEXT NOT NULL,
+ observation_date TEXT NOT NULL,
+ payload_json TEXT NOT NULL,
+ observed_finished_at TEXT NOT NULL,
+ target_id TEXT NOT NULL,
+ source_binding_id TEXT NOT NULL,
+ account_scope TEXT NOT NULL,
+ updated_at TEXT NOT NULL,
+ PRIMARY KEY (platform, account_key, observation_date)
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS account_facts_daily_account ON account_facts_daily (platform, account_key, observation_date)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS market_benchmark_daily (
+ series_id TEXT NOT NULL,
+ observation_date TEXT NOT NULL,
+ close TEXT NOT NULL,
+ source TEXT,
+ updated_at TEXT NOT NULL,
+ PRIMARY KEY (series_id, observation_date)
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS market_benchmark_daily_date ON market_benchmark_daily (observation_date)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS market_benchmark_revision_ledger (
+ proposal_sha256 TEXT NOT NULL,
+ entry_index INTEGER NOT NULL,
+ series_id_sha256 TEXT NOT NULL,
+ observation_date TEXT NOT NULL,
+ prior_close_sha256 TEXT NOT NULL,
+ new_close_sha256 TEXT NOT NULL,
+ candidate_source TEXT NOT NULL,
+ reason TEXT NOT NULL,
+ applied_at TEXT NOT NULL,
+ PRIMARY KEY (proposal_sha256, entry_index)
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS market_benchmark_revision_ledger_date ON market_benchmark_revision_ledger (observation_date)");
+ this.sql.exec(`CREATE TABLE IF NOT EXISTS hk_stop_request (
+ request_id TEXT PRIMARY KEY,
+ target_id TEXT NOT NULL,
+ identity_json TEXT NOT NULL,
+ source_revision INTEGER NOT NULL,
+ action TEXT NOT NULL,
+ requested_at TEXT NOT NULL,
+ phase TEXT NOT NULL,
+ dispatch_result TEXT,
+ workflow_run_id TEXT,
+ workflow_run_attempt TEXT,
+ updated_at TEXT NOT NULL
+ )`);
+ this.sql.exec("CREATE INDEX IF NOT EXISTS hk_stop_request_target ON hk_stop_request (target_id, requested_at)");
+ for (const column of ["source_identity_sha256", "runtime_identity_sha256", "result_json", "stopped_at"]) {
+ try { this.sql.exec(`ALTER TABLE hk_stop_request ADD COLUMN ${column} TEXT`); } catch { /* already present */ }
+ }
+ }
+
+ emptyCycleHealthState(targetId, bindingId) {
+ return {
+ schema_version: CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION,
+ target_id: targetId, source_binding_id: bindingId,
+ incident_count: 0, fault_attempt_count: 0, unresolved_count: 0,
+ highest_severity: null, active_category: null, latest_fault_at: null,
+ resolution_history_count: 0, history_complete: false,
+ execution_authority_granted: false,
+ };
+ }
+
+ cycleHealthHistoryCursor(sourceId, targetId, bindingFingerprint, throughId, afterId) {
+ return [sourceId, targetId, bindingFingerprint, throughId, afterId].join(":");
+ }
+
+ cycleHealthHistoryPage(sourceId, targetId, bindingFingerprint, cursor = null) {
+ let throughId, afterId;
+ if (cursor) {
+ const parts = cursor.split(":");
+ if (parts.length !== 5 || parts[0] !== sourceId || parts[1] !== targetId || parts[2] !== bindingFingerprint) {
+ throw new HttpError("cycle_health_history_cursor_mismatch", 400);
+ }
+ throughId = Number(parts[3]); afterId = Number(parts[4]);
+ if (!Number.isSafeInteger(throughId) || throughId < 0 || !Number.isSafeInteger(afterId) || afterId < 0 || afterId > throughId) {
+ throw new HttpError("cycle_health_history_cursor_invalid", 400);
+ }
+ } else {
+ throughId = Number(this.sql.exec("SELECT COALESCE(MAX(history_id), 0) AS highwater FROM runtime_cycle_health_attempt WHERE target_id = ? AND source_id = ?", targetId, sourceId).toArray()[0]?.highwater || 0);
+ afterId = 0;
+ }
+ const rows = this.sql.exec(`SELECT a.history_id, a.binding_fingerprint, a.cycle_id, a.attempt_key, a.fault_at,
+ a.category, a.configuration_sha256, a.cycle_json, a.resolution_ref, i.resolution_history_json
+ FROM runtime_cycle_health_attempt a JOIN runtime_cycle_health_incident i
+ ON i.target_id = a.target_id AND i.binding_fingerprint = a.binding_fingerprint
+ AND i.source_id = a.source_id AND i.cycle_id = a.cycle_id
+ WHERE a.target_id = ? AND a.source_id = ? AND a.history_id > ? AND a.history_id <= ?
+ ORDER BY a.history_id ASC LIMIT ?`, targetId, sourceId, afterId, throughId, CYCLE_HEALTH_HISTORY_PAGE_SIZE + 1).toArray();
+ const hasMore = rows.length > CYCLE_HEALTH_HISTORY_PAGE_SIZE;
+ const selected = rows.slice(0, CYCLE_HEALTH_HISTORY_PAGE_SIZE);
+ const items = selected.map(row => {
+ let cycle, resolutionHistory;
+ try { cycle = JSON.parse(row.cycle_json); resolutionHistory = JSON.parse(row.resolution_history_json); }
+ catch { throw new HttpError("cycle_health_history_stored_invalid", 409); }
+ return {
+ history_id: row.history_id, binding_fingerprint: row.binding_fingerprint,
+ continuity: row.binding_fingerprint === bindingFingerprint ? "same_binding" : "unconfirmed",
+ cycle_id: row.cycle_id, attempt_key: row.attempt_key, fault_at: row.fault_at,
+ category: row.category, configuration_sha256: row.configuration_sha256,
+ cycle, resolution_ref: row.resolution_ref, resolution_history: resolutionHistory,
+ };
+ });
+ const nextCursor = hasMore && selected.length
+ ? this.cycleHealthHistoryCursor(sourceId, targetId, bindingFingerprint, throughId, selected.at(-1).history_id)
+ : null;
+ return {
+ items, snapshot_through_id: throughId, complete: !hasMore,
+ next_cursor: nextCursor,
+ };
+ }
+
+ cycleHealthRecordAttempt({ targetId, bindingFingerprint, sourceId, configurationSha, cycle, resolutionRef = null, resolutionHistory = null, state }) {
+ const category = cycleHealthFaultCategory(cycle);
+ const attemptKey = cycleHealthAttemptKey(cycle);
+ const cycleJson = canonicalCycleJson(cycle);
+ const oldAttempt = this.sql.exec(`SELECT cycle_json FROM runtime_cycle_health_attempt
+ WHERE target_id = ? AND binding_fingerprint = ? AND source_id = ? AND attempt_key = ?`,
+ targetId, bindingFingerprint, sourceId, attemptKey).toArray()[0];
+ if (oldAttempt) {
+ if (oldAttempt.cycle_json !== cycleJson) throw new HttpError("cycle_health_fault_receipt_conflict", 409);
+ return { state, inserted: false };
+ }
+ if (!category) return { state, inserted: false };
+ const faultAt = cycleHealthFaultTime(cycle);
+ const prior = this.sql.exec(`SELECT * FROM runtime_cycle_health_incident
+ WHERE target_id = ? AND binding_fingerprint = ? AND source_id = ? AND cycle_id = ?`,
+ targetId, bindingFingerprint, sourceId, cycle.cycle_id).toArray()[0] || null;
+ let incidentCycle = cycle, incidentCategory = category, latestFaultAt = faultAt;
+ let activeCategory = resolutionRef === null ? category : null;
+ let attemptCount = 1;
+ let history = resolutionHistory || [];
+ if (prior) {
+ let oldCycle;
+ try { oldCycle = JSON.parse(prior.cycle_json); history = JSON.parse(prior.resolution_history_json); }
+ catch { throw new HttpError("cycle_health_checkpoint_invalid", 409); }
+ const oldRank = prior.category === "execution_uncertainty" ? 2 : 1;
+ const newRank = category === "execution_uncertainty" ? 2 : 1;
+ const timeOrder = compareCycleInstants(faultAt, prior.latest_fault_at);
+ if (newRank > oldRank || (newRank === oldRank && (timeOrder > 0 || (timeOrder === 0 && attemptKey > cycleHealthAttemptKey(oldCycle))))) {
+ incidentCycle = cycle;
+ } else {
+ incidentCycle = oldCycle;
+ }
+ incidentCategory = newRank > oldRank ? category : prior.category;
+ latestFaultAt = timeOrder > 0 ? faultAt : prior.latest_fault_at;
+ attemptCount = prior.attempt_count + 1;
+ if (resolutionRef === null) {
+ const priorActiveRank = prior.active_category === "execution_uncertainty" ? 2 : prior.active_category === "operational" ? 1 : 0;
+ activeCategory = newRank > priorActiveRank ? category : prior.active_category;
+ } else activeCategory = prior.active_category;
+ }
+ this.sql.exec(`INSERT INTO runtime_cycle_health_attempt (
+ target_id, binding_fingerprint, source_id, cycle_id, attempt_key, fault_at,
+ category, configuration_sha256, cycle_json, resolution_ref
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, targetId, bindingFingerprint, sourceId,
+ cycle.cycle_id, attemptKey, faultAt, category, configurationSha, cycleJson, resolutionRef);
+ this.sql.exec(`INSERT INTO runtime_cycle_health_incident (
+ target_id, binding_fingerprint, source_id, cycle_id, cycle_json, category,
+ active_category, latest_fault_at, attempt_count, resolution_history_json
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ON CONFLICT(target_id, binding_fingerprint, source_id, cycle_id) DO UPDATE SET
+ cycle_json = excluded.cycle_json, category = excluded.category,
+ active_category = excluded.active_category, latest_fault_at = excluded.latest_fault_at,
+ attempt_count = excluded.attempt_count, resolution_history_json = excluded.resolution_history_json`,
+ targetId, bindingFingerprint, sourceId, cycle.cycle_id, canonicalCycleJson(incidentCycle), incidentCategory,
+ activeCategory, latestFaultAt, attemptCount, JSON.stringify(history));
+ const next = { ...state };
+ if (!prior) next.incident_count += 1;
+ next.fault_attempt_count += 1;
+ if (activeCategory !== null && (!prior || prior.active_category === null)) next.unresolved_count += 1;
+ if (!prior && Array.isArray(history)) next.resolution_history_count += history.length;
+ if (activeCategory !== null && !next.active_category) next.active_category = activeCategory;
+ const stateRank = next.highest_severity === "execution_uncertainty" ? 2 : next.highest_severity === "operational" ? 1 : 0;
+ const incidentRank = incidentCategory === "execution_uncertainty" ? 2 : 1;
+ if (incidentRank > stateRank) next.highest_severity = incidentCategory;
+ const activeRank = next.active_category === "execution_uncertainty" ? 2 : next.active_category === "operational" ? 1 : 0;
+ const nextActiveRank = activeCategory === "execution_uncertainty" ? 2 : activeCategory === "operational" ? 1 : 0;
+ if (nextActiveRank > activeRank) next.active_category = activeCategory;
+ if (!next.latest_fault_at || compareCycleInstants(faultAt, next.latest_fault_at) > 0) next.latest_fault_at = faultAt;
+ next.history_complete = false;
+ return { state: next, inserted: true };
+ }
+
+ migrateCycleHealthCheckpoint(row) {
+ let checkpoint;
+ try { checkpoint = JSON.parse(row.payload_json); } catch { throw new HttpError("cycle_health_checkpoint_invalid", 409); }
+ if (checkpoint?.state?.schema_version === CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION) return checkpoint;
+ const oldState = checkpoint?.state;
+ if (!oldState || !Array.isArray(oldState.incidents)) throw new HttpError("cycle_health_checkpoint_invalid", 409);
+ let state = this.emptyCycleHealthState(row.target_id, oldState.source_binding_id);
+ for (const incident of oldState.incidents) {
+ if (!incident || !Array.isArray(incident.fault_attempts) || !incident.fault_attempts.length) throw new HttpError("cycle_health_checkpoint_invalid", 409);
+ for (const attempt of incident.fault_attempts) {
+ if (!attempt?.cycle || typeof attempt.configuration_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(attempt.configuration_sha256)
+ || (attempt.resolution_ref !== null && (typeof attempt.resolution_ref !== "string" || !/^[a-f0-9]{64}$/.test(attempt.resolution_ref)))) {
+ throw new HttpError("cycle_health_checkpoint_invalid", 409);
+ }
+ state = this.cycleHealthRecordAttempt({ targetId: row.target_id, bindingFingerprint: row.binding_fingerprint,
+ sourceId: row.source_id, configurationSha: attempt.configuration_sha256, cycle: attempt.cycle,
+ resolutionRef: attempt.resolution_ref, resolutionHistory: incident.resolution_history || [], state }).state;
+ }
+ }
+ checkpoint.state = state;
+ checkpoint.schema_version = "qsl_runtime_cycle_health_checkpoint_state.v2";
+ checkpoint.covered_through = null;
+ checkpoint.coverage_complete = false;
+ checkpoint.coverage_incomplete_reason = "legacy_watermark_unavailable";
+ const source = this.sql.exec("SELECT binding_fingerprint, configuration_sha256, required_from, observed_at, observation_json FROM runtime_cycle_health_source WHERE source_id = ?", row.source_id).toArray()[0];
+ if (row.binding_fingerprint === source?.binding_fingerprint && checkpoint.baseline_established === true
+ && checkpoint.configuration_sha256 === source.configuration_sha256 && checkpoint.required_from === source.required_from
+ && source.observation_json && source.observed_at) {
+ try {
+ const observation = JSON.parse(source.observation_json);
+ const coverage = observation?.targets?.[0]?.cycle_health?.coverage;
+ if (observation.computed_at === source.observed_at && compareCycleInstants(coverage?.through, observation.computed_at) <= 0
+ && cycleCoverageComplete(coverage, { since: source.required_from, through: source.required_from })) {
+ checkpoint.covered_through = coverage.through;
+ checkpoint.coverage_complete = true;
+ checkpoint.coverage_incomplete_reason = null;
+ }
+ } catch { /* Keep legacy coverage unproven when the stored source record is invalid. */ }
+ }
+ this.sql.exec("UPDATE runtime_cycle_health_checkpoint SET payload_json = ? WHERE target_id = ? AND binding_fingerprint = ? AND source_id = ? AND revision = ?",
+ JSON.stringify(checkpoint), row.target_id, row.binding_fingerprint, row.source_id, row.revision);
+ return checkpoint;
+ }
+
+ cycleHealthCommand(command) {
+ const rows = [...this.sql.exec("SELECT * FROM runtime_cycle_health_source WHERE source_id = ?", command.source_id)];
+ const a = rows[0];
+ if (!a || a.target_id !== command.target_id || a.binding_fingerprint !== command.binding_fingerprint
+ || !/^[a-f0-9]{64}$/.test(a.configuration_sha256)
+ || !Number.isSafeInteger(a.authority_revision) || a.authority_revision < 1) throw new HttpError("cycle_health_source_not_admitted", 409);
+ try { normalizeCycleInstant(a.required_from); } catch { throw new HttpError("cycle_health_baseline_not_admitted", 409); }
+ if (command.action === "cycle_health_admission") return {
+ authority_revision: a.authority_revision, configuration_sha256: a.configuration_sha256, required_from: a.required_from,
+ };
+ if (command.authority_revision !== a.authority_revision || command.configuration_sha256 !== a.configuration_sha256
+ || command.required_from !== a.required_from) throw new HttpError("cycle_health_admission_changed", 409);
+ let partitions = [...this.sql.exec("SELECT * FROM runtime_cycle_health_checkpoint WHERE target_id = ? AND source_id = ?", a.target_id, a.source_id)];
+ const owner = [...this.sql.exec("SELECT source_id FROM runtime_cycle_health_checkpoint WHERE target_id = ? AND binding_fingerprint = ?", a.target_id, a.binding_fingerprint)][0];
+ if (owner && owner.source_id !== a.source_id) throw new HttpError("cycle_health_source_partition_conflict", 409);
+ partitions = partitions.map(row => ({ ...row, checkpoint: this.migrateCycleHealthCheckpoint(row) }));
+ const row = partitions.find(p => p.binding_fingerprint === a.binding_fingerprint) || null;
+ const previous = row?.checkpoint || null;
+ const priorPartitions = partitions.filter(p => p.binding_fingerprint !== a.binding_fingerprint).map(p => ({
+ checkpoint_revision: p.revision, checkpoint: p.checkpoint,
+ }));
+ if (row && a.checkpoint_revision !== row.revision) throw new HttpError("cycle_health_checkpoint_revision_conflict", 409);
+ const state = previous?.state || this.emptyCycleHealthState(a.target_id, command.source_binding_id);
+ const admissionTransition = previous && (previous.configuration_sha256 !== a.configuration_sha256 || previous.required_from !== a.required_from);
+ const effectiveCheckpoint = admissionTransition ? {
+ ...previous, baseline_established: false, covered_through: null, coverage_complete: false,
+ coverage_incomplete_reason: "admission_changed",
+ } : previous;
+ const result = (status, checkpoint = previous, revision = row?.revision || 0) => ({
+ ok: true, schema_version: "qsl_runtime_cycle_health_checkpoint.v2", status,
+ source_id: a.source_id, target_id: a.target_id, authority_revision: a.authority_revision,
+ configuration_sha256: a.configuration_sha256, source_binding_id: command.source_binding_id,
+ checkpoint_revision: revision, observed_at: a.observed_at, observation_sha256: a.observation_sha256,
+ received_at: a.received_at, required_from: a.required_from, checkpoint,
+ covered_through: checkpoint?.covered_through || null,
+ coverage_complete: checkpoint?.coverage_complete === true,
+ coverage_incomplete_reason: checkpoint?.coverage_incomplete_reason || null,
+ ...(command.action === "cycle_health_read"
+ ? { history_page: this.cycleHealthHistoryPage(a.source_id, a.target_id, a.binding_fingerprint, command.history_cursor || null) }
+ : {}),
+ prior_partitions: priorPartitions, continuity: priorPartitions.length ? "unconfirmed" : "same_binding",
+ adopted: false, no_order: true, execution_authority_granted: false,
+ });
+ if (command.action === "cycle_health_read") {
+ const r = result(!previous ? "uninitialized" : state.unresolved_count || priorPartitions.length ? "blocked"
+ : !effectiveCheckpoint.baseline_established || effectiveCheckpoint.coverage_complete !== true ? "incomplete" : "complete", effectiveCheckpoint);
+ if (a.observed_at && (Date.now() - Date.parse(a.observed_at) > ACCOUNT_FACTS_STALE_MS || Date.parse(a.observed_at) - Date.now() > ACCOUNT_FACTS_FUTURE_SKEW_MS)) r.status = "stale";
+ if (previous && (previous.configuration_sha256 !== a.configuration_sha256 || previous.required_from !== a.required_from)) r.status = "incomplete";
+ if (priorPartitions.length || state.unresolved_count) r.status = "blocked";
+ return r;
+ }
+ if (command.action !== "cycle_health_put") throw new HttpError("unsupported_cycle_health_action", 400);
+ const packet = command.observation;
+ if (packet.targets[0].cycle_health.configuration_sha256 !== a.configuration_sha256) throw new HttpError("cycle_health_configuration_not_admitted", 409);
+ const order = a.observed_at ? compareCycleInstants(packet.computed_at, a.observed_at) : 1;
+ if (order < 0) throw new HttpError("cycle_health_stale_observation", 409);
+ if (order === 0) {
+ if (command.observation_json !== a.observation_json || command.observation_sha256 !== a.observation_sha256) throw new HttpError("cycle_health_observation_conflict", 409);
+ return { ...result("unchanged"), schema_version: "qsl_runtime_cycle_health_ack.v1", result: "unchanged" };
+ }
+ const h = packet.targets[0].cycle_health;
+ const transition = previous && (previous.configuration_sha256 !== a.configuration_sha256 || previous.required_from !== a.required_from);
+ const expectedCoverageFrom = !transition && previous?.covered_through ? previous.covered_through : a.required_from;
+ const scanComplete = cycleCoverageComplete(h.coverage);
+ const coverageContinuous = scanComplete
+ && compareCycleInstants(h.coverage.from, expectedCoverageFrom) <= 0
+ && compareCycleInstants(h.coverage.through, expectedCoverageFrom) >= 0;
+ const coveredThrough = coverageContinuous ? h.coverage.through : transition ? null : previous?.covered_through || null;
+ const incompleteReason = coverageContinuous ? null : !scanComplete ? "scan_incomplete"
+ : compareCycleInstants(h.coverage.from, expectedCoverageFrom) > 0 ? "coverage_gap" : "coverage_not_advanced";
+ let nextState = structuredClone(state);
+ for (const cycle of h.cycles) {
+ nextState = this.cycleHealthRecordAttempt({ targetId: a.target_id, bindingFingerprint: a.binding_fingerprint,
+ sourceId: a.source_id, configurationSha: h.configuration_sha256, cycle, state: nextState }).state;
+ }
+ const baselineEstablished = coverageContinuous
+ ? (!previous || transition || previous.baseline_established || !previous.covered_through)
+ : Boolean(previous && !transition && previous.baseline_established);
+ const checkpoint = {
+ schema_version: "qsl_runtime_cycle_health_checkpoint_state.v2",
+ configuration_sha256: a.configuration_sha256, required_from: a.required_from,
+ baseline_established: baselineEstablished,
+ covered_through: coveredThrough, coverage_complete: coverageContinuous,
+ coverage_incomplete_reason: incompleteReason,
+ state: nextState,
+ };
+ const revision = (row?.revision || 0) + 1;
+ this.sql.exec("UPDATE runtime_cycle_health_source SET observed_at = ?, observation_json = ?, observation_sha256 = ?, received_at = ?, checkpoint_revision = ? WHERE source_id = ?",
+ packet.computed_at, command.observation_json, command.observation_sha256, command.received_at, revision, a.source_id);
+ this.sql.exec(`INSERT INTO runtime_cycle_health_checkpoint (target_id, binding_fingerprint, source_id, revision, payload_json)
+ VALUES (?, ?, ?, ?, ?) ON CONFLICT(target_id, binding_fingerprint) DO UPDATE SET revision = excluded.revision, payload_json = excluded.payload_json`,
+ a.target_id, a.binding_fingerprint, a.source_id, revision, JSON.stringify(checkpoint));
+ a.observed_at = packet.computed_at; a.observation_sha256 = command.observation_sha256; a.received_at = command.received_at;
+ return { ...result("stored", checkpoint, revision), schema_version: "qsl_runtime_cycle_health_ack.v1", result: "stored" };
+ }
+
+ cycleHealthProvisionCommand(command) {
+ const { source_id: sourceId, target_id: targetId, binding_fingerprint: bindingFingerprint,
+ configuration_sha256: configurationSha, required_from: requiredFrom,
+ expected_authority_revision: expectedRevision } = command || {};
+ if (targetId !== "longbridge.paper" || !/^[a-f0-9]{64}$/.test(bindingFingerprint || "")
+ || !/^[a-f0-9]{64}$/.test(configurationSha || "")
+ || !Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
+ throw new HttpError("cycle_health_admission_request_invalid", 400);
+ }
+ const normalizedSourceId = normalizeControlPlaneIdentifier(sourceId, "source_id", false);
+ let normalizedRequiredFrom;
+ try { normalizedRequiredFrom = normalizeCycleInstant(requiredFrom); }
+ catch { throw new HttpError("cycle_health_baseline_not_admitted", 400); }
+ const current = [...this.sql.exec("SELECT * FROM runtime_cycle_health_source WHERE target_id = ?", targetId)][0] || null;
+ const sourceOwner = [...this.sql.exec("SELECT * FROM runtime_cycle_health_source WHERE source_id = ?", normalizedSourceId)][0] || null;
+ if (sourceOwner && sourceOwner.target_id !== targetId) throw new HttpError("cycle_health_source_target_conflict", 409);
+ if (current && current.source_id !== normalizedSourceId) throw new HttpError("cycle_health_source_id_change_requires_support", 409);
+ if (current?.binding_fingerprint !== bindingFingerprint
+ && [...this.sql.exec("SELECT 1 AS found FROM runtime_cycle_health_checkpoint WHERE target_id = ? AND binding_fingerprint = ?", targetId, bindingFingerprint)][0]) {
+ throw new HttpError("cycle_health_binding_partition_reuse_requires_support", 409);
+ }
+ const currentRevision = current?.authority_revision || 0;
+ const sameAdmission = current && current.binding_fingerprint === bindingFingerprint
+ && current.configuration_sha256 === configurationSha && current.required_from === normalizedRequiredFrom;
+ if (sameAdmission) {
+ if (expectedRevision > currentRevision || expectedRevision < currentRevision - 1) {
+ throw new HttpError("cycle_health_admission_revision_conflict", 409);
+ }
+ return {
+ ok: true, schema_version: "qsl_runtime_cycle_health_admission.v1", result: "unchanged",
+ source_id: normalizedSourceId, target_id: targetId, authority_revision: currentRevision,
+ configuration_sha256: configurationSha, required_from: normalizedRequiredFrom,
+ status: "admission_unchanged", adopted: false, no_order: true,
+ execution_authority_granted: false,
+ };
+ }
+ if (expectedRevision !== currentRevision) throw new HttpError("cycle_health_admission_revision_conflict", 409);
+ if (current && compareCycleInstants(normalizedRequiredFrom, current.required_from) > 0) {
+ throw new HttpError("cycle_health_baseline_range_shrink_rejected", 409);
+ }
+ const nextRevision = currentRevision + 1;
+ if (!Number.isSafeInteger(nextRevision)) throw new HttpError("cycle_health_admission_revision_exhausted", 409);
+ if (!current) {
+ this.sql.exec(`INSERT INTO runtime_cycle_health_source (
+ source_id, target_id, binding_fingerprint, configuration_sha256,
+ authority_revision, required_from, observed_at, observation_json,
+ observation_sha256, received_at, checkpoint_revision
+ ) VALUES (?, ?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL)`,
+ normalizedSourceId, targetId, bindingFingerprint, configurationSha, nextRevision, normalizedRequiredFrom);
+ } else {
+ const bindingChanged = current.binding_fingerprint !== bindingFingerprint;
+ this.sql.exec(`UPDATE runtime_cycle_health_source SET binding_fingerprint = ?, configuration_sha256 = ?,
+ authority_revision = ?, required_from = ?, observed_at = ?, observation_json = ?, observation_sha256 = ?,
+ received_at = ?, checkpoint_revision = ? WHERE source_id = ? AND authority_revision = ?`,
+ bindingFingerprint, configurationSha, nextRevision, normalizedRequiredFrom,
+ bindingChanged ? null : current.observed_at,
+ bindingChanged ? null : current.observation_json,
+ bindingChanged ? null : current.observation_sha256,
+ bindingChanged ? null : current.received_at,
+ bindingChanged ? null : current.checkpoint_revision,
+ normalizedSourceId, currentRevision);
+ if (this.sql.exec("SELECT changes() AS changed").toArray()[0]?.changed !== 1) {
+ throw new HttpError("cycle_health_admission_revision_conflict", 409);
+ }
+ }
+ return {
+ ok: true, schema_version: "qsl_runtime_cycle_health_admission.v1", result: "stored",
+ source_id: normalizedSourceId, target_id: targetId, authority_revision: nextRevision,
+ configuration_sha256: configurationSha, required_from: normalizedRequiredFrom,
+ status: "admission_configured", adopted: false, no_order: true,
+ execution_authority_granted: false,
+ };
+ }
+
+ accountFactsCommand(command) {
+ if (!command || typeof command.action !== "string") throw new HttpError("unsupported_account_facts_action", 400);
+ if (command.action === "account_daily_native_return_research_read") return this.researchNativeDailyReturns(command);
+ if (["binance_detail_put", "binance_detail_read"].includes(command.action)) return binanceDetailCommand(this.sql, command);
+ if (command.action === "binance_wallet_history_put" || command.action === "binance_wallet_history_read") {
+ return this.binanceWalletHistoryCommand(command);
+ }
+ if (command.action === "account_period_return_put" || command.action === "account_period_return_read") return this.accountPeriodReturnCommand(command);
+ if (["account_executions_put", "account_executions_read"].includes(command.action)) {
+ const context = this.accountFactsStorageContext(command);
+ if (context.platform !== "ibkr") throw new HttpError("invalid_execution_platform", 400);
+ return command.action === "account_executions_read"
+ ? { ok: true, executions: readExecutions(this.sql, context) }
+ : { ok: true, ...putExecutions(this.sql, context, command.payload) };
+ }
+ if (command.action === "account_external_flow_put") {
+ const context = this.accountFactsStorageContext(command);
+ const flow = normalizeExternalFlow(command.externalFlow);
+ if (!this.externalFlowEnabled && !dateOnlyExternalFlow(flow)) throw new HttpError("external_flow_disabled", 409);
+ const source = { ibkr: "ibkr_flex", schwab: "schwab_transactions", longbridge: "longbridge_cashflow" }[context.platform];
+ if (!source || flow.windows.some(w => w.source !== source)) throw new HttpError("external_flow_source_mismatch", 409);
+ const stored = putExternalFlow(this.sql, context, flow);
+ const readback = readExternalFlow(this.sql, context);
+ const readbackVerified = flow.windows.every(w => readback?.windows.some(saved => JSON.stringify(saved) === JSON.stringify(w)));
+ if (!readbackVerified) throw new HttpError("external_flow_readback_failed", 503);
+ return { ok: true, ...stored, readback_verified: true };
+ }
+ if (command.action === "account_facts_put") return this.putAccountFactsObservation(command);
+ if (command.action === "account_facts_history_put") return this.putAccountFactsHistoricalObservation(command);
+ if (command.action === "account_facts_read") return this.readAccountFactsObservation(command);
+ if (command.action === "account_facts_list") return this.listAccountFactsObservations(command);
+ if (command.action === "account_facts_history_read") return this.readAccountFactsDailyHistory(command);
+ throw new HttpError("unsupported_account_facts_action", 400);
+ }
+
+
+ marketBenchmarkCommand(command) {
+ if (!command || typeof command.action !== "string") throw new HttpError("unsupported_market_benchmark_action", 400);
+ if (command.action === "market_benchmark_read") return this.readMarketBenchmarkPoints(command);
+ if (command.action === "market_benchmark_put") return this.putMarketBenchmarkPoints(command);
+ if (command.action === "market_benchmark_revise") return this.reviseMarketBenchmarkPoints(command);
+ throw new HttpError("unsupported_market_benchmark_action", 400);
+ }
+
+ readMarketBenchmarkPoints(command = {}) {
+ const rows = this.sql.exec(
+ `SELECT series_id, observation_date, close, source FROM market_benchmark_daily
+ ORDER BY series_id ASC, observation_date ASC`,
+ ).toArray();
+ const points = rows.map((row) => ({
+ seriesId: row.series_id,
+ observationDate: row.observation_date,
+ close: row.close,
+ ...(row.source ? { source: row.source } : {}),
+ }));
+ if (command.performance === true) return { ok: true, points };
+ return { ok: true, ...publicMarketBenchmarkReadModel(points) };
+ }
+
+ putMarketBenchmarkPoints(command) {
+ let normalized;
+ try {
+ normalized = normalizeMarketBenchmarkSyncPayload(command.payload || command);
+ } catch (error) {
+ if (error instanceof MarketBenchmarkError) throw new HttpError(error.code, error.status || 400);
+ throw error;
+ }
+ const updatedAt = new Date().toISOString();
+ let written = 0;
+ let unchanged = 0;
+ for (const point of normalized.points) {
+ const existing = this.sql.exec(
+ `SELECT close, source FROM market_benchmark_daily WHERE series_id = ? AND observation_date = ?`,
+ point.seriesId,
+ point.observationDate,
+ ).toArray()[0];
+ if (existing && existing.close === point.close
+ && (existing.source || null) === (point.source || null)) {
+ unchanged += 1;
+ continue;
+ }
+ if (existing && existing.close !== point.close) {
+ throw new HttpError("market_benchmark_point_conflict", 409);
+ }
+ this.sql.exec(
+ `INSERT INTO market_benchmark_daily (series_id, observation_date, close, source, updated_at)
+ VALUES (?, ?, ?, ?, ?)
+ ON CONFLICT(series_id, observation_date) DO UPDATE SET
+ close = excluded.close,
+ source = excluded.source,
+ updated_at = excluded.updated_at`,
+ point.seriesId,
+ point.observationDate,
+ point.close,
+ point.source || null,
+ updatedAt,
+ );
+ written += 1;
+ }
+ return {
+ ok: true,
+ stored: true,
+ schema_version: MARKET_BENCHMARK_SCHEMA,
+ inception_date: this.readMarketBenchmarkPoints().inception_date,
+ written,
+ unchanged,
+ points: normalized.points.length,
+ };
+ }
+
+ reviseMarketBenchmarkPoints(command) {
+ const appliedAt = typeof command.applied_at === "string" && !Number.isNaN(Date.parse(command.applied_at))
+ ? command.applied_at
+ : new Date().toISOString();
+ // Plan is validated by the HTTP layer (hashes + concrete updates); DO only applies.
+ const plan = command.plan;
+ if (!plan || !Array.isArray(plan.updates) || !Array.isArray(plan.ledger_entries)) {
+ throw new HttpError("benchmark_revision_plan_required", 400);
+ }
+ if (plan.overwrites !== plan.updates.length || plan.deletes !== 0) {
+ throw new HttpError("benchmark_revision_plan_invalid", 400);
+ }
+ const existingProposal = this.sql.exec(
+ `SELECT proposal_sha256 FROM market_benchmark_revision_ledger WHERE proposal_sha256 = ? LIMIT 1`,
+ plan.proposal_sha256,
+ ).toArray()[0];
+ if (existingProposal) throw new HttpError("benchmark_revision_already_applied", 409);
+ let written = 0;
+ for (const point of plan.updates) {
+ const existing = this.sql.exec(
+ `SELECT close, source FROM market_benchmark_daily WHERE series_id = ? AND observation_date = ?`,
+ point.seriesId,
+ point.observationDate,
+ ).toArray()[0];
+ if (!existing) throw new HttpError("benchmark_revision_target_missing", 404);
+ if (existing.close === point.close) throw new HttpError("benchmark_revision_noop", 400);
+ this.sql.exec(
+ `UPDATE market_benchmark_daily SET close = ?, source = ?, updated_at = ? WHERE series_id = ? AND observation_date = ?`,
+ point.close,
+ point.source || null,
+ appliedAt,
+ point.seriesId,
+ point.observationDate,
+ );
+ written += 1;
+ }
+ for (const entry of plan.ledger_entries) {
+ this.sql.exec(
+ `INSERT INTO market_benchmark_revision_ledger (
+ proposal_sha256, entry_index, series_id_sha256, observation_date,
+ prior_close_sha256, new_close_sha256, candidate_source, reason, applied_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ entry.proposal_sha256,
+ entry.entry_index,
+ entry.series_id_sha256,
+ entry.observation_date,
+ entry.prior_close_sha256,
+ entry.new_close_sha256,
+ entry.candidate_source,
+ entry.reason,
+ entry.applied_at || appliedAt,
+ );
+ }
+ return {
+ ok: true,
+ applied: true,
+ proposal_sha256: plan.proposal_sha256,
+ overwrites: written,
+ deletes: 0,
+ ledger_entries: plan.ledger_entries.length,
+ };
+ }
+
+
+ binanceWalletHistoryContext(command) {
+ const accountKey = command?.account_key;
+ const sourceBindingId = command?.source_binding_id;
+ if (typeof accountKey !== "string" || !accountKey
+ || typeof sourceBindingId !== "string" || !/^[a-f0-9]{64}$/.test(sourceBindingId)
+ || command.storage_account_key !== `${accountKey}:${sourceBindingId}`
+ || typeof command.target_id !== "string" || !command.target_id
+ || typeof command.account_scope !== "string" || !command.account_scope) {
+ throw new HttpError("invalid_binance_wallet_history_account", 400);
+ }
+ return {
+ account_key: command.storage_account_key,
+ target_id: command.target_id,
+ account_scope: command.account_scope,
+ source_binding_id: sourceBindingId,
+ binding: {
+ target_id: command.target_id,
+ account_scope: command.account_scope,
+ source_binding: { kind: "binance_readonly_scope_revision", id: sourceBindingId },
+ },
+ };
+ }
+
+ binanceWalletHistoryCommand(command) {
+ const context = this.binanceWalletHistoryContext(command);
+ if (command.action === "binance_wallet_history_read") {
+ const rows = this.sql.exec(
+ `SELECT payload_json, target_id, source_binding_id, account_scope FROM account_facts_daily
+ WHERE platform = 'binance' AND account_key = ? ORDER BY observation_date ASC`,
+ context.account_key,
+ ).toArray();
+ const days = [];
+ for (const row of rows) {
+ if (row.target_id !== context.target_id || row.source_binding_id !== context.source_binding_id
+ || row.account_scope !== context.account_scope) {
+ throw new HttpError("binance_wallet_history_identity_mismatch", 409);
+ }
+ let payload;
+ try { payload = JSON.parse(row.payload_json); }
+ catch { throw new HttpError("binance_wallet_history_stored_invalid", 409); }
+ try { days.push(normalizeBinanceWalletHistoryEntry(payload, context.binding)); }
+ catch { throw new HttpError("binance_wallet_history_stored_invalid", 409); }
+ }
+ return { ok: true, days };
+ }
+
+ let history;
+ try { history = normalizeBinanceWalletHistoryEntry(command.history, context.binding); }
+ catch { throw new HttpError("invalid_binance_wallet_history", 400); }
+ const row = this.sql.exec(
+ `SELECT payload_json, target_id, source_binding_id, account_scope FROM account_facts_daily
+ WHERE platform = 'binance' AND account_key = ? AND observation_date = ?`,
+ context.account_key,
+ history.observation_date,
+ ).toArray()[0];
+ let existing = null;
+ if (row) {
+ if (row.target_id !== context.target_id || row.source_binding_id !== context.source_binding_id
+ || row.account_scope !== context.account_scope) {
+ throw new HttpError("binance_wallet_history_identity_mismatch", 409);
+ }
+ try { existing = normalizeBinanceWalletHistoryEntry(JSON.parse(row.payload_json), context.binding); }
+ catch { throw new HttpError("binance_wallet_history_stored_invalid", 409); }
+ }
+ if (existing) {
+ const existingTime = Date.parse(existing.report_observed_finished_at);
+ const incomingTime = Date.parse(history.report_observed_finished_at);
+ if (incomingTime < existingTime) return { ok: true, unchanged: true };
+ if (incomingTime === existingTime) {
+ if (JSON.stringify(existing) !== JSON.stringify(history)) {
+ throw new HttpError("binance_wallet_history_conflict", 409);
+ }
+ return { ok: true, unchanged: true };
+ }
+ }
+ const updatedAt = new Date().toISOString();
+ this.sql.exec(
+ `INSERT INTO account_facts_daily (
+ platform, account_key, observation_date, payload_json, observed_finished_at,
+ target_id, source_binding_id, account_scope, updated_at
+ ) VALUES ('binance', ?, ?, ?, ?, ?, ?, ?, ?)
+ ON CONFLICT(platform, account_key, observation_date) DO UPDATE SET
+ payload_json = excluded.payload_json,
+ observed_finished_at = excluded.observed_finished_at,
+ target_id = excluded.target_id,
+ source_binding_id = excluded.source_binding_id,
+ account_scope = excluded.account_scope,
+ updated_at = excluded.updated_at`,
+ context.account_key,
+ history.observation_date,
+ JSON.stringify(history),
+ history.report_observed_finished_at,
+ context.target_id,
+ context.source_binding_id,
+ context.account_scope,
+ updatedAt,
+ );
+ const latestDate = this.sql.exec(
+ "SELECT MAX(observation_date) AS latest_date FROM account_facts_daily WHERE platform = 'binance' AND account_key = ?",
+ context.account_key,
+ ).toArray()[0]?.latest_date;
+ const cutoff = historyRetentionCutoff(latestDate, BINANCE_WALLET_HISTORY_MAX_DAYS);
+ if (cutoff) {
+ this.sql.exec("DELETE FROM account_facts_daily WHERE platform = 'binance' AND account_key = ? AND observation_date < ?",
+ context.account_key, cutoff);
+ }
+ return { ok: true, unchanged: false };
+ }
+
+ accountPeriodReturnCommand(command) {
+ const context = this.accountFactsStorageContext(command);
+ if (context.platform !== "ibkr") throw new HttpError("invalid_account_period_return", 400);
+ const binding = { ...context, source_binding: { id: context.source_binding_id } };
+ const sourceIds = [context.source_binding_id, ...(context.history_source_binding_ids || [])];
+ const sources = new Set(sourceIds);
+ const readStored = (payloadJson) => {
+ const payload = JSON.parse(payloadJson);
+ if (!sources.has(payload?.source_binding_id)) throw new HttpError("account_period_return_source_unqualified", 409);
+ return normalizeIbkrPeriodReturn(payload, {
+ binding: { ...binding, source_binding: { id: payload.source_binding_id } }, enforceFresh: false,
+ });
+ };
+ const existing = this.sql.exec("SELECT payload_json FROM account_period_return WHERE account_key = ?", context.account_key).toArray()[0];
+ let prior = null;
+ if (existing) {
+ try { prior = readStored(existing.payload_json); }
+ catch { /* Keep the latest interval unavailable; independently qualify daily rows below. */ }
+ }
+ if (command.action === "account_period_return_read") {
+ const dailyByDay = new Map();
+ let conflictingDailyValues = false;
+ const conflictingNav = new Set();
+ const navByDay = new Map();
+ const addDaily = (row) => {
+ const key = `${row.currency}:${row.period.to}`;
+ const old = dailyByDay.get(key);
+ if (old && Number(old.value) !== Number(row.value)) {
+ conflictingDailyValues = true;
+ return;
+ }
+ if (row.nav_change) {
+ const nav = canonicalResearchTaskJson(row.nav_change);
+ if (navByDay.has(key) && navByDay.get(key) !== nav) conflictingNav.add(key);
+ else navByDay.set(key, nav);
+ }
+ if (!old || row.source_binding_id === context.source_binding_id
+ || (old.source_binding_id !== context.source_binding_id
+ && Date.parse(row.observed_at) > Date.parse(old.observed_at))) dailyByDay.set(key, row);
+ };
+ const rows = this.sql.exec(`SELECT payload_json FROM account_daily_native_return
+ WHERE account_key = ? AND source_binding_id IN (${sourceIds.map(() => "?").join(",")})
+ ORDER BY observation_date DESC LIMIT ?`, context.account_key, ...sourceIds, 366 * sourceIds.length);
+ for (const stored of rows) {
+ let row;
+ try { row = readStored(stored.payload_json); } catch { continue; }
+ addDaily(row);
+ }
+ if (prior && prior.period.from === prior.period.to) addDaily(prior);
+ if (conflictingDailyValues) return { ok: true, return: {
+ ...ACCOUNT_FACTS_RETURN_UNAVAILABLE, reason: "native_return_history_conflict",
+ } };
+ const daily = [...dailyByDay.values()].sort((a, b) => b.period.to.localeCompare(a.period.to)).slice(0, 366);
+ const latest = prior ? publicIbkrPeriodReturn(prior) : { ...ACCOUNT_FACTS_RETURN_UNAVAILABLE };
+ if (prior && prior.period.from === prior.period.to && conflictingNav.has(`${prior.currency}:${prior.period.to}`)) delete latest.nav_change;
+ return { ok: true, return: { ...latest,
+ daily: daily.sort((a, b) => a.period.to.localeCompare(b.period.to)).map(row => {
+ const projected = publicIbkrPeriodReturn(row);
+ if (conflictingNav.has(`${row.currency}:${row.period.to}`)) delete projected.nav_change;
+ return projected;
+ }) } };
+ }
+ const incoming = normalizeIbkrPeriodReturn(command.payload, { binding });
+ const historical = command.historical === true;
+ if (historical && (incoming.period.from !== incoming.period.to || Date.now() - Date.parse(incoming.period.to + "T00:00:00Z") > 366 * 86400000)) throw new HttpError("invalid_account_daily_return", 400);
+ if (prior && !historical) {
+ if (incoming.period.to < prior.period.to || Date.parse(incoming.observed_at) < Date.parse(prior.observed_at)) throw new HttpError("account_period_return_stale_write", 409);
+ if (incoming.observed_at === prior.observed_at && canonicalResearchTaskJson(incoming) !== canonicalResearchTaskJson(prior)) throw new HttpError("account_period_return_conflict", 409);
+ }
+ if (incoming.period.from === incoming.period.to) {
+ const oldDay = this.sql.exec("SELECT payload_json FROM account_daily_native_return WHERE account_key = ? AND source_binding_id = ? AND currency = ? AND observation_date = ?", context.account_key, context.source_binding_id, incoming.currency, incoming.period.to).toArray()[0];
+ if (oldDay) {
+ const old = normalizeIbkrPeriodReturn(JSON.parse(oldDay.payload_json), { binding, enforceFresh: false });
+ if (Date.parse(incoming.observed_at) < Date.parse(old.observed_at)) throw new HttpError("account_daily_return_stale_write", 409);
+ if (incoming.observed_at === old.observed_at && canonicalResearchTaskJson(incoming) !== canonicalResearchTaskJson(old)) throw new HttpError("account_daily_return_conflict", 409);
+ }
+ this.sql.exec("INSERT INTO account_daily_native_return (account_key, source_binding_id, currency, observation_date, payload_json) VALUES (?, ?, ?, ?, ?) ON CONFLICT(account_key, source_binding_id, currency, observation_date) DO UPDATE SET payload_json = excluded.payload_json", context.account_key, context.source_binding_id, incoming.currency, incoming.period.to, JSON.stringify(incoming));
+ }
+ if (historical && prior && (incoming.period.to < prior.period.to || Date.parse(incoming.observed_at) < Date.parse(prior.observed_at))) return { ok: true, unchanged: false };
+ if (prior && canonicalResearchTaskJson(incoming) === canonicalResearchTaskJson(prior)) return { ok: true, unchanged: true };
+ this.sql.exec("INSERT INTO account_period_return (account_key, payload_json) VALUES (?, ?) ON CONFLICT(account_key) DO UPDATE SET payload_json = excluded.payload_json", context.account_key, JSON.stringify(incoming));
+ return { ok: true, unchanged: false };
+ }
+
+ // Internal only: a future authorized caller must supply verified account and
+ // source bindings. The browser/session and publisher routes do not call this.
+ researchNativeDailyReturns(command) {
+ const context = this.accountFactsStorageContext(command);
+ const from = runtimeDailyCalendarDate(command.from), to = runtimeDailyCalendarDate(command.to);
+ const start = Date.parse(`${from}T00:00:00Z`), end = Date.parse(`${to}T00:00:00Z`);
+ if (context.platform !== "ibkr" || !/^[a-f0-9]{64}$/.test(context.source_binding_id)
+ || !context.account_scope || !context.account_selector || !context.target_id
+ || typeof command.currency !== "string" || !/^[A-Z]{3}$/.test(command.currency)
+ || !from || !to || end < start || (end - start) / 86400000 >= 366)
+ throw new HttpError("invalid_native_return_research_range", 400);
+ const sources = new Set([context.source_binding_id, ...(context.history_source_binding_ids || [])]);
+ let stored;
+ try {
+ stored = this.sql.exec(`SELECT source_binding_id, currency, observation_date, payload_json
+ FROM account_daily_native_return WHERE account_key = ? AND currency = ? AND observation_date >= ? AND observation_date <= ?
+ ORDER BY observation_date, source_binding_id LIMIT ?`, context.account_key, command.currency, from, to, 366 * 65 + 1).toArray();
+ } catch { throw new HttpError("native_return_read_failed", 503); }
+ if (stored.length > 366 * 65) throw new HttpError("native_return_read_limit_exceeded", 503);
+ const byDate = new Map();
+ const navByDate = new Map();
+ const decimal = text => {
+ const [whole, fraction = ""] = text.split(".");
+ return { number: BigInt(whole + fraction), scale: fraction.length };
+ };
+ const decimalEqual = (left, right) => {
+ const a = decimal(left), b = decimal(right);
+ return a.number * 10n ** BigInt(b.scale) === b.number * 10n ** BigInt(a.scale);
+ };
+ const navFields = ["startingValue", "endingValue", "depositsWithdrawals", "internalCashTransfers", "assetTransfers", "linkingAdjustments"];
+ for (const item of stored) {
+ const date = runtimeDailyCalendarDate(item.observation_date);
+ if (!date) return { ok: false, error: "native_return_record_invalid", date: null };
+ if (!sources.has(item.source_binding_id)) return { ok: false, error: "native_return_source_unqualified", date };
+ let raw;
+ try {
+ raw = JSON.parse(item.payload_json);
+ const validated = normalizeIbkrPeriodReturn(raw, { binding: { ...context, source_binding: { id: item.source_binding_id } }, enforceFresh: false });
+ if (validated.currency !== item.currency || validated.period.from !== date || validated.period.to !== date) throw Error();
+ } catch { return { ok: false, error: "native_return_record_invalid", date }; }
+ const previous = byDate.get(date);
+ if (previous) {
+ if (!decimalEqual(previous.value, raw.value))
+ return { ok: false, error: "native_return_history_conflict", date };
+ }
+ if (raw.nav_change) {
+ const priorNav = navByDate.get(date), nav = raw.nav_change;
+ if (priorNav && (!decimalEqual(priorNav.amount, nav.amount)
+ || navFields.some(field => !decimalEqual(priorNav.components[field], nav.components[field]))))
+ return { ok: false, error: "native_return_nav_conflict", date };
+ navByDate.set(date, nav);
+ }
+ // SQL order is deterministic; prefer the currently configured source.
+ if (!previous || raw.source_binding_id === context.source_binding_id) byDate.set(date, raw);
+ }
+ const rows = [...byDate.values()];
+ const datesWithoutRecords = [];
+ for (let day = start; day <= end; day += 86400000) {
+ const date = new Date(day).toISOString().slice(0, 10);
+ if (!byDate.has(date)) datesWithoutRecords.push(date);
+ }
+ return { ok: true, status: "ok", currency: command.currency, from, to, rows,
+ source_row_count: stored.length, duplicate_row_count: stored.length - rows.length,
+ returned_from: rows[0]?.period.to || null, returned_to: rows.at(-1)?.period.to || null,
+ dates_without_records: datesWithoutRecords, calendar_qualification: "unknown", published_at: null, historical_pit: "unknown" };
+ }
+
+ accountFactsStorageContext(command) {
+ if (!ACCOUNT_FACTS_SUPPORTED_PLATFORMS.includes(command?.platform)
+ || typeof command.account_key !== "string" || !command.account_key
+ || typeof command.account_scope !== "string"
+ || typeof command.account_selector !== "string"
+ || typeof command.target_id !== "string"
+ || typeof command.source_binding_id !== "string") {
+ throw new HttpError("invalid_account_facts_account", 400);
+ }
+ const historyIds = command.history_source_binding_ids;
+ if (historyIds !== undefined && (!["account_facts_history_read", "account_facts_history_put", "account_period_return_read", "account_period_return_put", "account_daily_native_return_research_read", "account_executions_read", "account_executions_put"].includes(command.action)
+ || !Array.isArray(historyIds) || historyIds.length < 1 || historyIds.length > 64
+ || new Set(historyIds).size !== historyIds.length
+ || historyIds.some(id => typeof id !== "string" || !/^[a-f0-9]{64}$/.test(id)
+ || id === command.source_binding_id))) throw new HttpError("invalid_account_facts_history_sources", 400);
+ const brokerAccountId = command.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? command.broker_account_id : null;
+ if (command.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM && !validFirstradeAccountId(brokerAccountId)) {
+ throw new HttpError("invalid_account_facts_account", 400);
+ }
+ const brokerAccountHash = command.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
+ ? command.broker_account_hash
+ : null;
+ if (command.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
+ && (typeof brokerAccountHash !== "string" || !brokerAccountHash || brokerAccountHash.length > 256)) {
+ throw new HttpError("invalid_account_facts_account", 400);
+ }
+ return {
+ platform: command.platform,
+ ...(command.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? { broker_account_id: brokerAccountId } : {}),
+ account_key: command.account_key,
+ account_scope: command.account_scope,
+ account_selector: command.account_selector,
+ target_id: command.target_id,
+ source_binding_id: command.source_binding_id,
+ ...(historyIds ? { history_source_binding_ids: [...historyIds] } : {}),
+ ...(command.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
+ ? { broker_account_hash: brokerAccountHash }
+ : {}),
+ };
+ }
+
+ validateAccountFactsStoragePayload(payload, context, { historical = false } = {}) {
+ try {
+ const normalize = historical ? normalizeAccountFactsHistoricalPayload : normalizeAccountFactsHistoryPayload;
+ return normalize(payload, {
+ expectedPlatform: context.platform,
+ expectedTargetId: context.target_id,
+ expectedBindingId: context.source_binding_id,
+ expectedOptionScope: context.account_scope,
+ expectedAccountSelector: context.platform === IBKR_ACCOUNT_FACTS_PLATFORM
+ ? context.account_selector
+ : null,
+ expectedBrokerAccountHash: context.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
+ ? context.broker_account_hash
+ : null,
+ expectedBrokerAccountId: context.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? context.broker_account_id : null,
+ enforceObservationWindow: false,
+ });
+ } catch (error) {
+ if (error instanceof AccountFactsError) throw new HttpError(error.code, error.status || 400);
+ throw error;
+ }
+ }
+
+ validatePriorAccountFactsForAccount(row, context) {
+ if (!row) return null;
+ if (row.platform !== context.platform || row.account_key !== context.account_key
+ || row.account_scope !== context.account_scope || row.target_id !== context.target_id) {
+ throw new HttpError("account_facts_identity_mismatch", 409);
+ }
+ const priorBindingId = row.payload?.source_binding?.id;
+ if (typeof priorBindingId !== "string") throw new HttpError("account_facts_stored_invalid", 409);
+ const priorContext = { ...context, source_binding_id: priorBindingId };
+ const payload = this.validateAccountFactsStoragePayload(row.payload, priorContext);
+ if (row.source_binding_id !== priorBindingId
+ || payload.target_id !== row.target_id
+ || payload.source_binding.id !== row.source_binding_id) {
+ throw new HttpError("account_facts_identity_mismatch", 409);
+ }
+ return { ...row, payload };
+ }
+
+ readAccountFactsRow(platform, accountKey, context = null) {
+ const row = this.sql.exec(
+ "SELECT payload_json, observed_finished_at, observation_date, target_id, source_binding_id, account_scope FROM account_facts_observation WHERE platform = ? AND account_key = ?",
+ platform,
+ accountKey,
+ ).toArray()[0];
+ if (!row) return null;
+ let payload;
+ try { payload = JSON.parse(row.payload_json); } catch { throw new HttpError("account_facts_stored_invalid", 409); }
+ if (context) {
+ if (platform !== context.platform || accountKey !== context.account_key
+ || row.target_id !== context.target_id
+ || row.source_binding_id !== context.source_binding_id
+ || row.account_scope !== context.account_scope) {
+ throw new HttpError("account_facts_identity_mismatch", 409);
+ }
+ payload = this.validateAccountFactsStoragePayload(payload, context);
+ }
+ return {
+ platform,
+ account_key: accountKey,
+ payload,
+ observed_finished_at: row.observed_finished_at,
+ observation_date: row.observation_date,
+ target_id: row.target_id,
+ source_binding_id: row.source_binding_id,
+ account_scope: row.account_scope,
+ };
+ }
+
+ putAccountFactsObservation(command) {
+ const context = this.accountFactsStorageContext(command);
+ if (!command.history || typeof command.history !== "object" || Array.isArray(command.history)) {
+ throw new HttpError("invalid_account_facts_history", 400);
+ }
+ let history;
+ try {
+ history = this.validateAccountFactsStoragePayload(command.history, context);
+ } catch (error) {
+ if (error instanceof AccountFactsError) throw new HttpError(error.code, error.status || 400);
+ throw error;
+ }
+ const existingRow = this.validatePriorAccountFactsForAccount(
+ this.readAccountFactsRow(command.platform, command.account_key),
+ context,
+ );
+ const decision = decideAccountFactsPut(existingRow?.payload || null, history);
+ if (decision.action === "reject") throw new HttpError(decision.reason, decision.status || 409);
+ let flowChanged = false;
+ if (command.externalFlow !== undefined) {
+ if (!this.externalFlowEnabled) throw new HttpError("external_flow_disabled", 409);
+ const flow = normalizeExternalFlow(command.externalFlow);
+ const source = { ibkr: "ibkr_flex", schwab: "schwab_transactions", longbridge: "longbridge_cashflow" }[context.platform];
+ const currencies = new Set(history.broker_reported_balances.map(b => b.currency));
+ if (flow.windows.some(w => w.source !== source || !currencies.has(w.currency)
+ || Date.parse(w.period_end) > Date.parse(history.observed_finished_at))) {
+ throw new HttpError("external_flow_observation_mismatch", 409);
+ }
+ flowChanged = !putExternalFlow(this.sql, context, flow).unchanged;
+ }
+ if (decision.action === "keep") {
+ // Latest table unchanged; still ensure the accepted day is retained.
+ this.upsertAccountFactsDaily(context, history);
+ return {
+ ok: true,
+ stored: true,
+ unchanged: !flowChanged,
+ platform: command.platform,
+ account_key: command.account_key,
+ observation_date: existingRow.observation_date,
+ observed_finished_at: existingRow.observed_finished_at,
+ };
+ }
+ const updatedAt = new Date().toISOString();
+ const payloadJson = JSON.stringify(history);
+ this.sql.exec(
+ `INSERT INTO account_facts_observation (
+ platform, account_key, payload_json, observed_finished_at, observation_date,
+ target_id, source_binding_id, account_scope, updated_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ON CONFLICT(platform, account_key) DO UPDATE SET
+ payload_json = excluded.payload_json,
+ observed_finished_at = excluded.observed_finished_at,
+ observation_date = excluded.observation_date,
+ target_id = excluded.target_id,
+ source_binding_id = excluded.source_binding_id,
+ account_scope = excluded.account_scope,
+ updated_at = excluded.updated_at`,
+ command.platform,
+ command.account_key,
+ payloadJson,
+ history.observed_finished_at,
+ history.observation_date,
+ history.target_id,
+ history.source_binding.id,
+ command.account_scope,
+ updatedAt,
+ );
+ this.upsertAccountFactsDaily(context, history);
+ return {
+ ok: true,
+ stored: true,
+ unchanged: false,
+ platform: command.platform,
+ account_key: command.account_key,
+ observation_date: history.observation_date,
+ observed_finished_at: history.observed_finished_at,
+ };
+ }
+
+ putAccountFactsHistoricalObservation(command) {
+ const context = this.accountFactsStorageContext(command);
+ const sourceId = command.history?.source_binding?.id;
+ if (![context.source_binding_id, ...(context.history_source_binding_ids || [])].includes(sourceId)) {
+ throw new HttpError("account_facts_binding_unmatched", 409);
+ }
+ const history = this.validateAccountFactsStoragePayload(command.history,
+ { ...context, source_binding_id: sourceId }, { historical: true });
+ // Deliberately bypass latest observation and external-flow writes. Reuse
+ // daily storage with replacement and retention deletion disabled.
+ return { ok: true, stored: true, ...this.upsertAccountFactsDaily(context, history, { appendOnly: true }) };
+ }
+
+ readAccountFactsDailyRow(platform, accountKey, observationDate, context = null) {
+ const row = this.sql.exec(
+ `SELECT payload_json, observed_finished_at, observation_date, target_id, source_binding_id, account_scope
+ FROM account_facts_daily WHERE platform = ? AND account_key = ? AND observation_date = ?`,
+ platform,
+ accountKey,
+ observationDate,
+ ).toArray()[0];
+ if (!row) return null;
+ let payload;
+ try { payload = JSON.parse(row.payload_json); } catch { throw new HttpError("account_facts_stored_invalid", 409); }
+ if (context) {
+ if (platform !== context.platform || accountKey !== context.account_key
+ || row.target_id !== context.target_id
+ || row.source_binding_id !== context.source_binding_id
+ || row.account_scope !== context.account_scope) {
+ throw new HttpError("account_facts_identity_mismatch", 409);
+ }
+ payload = this.validateAccountFactsStoragePayload(payload, context);
+ }
+ return {
+ platform,
+ account_key: accountKey,
+ observation_date: row.observation_date,
+ payload,
+ observed_finished_at: row.observed_finished_at,
+ target_id: row.target_id,
+ source_binding_id: row.source_binding_id,
+ account_scope: row.account_scope,
+ };
+ }
+
+ upsertAccountFactsDaily(context, history, { appendOnly = false } = {}) {
+ const { platform, account_key: accountKey, account_scope: accountScope } = context;
+ const existing = this.validatePriorAccountFactsForAccount(
+ this.readAccountFactsDailyRow(platform, accountKey, history.observation_date),
+ context,
+ );
+ if (appendOnly && existing) {
+ if (existing.observed_finished_at !== history.observed_finished_at
+ || canonicalizeAccountFactsHistory(existing.payload) !== canonicalizeAccountFactsHistory(history)) {
+ throw new HttpError("account_facts_daily_conflict", 409);
+ }
+ return { unchanged: true };
+ }
+ let decision;
+ try {
+ decision = decideAccountFactsDailyUpsert(existing?.payload || null, history);
+ } catch (error) {
+ if (error instanceof AccountFactsError) throw new HttpError(error.code, error.status || 400);
+ throw error;
+ }
+ if (decision.action === "reject") throw new HttpError(decision.reason, decision.status || 409);
+ if (decision.action === "skip" || decision.action === "keep") {
+ this.pruneAccountFactsDaily(platform, accountKey, history.observation_date);
+ return { unchanged: true };
+ }
+ const updatedAt = new Date().toISOString();
+ this.sql.exec(
+ `INSERT INTO account_facts_daily (
+ platform, account_key, observation_date, payload_json, observed_finished_at,
+ target_id, source_binding_id, account_scope, updated_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ${appendOnly ? "" : `ON CONFLICT(platform, account_key, observation_date) DO UPDATE SET
+ payload_json = excluded.payload_json,
+ observed_finished_at = excluded.observed_finished_at,
+ target_id = excluded.target_id,
+ source_binding_id = excluded.source_binding_id,
+ account_scope = excluded.account_scope,
+ updated_at = excluded.updated_at`}`,
+ platform,
+ accountKey,
+ history.observation_date,
+ JSON.stringify(history),
+ history.observed_finished_at,
+ history.target_id,
+ history.source_binding.id,
+ accountScope,
+ updatedAt,
+ );
+ if (!appendOnly) this.pruneAccountFactsDaily(platform, accountKey, history.observation_date);
+ return { unchanged: false };
+ }
+
+ pruneAccountFactsDaily(platform, accountKey, latestDate) {
+ const cutoff = historyRetentionCutoff(latestDate, ACCOUNT_FACTS_HISTORY_MAX_DAYS);
+ if (!cutoff) return;
+ this.sql.exec(
+ "DELETE FROM account_facts_daily WHERE platform = ? AND account_key = ? AND observation_date < ?",
+ platform,
+ accountKey,
+ cutoff,
+ );
+ }
+
+ readAccountFactsDailyHistory(command) {
+ const context = this.accountFactsStorageContext(command);
+ const { platform, account_key: accountKey } = context;
+ if (command.projection === "external-flow-coverage") {
+ return { ok: true, ...readExternalFlowCoverage(this.sql, context) };
+ }
+ if (command.projection !== undefined) {
+ const dates = accountFactsIdentityDates(command.from, command.to);
+ if (command.projection !== "identity" || !dates) {
+ throw new HttpError("invalid_account_facts_identity_query", 400);
+ }
+ // Deliberately exclude payload_json: identity inspection must not read assets.
+ const rows = this.sql.exec(
+ `SELECT observation_date, observed_finished_at, target_id, source_binding_id, account_scope
+ FROM account_facts_daily WHERE platform = ? AND account_key = ?
+ AND observation_date >= ? AND observation_date <= ? ORDER BY observation_date ASC`,
+ platform, accountKey, dates[0], dates.at(-1),
+ ).toArray();
+ const same = (value, expected) => typeof value === "string" && value.length > 0 && value.length <= 512
+ ? value === expected : null;
+ return { ok: true, records: dates.map(date => {
+ const matches = rows.filter(row => row.observation_date === date);
+ const row = matches.length === 1 ? matches[0] : null;
+ const source = row?.source_binding_id;
+ return {
+ observation_date: date, observed_finished_at: row?.observed_finished_at ?? null,
+ target_id_matches: same(row?.target_id, context.target_id),
+ source_binding_id_matches: same(source, context.source_binding_id),
+ account_scope_matches: same(row?.account_scope, context.account_scope),
+ record_revision: null,
+ row_present: matches.length > 1 ? null : Boolean(row),
+ source_binding_id_trusted: typeof source === "string" && source.length > 0 && source.length <= 512
+ ? [context.source_binding_id, ...(context.history_source_binding_ids || [])].includes(source) : null,
+ stored_source_binding_id: typeof source === "string" && /^[a-f0-9]{64}$/.test(source) ? source : null,
+ };
+ }) };
+ }
+ const rows = this.sql.exec(
+ `SELECT payload_json, observed_finished_at, observation_date, target_id, source_binding_id, account_scope
+ FROM account_facts_daily WHERE platform = ? AND account_key = ? ORDER BY observation_date ASC`,
+ platform,
+ accountKey,
+ ).toArray();
+ const days = [];
+ for (const row of rows) {
+ // Same-account history may use an explicitly qualified prior source.
+ // Current observations and ordinary sync still require the current source.
+ if (row.target_id !== context.target_id
+ || ![context.source_binding_id, ...(context.history_source_binding_ids || [])].includes(row.source_binding_id)
+ || row.account_scope !== context.account_scope) continue;
+ let payload;
+ try { payload = JSON.parse(row.payload_json); } catch { throw new HttpError("account_facts_stored_invalid", 409); }
+ payload = this.validateAccountFactsStoragePayload(payload, { ...context, source_binding_id: row.source_binding_id });
+ days.push({
+ observation_date: row.observation_date,
+ payload,
+ observed_finished_at: row.observed_finished_at,
+ target_id: row.target_id,
+ source_binding_id: row.source_binding_id,
+ account_scope: row.account_scope,
+ });
+ }
+ return { ok: true, days,
+ externalFlow: readExternalFlow(this.sql, context, { dateOnly: !this.externalFlowEnabled }),
+ };
+ }
+
+ readAccountFactsObservation(command) {
+ const context = this.accountFactsStorageContext(command);
+ const row = this.readAccountFactsRow(context.platform, context.account_key, context);
+ return { ok: true, observation: row };
+ }
+
+ listAccountFactsObservations(command) {
+ const wanted = Array.isArray(command.accounts) ? command.accounts : [];
+ const observations = [];
+ for (const item of wanted) {
+ if (!item || typeof item.platform !== "string" || typeof item.account_key !== "string") continue;
+ const context = this.accountFactsStorageContext(item);
+ try {
+ const row = this.readAccountFactsRow(context.platform, context.account_key, context);
+ if (row) observations.push(row);
+ } catch (error) {
+ // A trusted binding rotation makes older rows ineligible for display.
+ // Keep them stored for audit, but treat them as absent until refreshed.
+ if (!(error instanceof HttpError) || error.message !== "account_facts_identity_mismatch") throw error;
+ }
+ }
+ return { ok: true, observations };
+ }
+
+ accountSettingsCommand(command) {
+ if (!command || typeof command.actor !== "string" || !command.actor) throw new HttpError("runtime_instance_actor_required", 400);
+ if (command.action === "risk_profile_read") return this.readRiskProfileAuthority(command.legacy);
+ if (command.action === "risk_profile_replace") return this.replaceRiskProfileAuthority(command);
+ if (command.action === "risk_profile_set") return this.setRiskProfileAuthority(command);
+ if (command.action === "account_declarations_read") {
+ const state = this.read();
+ if (!state.initialized) throw new HttpError("runtime_instances_not_initialized", 409);
+ return { declarations: state.instances.filter(item => item.kind === "existing").map(item => ({
+ platform: item.platform, key: item.key, binding_environment: accountSettingsIdentity(item).broker_environment,
+ ...this.accountSettingDeclaration(item, accountSettingsIdentity(item)),
+ })) };
+ }
+ if (command.action === "account_settings_read") return this.readAccountSettings(command);
+ if (command.action === "account_settings_save") return this.saveAccountSettings(command);
+ if (command.action === "account_settings_profile_application_lookup") return this.readAccountSettingsProfileApplication(command);
+ if (command.action === "account_settings_profile_application_approve") return this.approveAccountSettingsProfileApplication(command);
+ if (command.action === "account_settings_profile_application_claim") return this.claimAccountSettingsProfileApplication(command);
+ throw new HttpError("unsupported_account_settings_action", 400);
+ }
+
+ ensureRiskProfileAuthority(legacy) {
+ const row = this.sql.exec("SELECT revision, imported, bindings_json FROM risk_profile_authority WHERE id = 1").toArray()[0];
+ if (row) return row;
+ if (legacy?.state === "blocked") throw new HttpError("risk_profile_bindings_invalid", 409);
+ const bindings = legacy?.state === "valid" && Array.isArray(legacy.bindings) ? legacy.bindings : [];
+ const payload = JSON.stringify(bindings);
+ this.sql.exec("INSERT INTO risk_profile_authority (id, revision, imported, bindings_json) VALUES (1, 0, 1, ?)", payload);
+ return { revision: 0, imported: 1, bindings_json: payload };
+ }
+
+ storedRiskBindings(row) {
+ let bindings;
+ try { bindings = JSON.parse(row.bindings_json); } catch { throw new HttpError("risk_profile_bindings_invalid", 409); }
+ if (!Array.isArray(bindings)) throw new HttpError("risk_profile_bindings_invalid", 409);
+ return bindings;
+ }
+
+ assertStoredRiskBinding(binding, accountOptions) {
+ if (!binding || Array.isArray(binding) || typeof binding !== "object") throw new HttpError("invalid_risk_profile_binding", 400);
+ if (binding.no_order !== true || binding.execution_authority_granted !== false) throw new HttpError("risk_profile_execution_authority_rejected", 400);
+ if (binding.scope_id !== riskProfileScopeId(binding.platform, binding.target_name)) throw new HttpError("invalid_risk_profile_binding", 400);
+ if (!RISK_PROFILE_PREFERENCES.includes(binding.profile_selection?.risk_preference)) throw new HttpError("invalid_risk_profile_binding", 400);
+ const policy = RISK_TIER_POLICY_BINDINGS[binding.profile_selection?.risk_preference];
+ if (!policy || binding.profile_selection?.profile_id !== policy.profile_id) {
+ throw new HttpError("risk_profile_policy_binding_invalid", 409);
+ }
+ if (!riskProfileBindingTargets(accountOptions).some((target) => target.platform === binding.platform && target.target_name === binding.target_name)) {
+ throw new HttpError("risk_profile_binding_target_not_configured", 409);
+ }
+ }
+
+ writeRiskProfileAuthority(row, bindings) {
+ const current = this.storedRiskBindings(row);
+ const same = canonicalResearchTaskJson(current) === canonicalResearchTaskJson(bindings);
+ const revision = same ? Number(row.revision) : Number(row.revision) + 1;
+ if (!same) this.sql.exec("UPDATE risk_profile_authority SET revision = ?, bindings_json = ? WHERE id = 1", revision, JSON.stringify(bindings));
+ const state = this.read();
+ return {
+ ok: true,
+ revision,
+ bindings,
+ account_options: runtimeInstanceAccountOptions(state.instances),
+ instance_revision: state.revision,
+ initialized: state.initialized,
+ no_order: true,
+ execution_authority_granted: false,
+ };
+ }
+
+ readRiskProfileAuthority(legacy) {
+ const row = this.ensureRiskProfileAuthority(legacy);
+ const state = this.read();
+ return {
+ ok: true,
+ revision: Number(row.revision),
+ bindings: this.storedRiskBindings(row),
+ account_options: runtimeInstanceAccountOptions(state.instances),
+ instance_revision: state.revision,
+ initialized: state.initialized,
+ no_order: true,
+ execution_authority_granted: false,
+ };
+ }
+
+ requireRiskRevision(command, row) {
+ if (!Number.isSafeInteger(command.expected_revision) || command.expected_revision !== Number(row.revision)) {
+ throw new HttpError("risk_profile_revision_conflict", 409);
+ }
+ }
+
+ replaceRiskProfileAuthority(command) {
+ const row = this.ensureRiskProfileAuthority(command.legacy);
+ this.requireRiskRevision(command, row);
+ const options = runtimeInstanceAccountOptions(this.read().instances);
+ if (!Array.isArray(command.bindings)) throw new HttpError("invalid_risk_profile_binding", 400);
+ for (const binding of command.bindings) this.assertStoredRiskBinding(binding, options);
+ const bindings = [...command.bindings].sort((left, right) => left.scope_id.localeCompare(right.scope_id));
+ return this.writeRiskProfileAuthority(row, bindings);
+ }
+
+ setRiskProfileAuthority(command) {
+ const row = this.ensureRiskProfileAuthority(command.legacy);
+ this.requireRiskRevision(command, row);
+ const options = runtimeInstanceAccountOptions(this.read().instances);
+ if (!riskProfileBindingTargets(options).some((target) => target.platform === command.platform && target.target_name === command.target_name)) {
+ throw new HttpError("risk_profile_binding_target_not_configured", 409);
+ }
+ const scopeId = riskProfileScopeId(command.platform, command.target_name);
+ const current = this.storedRiskBindings(row).filter((binding) => binding.scope_id !== scopeId);
+ if (command.risk_change === "clear") return this.writeRiskProfileAuthority(row, current);
+ if (command.risk_change !== "set") throw new HttpError("invalid_risk_profile_change", 400);
+ this.assertStoredRiskBinding(command.binding, options);
+ if (command.binding.scope_id !== scopeId) throw new HttpError("invalid_risk_profile_binding", 400);
+ current.push(command.binding);
+ current.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
+ return this.writeRiskProfileAuthority(row, current);
+ }
+
+ existingAccountInstance(platform, key) {
+ const state = this.read();
+ if (!state.initialized) throw new HttpError("runtime_instances_not_initialized", 409);
+ const item = state.instances.find((candidate) => candidate.kind === "existing" && candidate.platform === platform && candidate.key === key);
+ if (!item) throw new HttpError("account_settings_not_found", 404);
+ return { state, item, identity: accountSettingsIdentity(item) };
+ }
+
+ accountSettingDraftView(item, identity) {
+ const row = this.sql.exec(
+ "SELECT revision, identity_json, overrides_json FROM account_setting_draft WHERE platform = ? AND account_key = ?",
+ item.platform, item.key,
+ ).toArray()[0];
+ if (!row) return { status: "empty", revision: 0, identity: null, current_identity: identity, overrides: {} };
+ let storedIdentity = null;
+ let overrides = {};
+ try {
+ storedIdentity = JSON.parse(row.identity_json);
+ overrides = JSON.parse(row.overrides_json);
+ } catch {
+ throw new HttpError("account_settings_draft_invalid", 409);
+ }
+ const conflict = canonicalResearchTaskJson(storedIdentity) !== canonicalResearchTaskJson(identity);
+ return {
+ status: conflict ? "identity_conflict" : "current",
+ revision: Number(row.revision),
+ identity: storedIdentity,
+ current_identity: identity,
+ overrides: overrides && typeof overrides === "object" && !Array.isArray(overrides) ? overrides : {},
+ };
+ }
+
+ accountSettingDeclaration(item, identity) {
+ const row = this.sql.exec("SELECT revision, identity_json, declaration_json FROM account_setting_declaration WHERE platform = ? AND account_key = ?", item.platform, item.key).toArray()[0];
+ if (!row) return { status: "empty", revision: 0, environment: null, account_type: null, source: "user_declared" };
+ const matches = canonicalResearchTaskJson(JSON.parse(row.identity_json)) === canonicalResearchTaskJson(identity);
+ const value = JSON.parse(row.declaration_json);
+ return { status: matches ? "current" : "identity_conflict", revision: Number(row.revision),
+ environment: matches ? value.environment : null, account_type: matches ? value.account_type : null, source: "user_declared" };
+ }
+
+ saveAccountSettingDeclaration(item, identity, command) {
+ if (!command.identity || canonicalResearchTaskJson(command.identity) !== canonicalResearchTaskJson(identity)) throw new HttpError("account_settings_identity_conflict", 409);
+ const current = this.accountSettingDeclaration(item, identity);
+ if (!Number.isSafeInteger(command.expected_declaration_revision) || command.expected_declaration_revision !== current.revision) throw new HttpError("account_settings_declaration_revision_conflict", 409);
+ if (current.status === "identity_conflict") throw new HttpError("account_settings_identity_conflict", 409);
+ const value = command.declaration;
+ if (!value || Array.isArray(value) || typeof value !== "object" || Object.keys(value).some(k => !["environment", "account_type"].includes(k))
+ || ![null, "live", "paper"].includes(value.environment) || ![null, "cash", "margin"].includes(value.account_type)) throw new HttpError("invalid_account_settings_declaration", 400);
+ if (current.status === "current" && current.environment === value.environment && current.account_type === value.account_type) return;
+ this.sql.exec("INSERT INTO account_setting_declaration (platform, account_key, revision, identity_json, declaration_json) VALUES (?, ?, ?, ?, ?) ON CONFLICT (platform, account_key) DO UPDATE SET revision = excluded.revision, identity_json = excluded.identity_json, declaration_json = excluded.declaration_json", item.platform, item.key, current.revision + 1, JSON.stringify(identity), JSON.stringify(value));
+ }
+
+ readAccountSettings(command) {
+ const { state, item, identity } = this.existingAccountInstance(command.platform, command.key);
+ const risk = this.readRiskProfileAuthority(command.legacy);
+ const scopeId = riskProfileScopeId(item.platform, identity.target_name);
+ const binding = risk.bindings.find((entry) => entry.scope_id === scopeId) || null;
+ return {
+ ok: true,
+ found: true,
+ platform: item.platform,
+ key: item.key,
+ instance_revision: state.revision,
+ enabled: item.enabled,
+ identity,
+ config: item.config,
+ draft: this.accountSettingDraftView(item, identity),
+ declaration: this.accountSettingDeclaration(item, identity),
+ risk: {
+ revision: risk.revision,
+ scope_id: scopeId,
+ preference: binding?.profile_selection?.risk_preference || null,
+ binding,
+ },
+ bindings: risk.bindings,
+ account_options: risk.account_options,
+ no_order: true,
+ execution_authority_granted: false,
+ };
+ }
+
+ saveAccountSettingDraft(item, identity, command) {
+ if (!command.identity || Array.isArray(command.identity) || typeof command.identity !== "object") {
+ throw new HttpError("account_settings_identity_required", 400);
+ }
+ if (canonicalResearchTaskJson(command.identity) !== canonicalResearchTaskJson(identity)) {
+ throw new HttpError("account_settings_identity_conflict", 409);
+ }
+ if (!Number.isSafeInteger(command.expected_draft_revision) || command.expected_draft_revision < 0) {
+ throw new HttpError("account_settings_draft_revision_conflict", 409);
+ }
+ const row = this.sql.exec(
+ "SELECT revision, identity_json, overrides_json FROM account_setting_draft WHERE platform = ? AND account_key = ?",
+ item.platform, item.key,
+ ).toArray()[0];
+ const now = new Date().toISOString();
+ if (!row) {
+ if (command.expected_draft_revision !== 0) throw new HttpError("account_settings_draft_revision_conflict", 409);
+ const overrides = applyAccountSettingOverrides({}, command.overrides);
+ this.sql.exec(
+ "INSERT INTO account_setting_draft (platform, account_key, revision, identity_json, overrides_json, updated_at) VALUES (?, ?, 1, ?, ?, ?)",
+ item.platform, item.key, JSON.stringify(identity), JSON.stringify(overrides), now,
+ );
+ return;
+ }
+ if (command.expected_draft_revision !== Number(row.revision)) throw new HttpError("account_settings_draft_revision_conflict", 409);
+ const storedIdentity = JSON.parse(row.identity_json);
+ const conflict = canonicalResearchTaskJson(storedIdentity) !== canonicalResearchTaskJson(identity);
+ if (conflict && command.acknowledge_identity_conflict !== true) throw new HttpError("account_settings_identity_conflict", 409);
+ const storedOverrides = JSON.parse(row.overrides_json);
+ const base = conflict ? {} : storedOverrides;
+ const overrides = applyAccountSettingOverrides(base, command.overrides);
+ if (!conflict && canonicalResearchTaskJson(overrides) === canonicalResearchTaskJson(storedOverrides)) return;
+ this.sql.exec(
+ "UPDATE account_setting_draft SET revision = ?, identity_json = ?, overrides_json = ?, updated_at = ? WHERE platform = ? AND account_key = ?",
+ Number(row.revision) + 1, JSON.stringify(identity), JSON.stringify(overrides), now, item.platform, item.key,
+ );
+ }
+
+ saveAccountSettings(command) {
+ const { item, identity } = this.existingAccountInstance(command.platform, command.key);
+ const hasDraft = Object.prototype.hasOwnProperty.call(command, "overrides");
+ const hasRisk = Object.prototype.hasOwnProperty.call(command, "risk_change");
+ const hasDeclaration = Object.prototype.hasOwnProperty.call(command, "declaration");
+ if (!hasDraft && !hasRisk && !hasDeclaration) throw new HttpError("account_settings_change_required", 400);
+ if (hasDeclaration) this.saveAccountSettingDeclaration(item, identity, command);
+ if (hasDraft) this.saveAccountSettingDraft(item, identity, command);
+ if (hasRisk) {
+ if (!command.identity || Array.isArray(command.identity) || typeof command.identity !== "object") {
+ throw new HttpError("account_settings_identity_required", 400);
+ }
+ if (canonicalResearchTaskJson(command.identity) !== canonicalResearchTaskJson(identity)) {
+ throw new HttpError("account_settings_identity_conflict", 409);
+ }
+ this.setRiskProfileAuthority({
+ ...command,
+ platform: identity.platform,
+ target_name: identity.target_name,
+ expected_revision: command.expected_risk_revision,
+ });
+ }
+ return { ...this.readAccountSettings(command), adopted: false };
+ }
+
+ accountSettingsProfileApplicationFromRow(row) {
+ if (!row) return null;
+ let identity;
+ try { identity = JSON.parse(row.identity_json); } catch { throw new HttpError("account_settings_profile_application_invalid", 409); }
+ return {
+ request_key: row.request_key,
+ platform: row.platform,
+ key: row.account_key,
+ identity,
+ instance_revision: Number(row.instance_revision),
+ draft_revision: Number(row.draft_revision),
+ old_profile: row.old_profile,
+ new_profile: row.new_profile,
+ approved_by: row.approved_by,
+ approved_at: row.approved_at,
+ status: row.status,
+ workflow_run_id: row.workflow_run_id || null,
+ workflow_run_attempt: row.workflow_run_attempt || null,
+ claimed_at: row.claimed_at || null,
+ runtime_applied: false,
+ variables_updated: false,
+ no_order: true,
+ execution_authority_granted: false,
+ };
+ }
+
+ readAccountSettingsProfileApplication(command) {
+ const requestKey = String(command.request_key || "");
+ if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(requestKey)) {
+ throw new HttpError("account_settings_profile_application_request_invalid", 400);
+ }
+ const row = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
+ return { ok: true, application: this.accountSettingsProfileApplicationFromRow(row) };
+ }
+
+ approveAccountSettingsProfileApplication(command) {
+ const requestKey = String(command.request_key || "");
+ if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(requestKey)) {
+ throw new HttpError("account_settings_profile_application_request_invalid", 400);
+ }
+ if (!SUPPORTED_PLATFORMS.includes(command.platform) || typeof command.key !== "string" || !command.key) {
+ throw new HttpError("account_settings_account_required", 400);
+ }
+ if (!Number.isSafeInteger(command.expected_instance_revision) || command.expected_instance_revision < 0
+ || !Number.isSafeInteger(command.expected_draft_revision) || command.expected_draft_revision < 0) {
+ throw new HttpError("account_settings_profile_application_revision_invalid", 400);
+ }
+ const identity = command.identity;
+ if (!accountSettingsIdentityIsComplete(identity)) throw new HttpError("account_settings_identity_required", 400);
+ const identityJson = canonicalResearchTaskJson(identity);
+ const oldProfile = accountSettingsProfileName(command.old_profile);
+ const newProfile = accountSettingsProfileName(command.new_profile);
+ if (!oldProfile || !newProfile || oldProfile === newProfile) throw new HttpError("account_settings_profile_application_profile_invalid", 400);
+
+ const existing = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
+ if (existing) {
+ const sameRequest = existing.platform === command.platform
+ && existing.account_key === command.key
+ && existing.identity_json === identityJson
+ && Number(existing.instance_revision) === command.expected_instance_revision
+ && Number(existing.draft_revision) === command.expected_draft_revision
+ && existing.old_profile === oldProfile
+ && existing.new_profile === newProfile
+ && existing.approved_by === command.actor;
+ if (!sameRequest) throw new HttpError("account_settings_profile_application_conflict", 409);
+ return { ok: true, replayed: true, application: this.accountSettingsProfileApplicationFromRow(existing) };
+ }
+
+ if (command.current_profile !== oldProfile || command.runtime_target_enabled !== false) {
+ throw new HttpError("account_settings_profile_application_runtime_conflict", 409);
+ }
+ const { state, item, identity: currentIdentity } = this.existingAccountInstance(command.platform, command.key);
+ if (state.revision !== command.expected_instance_revision || identityJson !== canonicalResearchTaskJson(currentIdentity)) {
+ throw new HttpError("account_settings_profile_application_identity_conflict", 409);
+ }
+ const draft = this.accountSettingDraftView(item, currentIdentity);
+ if (draft.status !== "current" || draft.revision !== command.expected_draft_revision
+ || canonicalResearchTaskJson(draft.identity) !== identityJson
+ || Object.keys(draft.overrides).length !== 1
+ || draft.overrides.strategy_profile !== newProfile) {
+ throw new HttpError("account_settings_profile_application_draft_conflict", 409);
+ }
+ if (isDcaProfile(oldProfile) || isDcaProfile(newProfile)) {
+ throw new HttpError("account_settings_profile_application_profile_only_required", 409);
+ }
+
+ const priorApprovals = this.sql.exec(
+ "SELECT request_key, identity_json, instance_revision, draft_revision, old_profile, new_profile FROM account_setting_profile_application WHERE platform = ? AND account_key = ? AND status = 'approved'",
+ command.platform, command.key,
+ ).toArray();
+ for (const prior of priorApprovals) {
+ const stale = prior.identity_json !== identityJson
+ || Number(prior.instance_revision) !== state.revision
+ || Number(prior.draft_revision) !== draft.revision
+ || prior.old_profile !== oldProfile
+ || prior.new_profile !== newProfile;
+ if (stale) {
+ this.sql.exec(
+ "UPDATE account_setting_profile_application SET status = 'invalidated' WHERE request_key = ? AND status = 'approved'",
+ prior.request_key,
+ );
+ }
+ }
+ const active = this.sql.exec(
+ "SELECT request_key FROM account_setting_profile_application WHERE platform = ? AND account_key = ? AND status IN ('approved', 'claimed') LIMIT 1",
+ command.platform, command.key,
+ ).toArray()[0];
+ if (active) throw new HttpError("account_settings_profile_application_pending", 409);
+
+ const approvedAt = new Date().toISOString();
+ this.sql.exec(
+ `INSERT INTO account_setting_profile_application
+ (request_key, platform, account_key, identity_json, instance_revision, draft_revision,
+ old_profile, new_profile, approved_by, approved_at, status, workflow_run_id,
+ workflow_run_attempt, claimed_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'approved', NULL, NULL, NULL)`,
+ requestKey, command.platform, command.key, identityJson, command.expected_instance_revision,
+ command.expected_draft_revision, oldProfile, newProfile, command.actor, approvedAt,
+ );
+ const row = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
+ return { ok: true, replayed: false, application: this.accountSettingsProfileApplicationFromRow(row) };
+ }
+
+ claimAccountSettingsProfileApplication(command) {
+ const requestKey = String(command.request_key || "");
+ if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(requestKey)) {
+ throw new HttpError("account_settings_profile_application_request_invalid", 400);
+ }
+ const row = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
+ if (!row) throw new HttpError("account_settings_profile_application_not_found", 404);
+ const workflowRunId = String(command.workflow_run_id || "");
+ const workflowRunAttempt = String(command.workflow_run_attempt || "");
+ if (!/^\d{1,20}$/.test(workflowRunId) || !/^[1-9]\d{0,5}$/.test(workflowRunAttempt)) {
+ throw new HttpError("account_settings_profile_application_run_invalid", 400);
+ }
+ const identityJson = accountSettingsIdentityIsComplete(command.identity)
+ ? canonicalResearchTaskJson(command.identity)
+ : "";
+ const safeResult = { no_order: true, execution_authority_granted: false, runtime_applied: false, variables_updated: false };
+ const boundRequest = identityJson === row.identity_json
+ && Number(command.expected_instance_revision) === Number(row.instance_revision)
+ && Number(command.expected_draft_revision) === Number(row.draft_revision)
+ && command.old_profile === row.old_profile
+ && command.new_profile === row.new_profile
+ && command.current_profile === row.old_profile
+ && command.runtime_target_enabled === false;
+ if (!boundRequest) throw new HttpError("account_settings_profile_application_conflict", 409);
+ if (row.status === "claimed") {
+ if (row.workflow_run_id !== workflowRunId || row.workflow_run_attempt !== workflowRunAttempt) {
+ throw new HttpError("account_settings_profile_application_already_claimed", 409);
+ }
+ return { ok: true, claimed: false, replayed: true, application: this.accountSettingsProfileApplicationFromRow(row), ...safeResult };
+ }
+ if (row.status !== "approved") throw new HttpError("account_settings_profile_application_conflict", 409);
+ if (!Number.isSafeInteger(command.expected_instance_revision) || !Number.isSafeInteger(command.expected_draft_revision)) {
+ throw new HttpError("account_settings_profile_application_revision_invalid", 409);
+ }
+ const { state, item, identity: currentIdentity } = this.existingAccountInstance(row.platform, row.account_key);
+ if (state.revision !== Number(row.instance_revision)
+ || canonicalResearchTaskJson(currentIdentity) !== row.identity_json) {
+ throw new HttpError("account_settings_profile_application_identity_conflict", 409);
+ }
+ const draft = this.accountSettingDraftView(item, currentIdentity);
+ if (draft.status !== "current" || draft.revision !== Number(row.draft_revision)
+ || canonicalResearchTaskJson(draft.identity) !== row.identity_json
+ || Object.keys(draft.overrides).length !== 1
+ || draft.overrides.strategy_profile !== row.new_profile) {
+ throw new HttpError("account_settings_profile_application_draft_conflict", 409);
+ }
+ const claimedAt = new Date().toISOString();
+ this.sql.exec(
+ `UPDATE account_setting_profile_application
+ SET status = 'claimed', workflow_run_id = ?, workflow_run_attempt = ?, claimed_at = ?
+ WHERE request_key = ? AND status = 'approved'`,
+ workflowRunId, workflowRunAttempt, claimedAt, requestKey,
+ );
+ const claimedRow = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
+ return { ok: true, claimed: true, replayed: false, application: this.accountSettingsProfileApplicationFromRow(claimedRow), ...safeResult };
+ }
+
+ runtimeControlCommand(command) {
+ const platform = command?.platform;
+ const key = command?.key;
+ if (!["ibkr", "schwab"].includes(platform) || typeof key !== "string" || !key) throw new HttpError("runtime_control_target_invalid", 400);
+ const found = this.existingAccountInstance(platform, key);
+ const identity = found.identity;
+ if (!runtimeControlIdentityIsComplete(identity)) throw new HttpError("runtime_control_identity_incomplete", 409);
+ const targetId = `${platform}/${identity.target_name}`;
+ const latest = () => {
+ const row = this.sql.exec("SELECT * FROM hk_stop_request WHERE target_id = ? ORDER BY requested_at DESC, rowid DESC LIMIT 1", targetId).toArray()[0];
+ return row ? { ...this.hkStopPublic(row), result_json: row.result_json || null } : null;
+ };
+ if (command.action === "runtime_control_read") return { ok: true, record: latest() };
+ const requestId = String(command.request_id || "");
+ if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("runtime_control_request_invalid", 400);
+ const stored = this.hkStopStored(requestId);
+ if (command.action === "runtime_control_claim") {
+ if (!["enable", "disable"].includes(command.operation) || !Number.isSafeInteger(command.source_revision)
+ || found.state.revision !== command.source_revision
+ || canonicalResearchTaskJson(identity) !== canonicalResearchTaskJson(command.identity)) throw new HttpError("runtime_control_identity_conflict", 409);
+ if (stored) {
+ if (stored.target_id !== targetId || stored.action !== command.operation || stored.identity_json !== canonicalResearchTaskJson(identity)) throw new HttpError("runtime_control_identity_conflict", 409);
+ return { ok: true, state: "replay", record: stored };
+ }
+ const open = this.hkStopPublic(this.sql.exec(
+ "SELECT * FROM hk_stop_request WHERE target_id = ? AND phase IN ('reserved', 'unknown', 'accepted', 'partial') ORDER BY requested_at ASC LIMIT 1", targetId,
+ ).toArray()[0]);
+ if (open) return { ok: true, state: "blocked", record: open };
+ const now = new Date().toISOString();
+ this.sql.exec(`INSERT INTO hk_stop_request
+ (request_id, target_id, identity_json, source_revision, action, requested_at, phase, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, 'reserved', ?)`, requestId, targetId, canonicalResearchTaskJson(identity), command.source_revision, command.operation, now, now);
+ return { ok: true, state: "reserved", record: this.hkStopStored(requestId) };
+ }
+ if (!stored || stored.target_id !== targetId || stored.identity_json !== canonicalResearchTaskJson(identity)) throw new HttpError("runtime_control_identity_conflict", 409);
+ if (command.action === "runtime_control_record") {
+ if (!["accepted", "unknown", "rejected"].includes(command.phase)) throw new HttpError("runtime_control_result_invalid", 400);
+ if (command.run_id != null && !/^[1-9][0-9]*$/.test(String(command.run_id))) throw new HttpError("runtime_control_result_invalid", 400);
+ if (stored.workflow_run_id && command.run_id && String(stored.workflow_run_id) !== String(command.run_id)) throw new HttpError("runtime_control_result_invalid", 409);
+ if (stored.phase === "reserved") this.sql.exec(
+ "UPDATE hk_stop_request SET phase = ?, dispatch_result = ?, workflow_run_id = ?, updated_at = ? WHERE request_id = ? AND phase = 'reserved'",
+ command.phase, command.phase, command.run_id || null, new Date().toISOString(), requestId,
+ );
+ else if (stored.phase === "unknown" && !stored.workflow_run_id && command.run_id) this.sql.exec(
+ "UPDATE hk_stop_request SET workflow_run_id = ?, updated_at = ? WHERE request_id = ? AND phase = 'unknown' AND workflow_run_id IS NULL",
+ String(command.run_id), new Date().toISOString(), requestId,
+ );
+ return { ok: true, record: this.hkStopStored(requestId) };
+ }
+ if (command.action === "runtime_control_capture") {
+ if (!stored.workflow_run_id || String(stored.workflow_run_id) !== String(command.run_id)
+ || !/^[1-9][0-9]*$/.test(String(command.platform_run_id || ""))) throw new HttpError("runtime_control_result_invalid", 400);
+ let details = {};
+ try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
+ if (details.platform_run_id && details.platform_run_id !== String(command.platform_run_id)) throw new HttpError("runtime_control_result_invalid", 409);
+ details.platform_run_id = String(command.platform_run_id);
+ if (["platform_result_unavailable", "platform_dispatch_unverified"].includes(command.reason)) details.reason = command.reason;
+ this.sql.exec("UPDATE hk_stop_request SET result_json = ?, updated_at = ? WHERE request_id = ?", JSON.stringify(details), new Date().toISOString(), requestId);
+ return { ok: true, record: latest() };
+ }
+ if (command.action === "runtime_control_begin_check") {
+ let details = {};
+ try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
+ if (!["unknown", "accepted", "partial"].includes(stored.phase) || !details.platform_run_id) throw new HttpError("runtime_control_check_unavailable", 409);
+ if (details.check_id && !details.check_complete) return { ok: true, state: "replay", record: latest() };
+ if (!HK_STOP_REQUEST_ID.test(String(command.check_id || ""))) throw new HttpError("runtime_control_request_invalid", 400);
+ Object.assign(details, { check_id: command.check_id, check_run_id: null, check_complete: false, check_requested_at: new Date().toISOString() });
+ this.sql.exec("UPDATE hk_stop_request SET result_json = ?, updated_at = ? WHERE request_id = ?", JSON.stringify(details), new Date().toISOString(), requestId);
+ return { ok: true, state: "reserved", record: latest() };
+ }
+ if (command.action === "runtime_control_record_check") {
+ let details = {};
+ try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
+ if (!details.check_id || details.check_id !== command.check_id) throw new HttpError("runtime_control_result_invalid", 409);
+ if (command.run_id != null && !/^[1-9][0-9]*$/.test(String(command.run_id))) throw new HttpError("runtime_control_result_invalid", 400);
+ if (details.check_run_id && command.run_id && details.check_run_id !== String(command.run_id)) throw new HttpError("runtime_control_result_invalid", 409);
+ if (command.run_id) details.check_run_id = String(command.run_id);
+ if (command.complete === true) details.check_complete = true;
+ if (command.reason === "readback_dispatch_rejected") details.reason = command.reason;
+ this.sql.exec("UPDATE hk_stop_request SET result_json = ?, updated_at = ? WHERE request_id = ?", JSON.stringify(details), new Date().toISOString(), requestId);
+ return { ok: true, record: latest() };
+ }
+ if (command.action === "runtime_control_resolve") {
+ if (!["applied", "partial", "protected", "rejected"].includes(command.phase) || !command.run_id
+ || String(stored.workflow_run_id) !== String(command.run_id)) throw new HttpError("runtime_control_result_invalid", 400);
+ if (command.check_id) {
+ let check = {};
+ try { check = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
+ if (check.check_id !== command.check_id || check.check_run_id !== String(command.check_run_id)) throw new HttpError("runtime_control_result_invalid", 409);
+ }
+ const reason = ["runtime_control_workflow_permission_denied", "runtime_control_workflow_unavailable", "runtime_control_target_unsupported", "stop_source_permission_denied", "stop_source_not_accessible", "platform_dispatch_rejected", "platform_result_unavailable", "platform_dispatch_unverified"].includes(command.reason) ? command.reason : null;
+ let details = {};
+ try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
+ if (["accepted", "unknown", "partial"].includes(stored.phase)) this.sql.exec(
+ "UPDATE hk_stop_request SET phase = ?, result_json = ?, updated_at = ? WHERE request_id = ?", command.phase, JSON.stringify({ ...details, reason }), new Date().toISOString(), requestId,
+ );
+ return { ok: true, record: latest() };
+ }
+ throw new HttpError("runtime_control_action_invalid", 400);
+ }
+
+ hkStopCommand(command) {
+ if (command?.action === "hk_stop_read") return { ok: true, record: this.hkStopOpen() || this.hkStopLatest() };
+ if (command?.action === "hk_stop_claim") return this.hkStopClaim(command);
+ if (command?.action === "hk_stop_record") return this.hkStopRecord(command);
+ if (command?.action === "hk_stop_accept_result") return this.hkStopAcceptResult(command);
+ throw new HttpError("unsupported_hk_stop_action", 400);
+ }
+
+ hkStopPublic(row) {
+ if (!row) return null;
+ return {
+ target_id: row.target_id,
+ request_id: row.request_id,
+ identity_json: row.identity_json,
+ source_revision: Number(row.source_revision),
+ action: row.action,
+ requested_at: row.requested_at,
+ phase: row.phase,
+ dispatch_result: row.dispatch_result || null,
+ workflow_run_id: row.workflow_run_id || null,
+ workflow_run_attempt: row.workflow_run_attempt || null,
+ source_identity_sha256: row.source_identity_sha256 || null,
+ runtime_identity_sha256: row.runtime_identity_sha256 || null,
+ updated_at: row.updated_at,
+ };
+ }
+
+ hkStopStored(requestId) {
+ return this.hkStopPublic(this.sql.exec("SELECT * FROM hk_stop_request WHERE request_id = ?", requestId).toArray()[0]);
+ }
+
+ hkStopOpen() {
+ return this.hkStopPublic(this.sql.exec(
+ "SELECT * FROM hk_stop_request WHERE target_id = ? AND phase IN ('reserved', 'unknown', 'accepted', 'stopped') ORDER BY requested_at ASC",
+ HK_STOP_TARGET_ID,
+ ).toArray()[0]);
+ }
+
+ hkStopLatest() {
+ return this.hkStopPublic(this.sql.exec(
+ "SELECT * FROM hk_stop_request WHERE target_id = ? ORDER BY requested_at DESC",
+ HK_STOP_TARGET_ID,
+ ).toArray()[0]);
+ }
+
+ hkStopLiveIdentity(sourceRevision, identity) {
+ let found;
+ try {
+ found = this.existingAccountInstance("longbridge", "hk");
+ } catch {
+ throw new HttpError("hk_stop_source_conflict", 409);
+ }
+ if (found.state.revision !== sourceRevision) throw new HttpError("hk_stop_source_conflict", 409);
+ const live = hkStopSourceIdentity(found.item.config, found.item);
+ if (!hkStopIdentityComplete(live) || canonicalResearchTaskJson(live) !== canonicalResearchTaskJson(identity)) {
+ throw new HttpError("hk_stop_source_conflict", 409);
+ }
+ return live;
+ }
+
+ hkStopClaim(command) {
+ const requestId = String(command.request_id || "").toLowerCase();
+ if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("invalid_hk_stop_request_id", 400);
+ if (command.action_name !== "stop") throw new HttpError("hk_stop_action_conflict", 409);
+ const identity = command.identity;
+ if (!identity || Array.isArray(identity) || typeof identity !== "object") throw new HttpError("hk_stop_identity_incomplete", 400);
+ if (!Number.isSafeInteger(command.source_revision)) throw new HttpError("hk_stop_source_conflict", 409);
+ const storedIdentity = canonicalResearchTaskJson(identity);
+ const existing = this.hkStopStored(requestId);
+ if (existing) {
+ if (existing.action !== "stop" || existing.identity_json !== storedIdentity) {
+ throw new HttpError("hk_stop_identity_conflict", 409);
+ }
+ return { ok: true, state: "replay", record: existing };
+ }
+ const open = this.hkStopOpen();
+ if (open) {
+ if (open.identity_json !== storedIdentity) throw new HttpError("hk_stop_identity_conflict", 409);
+ return { ok: true, state: "blocked", record: open };
+ }
+ this.hkStopLiveIdentity(command.source_revision, identity);
+ const sourceHash = hkStopDigestOrEmpty(command.source_identity_sha256);
+ const runtimeHash = hkStopDigestOrEmpty(command.runtime_identity_sha256);
+ if ((sourceHash === "") !== (runtimeHash === "")) throw new HttpError("hk_stop_identity_incomplete", 400);
+ const now = new Date().toISOString();
+ this.sql.exec(
+ `INSERT INTO hk_stop_request (
+ request_id, target_id, identity_json, source_revision, action, requested_at, phase, dispatch_result, workflow_run_id, workflow_run_attempt, source_identity_sha256, runtime_identity_sha256, updated_at
+ ) VALUES (?, ?, ?, ?, 'stop', ?, 'reserved', NULL, NULL, NULL, ?, ?, ?)`,
+ requestId, HK_STOP_TARGET_ID, storedIdentity, command.source_revision, now, sourceHash || null, runtimeHash || null, now,
+ );
+ return { ok: true, state: "reserved", record: this.hkStopStored(requestId) };
+ }
+
+ hkStopRecord(command) {
+ const requestId = String(command.request_id || "").toLowerCase();
+ const phase = command.phase;
+ if (!HK_STOP_REQUEST_ID.test(requestId) || !["accepted", "rejected", "unknown"].includes(phase)) {
+ throw new HttpError("hk_stop_result_rejected", 400);
+ }
+ const existing = this.hkStopStored(requestId);
+ if (!existing) throw new HttpError("hk_stop_request_conflict", 409);
+ if (existing.phase === "stopped" || existing.phase !== "reserved") return { ok: true, recorded: false, record: existing };
+ const now = new Date().toISOString();
+ this.sql.exec(
+ "UPDATE hk_stop_request SET phase = ?, dispatch_result = ?, updated_at = ? WHERE request_id = ? AND phase = 'reserved'",
+ phase, phase, now, requestId,
+ );
+ return { ok: true, recorded: true, record: this.hkStopStored(requestId) };
+ }
+
+ hkStopAcceptResult(command) {
+ const result = command?.result;
+ const now = Date.parse(command?.now);
+ if (!result?.producer || !result.readback) throw new HttpError("hk_stop_result_rejected", 400);
+ const requestId = String(result?.request_id || "").toLowerCase();
+ if (!HK_STOP_REQUEST_ID.test(requestId) || !Number.isFinite(now)) throw new HttpError("hk_stop_result_rejected", 400);
+ const row = this.sql.exec("SELECT * FROM hk_stop_request WHERE request_id = ?", requestId).toArray()[0];
+ if (!row) throw new HttpError("hk_stop_request_conflict", 409);
+ if (!row.source_identity_sha256 || !row.runtime_identity_sha256) {
+ throw new HttpError("hk_stop_result_unlinked", 409);
+ }
+ const requestedAt = Date.parse(row.requested_at);
+ const observedAt = Date.parse(result.observed_at);
+ if (!Number.isFinite(requestedAt) || !Number.isFinite(observedAt)) throw new HttpError("hk_stop_result_rejected", 400);
+ if (result.source_revision !== Number(row.source_revision)
+ || result.source_identity_sha256 !== row.source_identity_sha256
+ || result.runtime_identity_sha256 !== row.runtime_identity_sha256
+ || result.target_id !== row.target_id) {
+ throw new HttpError("hk_stop_identity_conflict", 409);
+ }
+ let live;
+ try {
+ live = this.existingAccountInstance("longbridge", "hk");
+ } catch {
+ throw new HttpError("hk_stop_identity_conflict", 409);
+ }
+ const current = hkStopSourceIdentity(live.item.config, live.item);
+ if (!hkStopIdentityComplete(current) || canonicalResearchTaskJson(current) !== row.identity_json) {
+ throw new HttpError("hk_stop_identity_conflict", 409);
+ }
+ if (observedAt < requestedAt || observedAt > now + 60000) throw new HttpError("hk_stop_result_stale", 409);
+ const canonical = canonicalResearchTaskJson(result);
+ const sameRun = row.workflow_run_id === result.producer.run_id && String(row.workflow_run_attempt) === String(result.producer.run_attempt);
+ if (row.phase === "stopped") {
+ if (row.result_json === canonical && sameRun) return { ok: true, replayed: true, record: this.hkStopStored(requestId) };
+ throw new HttpError("hk_stop_result_conflict", 409);
+ }
+ if (!["reserved", "accepted", "unknown"].includes(row.phase)) throw new HttpError("hk_stop_result_conflict", 409);
+ if (now - requestedAt > 24 * 60 * 60 * 1000) throw new HttpError("hk_stop_result_stale", 409);
+ const stamp = new Date(now).toISOString();
+ this.sql.exec(
+ `UPDATE hk_stop_request
+ SET phase = 'stopped', workflow_run_id = ?, workflow_run_attempt = ?, result_json = ?, stopped_at = ?, updated_at = ?
+ WHERE request_id = ? AND phase IN ('reserved', 'accepted', 'unknown')`,
+ result.producer.run_id, String(result.producer.run_attempt), canonical, stamp, stamp, requestId,
+ );
+ const stored = this.hkStopStored(requestId);
+ if (stored?.phase !== "stopped") throw new HttpError("hk_stop_result_conflict", 409);
+ return { ok: true, replayed: false, record: stored };
+ }
+
+ read() {
+ const row = this.sql.exec("SELECT revision, payload FROM instance_state WHERE id = 1").toArray()[0];
+ return row ? { revision: row.revision, instances: JSON.parse(row.payload), initialized: true } : { revision: 0, instances: [], initialized: false };
+ }
+
+ response(state) {
+ return {
+ ok: true, ...state, account_options: runtimeInstanceAccountOptions(state.instances),
+ history: this.sql.exec("SELECT entry FROM instance_history ORDER BY revision DESC LIMIT 50").toArray().map((row) => JSON.parse(row.entry)),
+ no_order: true, execution_authority_granted: false,
+ };
+ }
+
+ async alarm() { await this.deskReadbacks.alarm(); }
+
+ async fetch(request) {
+ try {
+ if (new URL(request.url).pathname === DIRECTORY_PATH) {
+ if (request.method !== "POST") throw new HttpError("method_not_allowed", 405);
+ const result = await this.directory.command(await request.json());
+ return json(result, result.ok ? 200 : 503);
+ }
+ if (request.method === "GET") return json(this.response(this.read()));
+ if (request.method !== "POST") throw new HttpError("method_not_allowed", 405);
+ let command;
+ try { command = await request.json(); } catch { throw new HttpError("invalid_runtime_instance_request", 400); }
+ if (["desk_readback_start", "desk_readback_get", "desk_readback_fresh"].includes(command?.action)) {
+ try { return json(await this.deskReadbacks.command(command)); }
+ catch (error) { return deskErrorResponse(error); }
+ }
+ if (typeof command?.action === "string" && command.action.startsWith("rotation_")) {
+ return json(await durableRotationCommand(this.storage, this.sql, this.rotationEnv, command));
+ }
+ if (["credential_maintenance_read", "credential_maintenance_save", "credential_maintenance_claim", "credential_maintenance_ack"].includes(command?.action)) {
+ return json(this.storage.transactionSync(() => credentialMaintenanceCommand(this.sql, command)));
+ }
+ if (ACCOUNT_DIAGNOSIS_DO_ACTIONS.has(command?.action)) {
+ return json(await this.accountDiagnosisCommand(command));
+ }
+ if (["console_decision_history", "console_settings_history", "console_account_metadata", "console_audit_events"].includes(command?.action)) {
+ return json(this.consoleReadCommand(command));
+ }
+ if (HUMAN_DECISION_DO_ACTIONS.has(command?.action)) {
+ return json(this.humanDecisionCommand(command));
+ }
+ if (V7_PAPER_APPLICATION_DO_ACTIONS.has(command?.action)) {
+ return json(await this.applicationCommand(command));
+ }
+ if (typeof command?.action === "string" && command.action.startsWith("ux1_")) {
+ return json(this.ux1ResearchCommand(command));
+ }
+ if (["cycle_health_admission", "cycle_health_put", "cycle_health_read", "cycle_health_provision"].includes(command?.action)) {
+ if (command.action === "cycle_health_provision") {
+ return json(this.storage.transactionSync(() => this.cycleHealthProvisionCommand(command)));
+ }
+ return json(this.storage.transactionSync(() => this.cycleHealthCommand(command)));
+ }
+ if (ACCOUNT_SETTINGS_DO_ACTIONS.has(command?.action)) {
+ return json(this.storage.transactionSync(() => this.accountSettingsCommand(command)));
+ }
+ if (ACCOUNT_FACTS_DO_ACTIONS.has(command?.action)) {
+ const result = this.storage.transactionSync(() => this.accountFactsCommand(command));
+ return json(result, command.action === "account_daily_native_return_research_read" && !result.ok ? 409 : 200);
+ }
+ if (MARKET_BENCHMARK_DO_ACTIONS.has(command?.action)) {
+ return json(this.storage.transactionSync(() => this.marketBenchmarkCommand(command)));
+ }
+ if (RUNTIME_CONTROL_DO_ACTIONS.has(command?.action)) {
+ return json(this.storage.transactionSync(() => this.runtimeControlCommand(command)));
+ }
+ if (HK_STOP_DO_ACTIONS.has(command?.action)) {
+ return json(this.storage.transactionSync(() => this.hkStopCommand(command)));
+ }
+ // No awaits or external I/O inside this SQLite transaction. Every state
+ // change, version advance, and history row commits together or rolls back.
+ return json(this.storage.transactionSync(() => {
+ const state = this.read();
+ if (!command || typeof command.actor !== "string" || !command.actor) throw new HttpError("runtime_instance_actor_required", 400);
+ if (command.action !== "sync_defaults") {
+ if (!Number.isSafeInteger(command.expected_revision) || command.expected_revision < 0) throw new HttpError("runtime_instance_revision_required", 400);
+ if (command.expected_revision !== state.revision) throw new HttpError("runtime_instance_revision_conflict", 409);
+ }
+ const ts = new Date().toISOString();
+ let changed = true;
+ let before = null;
+ let after = null;
+ if (command.action === "initialize") {
+ if (state.initialized) throw new HttpError("runtime_instances_already_initialized", 409);
+ for (const [platform, options] of Object.entries(command.account_options)) {
+ for (const config of options) {
+ if (state.instances.some((item) => item.platform === platform && (item.key === config.key || item.config.target_name === config.target_name))) throw new HttpError("runtime_instance_identity_conflict", 409);
+ state.instances.push({ platform, key: config.key, kind: "existing", config, enabled: null, platform_applied: null, application_status: "unknown", retirement_status: "none", created_at: ts, updated_at: ts });
+ }
+ }
+ state.initialized = true;
+ } else {
+ if (!state.initialized) throw new HttpError("runtime_instances_not_initialized", 409);
+ const item = state.instances.find((candidate) => candidate.platform === command.platform && candidate.key === command.key);
+ if (command.action === "create") {
+ if (state.instances.length >= 120) throw new HttpError("runtime_instance_limit_reached", 409);
+ runtimeInstanceConflict(state.instances, command.platform, command.config);
+ after = { platform: command.platform, key: command.config.key, kind: "draft", config: command.config, enabled: false, platform_applied: false, application_status: "unapplied", retirement_status: "none", created_at: ts, updated_at: ts };
+ state.instances.push(after);
+ } else if (command.action === "edit") {
+ if (!item || item.kind !== "draft" || item.retirement_status !== "none") throw new HttpError("runtime_instance_draft_edit_required", 409);
+ if (item.key !== command.config.key) throw new HttpError("runtime_instance_key_immutable", 409);
+ runtimeInstanceConflict(state.instances, command.platform, command.config, item.key);
+ before = structuredClone(item);
+ item.config = command.config;
+ item.updated_at = ts;
+ after = item;
+ } else if (command.action === "request_retirement") {
+ if (!item) throw new HttpError("runtime_instance_not_found", 404);
+ before = structuredClone(item);
+ changed = item.retirement_status !== "requested";
+ item.retirement_status = "requested";
+ if (changed) item.updated_at = ts;
+ after = item;
+ } else if (command.action === "set_broker_environment") {
+ if (!item || item.kind !== "existing") throw new HttpError("runtime_instance_existing_required", 409);
+ if (!BROKER_ENVIRONMENTS.includes(command.broker_environment)
+ || !supportedBrokerEnvironmentsForPlatform(command.platform).includes(command.broker_environment)) {
+ throw new HttpError("invalid_broker_environment", 400);
+ }
+ before = structuredClone(item);
+ changed = item.config.broker_environment !== command.broker_environment;
+ if (changed) {
+ item.config = { ...item.config, broker_environment: command.broker_environment };
+ item.updated_at = ts;
+ }
+ after = item;
+ } else if (command.action === "sync_defaults") {
+ const current = runtimeInstanceAccountOptions(state.instances);
+ const update = updateAccountOptionsDefaultStrategy(current, command.inputs);
+ changed = update.changed;
+ for (const instance of state.instances) {
+ if (instance.kind !== "existing") continue;
+ const config = update.options[instance.platform]?.find((option) => option.key === instance.key);
+ if (config) {
+ const defaults = {};
+ for (const field of ["default_execution_mode", "default_strategy_profile"]) {
+ if (instance.config[field] !== undefined) defaults[field] = instance.config[field];
+ }
+ instance.config = { ...config, ...defaults };
+ }
+ }
+ } else {
+ throw new HttpError("unsupported_runtime_instance_action", 400);
+ }
+ }
+ if (changed) {
+ state.revision += 1;
+ this.sql.exec("INSERT INTO instance_state (id, revision, payload) VALUES (1, ?, ?) ON CONFLICT(id) DO UPDATE SET revision = excluded.revision, payload = excluded.payload", state.revision, JSON.stringify(state.instances));
+ try {
+ this.sql.exec("INSERT INTO instance_history (revision, entry) VALUES (?, ?)", state.revision, JSON.stringify({ revision: state.revision, ts, login: command.actor, action: command.action, before, after }));
+ } catch (error) {
+ // Fixture / storage aborts must surface as revision conflicts, not DO crashes.
+ throw new HttpError(error?.message || "runtime_instance_transaction_failed", 409);
+ }
+ }
+ return this.response(state);
+ }));
+ } catch (error) {
+ return json({ ok: false, error: error instanceof HttpError || error instanceof CycleHealthError || error instanceof CredentialMaintenanceError || error instanceof RotationError ? error.message : "runtime_instance_transaction_failed" }, error instanceof HttpError || error instanceof CycleHealthError || error instanceof CredentialMaintenanceError || error instanceof RotationError ? error.status : 409);
+ }
+ }
+
+ accountDiagnosisCommand(command) {
+ return this.storage.transactionSync(() => {
+ if (!command || typeof command.actor !== "string" || !command.actor) {
+ throw new HttpError("runtime_instance_actor_required", 400);
+ }
+ if (command.action === "diagnosis_create") {
+ const autoSource = command.auto_source === "source_sync" ? "source_sync" : "manual";
+ // Unclosed work keeps its original obligation regardless of age or fingerprint.
+ const unresolved = this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE target_id = ? AND status IN ('queued', 'running', 'unknown') ORDER BY updated_at DESC LIMIT 1", command.target_id).toArray()[0];
+ if (unresolved) return { ok: true, created: false, task: accountDiagnosisTaskFromRow(unresolved) };
+ const existing = autoSource === "source_sync"
+ ? this.sql.exec(
+ "SELECT * FROM account_diagnosis_tasks WHERE target_id = ? AND auto_source = ? AND updated_at >= ? ORDER BY updated_at DESC LIMIT 1",
+ command.target_id, autoSource, new Date(Number(command.now) - ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS).toISOString(),
+ ).toArray()[0]
+ : this.sql.exec(
+ "SELECT * FROM account_diagnosis_tasks WHERE target_id = ? AND state_fingerprint = ? ORDER BY updated_at DESC LIMIT 1",
+ command.target_id, command.state_fingerprint,
+ ).toArray()[0];
+ const existingAge = existing ? Date.parse(existing.updated_at) : Number.NaN;
+ const existingIsRecent = Number.isFinite(existingAge)
+ && existingAge >= Number(command.now) - ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS;
+ if (existing && existingIsRecent) return { ok: true, created: false, task: accountDiagnosisTaskFromRow(existing) };
+ const task = {
+ request_id: command.request_id,
+ platform: command.platform,
+ key: command.key,
+ target_id: command.target_id,
+ trigger: command.trigger,
+ observed_at: command.observed_at,
+ checks: command.checks,
+ state_fingerprint: command.state_fingerprint,
+ status: "queued",
+ workflow_run_id: null,
+ workflow_run_attempt: null,
+ job_id: null,
+ summary: "",
+ reason_code: "",
+ dispatch_state: "pending",
+ recheck_dispatch_state: "not_requested",
+ created_at: command.created_at,
+ updated_at: command.created_at,
+ };
+ this.sql.exec(
+ `INSERT INTO account_diagnosis_tasks
+ (request_id, platform, account_key, target_id, trigger, observed_at, checks_json, state_fingerprint,
+ status, workflow_run_id, workflow_run_attempt, job_id, summary, reason_code, dispatch_state,
+ recheck_dispatch_state, created_at, updated_at, auto_source)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ task.request_id, task.platform, task.key, task.target_id, task.trigger, task.observed_at,
+ JSON.stringify(task.checks), task.state_fingerprint, task.status, null, null, null,
+ task.summary, task.reason_code, task.dispatch_state, task.recheck_dispatch_state,
+ task.created_at, task.updated_at, autoSource,
+ );
+ return { ok: true, created: true, task };
+ }
+ if (command.action === "diagnosis_latest") {
+ const row = this.sql.exec(
+ "SELECT * FROM account_diagnosis_tasks WHERE platform = ? AND account_key = ? ORDER BY updated_at DESC LIMIT 1",
+ command.platform, command.key,
+ ).toArray()[0];
+ return { ok: true, task: accountDiagnosisTaskFromRow(row) };
+ }
+ const requestId = command.request_id;
+ const row = this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0];
+ if (!row) throw new HttpError("account_diagnosis_request_not_found", 404);
+ if (command.action === "diagnosis_read") return { ok: true, task: accountDiagnosisTaskFromRow(row) };
+ if (command.action === "diagnosis_native_intent") {
+ if (row.native_json) {
+ const old = JSON.parse(row.native_json);
+ if (canonicalResearchTaskJson(old.binding) !== canonicalResearchTaskJson(command.native.binding)
+ || old.request_sha256 !== command.native.request_sha256) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ return { ok: true, created: false, task: accountDiagnosisTaskFromRow(row) };
+ }
+ if (row.workflow_run_id || row.workflow_run_attempt || row.status !== "queued" || row.dispatch_state !== "pending") {
+ throw new HttpError("account_diagnosis_legacy_retired", 409);
+ }
+ this.sql.exec("UPDATE account_diagnosis_tasks SET native_json = ?, updated_at = ? WHERE request_id = ?",
+ JSON.stringify(command.native), command.updated_at, requestId);
+ return { ok: true, created: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
+ }
+ if (command.action === "diagnosis_native_cancel") {
+ if (!row.native_json) throw new HttpError("account_diagnosis_legacy_retired", 409);
+ const native = JSON.parse(row.native_json);
+ // The first durable terminal receipt or cancellation wins atomically.
+ if (native.receipt) return { ok: true, send_cancel: false, task: accountDiagnosisTaskFromRow(row) };
+ const send = Boolean(native.task_id && !native.cancel_sent);
+ native.cancel_requested = true;
+ native.cancel_sent = native.cancel_sent || send;
+ native.phase = "hold";
+ this.sql.exec("UPDATE account_diagnosis_tasks SET native_json = ?, status = 'unknown', summary = '', reason_code = '', recheck_dispatch_state = 'not_requested', updated_at = ? WHERE request_id = ?",
+ JSON.stringify(native), command.updated_at, requestId);
+ return { ok: true, send_cancel: send, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
+ }
+ if (command.action === "diagnosis_native_save") {
+ if (!row.native_json) throw new HttpError("account_diagnosis_legacy_retired", 409);
+ const old = JSON.parse(row.native_json), next = command.native;
+ for (const field of ["version", "binding", "request", "input_sha256", "request_sha256", "operation_key", "deadline"]) {
+ if (canonicalResearchTaskJson(old[field]) !== canonicalResearchTaskJson(next[field])) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ if ((old.task_id && old.task_id !== next.task_id) || (old.task_deadline !== null && old.task_deadline !== next.task_deadline)
+ || (old.claim && canonicalResearchTaskJson(old.claim) !== canonicalResearchTaskJson(next.claim))
+ || (old.cancel_sent && !next.cancel_sent) || (old.cancel_requested && !next.cancel_requested)
+ || !ACCOUNT_DIAGNOSIS_STATUSES.includes(command.status)) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ if (old.receipt) {
+ if (old.receipt !== next.receipt) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ return { ok: true, changed: false, task: accountDiagnosisTaskFromRow(row) };
+ }
+ if (command.status === "succeeded" && (old.cancel_requested || old.cancel_sent
+ || Date.now() / 1000 >= Math.min(old.deadline, next.task_deadline ?? Infinity))) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ const recheck = command.status === "succeeded" ? "pending" : row.recheck_dispatch_state;
+ this.sql.exec("UPDATE account_diagnosis_tasks SET native_json = ?, status = ?, summary = ?, reason_code = ?, dispatch_state = 'sent', recheck_dispatch_state = ?, updated_at = ? WHERE request_id = ?",
+ JSON.stringify(next), command.status, command.summary, command.reason_code, recheck, command.updated_at, requestId);
+ return { ok: true, changed: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
+ }
+ if (command.action === "diagnosis_mark_dispatch") {
+ if (row.dispatch_state !== "pending") return { ok: true, changed: false, task: accountDiagnosisTaskFromRow(row) };
+ if (command.dispatch_state === "unknown" && row.native_json) {
+ const native = { ...JSON.parse(row.native_json), phase: "hold" };
+ this.sql.exec("UPDATE account_diagnosis_tasks SET dispatch_state = 'unknown', status = 'unknown', native_json = ?, updated_at = ? WHERE request_id = ?",
+ JSON.stringify(native), command.updated_at, requestId);
+ } else {
+ this.sql.exec("UPDATE account_diagnosis_tasks SET dispatch_state = ?, updated_at = ? WHERE request_id = ?", command.dispatch_state, command.updated_at, requestId);
+ }
+ return { ok: true, changed: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
+ }
+ if (command.action === "diagnosis_claim" || command.action === "diagnosis_result") {
+ throw new HttpError("account_diagnosis_legacy_retired", 409);
+ }
+ if (command.action === "diagnosis_mark_recheck") {
+ if (row.recheck_dispatch_state !== "pending") return { ok: true, changed: false, task: accountDiagnosisTaskFromRow(row) };
+ this.sql.exec("UPDATE account_diagnosis_tasks SET recheck_dispatch_state = ?, updated_at = ? WHERE request_id = ?", command.recheck_dispatch_state, command.updated_at, requestId);
+ return { ok: true, changed: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
+ }
+ throw new HttpError("unsupported_account_diagnosis_action", 400);
+ });
+ }
+
+ consoleReadCommand(command) {
+ if (!command.actor) throw new HttpError("runtime_instance_actor_required", 400);
+ if (command.action === "console_audit_events") {
+ const limit = command.limit;
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > AUDIT_EVENTS_MAX_ROWS) throw new HttpError("invalid_pagination", 400);
+ const { snapshot, before } = command;
+ // Normalize time once, and use the same binary id tie-break as the HTTP merge.
+ return { rows: this.sql.exec(`
+ WITH events AS (
+ SELECT 'decision' AS source, kind, subject_id, material_key AS revision,
+ action, actor, strftime('%Y-%m-%dT%H:%M:%fZ', decided_at) AS occurred_at,
+ request_key AS ref, 'decided' AS status, 'durable_human_decision:' || request_key AS event_id
+ FROM human_decision_record
+ UNION ALL
+ SELECT 'promotion_application', 'promotion', ticket_id, '', status, '',
+ strftime('%Y-%m-%dT%H:%M:%fZ', updated_at), application_id, status,
+ 'research_promotion_application:' || application_id FROM research_promotion_applications
+ UNION ALL
+ SELECT 'account_settings_application', 'account_settings', platform || ':' || account_key, '',
+ status, approved_by, strftime('%Y-%m-%dT%H:%M:%fZ', approved_at), request_key, status,
+ 'account_settings_application:' || request_key FROM account_setting_profile_application
+ UNION ALL
+ SELECT 'credential_rotation', 'credential', 'ibkr_flex', '', action, actor,
+ occurred_at, operation_id, outcome, 'credential_rotation:' || event_id
+ FROM credential_rotation_audit
+ ) SELECT * FROM events WHERE occurred_at <= ?
+ AND (? IS NULL OR occurred_at < ? OR (occurred_at = ? AND event_id > ?))
+ ORDER BY occurred_at DESC, event_id ASC LIMIT ?`, snapshot,
+ before?.at ?? null, before?.at ?? null, before?.at ?? null, before?.id ?? null, limit).toArray() };
+ }
+ if (command.action === "console_decision_history") {
+ const { limit, offset } = command;
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100 || !Number.isSafeInteger(offset) || offset < 0 || offset > 100000) throw new HttpError("invalid_pagination", 400);
+ return { rows: this.sql.exec("SELECT request_key, kind, subject_id, material_key, action, actor, decided_at, target_json, json_extract(payload_json, '$.ticket.confirmation_execution_mode') AS confirmation_execution_mode FROM human_decision_record ORDER BY decided_at DESC, request_key DESC LIMIT ? OFFSET ?", limit + 1, offset).toArray() };
+ }
+ if (command.action === "console_settings_history") {
+ this.existingAccountInstance(command.platform, command.key);
+ return { approvals: this.sql.exec("SELECT request_key, status, identity_json, instance_revision, old_profile, new_profile, approved_at, approved_by, draft_revision FROM account_setting_profile_application WHERE platform = ? AND account_key = ? ORDER BY approved_at DESC", command.platform, command.key).toArray() };
+ }
+ const drafts = this.sql.exec("SELECT platform, account_key, overrides_json, updated_at FROM account_setting_draft").toArray();
+ const approvals = this.sql.exec("SELECT platform, account_key, MAX(approved_at) AS approved_at FROM account_setting_profile_application GROUP BY platform, account_key").toArray();
+ return { rows: this.read().instances.map(item => {
+ const draft = drafts.find(row => row.platform === item.platform && row.account_key === item.key);
+ const approval = approvals.find(row => row.platform === item.platform && row.account_key === item.key);
+ return { platform: item.platform, account_key: item.key,
+ pending_draft_count: draft ? new Set(Object.keys(JSON.parse(draft.overrides_json)).map(field => field.startsWith("dca_") ? "dca" : field.startsWith("reserved_") ? "cash" : field)).size : 0,
+ last_change_at: [draft?.updated_at, approval?.approved_at, item.updated_at].filter(Boolean).sort().at(-1) || null,
+ };
+ }) };
+ }
+
+ humanDecisionCommand(command) {
+ return this.storage.transactionSync(() => {
+ if (!command || typeof command.actor !== "string" || !command.actor) {
+ throw new HttpError("runtime_instance_actor_required", 400);
+ }
+ if (command.action === "owner_sync_materials") return this.syncHumanDecisionMaterials(command, "owner");
+ if (command.action === "recovery_sync_materials") return this.syncHumanDecisionMaterials(command, "recovery");
+ if (command.action === "promotion_sync_materials") return this.syncHumanDecisionMaterials(command, "promotion");
+ if (command.action === "owner_decide") return this.writeHumanDecision(command, "owner");
+ if (command.action === "recovery_decide") return this.writeHumanDecision(command, "recovery");
+ if (command.action === "promotion_decide") return this.writeHumanDecision(command, "promotion");
+ if (command.action === "owner_read") return this.readHumanDecision(command, "owner");
+ if (command.action === "recovery_read") return this.readHumanDecision(command, "recovery");
+ if (command.action === "promotion_read") return this.readHumanDecision(command, "promotion");
+ throw new HttpError("unsupported_human_decision_action", 400);
+ });
+ }
+
+ humanDecisionMaterialRow(kind, subjectId) {
+ return this.sql.exec(
+ "SELECT * FROM human_decision_material WHERE kind = ? AND subject_id = ?",
+ kind, subjectId,
+ ).toArray()[0] || null;
+ }
+
+ humanDecisionTerminalRow(kind, subjectId, materialKey) {
+ return this.sql.exec(
+ "SELECT * FROM human_decision_record WHERE kind = ? AND subject_id = ? AND material_key = ? ORDER BY decided_at ASC LIMIT 1",
+ kind, subjectId, materialKey,
+ ).toArray()[0] || null;
+ }
+
+ humanDecisionRecordPayload(row) {
+ let payload = {};
+ try {
+ payload = JSON.parse(row.payload_json);
+ } catch {
+ throw new HttpError("human_decision_record_invalid", 409);
+ }
+ return {
+ request_key: row.request_key,
+ kind: row.kind,
+ subject_id: row.subject_id,
+ material_key: row.material_key,
+ action: row.action,
+ actor: row.actor,
+ decided_at: row.decided_at,
+ target_json: row.target_json,
+ payload,
+ };
+ }
+
+ humanDecisionSourceRow(kind, subjectId, sourceId) {
+ return this.sql.exec(
+ "SELECT * FROM human_decision_source_material WHERE kind = ? AND subject_id = ? AND source_id = ?",
+ kind, subjectId, sourceId,
+ ).toArray()[0] || null;
+ }
+
+ upsertHumanDecisionSource(kind, subjectId, sourceId, item, eligible, updatedAt) {
+ if (this.humanDecisionSourceRow(kind, subjectId, sourceId)) {
+ this.sql.exec(
+ `UPDATE human_decision_source_material
+ SET material_key = ?, summary_json = ?, eligible = ?, expires_at_ms = ?, updated_at = ?
+ WHERE kind = ? AND subject_id = ? AND source_id = ?`,
+ item.material_key, item.summary_json || "{}", eligible, item.expires_at_ms ?? null, updatedAt, kind, subjectId, sourceId,
+ );
+ return;
+ }
+ this.sql.exec(
+ `INSERT INTO human_decision_source_material
+ (kind, subject_id, source_id, material_key, summary_json, eligible, expires_at_ms, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
+ kind, subjectId, sourceId, item.material_key, item.summary_json || "{}", eligible, item.expires_at_ms ?? null, updatedAt,
+ );
+ }
+
+ recomputeHumanDecisionSubject(kind, subjectId, updatedAt) {
+ const sources = this.sql.exec(
+ "SELECT * FROM human_decision_source_material WHERE kind = ? AND subject_id = ?",
+ kind, subjectId,
+ ).toArray();
+ let projection = this.humanDecisionMaterialRow(kind, subjectId);
+ if (!projection && !sources.length) return;
+ if (!projection) {
+ this.insertHumanDecisionMaterial(kind, subjectId, sources[0].source_id, sources[0], 0, { state: "none", block: "" }, updatedAt);
+ projection = this.humanDecisionMaterialRow(kind, subjectId);
+ }
+ if (projection.legacy_state === "blocked") {
+ this.sql.exec(
+ "UPDATE human_decision_material SET eligible = 0, updated_at = ? WHERE kind = ? AND subject_id = ?",
+ updatedAt, kind, subjectId,
+ );
+ return;
+ }
+ if (sources.length !== 1) {
+ const keys = new Set(sources.map((row) => row.material_key));
+ const materialKey = keys.size === 1 ? sources[0].material_key : "";
+ this.sql.exec(
+ "UPDATE human_decision_material SET source_id = ?, material_key = ?, eligible = 0, updated_at = ? WHERE kind = ? AND subject_id = ?",
+ "", materialKey, updatedAt, kind, subjectId,
+ );
+ return;
+ }
+ const only = sources[0];
+ this.sql.exec(
+ `UPDATE human_decision_material
+ SET source_id = ?, material_key = ?, summary_json = ?, eligible = ?, expires_at_ms = ?, updated_at = ?
+ WHERE kind = ? AND subject_id = ?`,
+ only.source_id, only.material_key, only.summary_json, only.eligible, only.expires_at_ms, updatedAt, kind, subjectId,
+ );
+ }
+
+ insertHumanDecisionMaterial(kind, subjectId, sourceId, item, eligible, legacyState, updatedAt) {
+ this.sql.exec(
+ `INSERT INTO human_decision_material
+ (kind, subject_id, source_id, material_key, summary_json, eligible, expires_at_ms, legacy_state, legacy_block, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ kind, subjectId, sourceId, item.material_key, item.summary_json || "{}", eligible,
+ item.expires_at_ms ?? null, legacyState.state, legacyState.block, updatedAt,
+ );
+ }
+
+ insertHumanDecisionRecord(record) {
+ this.sql.exec(
+ `INSERT INTO human_decision_record
+ (request_key, kind, subject_id, material_key, action, actor, decided_at, target_json, payload_json)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ record.request_key, record.kind, record.subject_id, record.material_key, record.action,
+ record.actor, record.decided_at, record.target_json, record.payload_json,
+ );
+ }
+
+ importHumanDecisionLegacy(kind, subjectId, item) {
+ const legacy = item.legacy;
+ if (!legacy) return { state: "none", block: "" };
+ const record = legacy.record;
+ if (legacy.blocked || !record || record.material_key !== item.material_key || !record.action || !record.actor || !record.decided_at || !record.payload || typeof record.payload !== "object") {
+ return { state: "blocked", block: "unexplained_legacy" };
+ }
+ this.insertHumanDecisionRecord({
+ request_key: `legacy:${kind}:${subjectId}:${item.material_key}`,
+ kind,
+ subject_id: subjectId,
+ material_key: item.material_key,
+ action: record.action,
+ actor: record.actor,
+ decided_at: record.decided_at,
+ target_json: record.target_json || "{}",
+ payload_json: JSON.stringify(record.payload),
+ });
+ return { state: "imported", block: "" };
+ }
+
+ syncHumanDecisionMaterials(command, kind) {
+ const sourceId = String(command.source_id || "");
+ const updatedAt = String(command.updated_at || "");
+ const materials = Array.isArray(command.materials) ? command.materials : [];
+ const seen = new Set();
+ const affected = new Set();
+ let terminal = false;
+ let terminalState = "";
+ let identityConflict = false;
+ let legacyBlocked = false;
+ for (const item of materials) {
+ const subjectId = String(item.subject_id || "");
+ if (!subjectId || seen.has(subjectId)) continue;
+ seen.add(subjectId);
+ const sourceRow = this.humanDecisionSourceRow(kind, subjectId, sourceId);
+ const incomingTerminal = this.humanDecisionTerminalRow(kind, subjectId, item.material_key);
+ if (
+ kind === "promotion" && sourceRow && sourceRow.material_key !== item.material_key && !incomingTerminal
+ && !this.humanDecisionTerminalRow(kind, subjectId, sourceRow.material_key)
+ ) {
+ identityConflict = true;
+ continue;
+ }
+ if (kind === "promotion" && incomingTerminal) {
+ terminal = true;
+ terminalState = incomingTerminal.action === "accept" ? "human_accepted" : "human_rejected";
+ }
+ let projection = this.humanDecisionMaterialRow(kind, subjectId);
+ if (!projection) {
+ const legacyState = this.importHumanDecisionLegacy(kind, subjectId, item);
+ this.insertHumanDecisionMaterial(kind, subjectId, sourceId, item, 0, legacyState, updatedAt);
+ if (legacyState.state === "blocked") legacyBlocked = true;
+ const imported = this.humanDecisionTerminalRow(kind, subjectId, item.material_key);
+ if (imported && kind === "promotion") {
+ terminal = true;
+ terminalState = imported.action === "accept" ? "human_accepted" : "human_rejected";
+ }
+ projection = this.humanDecisionMaterialRow(kind, subjectId);
+ } else if (projection.legacy_state === "blocked") {
+ legacyBlocked = true;
+ }
+ const blocked = projection?.legacy_state === "blocked";
+ this.upsertHumanDecisionSource(kind, subjectId, sourceId, item, blocked ? 0 : (item.eligible ? 1 : 0), updatedAt);
+ affected.add(subjectId);
+ }
+ if (command.replace_source) {
+ const rows = this.sql.exec(
+ "SELECT subject_id FROM human_decision_source_material WHERE kind = ? AND source_id = ?",
+ kind, sourceId,
+ ).toArray();
+ for (const row of rows) {
+ if (seen.has(row.subject_id)) continue;
+ this.sql.exec(
+ "DELETE FROM human_decision_source_material WHERE kind = ? AND subject_id = ? AND source_id = ?",
+ kind, row.subject_id, sourceId,
+ );
+ affected.add(row.subject_id);
+ }
+ }
+ for (const subjectId of command.duplicate_subject_ids || []) {
+ if (typeof subjectId !== "string" || !subjectId) continue;
+ this.sql.exec(
+ "UPDATE human_decision_source_material SET eligible = 0, updated_at = ? WHERE kind = ? AND subject_id = ? AND source_id = ?",
+ updatedAt, kind, subjectId, sourceId,
+ );
+ affected.add(subjectId);
+ }
+ for (const subjectId of affected) this.recomputeHumanDecisionSubject(kind, subjectId, updatedAt);
+ return { ok: true, terminal, terminal_state: terminalState, identity_conflict: identityConflict, legacy_blocked: legacyBlocked };
+ }
+
+ writeHumanDecision(command, kind) {
+ if (kind === "owner" && command.action_name === "retire_candidate") {
+ throw new HttpError("owner_retirement_proposal_required", 409);
+ }
+ const subjectId = String(command.subject_id || "");
+ const materialKey = String(command.material_key || "");
+ const actionName = String(command.action_name || "");
+ const requestKey = String(command.request_key || "");
+ const targetJson = String(command.target_json || "{}");
+ if (!subjectId || !materialKey || !actionName || !requestKey) throw new HttpError("human_decision_request_invalid", 400);
+ let row = this.humanDecisionMaterialRow(kind, subjectId);
+ if (!row && command.legacy) {
+ const legacyState = this.importHumanDecisionLegacy(kind, subjectId, { material_key: materialKey, legacy: command.legacy });
+ this.insertHumanDecisionMaterial(kind, subjectId, String(command.source_id || kind), {
+ material_key: materialKey,
+ summary_json: command.summary_json || "{}",
+ expires_at_ms: command.expires_at_ms ?? null,
+ }, legacyState.state === "blocked" ? 0 : 1, legacyState, String(command.decided_at || ""));
+ row = this.humanDecisionMaterialRow(kind, subjectId);
+ }
+ if (!row) throw new HttpError("human_decision_material_unavailable", 409);
+ if (row.legacy_state === "blocked") throw new HttpError("human_decision_legacy_blocked", 409);
+ if (row.material_key !== materialKey) throw new HttpError("human_decision_material_conflict", 409);
+ if (Number(row.eligible) !== 1) throw new HttpError("human_decision_material_ineligible", 409);
+ if (row.expires_at_ms != null && Number(command.now_ms) >= Number(row.expires_at_ms)) {
+ throw new HttpError("human_decision_material_expired", 409);
+ }
+ if (kind === "promotion" && command.review_binding !== undefined
+ && !promotionReviewBindingsMatch(command.review_binding, promotionMaterialReviewBinding(row))) {
+ throw new HttpError("human_decision_review_material_conflict", 409);
+ }
+ const assertReview = terminal => {
+ if (kind === "promotion" && command.review_binding !== undefined
+ && !promotionReviewBindingsMatch(command.review_binding, this.humanDecisionRecordPayload(terminal).payload?.review_binding)) {
+ throw new HttpError("human_decision_review_binding_unqualified", 409);
+ }
+ };
+ const byRequest = this.sql.exec("SELECT * FROM human_decision_record WHERE request_key = ?", requestKey).toArray()[0];
+ if (byRequest) {
+ if (byRequest.kind !== kind || byRequest.subject_id !== subjectId || byRequest.material_key !== materialKey || byRequest.action !== actionName || byRequest.target_json !== targetJson) {
+ throw new HttpError("human_decision_conflict", 409);
+ }
+ assertReview(byRequest);
+ return { ok: true, replayed: true, record: this.humanDecisionRecordPayload(byRequest) };
+ }
+ const terminal = this.humanDecisionTerminalRow(kind, subjectId, materialKey);
+ if (terminal) {
+ if (terminal.action !== actionName || terminal.target_json !== targetJson) throw new HttpError("human_decision_conflict", 409);
+ assertReview(terminal);
+ return { ok: true, replayed: true, record: this.humanDecisionRecordPayload(terminal) };
+ }
+ const payload = command.payload && typeof command.payload === "object" ? structuredClone(command.payload) : {};
+ if (kind === "promotion" && actionName === "accept") {
+ const instances = this.read();
+ if (instances.initialized) {
+ const preflightRevision = Number(command.preflight_revision);
+ if (!Number.isSafeInteger(preflightRevision) || preflightRevision !== instances.revision) {
+ throw new HttpError("runtime_instance_revision_conflict", 409);
+ }
+ payload.account_revision = instances.revision;
+ } else {
+ payload.account_revision = null;
+ }
+ }
+ const record = {
+ request_key: requestKey,
+ kind,
+ subject_id: subjectId,
+ material_key: materialKey,
+ action: actionName,
+ actor: String(command.actor || ""),
+ decided_at: String(command.decided_at || ""),
+ target_json: targetJson,
+ payload_json: JSON.stringify(payload),
+ };
+ this.insertHumanDecisionRecord(record);
+ return { ok: true, replayed: false, record: this.humanDecisionRecordPayload(this.humanDecisionTerminalRow(kind, subjectId, materialKey)) };
+ }
+
+ readHumanDecision(command, kind) {
+ const subjectId = String(command.subject_id || "");
+ const now = Number.isFinite(Number(command.now_ms)) ? Number(command.now_ms) : Date.now();
+ const row = this.humanDecisionMaterialRow(kind, subjectId);
+ const expiry = (material) => material.expires_at_ms == null ? null : new Date(Number(material.expires_at_ms)).toISOString();
+ const expired = (material) => material.expires_at_ms != null && now >= Number(material.expires_at_ms);
+ // Historical receipt lookup deliberately does not substitute the current material.
+ // It grants no eligibility or authority to act on the current material.
+ if (command.exact_material_key !== undefined) {
+ const materialKey = command.exact_material_key;
+ if (!/^[0-9a-f]{64}$/.test(materialKey) || !subjectId || subjectId.length > 256) {
+ throw new HttpError("human_decision_lookup_invalid", 400);
+ }
+ const terminal = this.humanDecisionTerminalRow(kind, subjectId, materialKey);
+ return {
+ ok: true,
+ exact_material_key: materialKey,
+ decision: terminal ? this.humanDecisionRecordPayload(terminal) : null,
+ current_material: row ? {
+ matches: row.material_key === materialKey,
+ eligible: Number(row.eligible) === 1 && !expired(row),
+ expired: expired(row),
+ expires_at: expiry(row),
+ blocked: row.legacy_state === "blocked",
+ ...(kind === "promotion" ? { review_binding: promotionMaterialReviewBinding(row) } : {}),
+ } : null,
+ };
+ }
+ if (!row) return { ok: true, migrated: false, blocked: false, eligible: false, expired: false, expires_at: null, material_key: null, decision: null };
+ const terminal = this.humanDecisionTerminalRow(kind, subjectId, row.material_key);
+ return {
+ ok: true,
+ migrated: true,
+ blocked: row.legacy_state === "blocked",
+ eligible: Number(row.eligible) === 1 && !expired(row),
+ expired: expired(row),
+ expires_at: expiry(row),
+ material_key: row.material_key,
+ ...(kind === "promotion" ? { review_binding: promotionMaterialReviewBinding(row) } : {}),
+ decision: terminal ? this.humanDecisionRecordPayload(terminal) : null,
+ };
+ }
+
+ applicationCommand(command) {
+ return this.storage.transactionSync(() => {
+ if (!command || typeof command.actor !== "string" || !command.actor) {
+ throw new HttpError("runtime_instance_actor_required", 400);
+ }
+ if (command.action === "application_create") {
+ const currentMaterial = this.humanDecisionMaterialRow("promotion", command.ticket_id);
+ if (!currentMaterial || currentMaterial.legacy_state === "blocked" || Number(currentMaterial.eligible) !== 1 || currentMaterial.material_key !== command.promotion_material_key) {
+ throw new HttpError("research candidate is not human_accepted", 409);
+ }
+ const decisionRow = this.humanDecisionTerminalRow("promotion", command.ticket_id, currentMaterial.material_key);
+ if (!decisionRow || decisionRow.action !== "accept") throw new HttpError("research candidate is not human_accepted", 409);
+ let decisionPayload = {};
+ try { decisionPayload = JSON.parse(decisionRow.payload_json); } catch { throw new HttpError("research candidate is not human_accepted", 409); }
+ const selected = decisionPayload.selected_account || {};
+ if (selected.platform !== command.platform_id || selected.key !== command.account_key) {
+ throw new HttpError("promotion_account_binding_conflict", 409);
+ }
+ const instances = this.read();
+ if (!instances.initialized || instances.revision !== Number(command.expected_revision) || !Number.isSafeInteger(decisionPayload.account_revision) || decisionPayload.account_revision !== instances.revision) {
+ throw new HttpError("runtime_instance_revision_conflict", 409);
+ }
+ const existing = this.sql.exec(
+ "SELECT * FROM research_promotion_applications WHERE ticket_id = ? AND platform_id = ? AND account_key = ? AND status <> 'rejected' ORDER BY created_at DESC LIMIT 1",
+ command.ticket_id, command.platform_id, command.account_key,
+ ).toArray()[0];
+ if (existing) return { ok: true, created: false, application: researchPromotionApplicationFromRow(existing) };
+ const application = {
+ application_id: command.application_id,
+ ticket_id: command.ticket_id,
+ status: "approved",
+ dispatch_state: "pending",
+ claim_token: command.claim_token,
+ platform_id: command.platform_id,
+ account_key: command.account_key,
+ account_scope: command.account_scope,
+ account_selector: command.account_selector,
+ service_name: command.service_name,
+ broker_environment: command.broker_environment,
+ expected_revision: command.expected_revision,
+ expected_strategy_profile: command.expected_strategy_profile,
+ strategy_profile: command.strategy_profile,
+ candidate_id: command.candidate_id,
+ config_sha256: command.config_sha256,
+ source_commit: command.source_commit,
+ approved_ues_revision: command.approved_ues_revision,
+ desired_state: "paused",
+ workflow_run_id: null,
+ workflow_run_attempt: null,
+ reason_code: "",
+ readback: null,
+ created_at: command.created_at,
+ updated_at: command.created_at,
+ };
+ this.sql.exec(
+ `INSERT INTO research_promotion_applications
+ (application_id, ticket_id, status, dispatch_state, claim_token, platform_id, account_key,
+ account_scope, account_selector, service_name, broker_environment, expected_revision,
+ expected_strategy_profile, strategy_profile, candidate_id, config_sha256, source_commit,
+ approved_ues_revision, desired_state, workflow_run_id, workflow_run_attempt, reason_code,
+ readback_json, created_at, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ application.application_id, application.ticket_id, application.status, application.dispatch_state,
+ application.claim_token, application.platform_id, application.account_key, application.account_scope,
+ application.account_selector, application.service_name, application.broker_environment,
+ application.expected_revision, application.expected_strategy_profile, application.strategy_profile,
+ application.candidate_id, application.config_sha256, application.source_commit,
+ application.approved_ues_revision, application.desired_state, null, null, application.reason_code,
+ null, application.created_at, application.updated_at,
+ );
+ return { ok: true, created: true, application };
+ }
+ if (command.action === "application_latest") {
+ const row = this.sql.exec(
+ "SELECT * FROM research_promotion_applications WHERE ticket_id = ? ORDER BY created_at DESC LIMIT 1",
+ command.ticket_id,
+ ).toArray()[0];
+ return { ok: true, application: researchPromotionApplicationFromRow(row) };
+ }
+ const applicationId = command.application_id;
+ const row = this.sql.exec("SELECT * FROM research_promotion_applications WHERE application_id = ?", applicationId).toArray()[0];
+ if (!row) throw new HttpError("research_promotion_application_not_found", 404);
+ if (command.action === "application_read") return { ok: true, application: researchPromotionApplicationFromRow(row) };
+ if (command.action === "application_mark_dispatch") {
+ if (row.status !== "approved" || row.dispatch_state !== "pending") return { ok: true, changed: false, application: researchPromotionApplicationFromRow(row) };
+ this.sql.exec("UPDATE research_promotion_applications SET dispatch_state = ?, updated_at = ? WHERE application_id = ?", command.dispatch_state, command.updated_at, applicationId);
+ return { ok: true, changed: true, application: researchPromotionApplicationFromRow(this.sql.exec("SELECT * FROM research_promotion_applications WHERE application_id = ?", applicationId).toArray()[0]) };
+ }
+ if (command.action === "application_claim") {
+ const state = this.read();
+ const instance = state.instances.find((item) => item.kind === "existing"
+ && item.platform === row.platform_id && item.key === row.account_key);
+ const config = instance?.config || {};
+ const bindingStillMatches = state.revision === Number(row.expected_revision)
+ && String(config.default_strategy_profile || "") === row.expected_strategy_profile
+ && String(config.broker_environment || "") === row.broker_environment
+ && String(config.account_selector || "") === row.account_selector
+ && String(config.service_name || "") === row.service_name;
+ const claimed = row.status === "approved" && ["pending", "sent", "unknown"].includes(row.dispatch_state)
+ && row.claim_token === command.claim_token && bindingStillMatches;
+ if (claimed) {
+ this.sql.exec(
+ "UPDATE research_promotion_applications SET status = 'claimed', workflow_run_id = ?, workflow_run_attempt = ?, updated_at = ? WHERE application_id = ? AND status = 'approved'",
+ command.workflow_run_id, command.workflow_run_attempt, command.updated_at, applicationId,
+ );
+ }
+ return { ok: true, claimed, reason: claimed ? "" : (bindingStillMatches ? "already_claimed_or_invalid_token" : "account_changed") };
+ }
+ if (command.action === "application_result") {
+ const sameRun = row.workflow_run_id === command.workflow_run_id
+ && row.workflow_run_attempt === command.workflow_run_attempt
+ && row.claim_token === command.claim_token;
+ if (["applied_paused", "rejected", "uncertain"].includes(row.status)) {
+ if (!sameRun) throw new HttpError("research_promotion_application_workflow_binding_conflict", 409);
+ return { ok: true, changed: false, application: researchPromotionApplicationFromRow(row) };
+ }
+ if (row.status !== "claimed" || !sameRun) throw new HttpError("research_promotion_application_workflow_binding_conflict", 409);
+ let effectiveStatus = command.status;
+ let effectiveReasonCode = command.reason_code;
+ if (command.status === "applied_paused") {
+ const state = this.read();
+ const instance = state.instances.find((item) => item.kind === "existing"
+ && item.platform === row.platform_id && item.key === row.account_key);
+ const config = instance?.config || {};
+ const bindingStillMatches = state.revision === Number(row.expected_revision)
+ && String(config.default_strategy_profile || "") === row.expected_strategy_profile
+ && String(config.broker_environment || "") === row.broker_environment
+ && String(config.account_selector || "") === row.account_selector
+ && String(config.service_name || "") === row.service_name;
+ if (!bindingStillMatches) {
+ effectiveStatus = "uncertain";
+ effectiveReasonCode = "account_changed";
+ } else {
+ const before = structuredClone(instance);
+ instance.config = { ...instance.config, default_strategy_profile: row.strategy_profile };
+ instance.enabled = false;
+ instance.platform_applied = true;
+ instance.application_status = "applied_paused";
+ instance.updated_at = command.updated_at;
+ state.revision += 1;
+ this.sql.exec("INSERT INTO instance_state (id, revision, payload) VALUES (1, ?, ?) ON CONFLICT(id) DO UPDATE SET revision = excluded.revision, payload = excluded.payload", state.revision, JSON.stringify(state.instances));
+ this.sql.exec("INSERT INTO instance_history (revision, entry) VALUES (?, ?)", state.revision, JSON.stringify({
+ revision: state.revision,
+ ts: command.updated_at,
+ login: command.actor,
+ action: "research_promotion_application_applied_paused",
+ before,
+ after: instance,
+ }));
+ }
+ }
+ this.sql.exec(
+ `UPDATE research_promotion_applications
+ SET status = ?, reason_code = ?, readback_json = ?, updated_at = ?
+ WHERE application_id = ?`,
+ effectiveStatus, effectiveReasonCode, command.readback ? JSON.stringify(command.readback) : null,
+ command.updated_at, applicationId,
+ );
+ return { ok: true, changed: true, application: researchPromotionApplicationFromRow(this.sql.exec("SELECT * FROM research_promotion_applications WHERE application_id = ?", applicationId).toArray()[0]) };
+ }
+ throw new HttpError("unsupported_research_promotion_application_action", 400);
+ });
+ }
+
+ ux1ResearchCommand(command) {
+ return this.storage.transactionSync(() => {
+ if (["ux1_begin_job", "ux1_record_dispatch", "ux1_lookup_job", "ux1_claim_job", "ux1_finish_job"].includes(command?.action)) {
+ return ux1MutateJob(this.sql, command);
+ }
+ const login = String(command?.login || "");
+ if (!/^[a-z0-9-]{1,39}$/.test(login)) throw new HttpError("ux1_login_invalid", 400);
+ const row = ux1SelectSlot(this.sql, login);
+ const found = ux1SlotPayload(row);
+ if (command.action === "ux1_read") return found;
+ if (command.action === "ux1_save") {
+ if (!Number.isSafeInteger(command.expected_revision) || command.expected_revision < 0) throw new HttpError("ux1_revision_required", 400);
+ if ((row ? Number(row.revision) : 0) !== command.expected_revision) throw new HttpError("ux1_revision_conflict", 409);
+ if (typeof command.draft_json !== "string" || typeof command.fingerprint !== "string" || command.draft_json.length > 16384) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ if (row && row.draft_json === command.draft_json && row.fingerprint === command.fingerprint) return { ...found, unchanged: true };
+ const revision = (row ? Number(row.revision) : 0) + 1;
+ this.sql.exec(
+ `INSERT INTO ux1_research_slot (login, revision, draft_json, fingerprint, preview_json, intent_json)
+ VALUES (?, ?, ?, ?, NULL, NULL)
+ ON CONFLICT(login) DO UPDATE SET revision = excluded.revision, draft_json = excluded.draft_json,
+ fingerprint = excluded.fingerprint, preview_json = NULL, intent_json = NULL`,
+ login, revision, command.draft_json, command.fingerprint,
+ );
+ return { ...ux1SlotPayload(ux1SelectSlot(this.sql, login)), unchanged: false };
+ }
+ if (command.action === "ux1_store_preview") {
+ if (!row || Number(row.revision) !== command.expected_revision || row.fingerprint !== command.fingerprint) throw new HttpError("ux1_preview_conflict", 409);
+ if (typeof command.preview_json !== "string" || command.preview_json.length > 65536) throw new HttpError("ux1_invalid_body", 400);
+ this.sql.exec("UPDATE ux1_research_slot SET preview_json = ? WHERE login = ? AND revision = ?", command.preview_json, login, Number(row.revision));
+ return { ...found, preview_json: command.preview_json };
+ }
+ if (command.action === "ux1_save_intent") {
+ if (!row || Number(row.revision) !== command.expected_revision || row.fingerprint !== command.fingerprint || !row.preview_json) {
+ throw new HttpError("ux1_intent_conflict", 409);
+ }
+ if (row.intent_json) {
+ const existing = JSON.parse(row.intent_json);
+ if (existing.revision === Number(row.revision) && existing.fingerprint === row.fingerprint) return { ...found, duplicate: true };
+ }
+ if (typeof command.intent_json !== "string" || command.intent_json.length > 4096) throw new HttpError("ux1_invalid_body", 400);
+ this.sql.exec("UPDATE ux1_research_slot SET intent_json = ? WHERE login = ? AND revision = ?", command.intent_json, login, Number(row.revision));
+ return { ...found, intent_json: command.intent_json, duplicate: false };
+ }
+ if (command.action === "ux1_clear_preview") {
+ if (!row) return found;
+ if (Number(row.revision) !== command.expected_revision || row.fingerprint !== command.fingerprint) return found;
+ this.sql.exec("UPDATE ux1_research_slot SET preview_json = NULL WHERE login = ? AND revision = ? AND fingerprint = ?", login, Number(row.revision), row.fingerprint);
+ return { ...found, preview_json: null };
+ }
+ throw new HttpError("unsupported_ux1_action", 400);
+ });
+ }
+}
diff --git a/web/strategy-switch-console/application/runtime_instances/promotion_application_row.js b/web/strategy-switch-console/application/runtime_instances/promotion_application_row.js
new file mode 100644
index 00000000..ed802f03
--- /dev/null
+++ b/web/strategy-switch-console/application/runtime_instances/promotion_application_row.js
@@ -0,0 +1,30 @@
+export function researchPromotionApplicationFromRow(row) {
+ if (!row) return null;
+ return {
+ application_id: row.application_id,
+ ticket_id: row.ticket_id,
+ status: row.status,
+ dispatch_state: row.dispatch_state,
+ claim_token: row.claim_token,
+ platform_id: row.platform_id,
+ account_key: row.account_key,
+ account_scope: row.account_scope,
+ account_selector: row.account_selector,
+ service_name: row.service_name,
+ broker_environment: row.broker_environment,
+ expected_revision: Number(row.expected_revision),
+ expected_strategy_profile: row.expected_strategy_profile,
+ strategy_profile: row.strategy_profile,
+ candidate_id: row.candidate_id,
+ config_sha256: row.config_sha256,
+ source_commit: row.source_commit,
+ approved_ues_revision: row.approved_ues_revision,
+ desired_state: row.desired_state,
+ workflow_run_id: row.workflow_run_id || null,
+ workflow_run_attempt: row.workflow_run_attempt || null,
+ reason_code: row.reason_code || "",
+ readback: row.readback_json ? JSON.parse(row.readback_json) : null,
+ created_at: row.created_at,
+ updated_at: row.updated_at,
+ };
+}
diff --git a/web/strategy-switch-console/application/security_headers.js b/web/strategy-switch-console/application/security_headers.js
new file mode 100644
index 00000000..632d18fb
--- /dev/null
+++ b/web/strategy-switch-console/application/security_headers.js
@@ -0,0 +1,18 @@
+export const SECURITY_HEADERS = {
+ "Content-Security-Policy": [
+ "default-src 'self'",
+ "base-uri 'none'",
+ "object-src 'none'",
+ "frame-ancestors 'none'",
+ "frame-src https://fred.stlouisfed.org/graph/graph-landing.php",
+ "form-action 'self'",
+ "img-src 'self' data:",
+ "connect-src 'self'",
+ "script-src 'self'",
+ "style-src 'self'",
+ ].join("; "),
+ "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=()",
+ "Referrer-Policy": "no-referrer",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "DENY",
+};
diff --git a/web/strategy-switch-console/application/ux1/constants.js b/web/strategy-switch-console/application/ux1/constants.js
new file mode 100644
index 00000000..b135b83a
--- /dev/null
+++ b/web/strategy-switch-console/application/ux1/constants.js
@@ -0,0 +1,17 @@
+export const UX1_CALCULATOR_DEADLINE_MS = 30000;
+export const UX1_CALCULATOR_MAX_BYTES = 65536;
+export const UX1_RESEARCH_REPOSITORY = "QuantStrategyLab/UsEquityStrategies";
+export const UX1_RESEARCH_WORKFLOW_FILE = "ux1-research-preview.yml";
+export const UX1_RESEARCH_WORKFLOW_PATH = ".github/workflows/ux1-research-preview.yml";
+export const UX1_JOB_BODY_MAX_BYTES = 80 * 1024;
+export const UX1_GITHUB_DEADLINE_MS = 8000;
+export const UX1_GITHUB_MAX_BYTES = 65536;
+export const UX1_JOB_UNKNOWN_AFTER_MS = 30 * 60 * 1000;
+export const UX1_PUBLIC_JOB_REASONS = new Set([
+ "dispatch_rejected",
+ "dispatch_unconfirmed",
+ "input_unavailable",
+ "calculator_failed",
+ "check_required",
+ "config_changed",
+]);
diff --git a/web/strategy-switch-console/application/ux1/research.js b/web/strategy-switch-console/application/ux1/research.js
new file mode 100644
index 00000000..f792269f
--- /dev/null
+++ b/web/strategy-switch-console/application/ux1/research.js
@@ -0,0 +1,934 @@
+import {
+ UX1_DRAFT_SCHEMA,
+ UX1_EVIDENCE_HASH_KEYS,
+ UX1_STUDY,
+ Ux1InputError,
+ assertUx1DraftPost,
+ assertUx1IntentPost,
+ assertUx1PreviewPost,
+ buildUx1PreviewRequest,
+ canonicalJson,
+ classifyUx1Draft,
+ defaultUx1Draft,
+ localUx1Preview,
+ normalizeUx1Draft,
+ projectUx1CalculatorResult,
+ ux1CustomDraft,
+ ux1Fingerprint,
+ ux1IntentAllowed,
+ ux1IntentRecord,
+ ux1ReceiptId,
+} from "../../ux1_research_contract.js";
+import { HttpError } from "../http_error.js";
+import { json } from "../http_response.js";
+import { requireSameOrigin } from "../http_request.js";
+import { githubHeaders } from "../auth/github.js";
+import { readSession } from "../auth/session.js";
+import { hasRuntimeInstanceStore, runtimeInstanceCommand } from "../runtime_instances/command.js";
+import {
+ UX1_CALCULATOR_DEADLINE_MS,
+ UX1_CALCULATOR_MAX_BYTES,
+ UX1_RESEARCH_REPOSITORY,
+ UX1_RESEARCH_WORKFLOW_FILE,
+ UX1_RESEARCH_WORKFLOW_PATH,
+ UX1_JOB_BODY_MAX_BYTES,
+ UX1_GITHUB_DEADLINE_MS,
+ UX1_GITHUB_MAX_BYTES,
+ UX1_JOB_UNKNOWN_AFTER_MS,
+ UX1_PUBLIC_JOB_REASONS,
+} from "./constants.js";
+
+let ux1ModuleEpoch = "";
+
+export function ux1RuntimeEpoch(env) {
+ const configured = env?.UX1_RUNTIME_EPOCH;
+ if (typeof configured === "string" && /^[a-f0-9]{32}$/.test(configured)) return configured;
+ if (!ux1ModuleEpoch) {
+ const bytes = new Uint8Array(16);
+ crypto.getRandomValues(bytes);
+ ux1ModuleEpoch = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+ }
+ return ux1ModuleEpoch;
+}
+
+function ux1PreviewMatchesEpoch(preview, env) {
+ return Boolean(preview && preview.runtime_epoch === ux1RuntimeEpoch(env));
+}
+
+function ux1ExpectedEvidenceMatches(preview, env) {
+ if (!preview.evidence) return !["computed", "no_advantage", "no_action"].includes(preview.status);
+ if (!env.UX1_EXPECTED_EVIDENCE_HASHES) return true;
+ let expected;
+ try { expected = JSON.parse(env.UX1_EXPECTED_EVIDENCE_HASHES); } catch { return false; }
+ return expected && typeof expected === "object" && !Array.isArray(expected)
+ && Object.keys(expected).length === UX1_EVIDENCE_HASH_KEYS.length
+ && UX1_EVIDENCE_HASH_KEYS.every((key) => /^[a-f0-9]{64}$/.test(expected[key]) && preview.evidence[key] === expected[key]);
+}
+
+export function ux1PreviewBindingStale(preview, env) {
+ if (!preview) return false;
+ if (!ux1PreviewMatchesEpoch(preview, env)) return true;
+ if (!preview.evidence || !env?.UX1_EXPECTED_EVIDENCE_HASHES) return false;
+ return !ux1ExpectedEvidenceMatches(preview, env);
+}
+
+export function presentUx1Preview(preview, env) {
+ if (!preview) return null;
+ if (!ux1PreviewBindingStale(preview, env)) return preview;
+ return {
+ ...preview,
+ status: "stale",
+ stale: true,
+ actionable: false,
+ recompute_required: true,
+ };
+}
+
+function ux1Flags() {
+ return {
+ schema_version: UX1_DRAFT_SCHEMA,
+ study: UX1_STUDY,
+ account_connection: "native_not_observed",
+ native_observed: false,
+ credential_access_unavailable: true,
+ research_only: true,
+ no_order: true,
+ execution_authority_granted: false,
+ workflow_dispatched: false,
+ runtime_mutated: false,
+ d1_native: "NATIVE_PENDING_EXTERNAL",
+ d1_status: "PARTIAL",
+ };
+}
+
+function ux1StatePayload(env, { revision, fingerprint, draft, preview, intent, job = null, duplicate = false, unchanged = false }) {
+ const publicJob = projectUx1Job(job, Date.now(), revision, env);
+ const waiting = Boolean(publicJob && ["queued", "running", "unknown"].includes(publicJob.status));
+ let shown = waiting ? null : presentUx1Preview(preview, env);
+ if (shown && ux1TerminalJobConfigStale(job, env)) {
+ shown = { ...shown, status: "stale", stale: true, actionable: false, recompute_required: true };
+ }
+ return {
+ ok: true,
+ ...ux1Flags(),
+ research_workflow_dispatched: job?.dispatch_state === "dispatched",
+ revision,
+ fingerprint,
+ custom_draft: ux1CustomDraft(draft),
+ draft,
+ preview: shown,
+ preview_stale: Boolean(shown?.stale),
+ intent: waiting ? null : intent,
+ job: publicJob,
+ duplicate,
+ unchanged,
+ };
+}
+
+export async function requireUx1Session(request, env) {
+ const session = await readSession(request, env);
+ if (!session) throw new HttpError("login required", 401);
+ if (!session.allowed) throw new HttpError("allowlist required", 403);
+ return session;
+}
+
+async function readUx1Body(request) {
+ const text = await request.text();
+ if (text.length > 16384) throw new Ux1InputError("ux1_body_too_large");
+ try {
+ return JSON.parse(text);
+ } catch {
+ throw new Ux1InputError("ux1_invalid_json");
+ }
+}
+
+function parseUx1Slot(result) {
+ if (!result?.found) return null;
+ return {
+ revision: result.revision,
+ fingerprint: result.fingerprint,
+ draft: JSON.parse(result.draft_json),
+ preview: result.preview_json ? JSON.parse(result.preview_json) : null,
+ intent: result.intent_json ? JSON.parse(result.intent_json) : null,
+ job: result.job_json ? JSON.parse(result.job_json) : null,
+ };
+}
+
+async function ux1ReadSlot(env, login) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("ux1_research_store_not_bound", 503);
+ return parseUx1Slot(await runtimeInstanceCommand(env, { action: "ux1_read", login }));
+}
+
+export async function ux1DraftGet(request, env) {
+ const session = await requireUx1Session(request, env);
+ const slot = await ux1ReadSlot(env, session.login);
+ if (!slot) {
+ const draft = defaultUx1Draft();
+ return json(ux1StatePayload(env, { revision: 0, fingerprint: await ux1Fingerprint(draft), draft, preview: null, intent: null }));
+ }
+ return json(ux1StatePayload(env, slot));
+}
+
+export async function ux1DraftPost(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await requireUx1Session(request, env);
+ const parsed = assertUx1DraftPost(await readUx1Body(request));
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("ux1_research_store_not_bound", 503);
+ const saved = await runtimeInstanceCommand(env, {
+ action: "ux1_save",
+ login: session.login,
+ expected_revision: parsed.expected_revision,
+ draft_json: canonicalJson(parsed.draft),
+ fingerprint: await ux1Fingerprint(parsed.draft),
+ });
+ return json(ux1StatePayload(env, { ...parseUx1Slot({ ...saved, found: true }), unchanged: Boolean(saved.unchanged) }));
+}
+
+function ux1AbortError() {
+ return new DOMException("The operation was aborted", "AbortError");
+}
+
+function abandonUx1Reader(reader) {
+ if (!reader) return;
+ try {
+ const canceling = reader.cancel();
+ if (canceling && typeof canceling.catch === "function") canceling.catch(() => {});
+ } catch {
+ /* cancel failed before returning a promise */
+ }
+}
+
+function abandonUx1Response(response) {
+ if (!response?.body) return;
+ try {
+ abandonUx1Reader(response.body.getReader());
+ } catch {
+ /* body already locked or disturbed */
+ }
+}
+
+export async function readLimitedUtf8Body(response, maxBytes, controller, abortPromise) {
+ if (!response?.body) return "";
+ const reader = response.body.getReader();
+ const decoder = new TextDecoder();
+ let received = 0;
+ let text = "";
+ const stopReader = () => {
+ if (!controller.signal.aborted) controller.abort();
+ abandonUx1Reader(reader);
+ };
+ const onAbort = () => { abandonUx1Reader(reader); };
+ controller.signal.addEventListener("abort", onAbort);
+ try {
+ while (true) {
+ if (controller.signal.aborted) throw ux1AbortError();
+ const readPromise = reader.read();
+ readPromise.catch(() => {});
+ const next = await Promise.race([readPromise, abortPromise]);
+ if (next.done) break;
+ const bytes = next.value?.byteLength ?? 0;
+ received += bytes;
+ if (received > maxBytes) {
+ stopReader();
+ throw new Error("ux1_calculator_body_limit");
+ }
+ text += decoder.decode(next.value, { stream: true });
+ }
+ text += decoder.decode();
+ return text;
+ } catch (error) {
+ stopReader();
+ throw error;
+ } finally {
+ controller.signal.removeEventListener("abort", onAbort);
+ }
+}
+
+export async function readUx1CalculatorExchange(binding, body, limits) {
+ const deadlineMs = Number.isFinite(limits?.deadlineMs) ? limits.deadlineMs : UX1_CALCULATOR_DEADLINE_MS;
+ const maxBytes = Number.isFinite(limits?.maxBytes) ? limits.maxBytes : UX1_CALCULATOR_MAX_BYTES;
+ const controller = new AbortController();
+ let rejectAbort = () => {};
+ const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
+ abortPromise.catch(() => {});
+ const onAbort = () => rejectAbort(ux1AbortError());
+ controller.signal.addEventListener("abort", onAbort);
+ const timer = setTimeout(() => controller.abort(), deadlineMs);
+ const pending = Promise.resolve().then(() => binding.fetch("https://ux1-research-calculator/preview", {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body,
+ signal: controller.signal,
+ }));
+ let accepted = false;
+ pending.then((response) => {
+ if (accepted || !controller.signal.aborted) return;
+ abandonUx1Response(response);
+ }, () => {});
+ try {
+ const response = await Promise.race([pending, abortPromise]);
+ accepted = true;
+ const text = await readLimitedUtf8Body(response, maxBytes, controller, abortPromise);
+ return { status: response.status, ok: response.ok, text };
+ } finally {
+ clearTimeout(timer);
+ controller.signal.removeEventListener("abort", onAbort);
+ }
+}
+
+async function ux1ClearStoredPreview(env, login, slot) {
+ await runtimeInstanceCommand(env, {
+ action: "ux1_clear_preview", login,
+ expected_revision: slot.revision,
+ fingerprint: slot.fingerprint,
+ });
+}
+
+export async function ux1PreviewPost(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await requireUx1Session(request, env);
+ const parsed = assertUx1PreviewPost(await readUx1Body(request));
+ const slot = await ux1ReadSlot(env, session.login);
+ if (!slot || slot.revision !== parsed.expected_revision) throw new HttpError("ux1_preview_conflict", 409);
+ const draft = normalizeUx1Draft(slot.draft);
+ const fingerprint = await ux1Fingerprint(draft);
+ if (fingerprint !== slot.fingerprint) throw new HttpError("ux1_preview_conflict", 409);
+ if (ux1StoredJobBlocks(slot.job)) return json(ux1StatePayload(env, slot));
+ const previewMode = ux1PreviewMode(env);
+ if (previewMode === "rejected") throw new HttpError("ux1_preview_mode_rejected", 400);
+ const gate = classifyUx1Draft(draft);
+ let preview;
+ if (gate.kind === "missing_input" || gate.kind === "unsupported_scope") {
+ preview = localUx1Preview({ draft, fingerprint, status: gate.kind, reasons: gate.reasons });
+ } else if (previewMode === "github_actions") {
+ return await ux1DispatchPreview(env, session, slot, draft, fingerprint);
+ } else {
+ const binding = env.UX1_RESEARCH_CALCULATOR;
+ if (!binding || typeof binding.fetch !== "function") {
+ await ux1ClearStoredPreview(env, session.login, slot);
+ return json({
+ ok: false,
+ error: "calculator_not_connected",
+ status: "calculator_not_connected",
+ recompute_required: true,
+ ...ux1Flags(),
+ revision: slot.revision,
+ fingerprint,
+ custom_draft: ux1CustomDraft(draft),
+ draft,
+ preview: null,
+ decision_preview: null,
+ historical_execution_check: null,
+ }, 503);
+ }
+ const calculatorRequest = buildUx1PreviewRequest(draft);
+ let exchange;
+ try {
+ exchange = await readUx1CalculatorExchange(binding, canonicalJson(calculatorRequest));
+ } catch {
+ await ux1ClearStoredPreview(env, session.login, slot);
+ throw new HttpError("calculator_failed", 502);
+ }
+ const calculatorText = exchange.text;
+ if (exchange.status === 429) {
+ let busy = false;
+ try { busy = JSON.parse(calculatorText).error === "calculator_busy"; } catch { busy = false; }
+ if (busy) throw new HttpError("calculator_busy", 429);
+ }
+ if (!exchange.ok) {
+ await ux1ClearStoredPreview(env, session.login, slot);
+ throw new HttpError("calculator_failed", 502);
+ }
+ let raw;
+ try {
+ raw = JSON.parse(calculatorText);
+ } catch {
+ await ux1ClearStoredPreview(env, session.login, slot);
+ throw new HttpError("calculator_failed", 502);
+ }
+ try {
+ preview = projectUx1CalculatorResult(raw, calculatorRequest, draft, fingerprint);
+ if (!ux1ExpectedEvidenceMatches(preview, env)) throw new Ux1InputError("calculator_result_rejected", 502);
+ } catch (error) {
+ await ux1ClearStoredPreview(env, session.login, slot);
+ if (error instanceof Ux1InputError) throw new HttpError(error.message, error.status || 502);
+ throw new HttpError("calculator_result_rejected", 502);
+ }
+ }
+ preview = { ...preview, runtime_epoch: ux1RuntimeEpoch(env) };
+ const stored = await runtimeInstanceCommand(env, {
+ action: "ux1_store_preview",
+ login: session.login,
+ expected_revision: slot.revision,
+ fingerprint,
+ preview_json: canonicalJson(preview),
+ });
+ return json(ux1StatePayload(env, parseUx1Slot({ ...stored, found: true })));
+}
+
+export async function ux1IntentPost(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await requireUx1Session(request, env);
+ const parsed = assertUx1IntentPost(await readUx1Body(request));
+ const slot = await ux1ReadSlot(env, session.login);
+ if (!slot || slot.revision !== parsed.expected_revision || slot.fingerprint !== parsed.fingerprint) {
+ throw new HttpError("ux1_intent_conflict", 409);
+ }
+ if (ux1StoredJobBlocks(slot.job)) throw new HttpError("ux1_job_active", 409);
+ if (ux1PreviewBindingStale(slot.preview, env) || ux1TerminalJobConfigStale(slot.job, env)) throw new HttpError("ux1_preview_stale", 409);
+ if (!ux1IntentAllowed(slot.preview) || slot.preview.fingerprint !== parsed.fingerprint) {
+ throw new HttpError("ux1_intent_conflict", 409);
+ }
+ const intent = ux1IntentRecord({
+ login: session.login,
+ revision: slot.revision,
+ fingerprint: slot.fingerprint,
+ receiptId: await ux1ReceiptId(session.login, slot.revision, slot.fingerprint),
+ });
+ const stored = await runtimeInstanceCommand(env, {
+ action: "ux1_save_intent",
+ login: session.login,
+ expected_revision: slot.revision,
+ fingerprint: slot.fingerprint,
+ intent_json: canonicalJson(intent),
+ });
+ return json(ux1StatePayload(env, { ...parseUx1Slot({ ...stored, found: true }), duplicate: Boolean(stored.duplicate) }));
+}
+
+function ux1PreviewMode(env) {
+ const mode = String(env?.UX1_PREVIEW_MODE ?? "").trim();
+ if (!mode) return "local";
+ if (mode === "github_actions") return "github_actions";
+ return "rejected";
+}
+
+function ux1EvidenceRecord(value) {
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
+ if (Object.keys(value).length !== UX1_EVIDENCE_HASH_KEYS.length) return null;
+ const evidence = {};
+ for (const key of UX1_EVIDENCE_HASH_KEYS) {
+ if (typeof value[key] !== "string" || !/^[a-f0-9]{64}$/.test(value[key])) return null;
+ evidence[key] = value[key];
+ }
+ return evidence;
+}
+
+function ux1AsyncConfig(env) {
+ const ues = String(env?.UX1_UES_REVISION || "");
+ const epoch = String(env?.UX1_RUNTIME_EPOCH || "");
+ const token = String(env?.UX1_RESEARCH_JOB_TOKEN || "");
+ if (!/^[a-f0-9]{40}$/.test(ues) || !/^[a-f0-9]{32}$/.test(epoch) || token.length < 16 || token.length > 256) return null;
+ return ux1EvidenceRecord(ux1ParseJsonObject(env?.UX1_EXPECTED_EVIDENCE_HASHES))
+ ? { ues, epoch, evidence: ux1EvidenceRecord(ux1ParseJsonObject(env.UX1_EXPECTED_EVIDENCE_HASHES)) }
+ : null;
+}
+
+function ux1ParseJsonObject(text) {
+ if (typeof text !== "string" || !text) return null;
+ try {
+ const parsed = JSON.parse(text);
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
+ } catch {
+ return null;
+ }
+}
+
+function ux1StoredJobBlocks(job) {
+ return Boolean(job && (job.status === "queued" || job.status === "running" || job.status === "unknown"));
+}
+
+function ux1PublicJobReason(reason) {
+ return UX1_PUBLIC_JOB_REASONS.has(reason) ? reason : null;
+}
+
+function ux1JobConfigStale(job, env) {
+ const config = ux1AsyncConfig(env);
+ if (!config || !job) return false;
+ if (job.runtime_epoch !== config.epoch || job.ues_revision !== config.ues) return true;
+ return UX1_EVIDENCE_HASH_KEYS.some((key) => job.evidence?.[key] !== config.evidence[key]);
+}
+
+function ux1TerminalJobConfigStale(job, env) {
+ return Boolean(job && !ux1StoredJobBlocks(job) && ux1JobConfigStale(job, env));
+}
+
+function ux1JobBindingMatchesConfig(job, env) {
+ return Boolean(job && ux1AsyncConfig(env) && !ux1JobConfigStale(job, env));
+}
+
+export function projectUx1Job(job, now, slotRevision, env) {
+ if (!job || typeof job !== "object") return null;
+ const created = Date.parse(job.created_at);
+ const age = Number.isFinite(created) ? now - created : 0;
+ let status = job.status;
+ let reason = job.reason || null;
+ if (ux1StoredJobBlocks(job) && age >= UX1_JOB_UNKNOWN_AFTER_MS) {
+ status = "unknown";
+ reason = "check_required";
+ } else if (!ux1StoredJobBlocks(job) && (job.revision !== slotRevision || ux1JobConfigStale(job, env))) {
+ status = "superseded";
+ reason = "config_changed";
+ }
+ return {
+ request_id: job.request_id,
+ status,
+ dispatch_state: job.dispatch_state,
+ created_at: job.created_at,
+ updated_at: job.updated_at,
+ reason: ux1PublicJobReason(reason),
+ };
+}
+
+function ux1BearerMatches(header, secret) {
+ const match = /^Bearer ([!-~]{16,256})$/.exec(String(header || ""));
+ if (!match || typeof secret !== "string" || secret.length < 16 || secret.length > 256) return false;
+ const left = new TextEncoder().encode(match[1]);
+ const right = new TextEncoder().encode(secret);
+ let diff = left.length ^ right.length;
+ const length = Math.max(left.length, right.length);
+ for (let index = 0; index < length; index += 1) diff |= (left[index] || 0) ^ (right[index] || 0);
+ return diff === 0;
+}
+
+export function ux1ExactKeys(value, keys) {
+ return Boolean(value && typeof value === "object" && !Array.isArray(value)
+ && Object.keys(value).length === keys.length
+ && keys.every((key) => Object.hasOwn(value, key)));
+}
+
+function ux1RequestIdOk(value) {
+ return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
+}
+
+function ux1PositiveInt(value) {
+ return typeof value === "string" && /^[1-9][0-9]{0,18}$/.test(value);
+}
+
+async function ux1Digest(value) {
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalJson(value)));
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+async function readUx1LimitedJson(request, maxBytes) {
+ const controller = new AbortController();
+ let rejectAbort = () => {};
+ const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
+ abortPromise.catch(() => {});
+ const onAbort = () => rejectAbort(ux1AbortError());
+ controller.signal.addEventListener("abort", onAbort);
+ const timer = setTimeout(() => controller.abort(), UX1_GITHUB_DEADLINE_MS);
+ try {
+ const text = await readLimitedUtf8Body(request, maxBytes, controller, abortPromise);
+ try {
+ return JSON.parse(text);
+ } catch {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ } catch (error) {
+ if (error instanceof HttpError) throw error;
+ if (String(error?.message || "") === "ux1_calculator_body_limit") throw new HttpError("ux1_body_too_large", 400);
+ throw new HttpError("ux1_invalid_body", 400);
+ } finally {
+ clearTimeout(timer);
+ controller.signal.removeEventListener("abort", onAbort);
+ }
+}
+
+async function ux1GithubExchange(url, init) {
+ const controller = new AbortController();
+ let rejectAbort = () => {};
+ const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
+ abortPromise.catch(() => {});
+ const onAbort = () => rejectAbort(ux1AbortError());
+ controller.signal.addEventListener("abort", onAbort);
+ const timer = setTimeout(() => controller.abort(), UX1_GITHUB_DEADLINE_MS);
+ const pending = Promise.resolve().then(() => fetch(url, { ...init, redirect: "manual", signal: controller.signal }));
+ let accepted = false;
+ pending.then((response) => {
+ if (accepted || !controller.signal.aborted) return;
+ abandonUx1Response(response);
+ }, () => {});
+ try {
+ const response = await Promise.race([pending, abortPromise]);
+ accepted = true;
+ const text = await readLimitedUtf8Body(response, UX1_GITHUB_MAX_BYTES, controller, abortPromise);
+ return { status: response.status, ok: response.ok, text };
+ } finally {
+ clearTimeout(timer);
+ controller.signal.removeEventListener("abort", onAbort);
+ }
+}
+
+async function ux1DispatchResearchJob(env, requestId) {
+ if (!env.RUNTIME_SETTINGS_DISPATCH_TOKEN) return "unknown";
+ try {
+ const exchange = await ux1GithubExchange(
+ `https://api.github.com/repos/${UX1_RESEARCH_REPOSITORY}/actions/workflows/${UX1_RESEARCH_WORKFLOW_FILE}/dispatches`,
+ {
+ method: "POST",
+ headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
+ body: JSON.stringify({ ref: "main", inputs: { ux1_request_id: requestId } }),
+ },
+ );
+ if (exchange.status >= 200 && exchange.status < 300) return "dispatched";
+ if (exchange.status >= 400 && exchange.status < 500) return "rejected";
+ return "unknown";
+ } catch {
+ return "unknown";
+ }
+}
+
+async function ux1DispatchPreview(env, session, slot, draft, fingerprint) {
+ const config = ux1AsyncConfig(env);
+ if (!config || !env.RUNTIME_SETTINGS_DISPATCH_TOKEN) {
+ await ux1ClearStoredPreview(env, session.login, slot);
+ return json({
+ ok: false,
+ error: "ux1_async_not_connected",
+ status: "ux1_async_not_connected",
+ recompute_required: true,
+ ...ux1Flags(),
+ research_workflow_dispatched: false,
+ revision: slot.revision,
+ fingerprint,
+ custom_draft: ux1CustomDraft(draft),
+ draft,
+ preview: null,
+ job: projectUx1Job(slot.job, Date.now(), slot.revision, env),
+ decision_preview: null,
+ historical_execution_check: null,
+ }, 503);
+ }
+ const begun = await runtimeInstanceCommand(env, {
+ action: "ux1_begin_job",
+ login: session.login,
+ revision: slot.revision,
+ fingerprint,
+ epoch: config.epoch,
+ ues: config.ues,
+ evidence: config.evidence,
+ request: buildUx1PreviewRequest(draft),
+ });
+ const job = JSON.parse(begun.job_json);
+ if (begun.created) {
+ const outcome = await ux1DispatchResearchJob(env, job.request_id);
+ await runtimeInstanceCommand(env, {
+ action: "ux1_record_dispatch",
+ login: session.login,
+ request_id: job.request_id,
+ outcome,
+ });
+ }
+ return json(ux1StatePayload(env, await ux1ReadSlot(env, session.login)));
+}
+
+export function ux1RunMatches(run, job, runId, runAttempt) {
+ if (!run || typeof run !== "object" || Array.isArray(run) || !job) return false;
+ const repository = run.repository;
+ const headRepository = run.head_repository;
+ if (!repository || typeof repository !== "object" || !headRepository || typeof headRepository !== "object") return false;
+ return String(run.id) === runId
+ && run.event === "workflow_dispatch"
+ && run.path === UX1_RESEARCH_WORKFLOW_PATH
+ && run.head_sha === job.ues_revision
+ && run.display_title === `UX1 preview ${job.request_id}`
+ && String(run.run_attempt) === runAttempt
+ && run.head_branch === "main"
+ && repository.full_name === UX1_RESEARCH_REPOSITORY
+ && headRepository.full_name === UX1_RESEARCH_REPOSITORY
+ && repository.fork !== true
+ && headRepository.fork !== true;
+}
+
+async function ux1FetchRun(env, runId) {
+ let exchange;
+ try {
+ exchange = await ux1GithubExchange(
+ `https://api.github.com/repos/${UX1_RESEARCH_REPOSITORY}/actions/runs/${runId}`,
+ { method: "GET", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN) },
+ );
+ } catch {
+ throw new HttpError("ux1_run_unverified", 502);
+ }
+ if (!exchange.ok) throw new HttpError("ux1_run_unverified", 502);
+ try {
+ return JSON.parse(exchange.text);
+ } catch {
+ throw new HttpError("ux1_run_unverified", 502);
+ }
+}
+
+function ux1ClaimDenied(requestId, runId, runAttempt) {
+ return json({ ok: true, claimed: false, request_id: requestId, run_id: runId, run_attempt: runAttempt });
+}
+
+export async function ux1JobClaimPost(request, env) {
+ if (!ux1BearerMatches(request.headers.get("Authorization"), env.UX1_RESEARCH_JOB_TOKEN)) {
+ throw new HttpError("ux1_job_unauthorized", 401);
+ }
+ const body = await readUx1LimitedJson(request, UX1_JOB_BODY_MAX_BYTES);
+ if (!ux1ExactKeys(body, ["request_id", "run_id", "run_attempt"]) || !ux1RequestIdOk(body.request_id) || !ux1PositiveInt(body.run_id) || !ux1PositiveInt(body.run_attempt)) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ const looked = await runtimeInstanceCommand(env, { action: "ux1_lookup_job", request_id: body.request_id });
+ if (!looked.found) throw new HttpError("ux1_job_not_found", 404);
+ const job = JSON.parse(looked.job_json);
+ if (job.claimed_run_id || (job.status !== "queued" && job.status !== "unknown")) {
+ return ux1ClaimDenied(body.request_id, body.run_id, body.run_attempt);
+ }
+ const draft = {
+ objective: job.request?.objective,
+ research_case_id: job.request?.research_case_id,
+ advanced_settings: job.request?.advanced_settings,
+ };
+ try {
+ if (!job.request || canonicalJson(buildUx1PreviewRequest(draft)) !== canonicalJson(job.request) || await ux1Fingerprint(draft) !== job.fingerprint) {
+ throw new HttpError("ux1_run_unverified", 502);
+ }
+ } catch (error) {
+ if (error instanceof HttpError) throw error;
+ throw new HttpError("ux1_run_unverified", 502);
+ }
+ const run = await ux1FetchRun(env, body.run_id);
+ if (!ux1RunMatches(run, job, body.run_id, body.run_attempt)) throw new HttpError("ux1_run_unverified", 502);
+ const claimed = await runtimeInstanceCommand(env, {
+ action: "ux1_claim_job",
+ request_id: body.request_id,
+ run_id: body.run_id,
+ run_attempt: body.run_attempt,
+ });
+ if (!claimed.claimed) return ux1ClaimDenied(body.request_id, body.run_id, body.run_attempt);
+ return json({
+ ok: true,
+ claimed: true,
+ request_id: body.request_id,
+ run_id: body.run_id,
+ run_attempt: body.run_attempt,
+ request: claimed.request,
+ });
+}
+
+export async function ux1JobResultPost(request, env) {
+ if (!ux1BearerMatches(request.headers.get("Authorization"), env.UX1_RESEARCH_JOB_TOKEN)) {
+ throw new HttpError("ux1_job_unauthorized", 401);
+ }
+ const body = await readUx1LimitedJson(request, UX1_JOB_BODY_MAX_BYTES);
+ if (!ux1ExactKeys(body, ["request_id", "run_id", "run_attempt", "result", "error_code"]) || !ux1RequestIdOk(body.request_id) || !ux1PositiveInt(body.run_id) || !ux1PositiveInt(body.run_attempt)) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ if (!(body.error_code === null || body.error_code === "input_unavailable" || body.error_code === "calculator_failed")) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ if (body.error_code === null ? body.result === null : body.result !== null) throw new HttpError("ux1_invalid_body", 400);
+ const looked = await runtimeInstanceCommand(env, { action: "ux1_lookup_job", request_id: body.request_id });
+ if (!looked.found) throw new HttpError("ux1_job_not_found", 404);
+ const job = JSON.parse(looked.job_json);
+ if (job.claimed_run_id !== body.run_id || job.claimed_run_attempt !== body.run_attempt) {
+ throw new HttpError("ux1_result_conflict", 409);
+ }
+ let previewJson = null;
+ if (!body.error_code) {
+ const draft = {
+ objective: job.request?.objective,
+ research_case_id: job.request?.research_case_id,
+ advanced_settings: job.request?.advanced_settings,
+ };
+ try {
+ if (canonicalJson(buildUx1PreviewRequest(draft)) !== canonicalJson(job.request)) throw new Ux1InputError("calculator_result_rejected", 502);
+ const preview = projectUx1CalculatorResult(body.result, job.request, draft, job.fingerprint);
+ const evidence = { evidence: Object.fromEntries(UX1_EVIDENCE_HASH_KEYS.map((key) => [key, preview.evidence?.[key]])) };
+ if (!preview.evidence || !ux1ExpectedEvidenceMatches(evidence, { UX1_EXPECTED_EVIDENCE_HASHES: JSON.stringify(job.evidence) })) {
+ throw new Ux1InputError("calculator_result_rejected", 502);
+ }
+ if (ux1JobBindingMatchesConfig(job, env)) previewJson = canonicalJson({ ...preview, runtime_epoch: job.runtime_epoch });
+ } catch (error) {
+ if (error instanceof Ux1InputError && error.message === "calculator_failed") throw new HttpError("calculator_failed", 502);
+ throw new HttpError("calculator_result_rejected", 502);
+ }
+ }
+ const finished = await runtimeInstanceCommand(env, {
+ action: "ux1_finish_job",
+ request_id: body.request_id,
+ run_id: body.run_id,
+ run_attempt: body.run_attempt,
+ error_code: body.error_code,
+ preview_json: previewJson,
+ terminal_digest: await ux1Digest({ error_code: body.error_code, result: body.result }),
+ });
+ return json({ ok: true, accepted: true, duplicate: Boolean(finished.duplicate) });
+}
+
+export function ux1SelectSlot(sql, login) {
+ return sql.exec(
+ "SELECT revision, draft_json, fingerprint, preview_json, intent_json, job_json FROM ux1_research_slot WHERE login = ?",
+ login,
+ ).toArray()[0] || null;
+}
+
+export function ux1SlotPayload(row, extra = {}) {
+ return {
+ ok: true,
+ found: Boolean(row),
+ revision: row ? Number(row.revision) : 0,
+ draft_json: row?.draft_json || null,
+ fingerprint: row?.fingerprint || null,
+ preview_json: row?.preview_json || null,
+ intent_json: row?.intent_json || null,
+ job_json: row?.job_json || null,
+ ...extra,
+ };
+}
+
+function ux1ParseStoredJob(text) {
+ if (!text) return null;
+ try {
+ const job = JSON.parse(text);
+ return job && typeof job === "object" && !Array.isArray(job) ? job : null;
+ } catch {
+ return null;
+ }
+}
+
+function ux1SelectJob(sql, requestId) {
+ return sql.exec(
+ `SELECT login, revision, draft_json, fingerprint, preview_json, intent_json, job_json
+ FROM ux1_research_slot WHERE json_extract(job_json, '$.request_id') = ?`,
+ requestId,
+ ).toArray()[0] || null;
+}
+
+function ux1WriteJob(sql, login, job) {
+ const text = JSON.stringify(job);
+ if (text.length > 65536) throw new HttpError("ux1_invalid_body", 400);
+ sql.exec("UPDATE ux1_research_slot SET job_json = ? WHERE login = ?", text, login);
+ return text;
+}
+
+function ux1SameSucceededBinding(job, command, row) {
+ const evidence = ux1EvidenceRecord(command.evidence);
+ if (!job || job.status !== "succeeded" || !evidence || !row) return false;
+ return job.revision === Number(row.revision)
+ && job.fingerprint === row.fingerprint
+ && job.revision === command.revision
+ && job.fingerprint === command.fingerprint
+ && job.runtime_epoch === command.epoch
+ && job.ues_revision === command.ues
+ && UX1_EVIDENCE_HASH_KEYS.every((key) => job.evidence?.[key] === evidence[key]);
+}
+
+export function ux1MutateJob(sql, command) {
+ if (command.action === "ux1_lookup_job") {
+ if (!ux1RequestIdOk(command.request_id)) throw new HttpError("ux1_invalid_body", 400);
+ const row = ux1SelectJob(sql, command.request_id);
+ return row ? ux1SlotPayload(row) : { ok: true, found: false };
+ }
+ if (command.action === "ux1_claim_job" || command.action === "ux1_finish_job") {
+ if (!ux1RequestIdOk(command.request_id) || !ux1PositiveInt(command.run_id) || !ux1PositiveInt(command.run_attempt)) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ const row = ux1SelectJob(sql, command.request_id);
+ if (!row) throw new HttpError("ux1_job_not_found", 404);
+ const job = ux1ParseStoredJob(row.job_json);
+ if (!job) throw new HttpError("ux1_job_not_found", 404);
+ const now = new Date().toISOString();
+ if (command.action === "ux1_claim_job") {
+ if (job.claimed_run_id || (job.status !== "queued" && job.status !== "unknown")) {
+ return { ok: true, claimed: false };
+ }
+ job.status = "running";
+ job.claimed_run_id = command.run_id;
+ job.claimed_run_attempt = command.run_attempt;
+ job.updated_at = now;
+ ux1WriteJob(sql, row.login, job);
+ return { ok: true, claimed: true, request: job.request };
+ }
+ if (job.claimed_run_id !== command.run_id || job.claimed_run_attempt !== command.run_attempt) {
+ throw new HttpError("ux1_result_conflict", 409);
+ }
+ if (job.terminal_digest) {
+ if (job.terminal_digest === command.terminal_digest) return { ok: true, duplicate: true };
+ throw new HttpError("ux1_result_conflict", 409);
+ }
+ if (job.status !== "running") throw new HttpError("ux1_result_conflict", 409);
+ if (typeof command.terminal_digest !== "string" || !/^[a-f0-9]{64}$/.test(command.terminal_digest)) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ job.status = command.error_code ? "failed" : "succeeded";
+ job.reason = command.error_code || null;
+ job.terminal_digest = command.terminal_digest;
+ job.updated_at = now;
+ ux1WriteJob(sql, row.login, job);
+ const sameSlot = Number(row.revision) === job.revision && row.fingerprint === job.fingerprint;
+ if (command.error_code && sameSlot) {
+ sql.exec(
+ "UPDATE ux1_research_slot SET preview_json = NULL, intent_json = NULL WHERE login = ? AND revision = ? AND fingerprint = ?",
+ row.login, Number(row.revision), row.fingerprint,
+ );
+ } else if (!command.error_code && sameSlot && typeof command.preview_json === "string" && command.preview_json.length <= 65536) {
+ sql.exec(
+ "UPDATE ux1_research_slot SET preview_json = ? WHERE login = ? AND revision = ? AND fingerprint = ?",
+ command.preview_json, row.login, Number(row.revision), row.fingerprint,
+ );
+ }
+ return { ok: true, duplicate: false };
+ }
+ const login = String(command?.login || "");
+ if (!/^[a-z0-9-]{1,39}$/.test(login)) throw new HttpError("ux1_login_invalid", 400);
+ const row = ux1SelectSlot(sql, login);
+ if (!row) throw new HttpError("ux1_preview_conflict", 409);
+ const job = ux1ParseStoredJob(row.job_json);
+ if (command.action === "ux1_begin_job") {
+ if (ux1StoredJobBlocks(job)) return { ...ux1SlotPayload(row), created: false };
+ if (ux1SameSucceededBinding(job, command, row)) return { ...ux1SlotPayload(row), created: false };
+ const evidence = ux1EvidenceRecord(command.evidence);
+ if (!evidence || command.revision !== Number(row.revision) || command.fingerprint !== row.fingerprint) {
+ throw new HttpError("ux1_preview_conflict", 409);
+ }
+ if (!/^[a-f0-9]{32}$/.test(String(command.epoch || "")) || !/^[a-f0-9]{40}$/.test(String(command.ues || ""))) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ if (!command.request || command.request.schema !== "qsl.ux1.preview_request.v1" || JSON.stringify(command.request).length > 16384) {
+ throw new HttpError("ux1_invalid_body", 400);
+ }
+ const now = new Date().toISOString();
+ const next = {
+ request_id: crypto.randomUUID(),
+ status: "queued",
+ dispatch_state: "pending",
+ revision: Number(row.revision),
+ fingerprint: row.fingerprint,
+ runtime_epoch: command.epoch,
+ ues_revision: command.ues,
+ evidence,
+ request: command.request,
+ created_at: now,
+ updated_at: now,
+ claimed_run_id: null,
+ claimed_run_attempt: null,
+ reason: null,
+ terminal_digest: null,
+ };
+ const jobJson = ux1WriteJob(sql, login, next);
+ sql.exec("UPDATE ux1_research_slot SET preview_json = NULL, intent_json = NULL WHERE login = ?", login);
+ return { ...ux1SlotPayload(row), preview_json: null, intent_json: null, job_json: jobJson, created: true };
+ }
+ if (command.action === "ux1_record_dispatch") {
+ if (!job || job.request_id !== command.request_id || job.dispatch_state !== "pending") {
+ return { ...ux1SlotPayload(row), recorded: false };
+ }
+ if (command.outcome === "dispatched") job.dispatch_state = "dispatched";
+ else if (command.outcome === "rejected") {
+ job.dispatch_state = "rejected";
+ if (job.status === "queued") job.status = "failed";
+ job.reason = "dispatch_rejected";
+ } else {
+ job.dispatch_state = "unknown";
+ if (job.status === "queued") job.status = "unknown";
+ job.reason = "dispatch_unconfirmed";
+ }
+ job.updated_at = new Date().toISOString();
+ const jobJson = ux1WriteJob(sql, login, job);
+ return { ...ux1SlotPayload(row), job_json: jobJson, recorded: true };
+ }
+ throw new HttpError("unsupported_ux1_action", 400);
+}
diff --git a/web/strategy-switch-console/application/worker/runtime_support.js b/web/strategy-switch-console/application/worker/runtime_support.js
new file mode 100644
index 00000000..ed10dc49
--- /dev/null
+++ b/web/strategy-switch-console/application/worker/runtime_support.js
@@ -0,0 +1,13981 @@
+import { performanceBenchmarkResponse } from "../console_api/performance_benchmarks.js";
+import { binanceDetailCommand } from "../../binance_detail_archive.js";
+import { createDeskAuth, DeskError, deskErrorResponse } from "../desk/http.js";
+import { DeskReadbackStore, deskReadbackResponse, buildReadback, readbackTargets } from "../desk/readback.js";
+import { deskCredentialsResponse } from "../desk/credentials.js";
+import { deskSwitchTargetsResponse } from "../desk/switch_targets.js";
+import { auditPageQuery, auditEventInPage, auditEventOrder, auditNextCursor } from "../console_api/audit_pagination.js";
+import { runtimeReadbackProjection } from "../console_api/runtime_readback.js";
+import { initialEnrollmentBindingsMatch, initialEnrollmentDigest } from "../console_api/initial_enrollment.js";
+import { readNotificationLog } from "../console_api/notification_receipts.js";
+import { readRuntimeControlReceipt } from "../console_api/runtime_control_receipts.js";
+import { KvDirectory, currentStrategiesSignature, DIRECTORY_PATH, directoryCommand, directoryList, directoryStatus, indexedKey, maintainDirectory } from "../../kv_directory.js";
+import { sourceListFailure } from "../console_api/read_failures.js";
+import { strategyTargetExecution, accountExecutionEvidence } from "../console_api/strategy_execution.js";
+import { performanceResponse } from "../console_api/performance_routes.js";
+import { consoleApiResponse } from "../console_api/routes.js";
+import { runControls } from "../console_api/run_controls.js";
+import { decorateQueue, decisionFields, actorAlias, pageQuery, shortId } from "../console_api/presentation.js";
+import { inbox } from "../console_api/inbox.js";
+import {
+ DECISION_ACTIONS, DECISION_REVIEW_SCHEMA_VERSION, decisionCategoryPart, decisionCurrentEligibility,
+ decisionExpiry, decisionExpiryState, decisionKind, decisionOperationId, decisionOperationReference,
+ decisionOperationSha256, decisionRevision, decisionWriteCategory,
+ operationIdFor, operationStatusFromApplication,
+} from "../console_api/decision_contract.js";
+import { RISK_TIER_POLICY_BINDINGS, riskTierBindingView, riskTierPolicyCatalog } from "../console_api/risk_tiers.js";
+import { recoveryMaterialPresentation, currentReconciliationObservationPresentation } from "../console_api/reconciliation_presentation.js";
+// deploy: 2026-06-30 — config driven by platform-config.json
+import { initializeSecretRotation, durableRotationCommand, credentialRotationResponse } from "../../secretRotation.js";
+import { RotationError } from "../../secretRotationStepUp.js";
+import { CredentialMaintenanceError, initializeCredentialMaintenance, credentialMaintenanceCommand } from "../../credentialMaintenance.js";
+import { V2_ASSETS, V2_PAGE_HTML, V2_BUILD_ID } from "../../v2_asset_map.js";
+import { CycleHealthError, canonicalCycleJson, cycleHealthSha256, normalizeCycleHealth, normalizeCycleInstant, compareCycleInstants, cycleCoverageComplete, cycleHealthAttemptKey, cycleHealthFaultCategory, cycleHealthFaultTime } from "../../runtime_cycle_health.js";
+import { RUNTIME_DAILY_TARGET, RUNTIME_DAILY_TARGETS, RUNTIME_DAILY_TIMEZONE, runtimeDailyBusinessDate, runtimeDailyTarget, runtimeDailyBoundAccountKey, runtimeDailyRunIssue, parseRuntimeDailyTargetKey } from "../../runtime_daily_contract.js";
+import {
+ BINANCE_FACTS_KEY, BINANCE_FACTS_MAX_BYTES, BinanceFactsError,
+ normalizeBinanceFactsBinding, binanceFactsOptionMatches, assertBinanceFactsSourceBinding,
+ normalizeBinanceAccountFacts, projectBinanceAccountFacts,
+ binanceWalletHistoryEntry, binanceWalletHistoryStorageKey, normalizeBinanceWalletHistoryEntry,
+ projectBinanceWalletHistoryFromSources,
+ assertBinanceFactsHistoryBindings, BINANCE_WALLET_HISTORY_MAX_DAYS,
+} from "../../binance_account_facts.js";
+import { DEFAULT_STRATEGY_PROFILES } from "../../strategy_profiles_asset.js";
+import { canonicalStrategyProfile, sameStrategyProfile } from "../../strategy_identity.js";
+import {
+ DCA_SUPPORTED_PLATFORMS,
+ DEFAULT_VARIABLE_SCOPES as DEFAULT_VARIABLE_SCOPE,
+ PLATFORM_REPOSITORIES,
+ DOMAIN_LABELS,
+ PLATFORM_MIN_RESERVED_CASH_VARIABLES,
+ PLATFORM_RESERVED_CASH_RATIO_VARIABLES,
+ PLATFORM_CONFIG,
+ PLATFORM_META,
+ DEFAULT_ACCOUNT_OPTIONS,
+ FALLBACK_INCOME_LAYER_DEFAULTS,
+ FALLBACK_OPTION_OVERLAY_DEFAULTS,
+ DCA_PROFILE_DEFAULTS,
+ RUNTIME_CATALOG_PROJECTION,
+ STRATEGY_FEATURES,
+ PLATFORM_REPOSITORY_ENV_KEYS,
+ OBSERVABILITY_PLATFORMS,
+} from "../../config.js";
+import {
+ DEFAULT_PLATFORM_REPOSITORIES,
+ PLATFORM_REPOSITORY_ENV,
+ PLATFORM_CASH_ONLY_EXECUTION_VARIABLES_MAP as PLATFORM_CASH_ONLY_EXECUTION_VARIABLES,
+ OBSERVABILITY_PLATFORM_IDS,
+ resolvePlatformRepositories,
+ isDcaSupportedPlatform,
+} from "../../platform_registry.js";
+import { assertLiveSwitchAllowed, catalogVersionMetadata, isLiveSwitchAllowed } from "../../catalog.js";
+import {
+ BROKER_ENVIRONMENTS,
+ normalizeAccountOptionsPayload as normalizeAccountOptionsSchemaPayload,
+ parseAccountOptionsJson as parseAccountOptionsSchemaJson,
+} from "../../account_options_schema.js";
+import {
+ normalizeIbkrPeriodReturn,
+ publicIbkrPeriodReturn,
+ ACCOUNT_FACTS_BINDINGS_KEY,
+ ACCOUNT_FACTS_HISTORY_MAX_DAYS,
+ ACCOUNT_FACTS_MAX_BODY_BYTES,
+ ACCOUNT_FACTS_STALE_MS,
+ ACCOUNT_FACTS_FUTURE_SKEW_MS,
+ ACCOUNT_FACTS_SUPPORTED_PLATFORMS,
+ ACCOUNT_FACTS_RETURN_UNAVAILABLE,
+ IBKR_ACCOUNT_FACTS_PLATFORM,
+ SCHWAB_ACCOUNT_FACTS_PLATFORM,
+ FIRSTRADE_ACCOUNT_FACTS_PLATFORM,
+ validFirstradeAccountId,
+ accountFactsOptionMatchesBinding,
+ accountFactsPlatformForHistory,
+ accountFactsReadModelEnabled,
+ accountFactsScopesMatchForPlatform,
+ buildAccountFactsHistoryReadModel,
+ buildAccountFactsReadModel,
+ canonicalizeAccountFactsHistory,
+ decideAccountFactsDailyUpsert,
+ decideAccountFactsPut,
+ historyRetentionCutoff,
+ normalizeAccountFactsBindings,
+ normalizeAccountFactsHistoryPayload,
+ normalizeAccountFactsHistoricalPayload,
+ resolveTrustedAccountFactsBinding,
+ AccountFactsError,
+} from "../../account_facts.js";
+import {
+ UX1_DRAFT_SCHEMA,
+ UX1_EVIDENCE_HASH_KEYS,
+ UX1_STUDY,
+ Ux1InputError,
+ assertUx1DraftPost,
+ assertUx1IntentPost,
+ assertUx1PreviewPost,
+ buildUx1PreviewRequest,
+ canonicalJson,
+ classifyUx1Draft,
+ defaultUx1Draft,
+ localUx1Preview,
+ normalizeUx1Draft,
+ projectUx1CalculatorResult,
+ ux1CustomDraft,
+ ux1Fingerprint,
+ ux1IntentAllowed,
+ ux1IntentRecord,
+ ux1ReceiptId,
+} from "../../ux1_research_contract.js";
+import {
+ OVERVIEW_FX_PROXY_PATH,
+ OVERVIEW_FX_UPSTREAM_URL,
+ overviewFxResponse as overviewFxResponseImpl,
+ resetOverviewFxCache,
+} from "../../infrastructure/fx/overview_fx.js";
+import {
+ MARKET_BENCHMARK_API_PATH,
+ MARKET_BENCHMARK_SYNC_PATH,
+ MARKET_BENCHMARK_SCHEMA,
+ MARKET_BENCHMARK_SERIES_IDS,
+ MarketBenchmarkError,
+ normalizeMarketBenchmarkSyncPayload,
+ publicMarketBenchmarkReadModel,
+} from "../../infrastructure/market_benchmark/market_benchmark.js";
+import {
+ MARKET_BENCHMARK_REVISION_PATH,
+ planRevisionApply,
+ revisionApplyLogSummary,
+ MarketBenchmarkRevisionError,
+} from "../../infrastructure/market_benchmark/market_benchmark_revision.js";
+import {
+ accountFactsResponse as accountFactsResponseImpl,
+ accountFactsHistoryResponse as accountFactsHistoryResponseImpl,
+ accountFactsIdentityDates,
+} from "../account_facts/read.js";
+import {
+ syncAccountFactsResponse as syncAccountFactsResponseImpl,
+} from "../account_facts/sync.js";
+import {
+ ownerDecisionQueueResponse as ownerDecisionQueueResponseImpl,
+ recordOwnerDecisionResponse as recordOwnerDecisionResponseImpl,
+} from "../approval/owner_decisions.js";
+import {
+ researchPromotionApplicationResponse as researchPromotionApplicationResponseImpl,
+ researchPromotionApplicationInternalResponse as researchPromotionApplicationInternalResponseImpl,
+} from "../research_promotion/applications.js";
+
+import { HttpError } from "../http_error.js";
+import { buildRiskEnvelopeView, attachRiskEnvelopeView } from "../risk_envelope.js";
+import {
+ ACCOUNT_DIAGNOSIS_REQUEST_PATH,
+ ACCOUNT_DIAGNOSIS_INTERNAL_PREFIX,
+ ACCOUNT_DIAGNOSIS_TARGET_ID,
+ ACCOUNT_DIAGNOSIS_TARGETS,
+ ACCOUNT_DIAGNOSIS_TRIGGERS,
+ ACCOUNT_DIAGNOSIS_STATUSES,
+ ACCOUNT_DIAGNOSIS_REASON_CODES,
+ ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES,
+ ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS,
+ ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS,
+ ACCOUNT_DIAGNOSIS_AUTO_ENABLED_ENV,
+ ACCOUNT_DIAGNOSIS_DO_ACTIONS,
+ ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT,
+} from "../account_diagnosis/constants.js";
+import {
+ accountDiagnosisConflict,
+ accountDiagnosisErrorPayload,
+ accountDiagnosisTaskFromRow,
+} from "../account_diagnosis/helpers.js";
+import {
+ UX1_CALCULATOR_DEADLINE_MS,
+ UX1_CALCULATOR_MAX_BYTES,
+ UX1_RESEARCH_REPOSITORY,
+ UX1_RESEARCH_WORKFLOW_FILE,
+ UX1_RESEARCH_WORKFLOW_PATH,
+ UX1_JOB_BODY_MAX_BYTES,
+ UX1_GITHUB_DEADLINE_MS,
+ UX1_GITHUB_MAX_BYTES,
+ UX1_JOB_UNKNOWN_AFTER_MS,
+ UX1_PUBLIC_JOB_REASONS,
+} from "../ux1/constants.js";
+import {
+ requireUx1Session,
+ ux1DraftGet,
+ ux1DraftPost,
+ ux1PreviewPost,
+ ux1IntentPost,
+ ux1JobClaimPost,
+ ux1JobResultPost,
+ ux1MutateJob,
+ ux1SelectSlot,
+ ux1SlotPayload,
+ presentUx1Preview,
+ projectUx1Job,
+ ux1RunMatches,
+ ux1RuntimeEpoch,
+ readUx1CalculatorExchange,
+ readLimitedUtf8Body,
+ ux1ExactKeys,
+} from "../ux1/research.js";
+import {
+ hasRuntimeInstanceStore,
+ runtimeInstanceCommand,
+ runtimeInstanceAccountOptions,
+ runtimeInstanceConflict,
+ runtimeInstanceFields,
+} from "../runtime_instances/command.js";
+import { startLogin, finishLogin } from "../auth/login.js";
+import { readSession, makeSession } from "../auth/session.js";
+
+export const CYCLE_HEALTH_HISTORY_PAGE_SIZE = 50;
+export const CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION = "qsl_runtime_cycle_health_state_summary.v1";
+export const DEFAULT_REPOSITORY = "QuantStrategyLab/QuantRuntimeSettings";
+export const DEFAULT_WORKFLOW = "manual-strategy-switch.yml";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_PATH = "/api/internal/account-settings/profile-application/claim";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_AUDIENCE = "qrs-profile-application";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REPOSITORY = "QuantStrategyLab/QuantRuntimeSettings";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REF = "refs/heads/main";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_WORKFLOW_REF = "QuantStrategyLab/QuantRuntimeSettings/.github/workflows/apply-approved-hk-profile.yml@refs/heads/main";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_JWKS_URL = "https://token.actions.githubusercontent.com/.well-known/jwks";
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_TOKEN_BYTES = 8192;
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_JWKS_BYTES = 32 * 1024;
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_TIMEOUT_MS = 5000;
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_TIMEOUT_MS = 1000;
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_MAX_BODY_BYTES = 1024;
+export const SESSION_COOKIE = "qsl_switch_session";
+export const OAUTH_STATE_COOKIE = "qsl_switch_oauth_state";
+export const SESSION_TTL_SECONDS = 8 * 60 * 60;
+export const AUTH_CONFIG_KEY = "auth_config";
+export const ACCOUNT_OPTIONS_KEY = "account_options";
+export const STRATEGY_PROFILES_KEY = "strategy_profiles";
+// Risk preferences are a separate, low-frequency owner-intent record. They
+// must never be merged into a strategy switch input, runtime target, or any
+// execution credential/policy path.
+export const RISK_PROFILE_BINDINGS_KEY = "risk_profile_bindings";
+export const RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION = "qsl.risk_profile_binding_registry.v1";
+export const RISK_PROFILE_BINDING_SCHEMA_VERSION = "qsl.risk_profile_binding.v1";
+export const RISK_PROFILE_SELECTION_SCHEMA_VERSION = "qsl.risk_profile_selection.v1";
+const RISK_PROFILE_IDS = {
+ CAPITAL_PRESERVATION: "capital_preservation_v1",
+ BALANCED_COMPOUNDING: "balanced_compounding_v1",
+ GROWTH_COMPOUNDING: "growth_compounding_v1",
+};
+export const RISK_PROFILE_PREFERENCES = Object.keys(RISK_PROFILE_IDS);
+export const DECISION_ACTION_SCHEMA_VERSION = "qsl.decision_action_result.v1";
+export const OPERATION_SCHEMA_VERSION = "qsl.operation.v1";
+export const AUDIT_EVENTS_SCHEMA_VERSION = "qsl.audit_events.v1";
+export const DECISION_ACTION_MAX_BODY_BYTES = 8 * 1024;
+export const AUDIT_EVENTS_MAX_ROWS = 101;
+export const AUDIT_LOG_KEY = "audit_log";
+export const AUDIT_LOG_LIMIT = 50;
+export const CURRENT_STRATEGIES_TIMEOUT_MS = 25000;
+export const CURRENT_STRATEGIES_CACHE_KEY = "current_strategies_cache";
+// The keep-alive bump stays below the KV fresh window so one missed cron tick
+// (the schedule is */5) still leaves the entry inside it; a cold isolate then
+// never has to fan out to GitHub just because the stamp aged out.
+export const CURRENT_STRATEGIES_MEMO_TTL_MS = 60_000; // 60 sec — a warm isolate re-checks GitHub after this
+export const CURRENT_STRATEGIES_KV_FRESH_MS = 1_800_000; // 30 min — a cold isolate serves the KV entry without any GitHub fan-out
+export const CURRENT_STRATEGIES_STALE_TTL_MS = 3_600_000; // 60 min — return stale plus background refresh before blocking on GitHub
+export const CURRENT_STRATEGIES_KV_BUMP_MS = 900_000; // 15 min — ceiling for ts-only rewrites when the content did not change
+export const GITHUB_API_TIMEOUT_MS = 8000;
+export const GITHUB_LOGIN_REQUEST_TIMEOUT_MS = 20000;
+export const STRATEGY_HEALTH_SNAPSHOT_KEY = "strategy_health_snapshot";
+export const STRATEGY_HEALTH_MAX_BODY_BYTES = 256 * 1024;
+export const STRATEGY_HEALTH_DEFAULT_STALE_TTL_SECONDS = 2 * 60 * 60;
+export const STRATEGY_HEALTH_STATUSES = ["healthy", "watch", "review", "critical"];
+// Derived from the generated platform config so a domain is declared once.
+const SUPPORTED_STRATEGY_DOMAINS = Object.freeze([
+ ...new Set(Object.values(PLATFORM_CONFIG).flatMap((platform) => platform.supported_domains || [])),
+]);
+export const STRATEGY_HEALTH_DOMAINS = SUPPORTED_STRATEGY_DOMAINS;
+export const STRATEGY_HEALTH_DATA_STATUSES = ["ready", "unavailable", "stale"];
+export const CONTROL_PLANE_SNAPSHOT_KEY = "control_plane_snapshot";
+export const CONTROL_PLANE_SOURCE_PREFIX = "control_plane_source:";
+export const CONTROL_PLANE_SOURCE_SCHEMA_VERSION = "qsl_control_plane_source_snapshot.v1";
+export const CONTROL_PLANE_SOURCE_RETIREMENTS_KEY = "control_plane_source_retirements";
+export const CONTROL_PLANE_ATTENTION_STATUSES = ["research_only", "attention_required", "unavailable"];
+export const CONTROL_PLANE_MAX_SOURCES = 100;
+export const CONTROL_PLANE_MAX_BODY_BYTES = 256 * 1024;
+// The current source is a once-per-trading-day P1/P3 lane, rather than a live
+// execution heartbeat. Freshness therefore preserves the normal TTL, but also
+// waits for the next scheduled research window across the weekend before it
+// calls an otherwise usable Friday/Saturday snapshot stale.
+export const CONTROL_PLANE_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
+export const CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_DAYS = new Set([2, 3, 4, 5, 6]);
+export const CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_HOUR = 3;
+export const CONTROL_PLANE_RESEARCH_DELIVERY_GRACE_MS = 4 * 60 * 60 * 1000;
+export const CONTROL_PLANE_CANDIDATE_KINDS = ["individual", "portfolio", "plugin"];
+export const CONTROL_PLANE_STAGES = ["P1", "P2", "P3", "P4", "P5", "P6"];
+const CONTROL_PLANE_LIFECYCLE_STATUSES = [
+ "research", "evidence_pending", "verified", "deferred", "parked", "paper", "shadow", "owner_decision_required",
+];
+const CONTROL_PLANE_RECOMMENDATIONS = [
+ "none", "keep_research", "defer", "park", "auto_paper_evaluation", "auto_shadow_evaluation", "owner_live_decision",
+];
+export const CONTROL_PLANE_AUTOMATION_STATES = ["not_configured", "configured", "active"];
+const FORWARD_OBSERVATION_STATES = [
+ "PARKED", "FORWARD_ACTIVE", "PAUSED", "FORWARD_COMPLETE_HUMAN_REVIEW", "MANUAL_HOLD", "IDENTITY_MISMATCH", "RISK_BLOCKED", "REVOKED", "SUPERSEDED",
+];
+export const FORWARD_OBSERVATION_RESEARCH_STAGES = new Set(["P1", "P2", "P3", "P4"]);
+// M1 adaptive selections are a separate read-only projection. They are not
+// lifecycle evidence, an account instruction, or an execution permission.
+export const ADAPTIVE_SELECTION_SOURCE_PREFIX = "adaptive_selection_source:";
+export const ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION = "qsl.adaptive_selection_source_snapshot.v1";
+export const ADAPTIVE_SELECTION_DASHBOARD_SCHEMA_VERSION = "qsl.adaptive_selection_dashboard.v1";
+export const ADAPTIVE_SELECTION_DECISION_SCHEMA_VERSION = "qsl.selection_decision.v1";
+export const ADAPTIVE_SELECTION_MAX_SOURCES = 100;
+export const ADAPTIVE_SELECTION_MAX_BODY_BYTES = 256 * 1024;
+export const ADAPTIVE_SELECTION_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
+export const ADAPTIVE_SELECTION_AUTHORITY = "shadow_only";
+// M0 research arrives through a separate, signed-at-transport-boundary
+// snapshot. It is deliberately neither an M1 selection input nor a research
+// task: this Worker only retains a closed, no-order ledger for authenticated
+// readers. No strategy/platform/runtime/broker helper may consume it here.
+export const M0_RESEARCH_TRANSPORT_SCHEMA_VERSION = "qsl_m0_research_publisher_envelope.v1";
+export const M0_RESEARCH_LEDGER_SCHEMA_VERSION = "qsl_m0_research_ledger.v1";
+export const M0_RESEARCH_DASHBOARD_SCHEMA_VERSION = "qsl_m0_research_dashboard.v1";
+export const M0_RESEARCH_STORAGE_SCHEMA_VERSION = "qsl_m0_research_ledger_storage.v1";
+export const M0_RESEARCH_CURRENT_KEY = "m0_research_ledger_current";
+export const M0_RESEARCH_ARCHIVE_PREFIX = "m0_research_ledger_archive:";
+export const M0_RESEARCH_MAX_BODY_BYTES = 256 * 1024;
+export const M0_RESEARCH_RETENTION_SECONDS = 14 * 24 * 60 * 60;
+export const M0_RESEARCH_ALLOWED_SOURCE_REPOSITORY = "QuantStrategyLab/QuantAdvisorResearch";
+export const M0_RESEARCH_ALLOWED_PRODUCER_REPOSITORY = "QuantStrategyLab/QuantRuntimeSettings";
+export const M0_RESEARCH_SUBJECT_KINDS = ["asset_idea", "theme_context", "strategy_hypothesis", "risk_context"];
+export const M0_RESEARCH_HORIZONS = ["short", "medium", "long", "not_applicable"];
+export const M0_RESEARCH_STATES = ["candidate", "source_verification_required", "deferred", "context_only"];
+export const M0_RESEARCH_CONFIDENCE = ["high", "medium", "low", "mixed", "no_event", "unknown"];
+export const M0_RESEARCH_STYLES = ["event_driven", "long_horizon_growth", "value_quality", "macro_context", "mixed_research"];
+const M0_RESEARCH_SUMMARY_FIELDS = [
+ "subject_count",
+ "observation_count",
+ "fresh_observation_count",
+ "stale_observation_count",
+ "unknown_observation_count",
+ "horizon_conflict_count",
+ "historical_stale_horizon_drift_count",
+];
+// A console decision is intentionally an auditable owner intent, not an
+// execution permit. It remains separate from workflow dispatch credentials,
+// broker credentials, and any future deterministic execution gateway.
+export const OWNER_DECISION_INTENT_PREFIX = "owner_decision_intent:";
+export const OWNER_DECISION_CURRENT_PREFIX = "owner_decision_current:";
+export const OWNER_DECISION_INTENT_SCHEMA_VERSION = "qsl_owner_decision_intent.v1";
+export const OWNER_DECISION_QUEUE_SCHEMA_VERSION = "qsl_owner_decision_queue.v1";
+export const OWNER_DECISION_CHOICES = ["approve_limited_live_canary", "keep_parked", "retire_candidate"];
+export const OWNER_DECISION_MAX_CANDIDATES = 100;
+// Reconciliation recovery has a different authority boundary from P6
+// strategy promotion. It can only describe an already-authorised legacy
+// target that is currently RECONCILE_ONLY; it can never create a new strategy
+// release, order, broker credential, or runtime mutation from this Worker.
+export const RECONCILIATION_RECOVERY_SOURCE_PREFIX = "reconciliation_recovery_source:";
+export const RECONCILIATION_RECOVERY_CONFIRMATION_PREFIX = "reconciliation_recovery_confirmation:";
+export const RECONCILIATION_RECOVERY_CURRENT_PREFIX = "reconciliation_recovery_current:";
+export const RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION = "qsl_reconciliation_recovery_source_snapshot.v1";
+export const RECONCILIATION_RECOVERY_DASHBOARD_SCHEMA_VERSION = "qsl_reconciliation_recovery_dashboard.v1";
+export const RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION = "qsl_reconciliation_recovery_confirmation.v1";
+export const RECONCILIATION_RECOVERY_CONTROLLER_READ_SCHEMA_VERSION = "qsl_reconciliation_recovery_controller_read.v1";
+export const RECONCILIATION_RECOVERY_MAX_SOURCES = 100;
+export const RECONCILIATION_RECOVERY_MAX_BODY_BYTES = 128 * 1024;
+export const RECONCILIATION_RECOVERY_DEFAULT_STALE_TTL_SECONDS = 30 * 60;
+export const RECONCILIATION_RECOVERY_MAX_SAMPLE_WINDOW_MS = 15 * 60 * 1000;
+export const RECONCILIATION_RECOVERY_PLATFORMS = OBSERVABILITY_PLATFORM_IDS;
+export const RECONCILIATION_RECOVERY_ENVIRONMENTS = ["live"];
+export const RECONCILIATION_RECOVERY_STATES = ["RECONCILE_ONLY"];
+export const RECONCILIATION_RECOVERY_READINESS = ["blocked", "awaiting_human_confirmation"];
+export const RECONCILIATION_RECOVERY_DUAL_REVIEW_OUTCOMES = ["approved", "rejected", "unavailable"];
+export const RECONCILIATION_RECOVERY_MAX_REQUESTS = 100;
+// Private Binance holdings use one isolated KV record. They are never folded
+// into public health, recovery, control-plane, or admin aggregates.
+export const BINANCE_PRIVATE_SCOPE_KEY = "private_binance_scope_report";
+export const BINANCE_PRIVATE_SCOPE_MAX_BODY_BYTES = 256 * 1024;
+export const BINANCE_PRIVATE_SCOPE_MAX_ASSETS = 5000;
+export const BINANCE_PRIVATE_SCOPE_WRITE_TTL_SECONDS = 24 * 60 * 60;
+export const BINANCE_PRIVATE_SCOPE_INGEST_MAX_AGE_MS = 10 * 60 * 1000;
+export const BINANCE_PRIVATE_SCOPE_FUTURE_SKEW_MS = 60 * 1000;
+export const BINANCE_PRIVATE_SCOPE_READ_MAX_AGE_MS = 24 * 60 * 60 * 1000;
+// Execution evidence is deliberately a separate, read-only projection. A
+// candidate's research lifecycle is portable; a broker/data/execution result
+// is only meaningful for the exact target platform and lane that produced it.
+// Keeping this contract separate prevents a P1/P3 source from accidentally
+// turning into an execution or P6 authority source.
+export const EXECUTION_EVIDENCE_SOURCE_PREFIX = "execution_evidence_source:";
+export const RUNTIME_DAILY_KEY_PREFIX = "runtime_daily:";
+export const RUNTIME_DAILY_MAX_BODY_BYTES = 64 * 1024;
+export const RUNTIME_DAILY_MAX_RUNS = 20;
+export const RUNTIME_DAILY_MAX_LIST = 20;
+// History coverage lists the already-stored business dates for one target. It
+// never reads record bodies and stays bounded so a large backlog cannot stall
+// the read model; hitting the page cap only marks the listing as truncated.
+export const RUNTIME_DAILY_HISTORY_PAGE = 100;
+export const RUNTIME_DAILY_HISTORY_MAX_PAGES = 10;
+export const RUNTIME_DAILY_STALE_MS = 36 * 60 * 60 * 1000;
+export const RUNTIME_DAILY_FUTURE_SKEW_MS = 5 * 60 * 1000;
+const RUNTIME_DAILY_STATUSES = [
+ "no_submission", "no_signal", "no_rebalance", "submitted", "broker_acknowledged", "partially_filled", "filled",
+ "reconciliation_required", "unknown", "failed", "blocked", "dry_run", "shadow", "validation",
+ "not_due", "market_closed", "outside_window", "within_grace", "missing_report", "read_incomplete", "insufficient", "conflict",
+];
+export const RUNTIME_DAILY_SCHEDULE_ONLY = ["not_due", "market_closed", "outside_window", "within_grace"];
+const RUNTIME_DAILY_ANOMALY_STATUSES = [
+ "reconciliation_required", "unknown", "failed", "blocked", "conflict", "missing_report", "read_incomplete", "insufficient",
+ "dry_run", "shadow", "validation",
+];
+const RUNTIME_DAILY_ACTIVITIES = [
+ "no_submission", "no_signal", "no_rebalance", "submitted", "broker_acknowledged", "partially_filled", "filled",
+ "reconciliation_required", "unknown", "failed", "blocked", "previewed", "insufficient",
+];
+export const RUNTIME_DAILY_LANES = ["paper", "live", "dry_run", "shadow", "validation", "insufficient"];
+export const RUNTIME_DAILY_SCHEDULE_STATES = ["unevaluable", "not_due", "market_closed", "within_grace", "due", "outside_window"];
+export const RUNTIME_DAILY_KINDS = ["run", "schedule", "incomplete"];
+export const EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION = "qsl_execution_evidence_source_snapshot.v1";
+export const EXECUTION_EVIDENCE_DASHBOARD_SCHEMA_VERSION = "qsl_execution_evidence_dashboard.v1";
+export const EXECUTION_EVIDENCE_MAX_SOURCES = 100;
+export const EXECUTION_EVIDENCE_MAX_BODY_BYTES = 256 * 1024;
+export const EXECUTION_EVIDENCE_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
+export const EXECUTION_EVIDENCE_PLATFORMS = OBSERVABILITY_PLATFORM_IDS;
+export const EXECUTION_EVIDENCE_ENVIRONMENTS = ["shadow", "paper", "live"];
+export const EXECUTION_EVIDENCE_CAPABILITIES = ["available", "unavailable", "unknown"];
+export const EXECUTION_EVIDENCE_STATUSES = ["verified", "pending", "unavailable", "not_applicable"];
+const EXECUTION_RECEIPT_OUTCOMES = [
+ "not_due", "no_action", "no_signal", "no_rebalance", "risk_blocked", "submitted", "broker_acknowledged", "partially_filled", "filled", "reconciliation_required", "failed",
+];
+const EXECUTION_RECEIPT_CONFIRMATIONS = [
+ "not_applicable", "not_observed", "acknowledged", "partially_filled", "filled", "reconciliation_required",
+];
+const EXECUTION_EVIDENCE_RECOMMENDATIONS = [
+ "continue_autonomous_shadow", "run_autonomous_paper", "owner_limited_live_canary_decision", "parked",
+];
+const EXECUTION_EVIDENCE_REASON_CODES = [
+ "none", "target_execution_evidence_missing", "paper_not_supported", "paper_execution_evidence_needed",
+ "policy_not_active", "source_stale", "manual_live_decision_required", "target_execution_receipt_observed",
+ "target_execution_reconciliation_required", "target_execution_receipt_failed",
+];
+// Runtime target lifecycle is intentionally separate from execution evidence:
+// it records whether a target is enabled and whether its no-order monitors are
+// healthy. A disabled target is not a missing broker or a paper/live result.
+export const RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX = "runtime_target_lifecycle_source:";
+export const RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION = "qsl_runtime_target_lifecycle_source_snapshot.v1";
+export const RUNTIME_TARGET_LIFECYCLE_DASHBOARD_SCHEMA_VERSION = "qsl_runtime_target_lifecycle_dashboard.v1";
+export const RUNTIME_TARGET_LIFECYCLE_MAX_SOURCES = 100;
+export const RUNTIME_TARGET_LIFECYCLE_MAX_BODY_BYTES = 256 * 1024;
+export const RUNTIME_TARGET_LIFECYCLE_CONFIGURED_STATES = ["enabled", "disabled"];
+export const RUNTIME_TARGET_LIFECYCLE_EXECUTION_MODES = ["dry_run", "paper", "live"];
+export const RUNTIME_TARGET_LIFECYCLE_CHECK_STATUSES = ["pass", "attention", "not_due", "not_applicable", "unavailable"];
+export const RUNTIME_TARGET_LIFECYCLE_DISPOSITIONS = ["continue_enabled_monitoring", "continue_disabled_validation", "parked"];
+export const RUNTIME_TARGET_LIFECYCLE_EXECUTION_OBSERVATIONS = ["not_due", "monitoring_only", "not_applicable", "attention", "unavailable"];
+const RUNTIME_TARGET_LIFECYCLE_REASON_CODES = [
+ "none", "target_intentionally_disabled", "runtime_guard_attention", "execution_heartbeat_attention", "monitoring_unavailable",
+];
+export const HUMAN_DECISION_DO_ACTIONS = new Set([
+ "owner_sync_materials", "recovery_sync_materials", "promotion_sync_materials",
+ "owner_decide", "recovery_decide", "promotion_decide",
+ "owner_read", "recovery_read", "promotion_read",
+]);
+export const ACCOUNT_SETTINGS_DO_ACTIONS = new Set([
+ "risk_profile_read", "risk_profile_replace", "risk_profile_set",
+ "account_settings_read", "account_settings_save", "account_declarations_read",
+ "account_settings_profile_application_lookup", "account_settings_profile_application_approve",
+ "account_settings_profile_application_claim",
+]);
+export const ACCOUNT_FACTS_DO_ACTIONS = new Set([
+ "account_external_flow_put",
+ "account_executions_put", "account_executions_read",
+ "account_period_return_put", "account_period_return_read", "account_daily_native_return_research_read",
+ "account_facts_put", "account_facts_read", "account_facts_list", "account_facts_history_read", "account_facts_history_put",
+ "binance_wallet_history_put", "binance_wallet_history_read",
+ "binance_detail_put", "binance_detail_read",
+]);
+export const MARKET_BENCHMARK_DO_ACTIONS = new Set([
+ "market_benchmark_put", "market_benchmark_read", "market_benchmark_revise",
+]);
+export const HK_STOP_DO_ACTIONS = new Set(["hk_stop_claim", "hk_stop_record", "hk_stop_read", "hk_stop_accept_result"]);
+export const RUNTIME_CONTROL_DO_ACTIONS = new Set(["runtime_control_claim", "runtime_control_record", "runtime_control_read", "runtime_control_resolve", "runtime_control_capture", "runtime_control_begin_check", "runtime_control_record_check"]);
+export const HK_STOP_TARGET_ID = "longbridge/hk";
+export const HK_STOP_REQUEST_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
+export const ACCOUNT_SETTING_OVERRIDE_FIELDS = ["strategy_profile", "income_layer_enabled", "option_overlay_enabled", "reserved_cash_floor", "reserved_cash_ratio", "dca_mode", "dca_base_investment_usd"];
+export const ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
+// Research tasks are a separate, immutable and no-order index. They do not
+// share storage or a sync credential with candidate lifecycle snapshots.
+export const RESEARCH_TASK_SOURCE_PREFIX = "research_task_source:";
+export const RESEARCH_TASK_SOURCE_SCHEMA_VERSION = "qsl_research_task_source_snapshot.v1";
+export const RESEARCH_TASK_SCHEMA_VERSION = "qsl.research_task.v1";
+export const RESEARCH_TASK_DASHBOARD_SCHEMA_VERSION = "qsl_research_task_dashboard.v1";
+export const RESEARCH_TASK_MAX_SOURCES = 100;
+export const RESEARCH_TASK_MAX_BODY_BYTES = 256 * 1024;
+export const RESEARCH_TASK_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
+const RESEARCH_TASK_TYPES = [
+ "strategy_diagnosis", "hypothesis_evaluation", "parameter_challenge", "strategy_candidate", "portfolio_candidate", "plugin_candidate",
+];
+export const RESEARCH_TASK_OBJECTIVES = ["diagnose_degradation", "test_hypothesis", "challenge_parameters", "evaluate_candidate"];
+
+// Research promotion tickets mirror QPK research_promotion_cycle.to_dict().
+// Console may record human intent only; live_authority_granted stays false.
+export const RESEARCH_PROMOTION_TICKET_PREFIX = "research_promotion_ticket:";
+export const RESEARCH_PROMOTION_TICKET_SCHEMA = "qsl.research_promotion_ticket.v1";
+export const RESEARCH_PROMOTION_QUEUE_SCHEMA = "qsl.research_promotion_ticket_queue.v1";
+export const RESEARCH_PROMOTION_MAX_TICKETS = 100;
+export const RESEARCH_PROMOTION_MAX_BODY_BYTES = 64 * 1024;
+const RESEARCH_PROMOTION_STATES = [
+ "parked",
+ "bounded_reopt",
+ "shadow_recorded",
+ "awaiting_human",
+ "human_accepted",
+ "human_rejected",
+];
+const RESEARCH_PROMOTION_RISK_PROFILES = [
+ "CAPITAL_PRESERVATION",
+ "BALANCED_COMPOUNDING",
+ "GROWTH_COMPOUNDING",
+];
+export const RESEARCH_PROMOTION_EXECUTION_MODES = ["live", "paper"];
+export const DEFAULT_RESEARCH_PROMOTION_RISK_PROFILE = "CAPITAL_PRESERVATION";
+export const V7_PAPER_PREVIEW_PROFILE = "soxl_soxx_core_only_p2_v7_longterm_compounding_cash_reserve";
+export const V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY = "QuantStrategyLab/LongBridgePlatform";
+export const V7_PAPER_APPLICATION_WORKFLOW = "apply-paper-candidate.yml";
+export const V7_PAPER_APPLICATION_UES_REVISION = "b83ef4b3ae67c47d132ddd660ba3ccc60d474c85";
+// Reviewed LongBridge application merge SHA for the paused validation slice.
+// This remains a server constant and is never caller input or an enablement.
+export const V7_PAPER_APPLICATION_SOURCE_COMMIT = "dcdcb579001e0be5579810121fc7894206e06445";
+export const V7_PAPER_APPLICATION_TICKET_RE = /^rpt_[0-9a-f]{64}$/;
+export const V7_PAPER_APPLICATION_ACCOUNT_KEY = "paper";
+export const V7_PAPER_APPLICATION_ACCOUNT_SCOPE = "PAPER";
+export const V7_PAPER_APPLICATION_SERVICE = "longbridge-quant-paper-service";
+export const V7_PAPER_APPLICATION_MAX_BODY_BYTES = 16 * 1024;
+export const V7_PAPER_APPLICATION_STATUSES = ["approved", "claimed", "applied_paused", "rejected", "uncertain"];
+export const V7_PAPER_APPLICATION_DISPATCH_STATES = ["pending", "sent", "unknown"];
+export const V7_PAPER_APPLICATION_REASON_CODES = ["", "readback_mismatch", "workflow_rejected", "workflow_uncertain", "dispatch_unverified", "account_changed", "qualification_failed"];
+export const V7_PAPER_APPLICATION_DO_ACTIONS = new Set([
+ "application_create", "application_latest", "application_read", "application_mark_dispatch", "application_claim", "application_result",
+]);
+// The workflow has an explicit fail-closed guard until immutable activation
+// and durable single-use consumption are connected. Keep the console from
+// dispatching a workflow that cannot apply the requested target.
+export const SWITCH_ACTIVATION_CONNECTED = false;
+
+
+
+
+
+export const SUPPORTED_PLATFORMS = Object.keys(PLATFORM_CONFIG);
+
+export function validateAccountOptionsSchemaOrThrow(payload, fieldName = "account_options") {
+ return normalizeAccountOptionsSchemaPayload(payload, fieldName);
+}
+
+
+const LIVE_CONTINUITY_STATES = [
+ "NONE",
+ "ACTIVE_LKG",
+ "ACTIVE_REDUCED",
+ "RECONCILE_ONLY",
+ "RISK_REDUCTION_ONLY",
+ "PAUSED",
+ "ROLLBACK_LKG",
+];
+export const LEGACY_CASH_ONLY_EXECUTION_VARIABLE = "CASH_ONLY_EXECUTION";
+export const CASH_ONLY_EXECUTION_MODES = ["current", "enabled", "disabled"];
+export const INCOME_LAYER_ENABLED_VARIABLE = "INCOME_LAYER_ENABLED";
+export const INCOME_LAYER_START_USD_VARIABLE = "INCOME_LAYER_START_USD";
+export const INCOME_LAYER_MAX_RATIO_VARIABLE = "INCOME_LAYER_MAX_RATIO";
+export const OPTION_OVERLAY_ENABLED_VARIABLE = "OPTION_OVERLAY_ENABLED";
+export const RUNTIME_TARGET_ENABLED_VARIABLE = "RUNTIME_TARGET_ENABLED";
+export const DCA_MODE_VARIABLE = "DCA_MODE";
+export const DCA_BASE_INVESTMENT_VARIABLE = "DCA_BASE_INVESTMENT_USD";
+export const IBIT_ZSCORE_EXIT_MODE_VARIABLE = "IBIT_ZSCORE_EXIT_MODE";
+export const IBIT_ZSCORE_EXIT_ENABLED_VARIABLE = "IBIT_ZSCORE_EXIT_ENABLED";
+export const IBIT_ZSCORE_EXIT_PARKING_SYMBOL_VARIABLE = "IBIT_ZSCORE_EXIT_PARKING_SYMBOL";
+const LEGACY_INCOME_LAYER_CONTROL_FIELDS = [
+ "income_threshold_usd",
+ "qqqi_income_ratio",
+ "income_layer_qqqi_weight",
+ "income_layer_spyi_weight",
+];
+const LEGACY_INCOME_LAYER_VARIABLES = [
+ "INCOME_THRESHOLD_USD",
+ "QQQI_INCOME_RATIO",
+ "INCOME_LAYER_QQQI_WEIGHT",
+ "INCOME_LAYER_SPYI_WEIGHT",
+];
+const OPTION_OVERLAY_CONTROL_FIELDS = [
+ "option_overlay_enabled",
+ "option_growth_overlay_enabled",
+ "option_growth_overlay_recipe",
+ "option_growth_overlay_start_usd",
+ "option_growth_overlay_nav_budget_ratio",
+ "option_income_overlay_enabled",
+ "option_income_overlay_recipe",
+ "option_income_overlay_start_usd",
+ "option_income_overlay_nav_risk_ratio",
+];
+export const OPTION_OVERLAY_VARIABLES = OPTION_OVERLAY_CONTROL_FIELDS.map((field) => field.toUpperCase());
+const OPTION_OVERLAY_PROFILE_FIELDS = [
+ ...OPTION_OVERLAY_CONTROL_FIELDS,
+ "option_overlay_live_gate",
+ "option_overlay_live_status",
+];
+export const OPTION_OVERLAY_MODES = ["current", "enabled", "disabled"];
+const DCA_PROFILE_CONFIG = Object.fromEntries(
+ Object.entries(DCA_PROFILE_DEFAULTS).map(([profile, defaults]) => [
+ profile,
+ {
+ default_mode: defaults.defaultMode || "fixed",
+ default_base_investment_usd: defaults.defaultBaseInvestmentUsd || "1000",
+ },
+ ]),
+);
+const SECURITY_HEADERS = {
+ "Content-Security-Policy": [
+ "default-src 'self'",
+ "base-uri 'none'",
+ "object-src 'none'",
+ "frame-ancestors 'none'",
+ "frame-src https://fred.stlouisfed.org/graph/graph-landing.php",
+ "form-action 'self'",
+ "img-src 'self' data:",
+ "connect-src 'self'",
+ "script-src 'self'",
+ "style-src 'self'",
+ ].join("; "),
+ "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=()",
+ "Referrer-Policy": "no-referrer",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "DENY",
+};
+
+// This is deliberately a same-origin, public configuration bootstrap. It
+// contains only the config projections already shown by the public console;
+// private account routing still arrives after an authenticated /api/config
+// request. Keeping it external preserves the strict CSP without unsafe-inline.
+export const BOOTSTRAP_CONFIG_JS = [
+ "// Generated from non-secret console configuration. Do not edit by hand.",
+ `window.__PLATFORM_META__ = ${JSON.stringify(PLATFORM_META)};`,
+ `window.__PLATFORM_REPOSITORIES__ = ${JSON.stringify(PLATFORM_REPOSITORIES)};`,
+ `window.__PLATFORM_CONFIG__ = ${JSON.stringify(PLATFORM_CONFIG)};`,
+ `window.__DEFAULT_ACCOUNT_OPTIONS__ = ${JSON.stringify(DEFAULT_ACCOUNT_OPTIONS)};`,
+ `window.__DOMAIN_LABELS__ = ${JSON.stringify(DOMAIN_LABELS)};`,
+ `window.__DEFAULT_STRATEGY_PROFILES__ = ${JSON.stringify(DEFAULT_STRATEGY_PROFILES)};`,
+ `window.__DCA_PROFILE_DEFAULTS__ = ${JSON.stringify(DCA_PROFILE_DEFAULTS)};`,
+ `window.__INCOME_LAYER_DEFAULTS__ = ${JSON.stringify(FALLBACK_INCOME_LAYER_DEFAULTS)};`,
+ `window.__OPTION_OVERLAY_DEFAULTS__ = ${JSON.stringify(FALLBACK_OPTION_OVERLAY_DEFAULTS)};`,
+ `window.__PLATFORM_MIN_RESERVED_CASH_VARIABLES__ = ${JSON.stringify(PLATFORM_MIN_RESERVED_CASH_VARIABLES)};`,
+ `window.__PLATFORM_RESERVED_CASH_RATIO_VARIABLES__ = ${JSON.stringify(PLATFORM_RESERVED_CASH_RATIO_VARIABLES)};`,
+].join("\n");
+
+// A secondary external script keeps a failed or stale main bundle from
+// trapping a visitor behind the loading screen forever. It does not fetch,
+// mutate configuration, or grant access: it only reveals the static login
+// surface after the main boot flow has had time to finish its own timeout.
+export const BOOT_RECOVERY_JS = [
+ "(() => {",
+ " const delayMs = 20_000;",
+ " window.setTimeout(() => {",
+ " if (!document.body?.classList.contains('app-loading')) return;",
+ " document.body.classList.remove('app-loading');",
+ " const login = document.getElementById('login-link');",
+ " if (login) login.hidden = false;",
+ " }, delayMs);",
+ "})();",
+].join("\n");
+
+
+
+export async function credentialMaintenanceResponse(request, env, url) {
+ const machine = url.pathname.startsWith("/api/internal/");
+ const suffix = url.pathname.split("/").at(-1);
+ let action = "credential_maintenance_read";
+ if (machine) {
+ const expected = typeof env.STRATEGY_SWITCH_SYNC_TOKEN === "string" ? env.STRATEGY_SWITCH_SYNC_TOKEN : "";
+ // No dispatch fallback, and no alias for broker, control or session authority.
+ const aliases = Object.entries(env).filter(([name, value]) => name !== "STRATEGY_SWITCH_SYNC_TOKEN" &&
+ (name.endsWith("_TOKEN") || name === "SESSION_SECRET") && typeof value === "string" && value && value === expected);
+ if (!expected || aliases.length) throw new HttpError("credential_maintenance_auth_unavailable", 503);
+ const supplied = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (supplied !== expected) throw new HttpError("credential_maintenance_auth_invalid", 401);
+ if (suffix === "claim" || suffix === "ack") {
+ if (request.method !== "POST") throw new HttpError("method_not_allowed", 405);
+ action = `credential_maintenance_${suffix}`;
+ } else if (request.method !== "GET") throw new HttpError("method_not_allowed", 405);
+ } else {
+ const session = await requireUx1Session(request, env);
+ if (request.method === "POST") {
+ if (!session.admin) throw new HttpError("admin required", 403);
+ requireSameOrigin(request, { requireOrigin: true });
+ action = "credential_maintenance_save";
+ } else if (request.method !== "GET") throw new HttpError("method_not_allowed", 405);
+ }
+ let body;
+ if (request.method === "POST") {
+ const text = await request.text();
+ if (text.length > 1024) throw new HttpError("invalid_credential_maintenance_request", 400);
+ try { body = JSON.parse(text); } catch { throw new HttpError("invalid_credential_maintenance_request", 400); }
+ }
+ const result = await runtimeInstanceCommand(env, { action, body });
+ return json(!machine && request.method === "GET" ? { ...result, ...decisionFields(result, "credential_maintenance") } : result);
+}
+
+
+
+
+export async function runtimeInstancesResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ if (request.method === "GET") return json(await runtimeInstanceCommand(env));
+ if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
+ requireSameOrigin(request, { requireOrigin: true });
+ let raw;
+ try {
+ const text = await request.text();
+ if (text.length > 16384) throw new Error();
+ raw = JSON.parse(text);
+ } catch {
+ throw new HttpError("invalid_runtime_instance_request", 400);
+ }
+ runtimeInstanceFields(raw, ["action", "expected_revision", "platform", "key", "config", "broker_environment", "confirm"]);
+ const command = { action: raw.action, expected_revision: raw.expected_revision, actor: session.login };
+ if (raw.action === "initialize") {
+ if (raw.confirm !== "IMPORT_EXISTING_CONFIG") throw new HttpError("runtime_instance_import_confirmation_required", 400);
+ // Explicit, one-time import only. A deployment must freeze legacy writers
+ // and review this input before enabling the binding and importing it.
+ command.account_options = (await loadLegacyAccountOptionsConfig(env)).options || {};
+ } else if (raw.action === "create" || raw.action === "edit") {
+ try {
+ if (!SUPPORTED_PLATFORMS.includes(raw.platform) || PLATFORM_CONFIG[raw.platform].dry_run_only) throw new Error();
+ runtimeInstanceFields(raw.config, ["key", "label", "target_name", "account_selector", "deployment_selector", "account_scope", "service_name", "github_environment", "variable_scope", "cash_currency", "supported_domains", "broker_environment", "default_strategy_profile", "default_execution_mode"]);
+ const option = cleanAccountOption(raw.config, raw.platform, 0);
+ if (!option.account_selector || !option.deployment_selector || !option.service_name) throw new Error();
+ option.default_execution_mode = raw.config.default_execution_mode || "dry_run";
+ option.default_strategy_profile = cleanSlug(raw.config.default_strategy_profile, "default_strategy_profile");
+ assertStrategyAllowedForAccount({ platform: raw.platform, strategy_profile: option.default_strategy_profile, execution_mode: option.default_execution_mode }, option, await loadStrategyProfilesConfig(env));
+ command.platform = raw.platform;
+ command.config = option;
+ if (raw.action === "edit") command.key = cleanSlug(raw.key, "key");
+ } catch {
+ throw new HttpError("invalid_runtime_instance_config", 400);
+ }
+ } else if (raw.action === "set_broker_environment") {
+ try {
+ if (!SUPPORTED_PLATFORMS.includes(raw.platform) || PLATFORM_CONFIG[raw.platform].dry_run_only) throw new Error();
+ command.platform = cleanChoice(raw.platform, SUPPORTED_PLATFORMS, "platform");
+ command.key = cleanSlug(raw.key, "key");
+ command.broker_environment = normalizeBrokerEnvironment(raw.broker_environment);
+ if (!supportedBrokerEnvironmentsForPlatform(command.platform).includes(command.broker_environment)) throw new Error();
+ } catch {
+ throw new HttpError("invalid_broker_environment", 400);
+ }
+ } else if (raw.action === "request_retirement") {
+ command.platform = raw.platform;
+ command.key = raw.key;
+ } else {
+ throw new HttpError("unsupported_runtime_instance_action", 400);
+ }
+ return json(await runtimeInstanceCommand(env, command));
+}
+
+export async function sessionPayload(request, env) {
+ const session = await readSession(request, env);
+ return {
+ authenticated: Boolean(session),
+ login: session?.login || null,
+ allowed: Boolean(session?.allowed),
+ admin: Boolean(session?.admin),
+ server_time: new Date().toISOString(),
+ };
+}
+
+export async function adminConfigResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ return json(await buildAdminState(session, env));
+}
+
+import { dateOnlyExternalFlow, externalFlowEnabled, initializeExternalFlow, normalizeExternalFlow, putExternalFlow, readExternalFlow, readExternalFlowCoverage } from "../account_facts/external_flow.js";
+import { initializeExecutions, normalizeExecutions, putExecutions, readExecutions } from "../account_facts/executions.js";
+
+
+
+export async function saveAdminConfig(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "STRATEGY_SWITCH_CONFIG KV binding is required to save admin config" }, 400);
+ }
+
+ let raw;
+ try {
+ raw = await request.json();
+ } catch (error) {
+ return json({ ok: false, error: "request body must be valid JSON" }, 400);
+ }
+ const bootstrapAdmins = parseLoginList(env.STRATEGY_SWITCH_ADMIN_LOGINS || "", "STRATEGY_SWITCH_ADMIN_LOGINS");
+ const bootstrapAdminOrgs = parseOrgList(env.STRATEGY_SWITCH_ADMIN_ORGS || "", "STRATEGY_SWITCH_ADMIN_ORGS");
+ const allowedLogins = normalizeLoginList(raw.allowed_logins, "allowed_logins");
+ const allowedOrgs = normalizeOrgList(raw.allowed_orgs, "allowed_orgs");
+ const submittedAdmins = normalizeLoginList(raw.admin_logins, "admin_logins");
+ const submittedAdminOrgs = normalizeOrgList(raw.admin_orgs, "admin_orgs");
+ const effectiveAdmins = uniqueStrings([...bootstrapAdmins, ...submittedAdmins]);
+ const effectiveAdminOrgs = uniqueStrings([...bootstrapAdminOrgs, ...submittedAdminOrgs]);
+ if (!effectiveAdmins.includes(session.login) && !hasOrgMatch(session.orgs, effectiveAdminOrgs)) {
+ throw new Error("current admin login or org must remain in admin config");
+ }
+ const authConfig = {
+ allowed_logins: uniqueStrings([...allowedLogins, ...effectiveAdmins]),
+ allowed_orgs: allowedOrgs,
+ admin_logins: effectiveAdmins,
+ admin_orgs: effectiveAdminOrgs,
+ };
+ const accountOptions = normalizeAccountOptionsInput(raw.account_options, "account_options");
+
+ if (hasRuntimeInstanceStore(env)) {
+ const instances = await runtimeInstanceCommand(env);
+ if (!instances.initialized || canonicalResearchTaskJson(accountOptions) !== canonicalResearchTaskJson(normalizeAccountOptionsPayload(instances.account_options))) {
+ throw new HttpError("runtime_instances_managed_separately", 409);
+ }
+ }
+ await writeConfigJson(env, AUTH_CONFIG_KEY, authConfig);
+ if (!hasRuntimeInstanceStore(env)) await writeConfigJson(env, ACCOUNT_OPTIONS_KEY, validateAccountOptionsSchemaOrThrow(accountOptions));
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: session.login,
+ action: "save_config",
+ allowed_count: authConfig.allowed_logins.length,
+ allowed_org_count: authConfig.allowed_orgs.length,
+ admin_count: authConfig.admin_logins.length,
+ admin_org_count: authConfig.admin_orgs.length,
+ account_counts: accountCounts(accountOptions),
+ });
+ return json(await buildAdminState(session, env));
+}
+
+export async function riskProfileBindingsResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ const bindingState = await loadRiskProfileBindings(env);
+ if (bindingState.error) {
+ return json({
+ ok: false,
+ error: "risk profile bindings are unavailable",
+ reason: bindingState.error,
+ no_order: true,
+ execution_authority_granted: false,
+ }, bindingState.status || 409);
+ }
+ return json({
+ ok: true,
+ revision: bindingState.revision,
+ bindings: bindingState.bindings,
+ tier_bindings: bindingState.bindings.map((binding) => riskTierBindingView({
+ scope_id: binding.scope_id,
+ platform: binding.platform,
+ target_name: binding.target_name,
+ binding,
+ revision: bindingState.revision,
+ })),
+ configured_targets: riskProfileBindingTargets(bindingState.account_options || {}),
+ no_order: true,
+ execution_authority_granted: false,
+ });
+}
+
+export async function saveRiskProfileBindings(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ let raw;
+ try {
+ raw = await request.json();
+ } catch {
+ return json({ ok: false, error: "request body must be valid JSON" }, 400);
+ }
+ if (!hasRuntimeInstanceStore(env)) {
+ try {
+ await buildRiskProfileBindings({ bindings: raw?.bindings }, (await loadLegacyAccountOptionsConfig(env)).options || {}, session.login);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "risk profile bindings are invalid" }, 400);
+ }
+ return json({ ok: false, error: "runtime_instances_not_bound", no_order: true, execution_authority_granted: false }, 503);
+ }
+ const legacy = await readRiskProfileLegacy(env);
+ let observed;
+ try {
+ observed = await runtimeInstanceCommand(env, { action: "risk_profile_read", actor: session.login, legacy });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+ if (!Number.isSafeInteger(raw?.expected_revision)) return json({ ok: false, error: "risk_profile_revision_required" }, 400);
+ if (raw.expected_revision !== observed.revision) return json({ ok: false, error: "risk_profile_revision_conflict" }, 409);
+ let bindings;
+ try {
+ bindings = await buildRiskProfileBindings({ bindings: raw.bindings }, observed.account_options, session.login);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "risk profile bindings are invalid" }, 400);
+ }
+ let saved;
+ try {
+ saved = await runtimeInstanceCommand(env, {
+ action: "risk_profile_replace",
+ actor: session.login,
+ expected_revision: observed.revision,
+ bindings,
+ legacy,
+ });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+ if (hasConfigStore(env)) {
+ await mirrorConfigJson(env, RISK_PROFILE_BINDINGS_KEY, {
+ schema_version: RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION,
+ bindings: saved.bindings,
+ });
+ }
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: session.login,
+ action: "save_risk_profile_bindings",
+ binding_count: saved.bindings.length,
+ });
+ } catch { /* audit failure does not undo the durable object decision */ }
+ return json({
+ ok: true,
+ revision: saved.revision,
+ bindings: saved.bindings,
+ configured_targets: riskProfileBindingTargets(saved.account_options || {}),
+ no_order: true,
+ execution_authority_granted: false,
+ });
+}
+
+export async function consoleRunControls(_request, env, account, session) {
+ return runControls(account, session, {
+ dispatchAvailable: Boolean(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
+ platformControl: ["ibkr", "schwab"].includes(account.platform)
+ ? () => readPlatformRuntimeControl(env, account.platform, account.target_name) : null,
+ stopReady: async () => {
+ if (account.platform === "longbridge" && account.target_name === "hk") {
+ if (account.key !== "hk") return false;
+ await loadHkStopAccount(env);
+ const { record } = await runtimeInstanceCommand(env, { action: "hk_stop_read" });
+ return !record || !["reserved", "accepted", "unknown", "stopped"].includes(record.phase);
+ }
+ const config = await loadAccountOptionsConfig(env);
+ if (!account.target_name || (config.options?.[account.platform] || []).filter(a => a.target_name === account.target_name).length !== 1) return false;
+ const inputs = { ...account, platform: account.platform };
+ const values = Object.fromEntries(["deployment_selector", "account_scope", "account_selector", "service_name"]
+ .map(field => [field, inputs[field] || defaultInputValue(field, inputs)]));
+ return Object.values(values).every(Boolean) && String(values.account_selector).split(",").some(value => value.trim());
+ },
+ resumeTarget: async () => {
+ const repository = platformRepositories(env).binance;
+ const config = await loadAccountOptionsConfig(env);
+ if (repository !== "QuantStrategyLab/BinancePlatform" || !account.target_name ||
+ (config.options?.binance || []).filter(a => a.target_name === account.target_name).length !== 1 ||
+ resolvedVariableScope(account.variable_scope, { ...account, platform: "binance" }) !== "repository") return null;
+ const variables = await fetchGithubVariables(env.RUNTIME_SETTINGS_DISPATCH_TOKEN, repository, "repository", "");
+ return binanceResumeTarget(Object.fromEntries(variables), account);
+ },
+ profileState: async () => {
+ if (!hasRuntimeInstanceStore(env)) return { reason: "runtime_instances_not_bound" };
+ const observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor: session.login, platform: account.platform, key: account.key });
+ const draft = observed.draft;
+ if (draft?.status === "identity_conflict") return { reason: "account_settings_identity_conflict" };
+ const next = draft?.overrides?.strategy_profile;
+ if (draft?.status !== "current" || typeof next !== "string" || Object.keys(draft.overrides).length !== 1 ||
+ !accountSettingsIdentityIsComplete(observed.identity) ||
+ canonicalResearchTaskJson(draft.identity) !== canonicalResearchTaskJson(observed.identity)) return { reason: "profile_draft_required" };
+ if (isDcaProfile(next)) return { reason: "profile_only_required" };
+ const profiles = await loadAccountDraftProfiles(env);
+ if (!accountDraftStrategyChoices(account.platform, observed.config, profiles).some(p => p.profile === next && !p.dca_supported)) return { reason: "profile_not_selectable" };
+ const readback = await accountSettingsProfileRuntimeReadback(env, observed);
+ if (!readback) return { reason: "runtime_readback_unavailable" };
+ if (readback.runtime_target_enabled !== "false") return { reason: "runtime_target_not_disabled" };
+ if (!readback.strategy_profile || readback.strategy_profile === next || isDcaProfile(readback.strategy_profile)) return { reason: "current_profile_conflict" };
+ const history = await runtimeInstanceCommand(env, { action: "console_settings_history", actor: session.login, platform: account.platform, key: account.key });
+ if (history.approvals.some(row => row.status === "claimed" || (row.status === "approved" &&
+ row.identity_json === canonicalResearchTaskJson(observed.identity) && Number(row.instance_revision) === observed.instance_revision &&
+ Number(row.draft_revision) === draft.revision && row.old_profile === readback.strategy_profile && row.new_profile === next)))
+ return { reason: "profile_application_pending" };
+ return { ready: true };
+ },
+ });
+}
+
+export function accountSettingsOperations(admin, optionSupported) {
+ const allowed = Boolean(admin);
+ return {
+ save_draft: allowed,
+ save_draft_reason: allowed ? "available" : "admin_required",
+ save_risk_preference: allowed,
+ save_risk_preference_reason: allowed ? "available" : "admin_required",
+ save_declaration: allowed,
+ save_declaration_reason: allowed ? "available" : "admin_required",
+ save_option_draft: allowed && optionSupported === true,
+ save_option_draft_reason: !allowed ? "admin_required" : optionSupported === true ? "available" : "option_overlay_not_defined",
+ apply_strategy: false,
+ activation: false,
+ reason: "strategy_application_not_connected",
+ apply_strategy_reason: "strategy_application_not_connected",
+ activation_reason: "strategy_application_not_connected",
+ };
+}
+
+export function accountSettingsPayload(observed, effective, admin, extras = {}) {
+ const optionSupported = extras.pendingStrategy ? extras.pendingOptionSupported === true : extras.currentOptionSupported === true;
+ return {
+ ok: true,
+ platform: observed.platform,
+ key: observed.key,
+ instance_revision: observed.instance_revision,
+ identity: observed.identity,
+ effective,
+ effective_read: extras.effectiveRead,
+ draft: observed.draft,
+ declaration: observed.declaration,
+ strategy_options: Array.isArray(extras.strategyOptions) ? extras.strategyOptions : [],
+ current_option_supported: extras.currentOptionSupported === true,
+ risk: {
+ revision: observed.risk.revision,
+ scope_id: observed.risk.scope_id,
+ preference: observed.risk.preference,
+ },
+ tier_binding: riskTierBindingView({
+ scope_id: observed.risk.scope_id,
+ platform: observed.platform,
+ target_name: observed.identity?.target_name || null,
+ binding: observed.risk.binding || null,
+ revision: observed.risk.revision,
+ }),
+ operations: accountSettingsOperations(admin, optionSupported),
+ adopted: false,
+ no_order: true,
+ execution_authority_granted: false,
+ current_dca_supported: extras.currentDcaSupported === true,
+ };
+}
+
+export async function accountSettingsResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ const url = new URL(request.url);
+ const platform = url.searchParams.get("platform") || "";
+ const key = url.searchParams.get("key") || "";
+ if (!SUPPORTED_PLATFORMS.includes(platform) || !key) return json({ ok: false, error: "account_settings_account_required" }, 400);
+ if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "runtime_instances_not_bound", no_order: true, execution_authority_granted: false }, 503);
+ const legacy = await readRiskProfileLegacy(env);
+ let observed;
+ try {
+ observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor: session.login, platform, key, legacy });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+ return json(await presentAccountSettings(env, observed, session.admin));
+}
+
+export async function presentAccountSettings(env, observed, admin) {
+ const { effective, effectiveRead } = await effectiveAccountSettings(env, observed);
+ const profiles = await loadAccountDraftProfiles(env);
+ const strategyOptions = profiles ? accountDraftStrategyChoices(observed.platform, observed.config, profiles) : [];
+ const conflict = observed.draft?.status === "identity_conflict";
+ const pending = !conflict && typeof observed.draft?.overrides?.strategy_profile === "string" ? observed.draft.overrides.strategy_profile : "";
+ const trusted = effective.strategy_profile?.status === "known" && typeof effective.strategy_profile.value === "string" ? effective.strategy_profile.value : "";
+ return accountSettingsPayload(observed, effective, admin, {
+ effectiveRead,
+ strategyOptions,
+ pendingStrategy: Boolean(pending),
+ pendingOptionSupported: Boolean(pending) && optionOverlayDraftAllowed(observed.platform, profiles, pending),
+ currentOptionSupported: Boolean(trusted) && optionOverlayDraftAllowed(observed.platform, profiles, trusted),
+ currentDcaSupported: dcaDraftSupported(observed.platform, profiles, trusted),
+ });
+}
+
+export async function loadAccountDraftProfiles(env) {
+ try {
+ return await loadStrategyProfilesConfig(env);
+ } catch {
+ return null;
+ }
+}
+
+export function profileDefinesOptionOverlay(profiles, profileId) {
+ if (!Array.isArray(profiles) || typeof profileId !== "string" || !profileId) return false;
+ const found = profiles.find((item) => sameStrategyProfile(item?.profile, profileId));
+ return found?.option_overlay_enabled === true;
+}
+
+export function optionOverlayDraftAllowed(platform, profiles, profileId) {
+ return PLATFORM_CONFIG[platform]?.option_overlay === true && profileDefinesOptionOverlay(profiles, profileId);
+}
+
+export function dcaDraftSupported(platform, profiles, profileId) {
+ if (!profileId || !Array.isArray(profiles)) return false;
+ if (!DCA_SUPPORTED_PLATFORMS.has(platform) || !isDcaProfile(profileId)) return false;
+ return profiles.some((item) => sameStrategyProfile(item?.profile, profileId));
+}
+
+export function accountDraftStrategyChoices(platform, accountOption, profiles) {
+ if (!Array.isArray(profiles)) return [];
+ let domains = [];
+ try {
+ domains = supportedDomainsForAccount(platform, accountOption || {});
+ } catch {
+ return [];
+ }
+ const choices = [];
+ const allowsDryRunOnly = accountOption?.default_execution_mode === "dry_run"
+ && supportedExecutionModesForPlatform(platform).includes("dry_run");
+ for (const profile of profiles) {
+ if (!profile || typeof profile.profile !== "string" || !profile.profile) continue;
+ if (profile.domain_explicit !== true || profile.lifecycle_stage === "frozen" || isFrozenStrategyProfile(profile)) continue;
+ if (!profile.domain || !domains.includes(profile.domain)) continue;
+ const modes = Array.isArray(profile.allowed_execution_modes) ? profile.allowed_execution_modes : [];
+ if (!modes.some((mode) => mode === "paper" || mode === "live"
+ || (allowsDryRunOnly && mode === "dry_run"))) continue;
+ try {
+ assertDcaPlatform(platform, profile.profile);
+ } catch {
+ continue;
+ }
+ choices.push({
+ profile: profile.profile,
+ label: profile.label || profile.profile,
+ label_zh: profile.label_zh || profile.label || profile.profile,
+ label_en: profile.label_en || profile.label || profile.profile,
+ domain: profile.domain,
+ // Existing catalog declarations only, never broker or execution permission.
+ lifecycle_stage: typeof profile.lifecycle_stage === "string" ? profile.lifecycle_stage : null,
+ allowed_execution_modes: Array.isArray(profile.allowed_execution_modes) && profile.allowed_execution_modes.length ? [...profile.allowed_execution_modes] : null,
+ can_switch_live: typeof profile.can_switch_live === "boolean" ? profile.can_switch_live : null,
+ blocked_live_reason: typeof profile.blocked_live_reason === "string" ? profile.blocked_live_reason : null,
+ option_overlay_enabled: profile.option_overlay_enabled === true,
+ dca_supported: dcaDraftSupported(platform, profiles, profile.profile),
+ });
+ }
+ return choices;
+}
+
+export function assertAccountDraftPatch(profiles, observed, patch, trustedProfile, options = {}) {
+ if (!patch || Array.isArray(patch) || typeof patch !== "object") throw new HttpError("invalid_account_setting_overrides", 400);
+ const choices = profiles ? accountDraftStrategyChoices(observed.platform, observed.config, profiles) : [];
+ const rebuilding = observed.draft?.status === "identity_conflict" && options.acknowledgeIdentityConflict === true;
+ const stored = observed.draft?.overrides && typeof observed.draft.overrides === "object" && !Array.isArray(observed.draft.overrides) ? observed.draft.overrides : {};
+ const current = rebuilding ? {} : stored;
+ const touchesStrategy = Object.prototype.hasOwnProperty.call(patch, "strategy_profile");
+ const touchesOption = Object.prototype.hasOwnProperty.call(patch, "option_overlay_enabled");
+ const touchesDcaMode = Object.prototype.hasOwnProperty.call(patch, "dca_mode");
+ const touchesDcaBase = Object.prototype.hasOwnProperty.call(patch, "dca_base_investment_usd");
+ if (touchesDcaMode !== touchesDcaBase) throw new HttpError("account_settings_dca_rejected", 400);
+ if (touchesDcaMode && (patch.dca_mode === null) !== (patch.dca_base_investment_usd === null)) {
+ throw new HttpError("account_settings_dca_rejected", 400);
+ }
+ if (touchesDcaMode && patch.dca_mode !== null && patch.dca_mode !== "fixed" && patch.dca_mode !== "smart") {
+ throw new HttpError("invalid_account_setting_overrides", 400);
+ }
+ if (touchesDcaBase && patch.dca_base_investment_usd !== null && !accountSettingPositiveAmount(patch.dca_base_investment_usd)) {
+ throw new HttpError("invalid_account_setting_overrides", 400);
+ }
+ if (!profiles && (touchesDcaMode || touchesDcaBase)) throw new HttpError("account_settings_dca_rejected", 400);
+ if (touchesStrategy && patch.strategy_profile !== null) {
+ const allowedChoice = choices.some((item) => sameStrategyProfile(item.profile, patch.strategy_profile));
+ const currentEditable = sameStrategyProfile(patch.strategy_profile, trustedProfile) && dcaDraftSupported(observed.platform, profiles, patch.strategy_profile);
+ if (typeof patch.strategy_profile !== "string" || (!allowedChoice && !currentEditable)) {
+ throw new HttpError("account_settings_strategy_rejected", 400);
+ }
+ }
+ if (!touchesStrategy && !touchesOption && !touchesDcaMode && !touchesDcaBase) return;
+ const bound = touchesStrategy
+ ? patch.strategy_profile || trustedProfile || ""
+ : (typeof current.strategy_profile === "string" && current.strategy_profile ? current.strategy_profile : trustedProfile || "");
+ const supports = optionOverlayDraftAllowed(observed.platform, profiles, bound);
+ if (touchesOption && patch.option_overlay_enabled !== null && (typeof patch.option_overlay_enabled !== "boolean" || !supports)) {
+ throw new HttpError("account_settings_option_rejected", 400);
+ }
+ const nextOption = touchesOption
+ ? patch.option_overlay_enabled
+ : (Object.prototype.hasOwnProperty.call(current, "option_overlay_enabled") ? current.option_overlay_enabled : undefined);
+ if ((nextOption === true || nextOption === false) && !supports) throw new HttpError("account_settings_option_strategy_conflict", 400);
+ // Other setting groups can be edited on a DCA account without rebinding its strategy.
+ if (!touchesStrategy && !touchesDcaMode && !touchesDcaBase) return;
+ const previous = typeof current.strategy_profile === "string" && current.strategy_profile ? current.strategy_profile : trustedProfile || "";
+ const next = touchesStrategy
+ ? (patch.strategy_profile === null ? trustedProfile || "" : String(patch.strategy_profile || ""))
+ : previous;
+ const mergedMode = touchesDcaMode ? patch.dca_mode : (Object.prototype.hasOwnProperty.call(current, "dca_mode") ? current.dca_mode : null);
+ const mergedBase = touchesDcaBase ? patch.dca_base_investment_usd : (Object.prototype.hasOwnProperty.call(current, "dca_base_investment_usd") ? current.dca_base_investment_usd : null);
+ const hasMergedDca = (mergedMode !== null && mergedMode !== undefined) || (mergedBase !== null && mergedBase !== undefined);
+ if (!dcaDraftSupported(observed.platform, profiles, next)) {
+ if (hasMergedDca) throw new HttpError("account_settings_dca_rejected", 400);
+ if (!sameStrategyProfile(previous, next) && dcaDraftSupported(observed.platform, profiles, previous)
+ && (!touchesDcaMode || patch.dca_mode !== null || !touchesDcaBase || patch.dca_base_investment_usd !== null)) {
+ throw new HttpError("account_settings_dca_rejected", 400);
+ }
+ return;
+ }
+ if (touchesDcaMode || touchesDcaBase) {
+ const clearingDca = patch.dca_mode === null && patch.dca_base_investment_usd === null;
+ const boundToProfile = sameStrategyProfile(patch.strategy_profile, next);
+ const clearingCurrentBinding = patch.strategy_profile === null && clearingDca;
+ if (!touchesStrategy || (!boundToProfile && !clearingCurrentBinding)) {
+ throw new HttpError("account_settings_dca_rejected", 400);
+ }
+ }
+ if (!sameStrategyProfile(previous, next) || touchesDcaMode || touchesDcaBase) {
+ if (!touchesDcaMode || !touchesDcaBase) throw new HttpError("account_settings_dca_rejected", 400);
+ }
+}
+
+export async function saveCombinedAccountDraft(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ let raw;
+ try { raw = await readBoundedJson(request, 16 * 1024); } catch (error) { return json({ ok: false, error: "invalid_account_setting_overrides" }, error.status || 400); }
+ const allowed = ["platform", "key", "identity", "expected_draft_revision", "acknowledge_identity_conflict", "overrides"];
+ if (!raw || Array.isArray(raw) || Object.keys(raw).some(key => !allowed.includes(key)) || !Object.hasOwn(raw, "overrides")) return json({ ok: false, error: "invalid_account_setting_overrides" }, 400);
+ return saveAccountSettings(new Request(request.url, { method: "POST", headers: request.headers, body: JSON.stringify(raw) }), env);
+}
+
+export async function saveAccountSettings(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ let raw;
+ try { raw = await request.json(); } catch { return json({ ok: false, error: "request body must be valid JSON" }, 400); }
+ const platform = raw?.platform;
+ const key = raw?.key;
+ if (!SUPPORTED_PLATFORMS.includes(platform) || typeof key !== "string" || !key) return json({ ok: false, error: "account_settings_account_required" }, 400);
+ if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "runtime_instances_not_bound", no_order: true, execution_authority_granted: false }, 503);
+ const legacy = await readRiskProfileLegacy(env);
+ let observed;
+ try {
+ observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor: session.login, platform, key, legacy });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+ const wantsDraft = Object.prototype.hasOwnProperty.call(raw, "overrides");
+ const wantsRisk = Object.prototype.hasOwnProperty.call(raw, "risk_preference");
+ const wantsDeclaration = Object.prototype.hasOwnProperty.call(raw, "declaration");
+ if ((wantsDraft || wantsRisk || wantsDeclaration) && (!raw.identity || Array.isArray(raw.identity) || typeof raw.identity !== "object")) {
+ return json({ ok: false, error: "account_settings_identity_required" }, 400);
+ }
+ if ((wantsDraft || wantsRisk || wantsDeclaration) && canonicalResearchTaskJson(raw.identity) !== canonicalResearchTaskJson(observed.identity)) {
+ return json({ ok: false, error: "account_settings_identity_conflict" }, 409);
+ }
+ const command = { action: "account_settings_save", actor: session.login, platform, key, legacy };
+ if (wantsDraft || wantsRisk || wantsDeclaration) command.identity = raw.identity;
+ if (wantsDeclaration) {
+ if (!Number.isSafeInteger(raw.expected_declaration_revision) || raw.expected_declaration_revision !== observed.declaration.revision) return json({ ok: false, error: "account_settings_declaration_revision_conflict" }, 409);
+ command.declaration = raw.declaration;
+ command.expected_declaration_revision = raw.expected_declaration_revision;
+ }
+ if (wantsDraft) {
+ if (!Number.isSafeInteger(raw.expected_draft_revision)) return json({ ok: false, error: "account_settings_draft_revision_required" }, 400);
+ if (raw.expected_draft_revision !== observed.draft.revision) return json({ ok: false, error: "account_settings_draft_revision_conflict" }, 409);
+ command.overrides = raw.overrides;
+ command.expected_draft_revision = observed.draft.revision;
+ if (raw.acknowledge_identity_conflict === true) command.acknowledge_identity_conflict = true;
+ const profiles = await loadAccountDraftProfiles(env);
+ const { effective: beforeEffective } = await effectiveAccountSettings(env, observed);
+ const trusted = beforeEffective.strategy_profile?.status === "known" && typeof beforeEffective.strategy_profile.value === "string" ? beforeEffective.strategy_profile.value : "";
+ try {
+ assertAccountDraftPatch(profiles, observed, raw.overrides, trusted, { acknowledgeIdentityConflict: raw.acknowledge_identity_conflict === true });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 400;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "invalid_account_setting_overrides", no_order: true, execution_authority_granted: false }, status);
+ }
+ }
+ if (wantsRisk) {
+ if (!Number.isSafeInteger(raw.expected_risk_revision)) return json({ ok: false, error: "risk_profile_revision_required" }, 400);
+ if (raw.expected_risk_revision !== observed.risk.revision) return json({ ok: false, error: "risk_profile_revision_conflict" }, 409);
+ command.expected_risk_revision = observed.risk.revision;
+ if (raw.risk_preference === null) command.risk_change = "clear";
+ else {
+ let built;
+ try {
+ built = await buildRiskProfileBindings(
+ { bindings: [{ platform, target_name: observed.identity.target_name, risk_preference: raw.risk_preference }] },
+ observed.account_options,
+ session.login,
+ );
+ } catch (error) {
+ return json({ ok: false, error: error.message || "risk profile bindings are invalid" }, 400);
+ }
+ command.risk_change = "set";
+ command.binding = built[0];
+ }
+ }
+ if (!Object.prototype.hasOwnProperty.call(command, "overrides") && !Object.prototype.hasOwnProperty.call(command, "risk_change") && !Object.prototype.hasOwnProperty.call(command, "declaration")) {
+ return json({ ok: false, error: "account_settings_change_required" }, 400);
+ }
+ let saved;
+ try {
+ saved = await runtimeInstanceCommand(env, command);
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+ if (command.risk_change && hasConfigStore(env)) {
+ await mirrorConfigJson(env, RISK_PROFILE_BINDINGS_KEY, {
+ schema_version: RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION,
+ bindings: saved.bindings,
+ });
+ }
+ const changes = accountSettingsAuditChanges(observed, saved, command);
+ let auditLogged = false;
+ if (changes.length && hasConfigStore(env)) {
+ const entry = {
+ ts: new Date().toISOString(),
+ login: session.login,
+ action: "save_account_settings",
+ platform,
+ key,
+ changes,
+ };
+ if (changes.some((kind) => kind === "cash_draft" || kind === "income_draft" || kind === "option_draft" || kind === "strategy_draft")) entry.draft_revision = saved.draft.revision;
+ if (changes.includes("risk_saved") || changes.includes("risk_cleared")) entry.risk_revision = saved.risk.revision;
+ if (changes.includes("account_declaration_saved")) entry.declaration_revision = saved.declaration.revision;
+ try {
+ await appendAuditLog(env, entry);
+ auditLogged = true;
+ } catch { /* the setting is already stored; a missed audit line must not be saved again */ }
+ }
+ const presented = await presentAccountSettings(env, saved, true);
+ presented.audit_logged = auditLogged;
+ return json(presented);
+}
+
+export async function approveAccountSettingsProfileApplication(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ let raw;
+ try { raw = await request.json(); } catch { return json({ ok: false, error: "request body must be valid JSON" }, 400); }
+ const allowedFields = new Set([
+ "platform", "key", "request_key", "identity", "expected_instance_revision",
+ "expected_draft_revision", "old_profile", "new_profile",
+ ]);
+ if (!raw || Array.isArray(raw) || typeof raw !== "object" || Object.keys(raw).some((key) => !allowedFields.has(key))) {
+ return json({ ok: false, error: "account_settings_profile_application_request_invalid" }, 400);
+ }
+ if (!SUPPORTED_PLATFORMS.includes(raw.platform) || typeof raw.key !== "string" || !raw.key) {
+ return json({ ok: false, error: "account_settings_account_required" }, 400);
+ }
+ if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(String(raw.request_key || ""))
+ || !Number.isSafeInteger(raw.expected_instance_revision) || raw.expected_instance_revision < 0
+ || !Number.isSafeInteger(raw.expected_draft_revision) || raw.expected_draft_revision < 0
+ || !accountSettingsIdentityIsComplete(raw.identity)) {
+ return json({ ok: false, error: "account_settings_profile_application_request_invalid" }, 400);
+ }
+ const oldProfile = accountSettingsProfileName(raw.old_profile);
+ const newProfile = accountSettingsProfileName(raw.new_profile);
+ if (!oldProfile || !newProfile || oldProfile === newProfile) {
+ return json({ ok: false, error: "account_settings_profile_application_profile_invalid" }, 400);
+ }
+ if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "runtime_instances_not_bound" }, 503);
+
+ const command = {
+ action: "account_settings_profile_application_approve",
+ actor: session.login,
+ platform: raw.platform,
+ key: raw.key,
+ request_key: raw.request_key,
+ identity: raw.identity,
+ expected_instance_revision: raw.expected_instance_revision,
+ expected_draft_revision: raw.expected_draft_revision,
+ old_profile: oldProfile,
+ new_profile: newProfile,
+ };
+ try {
+ const prior = await runtimeInstanceCommand(env, {
+ action: "account_settings_profile_application_lookup",
+ actor: session.login,
+ request_key: raw.request_key,
+ });
+ if (prior.application) {
+ const replay = await runtimeInstanceCommand(env, command);
+ return json({
+ ok: true,
+ replayed: true,
+ application: replay.application,
+ runtime_applied: false,
+ variables_updated: false,
+ no_order: true,
+ execution_authority_granted: false,
+ });
+ }
+
+ const observed = await runtimeInstanceCommand(env, {
+ action: "account_settings_read", actor: session.login, platform: raw.platform, key: raw.key,
+ });
+ if (observed.instance_revision !== raw.expected_instance_revision
+ || canonicalResearchTaskJson(observed.identity) !== canonicalResearchTaskJson(raw.identity)) {
+ return json({ ok: false, error: "account_settings_profile_application_identity_conflict" }, 409);
+ }
+ const draft = observed.draft;
+ if (draft?.status !== "current" || draft.revision !== raw.expected_draft_revision
+ || canonicalResearchTaskJson(draft.identity) !== canonicalResearchTaskJson(observed.identity)
+ || Object.keys(draft.overrides || {}).length !== 1
+ || draft.overrides?.strategy_profile !== newProfile) {
+ return json({ ok: false, error: "account_settings_profile_application_draft_conflict" }, 409);
+ }
+ if (isDcaProfile(oldProfile) || isDcaProfile(newProfile)) {
+ return json({ ok: false, error: "account_settings_profile_application_profile_only_required" }, 409);
+ }
+ const profiles = await loadAccountDraftProfiles(env);
+ const selectable = accountDraftStrategyChoices(raw.platform, observed.config, profiles);
+ if (!selectable.some((profile) => profile.profile === newProfile && profile.dca_supported !== true)) {
+ return json({ ok: false, error: "account_settings_profile_application_profile_not_selectable" }, 409);
+ }
+ const readback = await accountSettingsProfileRuntimeReadback(env, observed);
+ if (!readback) return json({ ok: false, error: "account_settings_runtime_readback_unavailable" }, 503);
+ if (readback.runtime_target_enabled !== "false") {
+ return json({ ok: false, error: "account_settings_runtime_target_not_disabled" }, 409);
+ }
+ if (readback.strategy_profile !== oldProfile) {
+ return json({ ok: false, error: "account_settings_profile_application_current_profile_conflict" }, 409);
+ }
+ command.current_profile = readback.strategy_profile;
+ command.runtime_target_enabled = false;
+ const approved = await runtimeInstanceCommand(env, command);
+ let auditLogged = false;
+ if (!approved.replayed && hasConfigStore(env)) {
+ try {
+ await appendAuditLog(env, {
+ ts: approved.application.approved_at,
+ login: session.login,
+ action: "approve_account_settings_profile_application",
+ platform: raw.platform,
+ key: raw.key,
+ request_key: raw.request_key,
+ instance_revision: raw.expected_instance_revision,
+ draft_revision: raw.expected_draft_revision,
+ old_profile: oldProfile,
+ new_profile: newProfile,
+ });
+ auditLogged = true;
+ } catch { /* the durable approval is authoritative if its audit mirror is unavailable */ }
+ }
+ return json({
+ ok: true,
+ replayed: approved.replayed === true,
+ application: approved.application,
+ audit_logged: auditLogged,
+ runtime_applied: false,
+ variables_updated: false,
+ no_order: true,
+ execution_authority_granted: false,
+ });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+}
+
+export function decodeProfileApplicationJwtPart(value, maxBytes, parseJson = true) {
+ if (typeof value !== "string" || value.length === 0 || value.length > maxBytes * 2
+ || !/^[A-Za-z0-9_-]+$/.test(value)) throw new HttpError("github_oidc_token_invalid", 401);
+ const padded = value.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - value.length % 4) % 4);
+ let binary;
+ try { binary = atob(padded); } catch { throw new HttpError("github_oidc_token_invalid", 401); }
+ if (binary.length > maxBytes) throw new HttpError("github_oidc_token_invalid", 401);
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
+ if (!parseJson) return { bytes };
+ try { return { bytes, value: JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes)) }; }
+ catch { throw new HttpError("github_oidc_token_invalid", 401); }
+}
+
+export async function readGitHubProfileApplicationJwks() {
+ const controller = new AbortController();
+ let rejectAbort = () => {};
+ const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
+ abortPromise.catch(() => {});
+ const onAbort = () => rejectAbort(new HttpError("github_oidc_jwks_unavailable", 503));
+ controller.signal.addEventListener("abort", onAbort);
+ const timeout = setTimeout(() => controller.abort(), ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_TIMEOUT_MS);
+ let response;
+ try {
+ response = await Promise.race([
+ fetch(ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_JWKS_URL, {
+ method: "GET",
+ headers: { Accept: "application/json" },
+ redirect: "manual",
+ signal: controller.signal,
+ }),
+ abortPromise,
+ ]);
+ if (response.status !== 200 || response.redirected) throw new HttpError("github_oidc_jwks_unavailable", 503);
+ const contentLength = response.headers.get("Content-Length");
+ if (contentLength && (!/^\d+$/.test(contentLength) || Number(contentLength) > ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_JWKS_BYTES)) {
+ throw new HttpError("github_oidc_jwks_unavailable", 503);
+ }
+ const contentType = response.headers.get("Content-Type") || "";
+ if (!/^application\/json(?:\s*;|$)/i.test(contentType)) throw new HttpError("github_oidc_jwks_unavailable", 503);
+ const text = await readLimitedUtf8Body(response, ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_JWKS_BYTES, controller, abortPromise);
+ const jwks = JSON.parse(text);
+ if (!jwks || Array.isArray(jwks) || typeof jwks !== "object" || !Array.isArray(jwks.keys) || jwks.keys.length < 1 || jwks.keys.length > 16) {
+ throw new HttpError("github_oidc_jwks_unavailable", 503);
+ }
+ return jwks.keys;
+ } catch (error) {
+ if (error instanceof HttpError) throw error;
+ throw new HttpError("github_oidc_jwks_unavailable", 503);
+ } finally {
+ clearTimeout(timeout);
+ controller.signal.removeEventListener("abort", onAbort);
+ }
+}
+
+export async function verifyGitHubProfileApplicationToken(request, env) {
+ const workflowSha = env.ACCOUNT_SETTINGS_PROFILE_APPLICATION_WORKFLOW_SHA;
+ if (typeof workflowSha !== "string" || !/^[a-f0-9]{40}$/.test(workflowSha)) {
+ throw new HttpError("github_oidc_workflow_sha_not_configured", 503);
+ }
+ const authorization = request.headers.get("Authorization") || "";
+ const match = /^Bearer ([A-Za-z0-9._~-]+)$/.exec(authorization);
+ if (!match || match[1].length > ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_TOKEN_BYTES) {
+ throw new HttpError("github_oidc_token_invalid", 401);
+ }
+ const parts = match[1].split(".");
+ if (parts.length !== 3) throw new HttpError("github_oidc_token_invalid", 401);
+ const header = decodeProfileApplicationJwtPart(parts[0], 2048).value;
+ const claims = decodeProfileApplicationJwtPart(parts[1], 4096).value;
+ const signature = decodeProfileApplicationJwtPart(parts[2], 1024, false).bytes;
+ if (!header || Array.isArray(header) || typeof header !== "object"
+ || header.alg !== "RS256" || header.typ !== "JWT"
+ || typeof header.kid !== "string" || !/^[A-Za-z0-9._-]{1,128}$/.test(header.kid)
+ || Object.hasOwn(header, "jku") || Object.hasOwn(header, "x5u") || Object.hasOwn(header, "crit")) {
+ throw new HttpError("github_oidc_token_invalid", 401);
+ }
+ if (!claims || Array.isArray(claims) || typeof claims !== "object"
+ || claims.iss !== "https://token.actions.githubusercontent.com"
+ || claims.aud !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_AUDIENCE
+ || claims.repository !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REPOSITORY
+ || claims.ref !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REF
+ || claims.workflow_ref !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_WORKFLOW_REF
+ || claims.workflow_sha !== workflowSha
+ || Object.hasOwn(claims, "job_workflow_ref") || Object.hasOwn(claims, "job_workflow_sha")
+ || claims.event_name !== "workflow_dispatch"
+ || typeof claims.run_id !== "string" || !/^[1-9]\d{0,19}$/.test(claims.run_id)
+ || typeof claims.run_attempt !== "string" || !/^[1-9]\d{0,5}$/.test(claims.run_attempt)) {
+ throw new HttpError("github_oidc_token_invalid", 401);
+ }
+ const now = Math.floor(Date.now() / 1000);
+ if (![claims.iat, claims.nbf, claims.exp].every(Number.isSafeInteger)
+ || claims.iat > now + 30 || claims.iat < now - 600
+ || claims.nbf > now + 30 || claims.nbf > claims.exp
+ || claims.exp <= now || claims.exp <= claims.iat || claims.exp - claims.iat > 600) {
+ throw new HttpError("github_oidc_token_invalid", 401);
+ }
+ const keys = await readGitHubProfileApplicationJwks();
+ const matches = keys.filter((key) => key?.kid === header.kid);
+ if (matches.length !== 1) throw new HttpError("github_oidc_token_invalid", 401);
+ const jwk = matches[0];
+ if (jwk.kty !== "RSA" || jwk.use !== "sig" || (jwk.alg && jwk.alg !== "RS256")
+ || (jwk.key_ops !== undefined && (!Array.isArray(jwk.key_ops) || !jwk.key_ops.includes("verify")))
+ || typeof jwk.n !== "string" || typeof jwk.e !== "string") {
+ throw new HttpError("github_oidc_token_invalid", 401);
+ }
+ let valid = false;
+ try {
+ const publicKey = await crypto.subtle.importKey(
+ "jwk", jwk, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"],
+ );
+ valid = await crypto.subtle.verify(
+ "RSASSA-PKCS1-v1_5", publicKey, signature, new TextEncoder().encode(`${parts[0]}.${parts[1]}`),
+ );
+ } catch { throw new HttpError("github_oidc_token_invalid", 401); }
+ if (!valid) throw new HttpError("github_oidc_token_invalid", 401);
+ return { runId: claims.run_id, runAttempt: claims.run_attempt };
+}
+
+export function accountSettingsProfileApplicationIsFixedHk(application) {
+ const identity = application?.identity;
+ return application?.platform === "longbridge" && application?.key === "hk"
+ && accountSettingsIdentityIsComplete(identity)
+ && identity.platform === "longbridge" && identity.key === "hk";
+}
+
+export async function claimAccountSettingsProfileApplicationFromGitHub(request, env) {
+ if (new URL(request.url).search || !hasRuntimeInstanceStore(env)) {
+ return json({ ok: false, error: "account_settings_profile_application_unavailable", no_order: true, execution_authority_granted: false }, 503);
+ }
+ try {
+ const run = await verifyGitHubProfileApplicationToken(request, env);
+ const raw = await readGitHubProfileApplicationRequestBody(request);
+ if (!ux1ExactKeys(raw, ["request_key"]) || !ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(String(raw.request_key || ""))) {
+ return json({ ok: false, error: "account_settings_profile_application_request_invalid", no_order: true, execution_authority_granted: false }, 400);
+ }
+ const actor = "github-oidc-profile-application";
+ const lookup = await runtimeInstanceCommand(env, {
+ action: "account_settings_profile_application_lookup", actor, request_key: raw.request_key,
+ });
+ const application = lookup.application;
+ if (!application) return json({ ok: false, error: "account_settings_profile_application_not_found", no_order: true, execution_authority_granted: false }, 404);
+ if (!accountSettingsProfileApplicationIsFixedHk(application)) {
+ return json({ ok: false, error: "account_settings_profile_application_target_conflict", no_order: true, execution_authority_granted: false }, 409);
+ }
+ const command = {
+ action: "account_settings_profile_application_claim",
+ actor,
+ request_key: application.request_key,
+ identity: application.identity,
+ expected_instance_revision: application.instance_revision,
+ expected_draft_revision: application.draft_revision,
+ old_profile: application.old_profile,
+ new_profile: application.new_profile,
+ current_profile: application.old_profile,
+ runtime_target_enabled: false,
+ workflow_run_id: run.runId,
+ workflow_run_attempt: run.runAttempt,
+ };
+ if (application.status === "claimed") {
+ const replay = await runtimeInstanceCommand(env, command);
+ return json({ ...replay, ok: true });
+ }
+ if (application.status !== "approved") {
+ return json({ ok: false, error: "account_settings_profile_application_conflict", no_order: true, execution_authority_granted: false }, 409);
+ }
+ const observed = await runtimeInstanceCommand(env, {
+ action: "account_settings_read", actor, platform: application.platform, key: application.key,
+ });
+ if (observed.instance_revision !== application.instance_revision
+ || canonicalResearchTaskJson(observed.identity) !== canonicalResearchTaskJson(application.identity)) {
+ return json({ ok: false, error: "account_settings_profile_application_identity_conflict", no_order: true, execution_authority_granted: false }, 409);
+ }
+ const draft = observed.draft;
+ if (draft?.status !== "current" || draft.revision !== application.draft_revision
+ || canonicalResearchTaskJson(draft.identity) !== canonicalResearchTaskJson(application.identity)
+ || Object.keys(draft.overrides || {}).length !== 1
+ || draft.overrides?.strategy_profile !== application.new_profile) {
+ return json({ ok: false, error: "account_settings_profile_application_draft_conflict", no_order: true, execution_authority_granted: false }, 409);
+ }
+ const variableScope = resolveVariableScope(application.platform, observed.config);
+ const githubEnvironment = resolveGithubEnvironment(application.platform, observed.config, variableScope);
+ const repository = platformRepositories(env)?.[application.platform];
+ if (repository !== "QuantStrategyLab/LongBridgePlatform"
+ || variableScope !== "environment"
+ || githubEnvironment !== "longbridge-hk") {
+ return json({ ok: false, error: "account_settings_profile_application_target_conflict", no_order: true, execution_authority_granted: false }, 409);
+ }
+ const readback = await accountSettingsProfileRuntimeReadback(env, observed, {
+ repository, variableScope, githubEnvironment,
+ });
+ if (!readback) return json({ ok: false, error: "account_settings_runtime_readback_unavailable", no_order: true, execution_authority_granted: false }, 503);
+ if (readback.runtime_target_enabled !== "false" || readback.strategy_profile !== application.old_profile) {
+ return json({ ok: false, error: "account_settings_profile_application_runtime_conflict", no_order: true, execution_authority_granted: false }, 409);
+ }
+ const claimed = await runtimeInstanceCommand(env, command);
+ return json({ ...claimed, ok: true });
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return json({ ok: false, error: error instanceof HttpError ? error.message : "account_settings_profile_application_unavailable", no_order: true, execution_authority_granted: false }, status);
+ }
+}
+
+export async function readGitHubProfileApplicationRequestBody(request) {
+ const contentLength = request.headers.get("Content-Length");
+ if (contentLength && (!/^\d+$/.test(contentLength) || Number(contentLength) > ACCOUNT_SETTINGS_PROFILE_APPLICATION_MAX_BODY_BYTES)) {
+ throw new HttpError("account_settings_profile_application_body_too_large", 413);
+ }
+ const controller = new AbortController();
+ let rejectAbort = () => {};
+ const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
+ abortPromise.catch(() => {});
+ const onAbort = () => rejectAbort(new HttpError("account_settings_profile_application_body_timeout", 408));
+ controller.signal.addEventListener("abort", onAbort);
+ const timeout = setTimeout(() => controller.abort(), ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_TIMEOUT_MS);
+ try {
+ const text = await readLimitedUtf8Body(request, ACCOUNT_SETTINGS_PROFILE_APPLICATION_MAX_BODY_BYTES, controller, abortPromise);
+ try { return JSON.parse(text); } catch { throw new HttpError("request body must be valid JSON", 400); }
+ } catch (error) {
+ if (error instanceof HttpError) throw error;
+ if (String(error?.message || "") === "ux1_calculator_body_limit") {
+ throw new HttpError("account_settings_profile_application_body_too_large", 413);
+ }
+ throw new HttpError("account_settings_profile_application_body_invalid", 400);
+ } finally {
+ clearTimeout(timeout);
+ controller.signal.removeEventListener("abort", onAbort);
+ }
+}
+
+export function accountSettingsAuditChanges(before, after, requested) {
+ const changes = [];
+ const left = before?.draft?.overrides && typeof before.draft.overrides === "object" && !Array.isArray(before.draft.overrides) ? before.draft.overrides : {};
+ const right = after?.draft?.overrides && typeof after.draft.overrides === "object" && !Array.isArray(after.draft.overrides) ? after.draft.overrides : {};
+ const patch = requested?.overrides && typeof requested.overrides === "object" && !Array.isArray(requested.overrides) ? requested.overrides : {};
+ const stored = (record, name) => Object.prototype.hasOwnProperty.call(record, name) ? record[name] : undefined;
+ const asked = (name) => Object.prototype.hasOwnProperty.call(patch, name);
+ if (["reserved_cash_floor", "reserved_cash_ratio"].some(asked) && ["reserved_cash_floor", "reserved_cash_ratio"].some((name) => stored(left, name) !== stored(right, name))) changes.push("cash_draft");
+ if (asked("income_layer_enabled") && stored(left, "income_layer_enabled") !== stored(right, "income_layer_enabled")) changes.push("income_draft");
+ if (asked("option_overlay_enabled") && stored(left, "option_overlay_enabled") !== stored(right, "option_overlay_enabled")) changes.push("option_draft");
+ const strategyDraftChanged = (asked("strategy_profile") && stored(left, "strategy_profile") !== stored(right, "strategy_profile"))
+ || ((asked("dca_mode") || asked("dca_base_investment_usd")) && ["dca_mode", "dca_base_investment_usd"].some((name) => stored(left, name) !== stored(right, name)));
+ if (strategyDraftChanged) changes.push("strategy_draft");
+ if (requested?.declaration && before?.declaration?.revision !== after?.declaration?.revision) changes.push("account_declaration_saved");
+ const beforePreference = before?.risk?.preference || null;
+ const afterPreference = after?.risk?.preference || null;
+ if ((requested?.risk_change === "set" || requested?.risk_change === "clear") && beforePreference !== afterPreference) changes.push(afterPreference ? "risk_saved" : "risk_cleared");
+ return changes;
+}
+
+export async function buildAdminState(session, env) {
+ const authConfig = await loadAuthConfig(env);
+ const accountConfig = await loadAccountOptionsConfig(env);
+ const riskProfileBindingState = await loadRiskProfileBindings(env);
+ const runtimeInstances = hasRuntimeInstanceStore(env) ? await runtimeInstanceCommand(env) : null;
+ let runtimeInstanceStrategies = [];
+ if (runtimeInstances) {
+ try {
+ runtimeInstanceStrategies = (await loadStrategyProfilesConfig(env)).filter((item) => !isFrozenStrategyProfile(item) && (item.allowed_execution_modes || []).includes("dry_run")).map((item) => ({ profile: item.profile, label: item.label, domain: item.domain }));
+ } catch {
+ // Catalog failure affects draft authoring, never existing instance
+ // readback, retirement requests, or `/api/admin/config` readback.
+ }
+ }
+ return {
+ ok: true,
+ session: { login: session.login, admin: true },
+ kvAvailable: hasConfigStore(env),
+ authConfig,
+ accountOptions: accountConfig.options || {},
+ accountOptionSource: accountConfig.source,
+ riskProfileBindings: riskProfileBindingState.bindings,
+ riskProfileRevision: riskProfileBindingState.revision,
+ riskProfileBindingsError: riskProfileBindingState.error,
+ riskProfileBindingTargets: riskProfileBindingTargets(riskProfileBindingState.account_options || accountConfig.options || {}),
+ auditLog: await loadAuditLog(env),
+ runtimeInstances,
+ runtimeInstanceStrategies,
+ runtimeInstanceStrategiesAvailable: runtimeInstanceStrategies.length > 0,
+ };
+}
+
+export async function loadPlatformMeta(env = {}) {
+ // Use the same bundled configuration as routing and capability validation.
+ // Fetching GitHub main here could mix a newer catalog with an older Worker.
+ const merged = Object.fromEntries(Object.entries(PLATFORM_META)
+ .map(([platform, meta]) => [platform, { ...meta }]));
+ const hidden = new Set(String(env.STRATEGY_SWITCH_HIDDEN_PLATFORMS || "")
+ .split(",").map((value) => value.trim().toLowerCase()).filter(Boolean));
+ for (const [platform, meta] of Object.entries(merged)) {
+ meta.console_visible = !hidden.has(platform);
+ }
+ return merged;
+}
+
+// In-memory cache for the lifetime of this Worker isolate.
+let _memCurrentStrategies = null;
+let _memCurrentStrategiesTs = 0;
+let _memRefreshing = false; // prevent concurrent background refreshes
+
+// KV free tier caps writes at 1,000/day account-wide and the */5 cron plus every
+// background refresh reaches this helper, so a write is paid for only when the
+// rendered content changed or the stored entry needs its ts bumped to stay inside
+// the fresh window that cold isolates serve from.
+// current_strategies_cache carries per-account execution_evidence.observed_at
+// stamped with new Date() (see accountExecutionEvidence callers), so whole-payload
+// byte equality can never hold; the comparison drops those stamps and keeps the
+// stored value untouched for readers.
+
+// readConfigJson reports a damaged value as `STRATEGY_SWITCH_CONFIG. must be
+// valid JSON`. Only that shape is a cache miss; a KV read that failed for any other
+// reason is an outage and has to reach the caller instead of being mistaken for an
+// empty cache — the difference is what keeps cold isolates from fanning out to
+// GitHub on every request while the store is unhealthy.
+export function isConfigJsonParseError(error) {
+ return /^STRATEGY_SWITCH_CONFIG\.[^\s]+ must be valid JSON$/.test(String(error?.message || ""));
+}
+
+export async function readCurrentStrategiesCacheEntry(env) {
+ try {
+ return await readConfigJson(env, CURRENT_STRATEGIES_CACHE_KEY);
+ } catch (error) {
+ if (!isConfigJsonParseError(error)) throw error;
+ return null;
+ }
+}
+
+export async function writeCurrentStrategiesCache(env, payload, ts) {
+ if (env.STRATEGY_SWITCH_RUNTIME_INSTANCES) {
+ try {
+ await directoryCommand(env, { action: "cache", payload, ts });
+ return;
+ } catch (error) {
+ // Receiver-first compatibility only; a real storage failure remains loud.
+ if (error.message !== "kv_directory_legacy_receiver" && error.message !== "kv_directory_invalid_request") throw error;
+ }
+ }
+ const signature = currentStrategiesSignature(payload);
+ // A damaged stored value must not wedge the cache; this is the only path that can
+ // overwrite it, so the comparison reads through the same repair-aware helper.
+ const cached = await readCurrentStrategiesCacheEntry(env);
+ if (cached?.data && currentStrategiesSignature(cached.data) === signature
+ && cached.ts && ts - cached.ts < CURRENT_STRATEGIES_KV_BUMP_MS) {
+ return;
+ }
+ await writeConfigJson(env, CURRENT_STRATEGIES_CACHE_KEY, { ts, data: payload });
+}
+
+// loadCurrentStrategiesSafely answers with evidence-only account entries whenever
+// GitHub timed out or threw, so a payload whose every account is exactly that
+// shape carries no strategy information and must not be served as fresh.
+export function isDegradedCurrentStrategies(payload) {
+ const accounts = Object.values(payload || {}).flatMap(options => Object.values(options || {}));
+ if (!accounts.length) return false;
+ return accounts.every(account => account && typeof account === "object"
+ && Object.keys(account).length === 1
+ && account.execution_evidence?.status === "read_failed");
+}
+
+export async function configPayload(request, env, ctx) {
+ const session = await readSession(request, env);
+ const meta = await loadPlatformMeta(env);
+ if (!session?.allowed) return { accountOptions: null, platformMeta: meta };
+ const accountConfig = await loadAccountOptionsConfig(env);
+ const strategyProfiles = await loadStrategyProfilesConfig(env);
+
+ const currentStrategies = await readCurrentStrategies(accountConfig.options, env, ctx);
+
+ return {
+ accountOptions: accountConfig.options,
+ accountOptionsRevision: accountConfig.revision ?? null,
+ runtimeDailyBindings: runtimeDailyReadModelEnabled(env) ? await runtimeDailyPublicBindings(env, accountConfig.options) : [],
+ platformRepositories: platformRepositories(env),
+ platformMeta: meta,
+ strategyProfiles,
+ currentStrategies,
+ };
+}
+
+export async function readCurrentStrategies(accountOptions, env, ctx) {
+ let currentStrategies = null;
+ let cacheFresh = false;
+
+ // 1) In-memory cache
+ if (_memCurrentStrategies) {
+ const age = Date.now() - _memCurrentStrategiesTs;
+ if (age < CURRENT_STRATEGIES_MEMO_TTL_MS) {
+ currentStrategies = _memCurrentStrategies;
+ cacheFresh = true;
+ } else if (age < CURRENT_STRATEGIES_STALE_TTL_MS) {
+ currentStrategies = _memCurrentStrategies;
+ // stale — trigger background refresh below
+ }
+ }
+
+ // 2) KV cache
+ if (!currentStrategies && hasConfigStore(env)) {
+ const cached = await readCurrentStrategiesCacheEntry(env);
+ if (cached?.ts && cached.data) {
+ const age = Date.now() - cached.ts;
+ // A degraded entry stays inside the freshness window but is never *fresh*:
+ // the next request must revalidate instead of serving a read_failed payload
+ // for the whole 30 minutes.
+ if (age < CURRENT_STRATEGIES_KV_FRESH_MS && !isDegradedCurrentStrategies(cached.data)) {
+ currentStrategies = cached.data;
+ cacheFresh = true;
+ } else if (age < CURRENT_STRATEGIES_STALE_TTL_MS) {
+ currentStrategies = cached.data;
+ // stale — trigger background refresh below
+ }
+ if (currentStrategies && !_memCurrentStrategies) {
+ _memCurrentStrategies = currentStrategies;
+ _memCurrentStrategiesTs = cached.ts;
+ }
+ }
+ }
+
+ // 3) Background refresh when stale (return old data immediately)
+ if (currentStrategies && !cacheFresh && !_memRefreshing && hasConfigStore(env) && ctx) {
+ _memRefreshing = true;
+ ctx.waitUntil((async () => {
+ try {
+ const fresh = await loadCurrentStrategiesSafely(accountOptions, env);
+ _memCurrentStrategies = fresh;
+ _memCurrentStrategiesTs = Date.now();
+ await writeCurrentStrategiesCache(env, fresh, _memCurrentStrategiesTs);
+ } catch { /* keep stale data */ }
+ finally { _memRefreshing = false; }
+ })());
+ }
+
+ // 4) Complete miss — must wait for GitHub
+ if (!currentStrategies) {
+ currentStrategies = await loadCurrentStrategiesSafely(accountOptions, env);
+ _memCurrentStrategies = currentStrategies;
+ _memCurrentStrategiesTs = Date.now();
+ if (hasConfigStore(env) && ctx) {
+ ctx.waitUntil(writeCurrentStrategiesCache(env, currentStrategies, _memCurrentStrategiesTs));
+ }
+ }
+
+ return currentStrategies;
+}
+
+export async function strategyProfilesPayload(env) {
+ return {
+ strategyProfiles: await loadStrategyProfilesConfig(env),
+ platformMeta: await loadPlatformMeta(env),
+ };
+}
+
+export async function runtimeCatalogResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ // This is a generated gate catalog, not a deployment observation. Keeping
+ // the distinction in the response makes it unsuitable as an accidental
+ // substitute for the independently refreshed control-plane/evidence views.
+ return json(RUNTIME_CATALOG_PROJECTION);
+}
+
+export async function loadCurrentStrategies(accountOptions, env) {
+ const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
+ if (!token || !accountOptions) return executionEvidenceFallback(accountOptions, "not_connected");
+ const repositories = platformRepositories(env);
+
+ const variableCache = new Map();
+ const readVariable = async (repository, scope, githubEnvironment, name) => {
+ const cacheKey = [repository, scope, githubEnvironment || ""].join("|");
+ if (!variableCache.has(cacheKey)) {
+ variableCache.set(cacheKey, (async () => {
+ let status = "ok";
+ const values = await fetchGithubVariables(token, repository, scope, githubEnvironment, {
+ reportReadErrors: true, onReadFailure: reason => { status = reason; },
+ });
+ return { values, status };
+ })());
+ }
+ const result = await variableCache.get(cacheKey);
+ return result.values?.get(name) || "";
+ };
+
+ readVariable.readStatus = async (repository, scope, githubEnvironment) =>
+ (await variableCache.get([repository, scope, githubEnvironment || ""].join("|")))?.status || "ok";
+ const currentStrategies = {};
+ // Process platforms sequentially: each platform's account list is also
+ // processed one at a time (not Promise.all). This keeps GitHub API
+ // concurrency low enough to avoid secondary rate limiting.
+ for (const platform of SUPPORTED_PLATFORMS) {
+ const platformStrategies = await loadStrategiesForPlatform(platform, accountOptions, repositories, readVariable);
+ if (Object.keys(platformStrategies).length) currentStrategies[platform] = platformStrategies;
+ // 100ms gap between platforms to respect GitHub secondary rate limit
+ await new Promise((r) => setTimeout(r, 100));
+ }
+ return currentStrategies;
+}
+
+export async function loadStrategiesForPlatform(platform, accountOptions, repositories, readVariable) {
+ const options = Array.isArray(accountOptions[platform]) ? accountOptions[platform] : [];
+ if (!options.length) return {};
+ const repository = repositories[platform];
+ if (!repository) return executionEvidenceFallback({ [platform]: options }, "not_connected")[platform];
+
+ // Process accounts sequentially within each platform to stay within
+ // GitHub's concurrent request budget per token (~30 burst limit).
+ const platformStrategies = {};
+ for (const option of options) {
+ let status = "ok";
+ const trackedRead = async (...args) => {
+ const value = await readVariable(...args);
+ const result = await readVariable.readStatus?.(...args.slice(0, 3));
+ if (result && result !== "ok") status = result;
+ return value;
+ };
+ const current = await resolveCurrentStrategyForAccount({
+ platform,
+ option,
+ optionsCount: options.length,
+ repository,
+ readVariable: trackedRead,
+ });
+ platformStrategies[option.key] = { ...current,
+ execution_evidence: accountExecutionEvidence(option, current || {}, { status, observedAt: new Date().toISOString() }) };
+ }
+ return platformStrategies;
+}
+
+export function executionEvidenceFallback(accountOptions, status) {
+ return Object.fromEntries(Object.entries(accountOptions || {}).map(([platform, options]) => [platform,
+ Object.fromEntries(options.map(option => [option.key, {
+ execution_evidence: accountExecutionEvidence(option, {}, { status, observedAt: new Date().toISOString() }),
+ }]))]));
+}
+
+export async function loadCurrentStrategiesSafely(accountOptions, env) {
+ try {
+ return await withTimeout(
+ loadCurrentStrategies(accountOptions, env),
+ CURRENT_STRATEGIES_TIMEOUT_MS,
+ executionEvidenceFallback(accountOptions, "read_failed"),
+ );
+ } catch {
+ return executionEvidenceFallback(accountOptions, "read_failed");
+ }
+}
+
+export function withTimeout(promise, timeoutMs, fallback) {
+ let timeoutId;
+ const timeout = new Promise((resolve) => {
+ timeoutId = setTimeout(() => resolve(fallback), timeoutMs);
+ });
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(timeoutId));
+}
+
+export async function fetchWithTimeout(resource, init = {}, timeoutMs = GITHUB_API_TIMEOUT_MS, fetchImpl = fetch) {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
+ try {
+ return await fetchImpl(resource, { ...init, signal: controller.signal });
+ } catch (error) {
+ if (error?.name === "AbortError") throw new Error("GitHub request timed out");
+ throw error;
+ } finally {
+ clearTimeout(timeoutId);
+ }
+}
+
+export async function resolveCurrentStrategyForAccount({ platform, option, optionsCount, repository, readVariable }) {
+ const serviceTargetsValue = usesServiceTargetsAsRuntimeSource(platform)
+ ? await readVariable(repository, "repository", "", "CLOUD_RUN_SERVICE_TARGETS_JSON")
+ : "";
+ const serviceTarget = runtimeTargetFromServiceTargets(serviceTargetsValue, platform, option);
+ const serviceTargetProfile = cleanCurrentStrategy(serviceTarget?.strategy_profile);
+ const serviceTargetReservedCashPayload = reservedCashPayloadFromObject(platform, serviceTarget);
+ const serviceTargetIncomeLayerPayload = incomeLayerPayloadFromObject(serviceTarget);
+ const serviceTargetOptionOverlayPayload = optionOverlayPayloadFromObject(serviceTarget);
+ let serviceTargetRuntimeTargetEnabledPayload = runtimeTargetEnabledPayloadFromObject(serviceTarget);
+ if (serviceTarget && !Object.keys(serviceTargetRuntimeTargetEnabledPayload).length) {
+ const variableScope = resolveVariableScope(platform, option);
+ serviceTargetRuntimeTargetEnabledPayload = await readRuntimeTargetEnabledVariable({
+ repository, variableScope,
+ githubEnvironment: resolveGithubEnvironment(platform, option, variableScope), readVariable,
+ });
+ }
+ const serviceTargetDcaPayload = dcaPayloadFromObject(serviceTarget);
+ const serviceTargetCashOnlyPayload = cashOnlyPayloadFromObject(platform, serviceTarget);
+ if (serviceTargetProfile) {
+ return {
+ strategy_profile: serviceTargetProfile,
+ ...runtimeModePayload(serviceTarget),
+ strategy_execution: strategyTargetExecution(serviceTarget),
+ ...serviceTargetReservedCashPayload,
+ ...serviceTargetIncomeLayerPayload,
+ ...serviceTargetOptionOverlayPayload,
+ ...serviceTargetRuntimeTargetEnabledPayload,
+ ...serviceTargetCashOnlyPayload,
+ ...dcaPayloadForProfile(serviceTargetProfile, serviceTargetDcaPayload),
+ source: "CLOUD_RUN_SERVICE_TARGETS_JSON",
+ variable_scope: "repository",
+ };
+ }
+ if (
+ Object.keys(serviceTargetReservedCashPayload).length ||
+ Object.keys(serviceTargetIncomeLayerPayload).length ||
+ Object.keys(serviceTargetOptionOverlayPayload).length ||
+ Object.keys(serviceTargetCashOnlyPayload).length ||
+ Object.keys(serviceTargetRuntimeTargetEnabledPayload).length
+ ) {
+ return {
+ ...runtimeModePayload(serviceTarget),
+ strategy_execution: strategyTargetExecution(serviceTarget),
+ ...serviceTargetReservedCashPayload,
+ ...serviceTargetIncomeLayerPayload,
+ ...serviceTargetOptionOverlayPayload,
+ ...serviceTargetCashOnlyPayload,
+ ...serviceTargetRuntimeTargetEnabledPayload,
+ source: "CLOUD_RUN_SERVICE_TARGETS_JSON",
+ variable_scope: "repository",
+ };
+ }
+
+ const variableScope = resolveVariableScope(platform, option);
+ const githubEnvironment = resolveGithubEnvironment(platform, option, variableScope);
+ const reservedCashPayloadPromise = readReservedCashVariables({
+ platform,
+ repository,
+ variableScope,
+ githubEnvironment,
+ readVariable,
+ });
+ const incomeLayerPayloadPromise = readIncomeLayerVariables({
+ repository,
+ variableScope,
+ githubEnvironment,
+ readVariable,
+ });
+ const optionOverlayPayloadPromise = readOptionOverlayVariables({
+ repository,
+ variableScope,
+ githubEnvironment,
+ readVariable,
+ });
+ const runtimeTargetEnabledPayloadPromise = readRuntimeTargetEnabledVariable({
+ repository,
+ variableScope,
+ githubEnvironment,
+ readVariable,
+ });
+ const dcaPayloadPromise = readDcaVariables({
+ repository,
+ variableScope,
+ githubEnvironment,
+ readVariable,
+ });
+ const cashOnlyPayloadPromise = readCashOnlyVariables({
+ platform,
+ repository,
+ variableScope,
+ githubEnvironment,
+ readVariable,
+ });
+ // All fields share one scoped variable-list read; missing fields are not retried.
+ const runtimeTargetValue = await readVariable(repository, variableScope, githubEnvironment, "RUNTIME_TARGET_JSON");
+ const [
+ reservedCashPayload,
+ incomeLayerPayload,
+ optionOverlayPayload,
+ runtimeTargetEnabledPayload,
+ dcaPayload,
+ cashOnlyPayload,
+ ] = await Promise.all([
+ reservedCashPayloadPromise,
+ incomeLayerPayloadPromise,
+ optionOverlayPayloadPromise,
+ runtimeTargetEnabledPayloadPromise,
+ dcaPayloadPromise,
+ cashOnlyPayloadPromise,
+ ]);
+ const runtimeTarget = parseJsonObject(runtimeTargetValue);
+ const runtimeTargetMatches = runtimeTarget && runtimeTargetMatchesAccount(runtimeTarget, platform, option);
+ const runtimeTargetProfile = runtimeTargetMatches ? cleanCurrentStrategy(runtimeTarget.strategy_profile) : "";
+ if (runtimeTargetProfile) {
+ let resumeTarget = null;
+ if (platform === "binance" && repository === "QuantStrategyLab/BinancePlatform" && variableScope === "repository") {
+ const values = { RUNTIME_TARGET_JSON: runtimeTargetValue };
+ for (const name of ["RUNTIME_TARGET_ENABLED", "BINANCE_RECOVERY_CONTROL_ENABLED", "BINANCE_DRY_RUN", "STRATEGY_PROFILE", "CLOUD_RUN_SERVICE_TARGETS_JSON"]) {
+ values[name] = await readVariable(repository, variableScope, githubEnvironment, name);
+ }
+ resumeTarget = await binanceResumeTarget(values, option);
+ }
+ return {
+ strategy_profile: runtimeTargetProfile,
+ ...(resumeTarget ? { binance_resume_target_sha256: resumeTarget.runtime_target_sha256 } : {}),
+ ...runtimeModePayload(runtimeTarget),
+ strategy_execution: strategyTargetExecution(runtimeTarget),
+ ...reservedCashPayload,
+ ...incomeLayerPayload,
+ ...optionOverlayPayload,
+ ...runtimeTargetEnabledPayload,
+ ...dcaPayloadForProfile(runtimeTargetProfile, dcaPayload),
+ ...cashOnlyPayload,
+ source: "RUNTIME_TARGET_JSON",
+ variable_scope: variableScope,
+ github_environment: githubEnvironment || "",
+ };
+ }
+
+ if (variableScope === "environment" || optionsCount <= 1) {
+ const profileValue = await readVariable(repository, variableScope, githubEnvironment, "STRATEGY_PROFILE");
+ const profile = cleanCurrentStrategy(profileValue);
+ if (profile) {
+ const current = {
+ strategy_profile: profile,
+ ...reservedCashPayload,
+ ...incomeLayerPayload,
+ ...optionOverlayPayload,
+ ...runtimeTargetEnabledPayload,
+ ...dcaPayloadForProfile(profile, dcaPayload),
+ ...cashOnlyPayload,
+ source: "STRATEGY_PROFILE",
+ variable_scope: variableScope,
+ github_environment: githubEnvironment || "",
+ };
+ if (variableScope === "environment" && normalizeMatchValue(option?.target_name) === "paper") {
+ current.execution_mode = "paper";
+ }
+ return current;
+ }
+ }
+
+ if (
+ Object.keys(reservedCashPayload).length ||
+ Object.keys(incomeLayerPayload).length ||
+ Object.keys(optionOverlayPayload).length ||
+ Object.keys(runtimeTargetEnabledPayload).length ||
+ Object.keys(cashOnlyPayload).length
+ ) {
+ return {
+ ...reservedCashPayload,
+ ...incomeLayerPayload,
+ ...optionOverlayPayload,
+ ...runtimeTargetEnabledPayload,
+ ...cashOnlyPayload,
+ source: Object.keys(reservedCashPayload).length
+ ? "RESERVED_CASH_VARIABLES"
+ : (Object.keys(incomeLayerPayload).length
+ ? "INCOME_LAYER_VARIABLES"
+ : (Object.keys(runtimeTargetEnabledPayload).length
+ ? "RUNTIME_TARGET_ENABLED_VARIABLE"
+ : (Object.keys(optionOverlayPayload).length
+ ? "OPTION_OVERLAY_VARIABLES"
+ : "CASH_ONLY_EXECUTION_VARIABLE"))),
+ variable_scope: variableScope,
+ github_environment: githubEnvironment || "",
+ };
+ }
+
+ return null;
+}
+
+export function usesServiceTargetsAsRuntimeSource(platform) {
+ return ["ibkr", "schwab", "firstrade"].includes(platform);
+}
+
+export function logout(request) {
+ requireSameOrigin(request, { requireOrigin: true });
+ return json({ ok: true }, 200, {
+ "Set-Cookie": clearCookie(SESSION_COOKIE),
+ });
+}
+
+export function hkStopSourceIdentity(config, item = {}) {
+ const source = config || {};
+ const selector = source.account_selector;
+ const selectors = Array.isArray(selector)
+ ? selector.map((value) => String(value).trim()).filter(Boolean)
+ : String(selector || "").split(",").map((value) => value.trim()).filter(Boolean);
+ const broker = source.broker_environment;
+ return {
+ key: String(source.key || item.key || ""),
+ target_name: String(source.target_name || ""),
+ platform_id: "longbridge",
+ deployment_selector: String(source.deployment_selector || "").trim(),
+ account_selector: selectors,
+ account_scope: String(source.account_scope || "").trim(),
+ service_name: String(source.service_name || "").trim(),
+ variable_scope: source.variable_scope === "environment" ? "environment" : "",
+ github_environment: String(source.github_environment || "").trim(),
+ broker_environment: broker === "live" || broker === "paper" ? broker : null,
+ runtime_status_target_id: String(source.runtime_status_target_id || "").trim(),
+ };
+}
+
+export function hkStopDigestOrEmpty(value) {
+ return typeof value === "string" && /^[0-9a-f]{64}$/.test(value) ? value : "";
+}
+
+export function hkStopExactObject(value, keys) {
+ return Boolean(value) && !Array.isArray(value) && typeof value === "object"
+ && Object.keys(value).length === keys.length
+ && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
+}
+
+export function normalizeHkStopResult(raw, env) {
+ const expectedProject = env?.HK_STOP_GCP_PROJECT_ID;
+ if (typeof expectedProject !== "string" || !/^[a-z][a-z0-9-]{4,61}[a-z0-9]$/.test(expectedProject)) {
+ throw new HttpError("hk_stop_project_not_configured", 503);
+ }
+ const top = ["schema_version", "request_id", "source_revision", "source_identity_sha256", "target_id", "runtime_identity_sha256", "producer", "observed_at", "readback", "no_order", "in_flight_state", "retirement_complete"];
+ const producerKeys = ["repository", "workflow_path", "run_id", "run_attempt", "head_sha"];
+ const readbackKeys = ["project", "region", "service", "revision_name", "runtime_enabled", "scheduler_state", "scheduler_count", "scheduler_set_sha256", "complete"];
+ if (!hkStopExactObject(raw, top)
+ || raw.schema_version !== "qsl_hk_stop_result.v1"
+ || !HK_STOP_REQUEST_ID.test(String(raw.request_id || ""))
+ || !Number.isSafeInteger(raw.source_revision) || raw.source_revision < 0
+ || !hkStopDigestOrEmpty(raw.source_identity_sha256) || !hkStopDigestOrEmpty(raw.runtime_identity_sha256)
+ || raw.target_id !== HK_STOP_TARGET_ID
+ || !hkStopExactObject(raw.producer, producerKeys)
+ || raw.producer.repository !== "QuantStrategyLab/LongBridgePlatform"
+ || raw.producer.workflow_path !== ".github/workflows/stop-hk-runtime.yml"
+ || !/^(0|[1-9][0-9]*)$/.test(raw.producer.run_id)
+ || raw.producer.run_attempt !== 1
+ || !/^[0-9a-f]{40}$/.test(raw.producer.head_sha)
+ || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/.test(raw.observed_at)
+ || !hkStopExactObject(raw.readback, readbackKeys)
+ || raw.readback.project !== expectedProject
+ || raw.readback.region !== "asia-east2"
+ || raw.readback.service !== "longbridge-quant-hk-service"
+ || typeof raw.readback.revision_name !== "string"
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(raw.readback.revision_name)
+ || raw.readback.runtime_enabled !== false
+ || raw.readback.scheduler_state !== "paused"
+ || !Number.isSafeInteger(raw.readback.scheduler_count) || raw.readback.scheduler_count < 1
+ || !hkStopDigestOrEmpty(raw.readback.scheduler_set_sha256)
+ || raw.readback.complete !== true
+ || raw.no_order !== true
+ || raw.in_flight_state !== "unknown"
+ || raw.retirement_complete !== false) {
+ throw new HttpError("hk_stop_result_rejected", 400);
+ }
+ return {
+ schema_version: raw.schema_version,
+ request_id: String(raw.request_id).toLowerCase(),
+ source_revision: raw.source_revision,
+ source_identity_sha256: raw.source_identity_sha256,
+ target_id: raw.target_id,
+ runtime_identity_sha256: raw.runtime_identity_sha256,
+ producer: {
+ repository: raw.producer.repository,
+ workflow_path: raw.producer.workflow_path,
+ run_id: raw.producer.run_id,
+ run_attempt: raw.producer.run_attempt,
+ head_sha: raw.producer.head_sha,
+ },
+ observed_at: raw.observed_at,
+ readback: { ...raw.readback },
+ no_order: true,
+ in_flight_state: "unknown",
+ retirement_complete: false,
+ };
+}
+
+export async function acceptHkStopResult(request, env) {
+ requireDedicatedExecutionEvidenceSyncToken(request, env);
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const result = normalizeHkStopResult(await readBoundedJson(request, 8192), env);
+ const recorded = await runtimeInstanceCommand(env, {
+ action: "hk_stop_accept_result",
+ result,
+ now: new Date().toISOString(),
+ });
+ return json({
+ ok: true,
+ replayed: recorded.replayed === true,
+ phase: "stopped",
+ stop_confirmed: true,
+ platform_applied: false,
+ request_succeeded: false,
+ in_flight_state: "unknown",
+ });
+}
+
+export function hkStopIdentityComplete(identity) {
+ return identity?.key === "hk"
+ && identity.target_name === "hk"
+ && identity.platform_id === "longbridge"
+ && identity.deployment_selector
+ && identity.account_selector?.length
+ && identity.account_scope === "HK"
+ && identity.service_name === "longbridge-quant-hk-service"
+ && identity.variable_scope === "environment"
+ && identity.github_environment === "longbridge-hk";
+}
+
+export function presentHkStop(record, observation, repository) {
+ const dispatchResult = record?.dispatch_result || null;
+ return {
+ ok: true,
+ configured: false,
+ platform_applied: false,
+ request_succeeded: false,
+ stop_confirmed: record?.phase === "stopped",
+ in_flight_state: "unknown",
+ reused: record?.reused === true,
+ persisted: record?.persisted !== false,
+ request_id: record?.request_id || null,
+ phase: record?.phase || null,
+ dispatch_result: dispatchResult,
+ action: record ? "stop" : null,
+ requested_at: record?.requested_at || null,
+ updated_at: record?.updated_at || null,
+ workflow_run_id: null,
+ workflow_run_attempt: null,
+ actions_url: dispatchResult === "accepted"
+ ? `https://github.com/${repository}/actions/workflows/manual-runtime-stop.yml`
+ : null,
+ runtime_observation: observation || { status: "unknown", request_succeeded: false },
+ };
+}
+
+export async function hkStopObservation() {
+ // Lifecycle snapshots identify a target id, not this stop request's account.
+ // A fresh disabled snapshot can belong to an older identity, so it stays unknown.
+ return { status: "unknown", request_succeeded: false };
+}
+
+export async function loadHkStopAccount(env) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const loaded = await loadAccountOptionsConfig(env);
+ if (loaded.source !== "durable_object" || !Number.isSafeInteger(loaded.revision)) {
+ throw new HttpError("hk_stop_source_unavailable", 409);
+ }
+ const matches = (loaded.options?.longbridge || []).filter((item) => item.key === "hk" && item.target_name === "hk");
+ if (matches.length !== 1) throw new HttpError("stop requires one configured target", 400);
+ const identity = hkStopSourceIdentity(matches[0], { key: "hk" });
+ if (!hkStopIdentityComplete(identity)) throw new HttpError("hk_stop_identity_incomplete", 400);
+ return { revision: loaded.revision, identity };
+}
+
+export async function runtimeControlSource(env, platform, targetName) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const source = await loadAccountOptionsConfig(env);
+ if (source.source !== "durable_object" || !Number.isSafeInteger(source.revision)) throw new HttpError("runtime_control_source_unavailable", 409);
+ const matches = (source.options?.[platform] || []).filter(item => item.target_name === targetName);
+ if (matches.length !== 1) throw new HttpError("runtime_control_identity_incomplete", 409);
+ const item = matches[0];
+ const identity = accountSettingsIdentity({ platform, key: item.key, config: item });
+ if (!runtimeControlIdentityIsComplete(identity)) throw new HttpError("runtime_control_identity_incomplete", 409);
+ return { item, identity, revision: source.revision };
+}
+
+export function presentRuntimeControl(record) {
+ let reason = null;
+ try { reason = record?.result_json ? JSON.parse(record.result_json).reason || null : null; } catch { /* invalid persisted result stays unclassified */ }
+ return { ok: record?.phase !== "rejected", request_id: record?.request_id || null, action: record?.action || null,
+ phase: record?.phase || null, updated_at: record?.updated_at || null,
+ unavailable_reason: reason || (record?.phase === "unknown" ? "runtime_control_result_unavailable" : null),
+ platform_applied: record?.phase === "applied" };
+}
+
+export async function readPlatformRuntimeControl(env, platform, targetName) {
+ const source = await runtimeControlSource(env, platform, targetName);
+ const args = { platform, key: source.item.key };
+ let { record } = await runtimeInstanceCommand(env, { action: "runtime_control_read", ...args });
+ if (record && ["reserved", "accepted", "unknown", "partial"].includes(record.phase)) {
+ const result = await readRuntimeControlReceipt({ repository: env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY,
+ token: env.RUNTIME_SETTINGS_DISPATCH_TOKEN, requestId: record.request_id, operation: record.action,
+ runId: record.workflow_run_id, requestedAt: record.requested_at });
+ if (result.run_id && !record.workflow_run_id) {
+ ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_record", ...args,
+ request_id: record.request_id, phase: "unknown", run_id: result.run_id }));
+ }
+ if (result.platform_run_id && record.workflow_run_id) {
+ ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_capture", ...args,
+ request_id: record.request_id, run_id: record.workflow_run_id, platform_run_id: result.platform_run_id, reason: result.reason }));
+ }
+ if (["applied", "partial", "protected", "rejected"].includes(result.status) && record.workflow_run_id) {
+ ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_resolve", ...args,
+ request_id: record.request_id, phase: result.status, run_id: record.workflow_run_id, reason: result.reason }));
+ }
+ }
+ let details = {};
+ try { details = JSON.parse(record?.result_json || "{}"); } catch { /* retain unknown */ }
+ if (record && ["accepted", "unknown", "partial"].includes(record.phase) && details.check_id && !details.check_complete) {
+ const checked = await readRuntimeControlReceipt({ repository: env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY,
+ token: env.RUNTIME_SETTINGS_DISPATCH_TOKEN, requestId: record.request_id, operation: record.action,
+ checkId: details.check_id, runId: details.check_run_id, requestedAt: details.check_requested_at });
+ if (checked.run_id) {
+ ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_record_check", ...args,
+ request_id: record.request_id, check_id: details.check_id, run_id: checked.run_id, complete: checked.complete === true }));
+ }
+ if (["applied", "partial", "protected", "rejected"].includes(checked.status) && checked.complete
+ && checked.platform_run_id === details.platform_run_id) {
+ ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_resolve", ...args,
+ request_id: record.request_id, phase: checked.status, run_id: record.workflow_run_id,
+ check_id: details.check_id, check_run_id: checked.run_id, reason: checked.reason }));
+ }
+ }
+ return presentRuntimeControl(record);
+}
+
+export function runtimeControlStopRequest(env, platform, targetName, source) {
+ const item = source.item;
+ const inputs = { ...item, platform, target_name: targetName };
+ const github = { repository: platformRepositories(env)[platform], variable_scope: resolvedVariableScope(item.variable_scope, inputs) };
+ if (github.variable_scope === "environment") github.environment = item.github_environment;
+ return { target_id: `${platform}/${targetName}`, github, runtime_target: {
+ platform_id: platform, deployment_selector: source.identity.deployment_selector,
+ account_selector: source.identity.account_selector.split(',').map(value => value.trim()).filter(Boolean),
+ account_scope: source.identity.account_scope, service_name: source.identity.service_name,
+ } };
+}
+
+export async function dispatchPlatformControlReadback(env, raw) {
+ if (raw.confirm !== "READ_ONLY" || !["ibkr", "schwab"].includes(raw.platform)
+ || Object.keys(raw).some(key => !["platform", "target_name", "operation", "confirm"].includes(key))) throw new HttpError("runtime_control_request_invalid", 400);
+ const targetName = cleanSlug(raw.target_name, "target_name");
+ const source = await runtimeControlSource(env, raw.platform, targetName);
+ const args = { platform: raw.platform, key: source.item.key };
+ // Reconcile the original QRS run first. The platform run ID can only come
+ // from its validated safe artifact and never from the client.
+ await readPlatformRuntimeControl(env, raw.platform, targetName);
+ let { record } = await runtimeInstanceCommand(env, { action: "runtime_control_read", ...args });
+ if (!record || !["accepted", "unknown", "partial"].includes(record.phase)) return json(presentRuntimeControl(record));
+ const checkId = crypto.randomUUID();
+ const begun = await runtimeInstanceCommand(env, { action: "runtime_control_begin_check", ...args, request_id: record.request_id, check_id: checkId });
+ if (begun.state !== "reserved") return json(presentRuntimeControl(begun.record));
+ record = begun.record;
+ const details = JSON.parse(record.result_json || "{}");
+ let runId = null, rejected = false;
+ try {
+ const response = await fetchWithTimeout(`https://api.github.com/repos/${env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY}/actions/workflows/manual-runtime-stop.yml/dispatches`, {
+ method: "POST", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN), body: JSON.stringify({ ref: "main", return_run_details: true,
+ inputs: { stop_request: JSON.stringify(runtimeControlStopRequest(env, raw.platform, targetName, source)), apply: "false", confirm: "READ_ONLY", apply_hk_stop: "false",
+ runtime_control_mode: "readback", runtime_control_operation: record.action, runtime_control_request_id: record.request_id,
+ runtime_control_check_id: checkId, runtime_control_platform_run_id: details.platform_run_id } }),
+ });
+ if (response.status === 200) {
+ const body = await response.json();
+ if (Number.isSafeInteger(body.workflow_run_id) && body.workflow_run_id > 0) runId = String(body.workflow_run_id);
+ } else if (response.status >= 400 && response.status < 500 && response.status !== 429) rejected = true;
+ } catch { /* Readback outcome may be unknown; next explicit refresh reads the same check. */ }
+ if (runId || rejected) ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_record_check", ...args,
+ request_id: record.request_id, check_id: checkId, run_id: runId, complete: rejected, reason: rejected ? "readback_dispatch_rejected" : null }));
+ return json(presentRuntimeControl(record));
+}
+
+export async function dispatchPlatformRuntimeControl(env, raw) {
+ if (raw.confirm !== "CONTROL_ONLY" || !["ibkr", "schwab"].includes(raw.platform)
+ || !["enable", "disable"].includes(raw.operation)
+ || Object.keys(raw).some(key => !["platform", "target_name", "operation", "request_id", "confirm"].includes(key))) throw new HttpError("runtime_control_request_invalid", 400);
+ const targetName = cleanSlug(raw.target_name, "target_name");
+ const requestId = raw.request_id || crypto.randomUUID();
+ if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("runtime_control_request_invalid", 400);
+ const source = await runtimeControlSource(env, raw.platform, targetName);
+ const args = { platform: raw.platform, key: source.item.key };
+ const claimed = await runtimeInstanceCommand(env, { action: "runtime_control_claim", ...args, identity: source.identity,
+ source_revision: source.revision, request_id: requestId, operation: raw.operation });
+ if (claimed.state !== "reserved") {
+ const body = presentRuntimeControl(claimed.record);
+ return json(claimed.state === "blocked" ? { ...body, ok: false, error: "runtime_control_pending" } : body, claimed.state === "blocked" ? 409 : 200);
+ }
+ const stopRequest = runtimeControlStopRequest(env, raw.platform, targetName, source);
+ let phase = "unknown", runId = null;
+ try {
+ const response = await fetchWithTimeout(`https://api.github.com/repos/${env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY}/actions/workflows/manual-runtime-stop.yml/dispatches`, {
+ method: "POST", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN), body: JSON.stringify({ ref: "main", return_run_details: true,
+ inputs: { stop_request: JSON.stringify(stopRequest), apply: "true", confirm: "CONTROL_ONLY", apply_hk_stop: "false",
+ runtime_control_operation: raw.operation, runtime_control_request_id: requestId } }),
+ });
+ if (response.status === 200) {
+ const body = await response.json();
+ if (Number.isSafeInteger(body.workflow_run_id) && body.workflow_run_id > 0) { phase = "accepted"; runId = String(body.workflow_run_id); }
+ } else if (response.status >= 400 && response.status < 500 && response.status !== 429) phase = "rejected";
+ } catch { /* Outcome may already have occurred; never resend. */ }
+ try {
+ const recorded = await runtimeInstanceCommand(env, { action: "runtime_control_record", ...args, request_id: requestId, phase, run_id: runId });
+ return json(presentRuntimeControl(recorded.record), recorded.record?.phase === "rejected" ? 502 : 200);
+ } catch { return json({ ...presentRuntimeControl(claimed.record), phase: "unknown" }); }
+}
+
+export async function readRuntimeStop(request, env, url) {
+ requireSameOrigin(request);
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ const platform = url.searchParams.get("platform");
+ const targetName = url.searchParams.get("target_name");
+ if (["ibkr", "schwab"].includes(platform) && targetName) return json(await readPlatformRuntimeControl(env, platform, targetName));
+ if (platform !== "longbridge" || targetName !== "hk") {
+ return json({
+ ok: true, configured: false, platform_applied: false, request_succeeded: false,
+ phase: null, runtime_observation: { status: "unknown", request_succeeded: false },
+ });
+ }
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const stored = await runtimeInstanceCommand(env, { action: "hk_stop_read" });
+ const observation = await hkStopObservation(env, stored.record);
+ const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
+ return json(presentHkStop(stored.record, observation, repository));
+}
+
+export async function dispatchHkRuntimeStop(env, raw) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const requestId = raw.request_id ? String(raw.request_id).trim().toLowerCase() : crypto.randomUUID();
+ if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("invalid_hk_stop_request_id", 400);
+ const source = await loadHkStopAccount(env);
+ const identity = source.identity;
+ const identityJson = canonicalResearchTaskJson(identity);
+ const runtimeJson = canonicalResearchTaskJson({
+ platform_id: identity.platform_id,
+ deployment_selector: identity.deployment_selector,
+ account_selector: identity.account_selector,
+ account_scope: identity.account_scope,
+ service_name: identity.service_name,
+ });
+ const claimed = await runtimeInstanceCommand(env, {
+ action: "hk_stop_claim",
+ request_id: requestId,
+ action_name: "stop",
+ source_revision: source.revision,
+ identity: source.identity,
+ source_identity_sha256: await sha256Hex(identityJson),
+ runtime_identity_sha256: await sha256Hex(runtimeJson),
+ });
+ const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
+ if (claimed.state !== "reserved") {
+ const observation = await hkStopObservation(env, claimed.record);
+ const body = presentHkStop({ ...claimed.record, reused: true }, observation, repository);
+ if (claimed.state === "blocked") return json({ ...body, ok: false, error: "hk_stop_request_pending" }, 409);
+ return json(body);
+ }
+ const stored = claimed.record;
+ const stopRequest = {
+ target_id: HK_STOP_TARGET_ID,
+ github: {
+ repository: "QuantStrategyLab/LongBridgePlatform",
+ variable_scope: "environment",
+ environment: identity.github_environment,
+ },
+ runtime_target: {
+ platform_id: "longbridge",
+ deployment_selector: identity.deployment_selector,
+ account_selector: identity.account_selector,
+ account_scope: identity.account_scope,
+ service_name: identity.service_name,
+ },
+ correlation: {
+ request_id: stored.request_id,
+ source_revision: stored.source_revision,
+ source_identity_sha256: stored.source_identity_sha256,
+ },
+ };
+ let outcome = "unknown";
+ try {
+ const response = await fetchWithTimeout(`https://api.github.com/repos/${repository}/actions/workflows/manual-runtime-stop.yml/dispatches`, {
+ method: "POST",
+ headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
+ body: JSON.stringify({
+ ref: env.RUNTIME_SETTINGS_REF || "main",
+ inputs: {
+ stop_request: JSON.stringify(stopRequest),
+ apply: "true",
+ confirm: "STOP_ONLY",
+ apply_hk_stop: "true",
+ },
+ }),
+ });
+ if (response.status === 204) outcome = "accepted";
+ else if (response.status >= 400 && response.status < 500) outcome = "rejected";
+ } catch {
+ outcome = "unknown";
+ }
+ try {
+ const recorded = await runtimeInstanceCommand(env, {
+ action: "hk_stop_record",
+ request_id: claimed.record.request_id,
+ phase: outcome,
+ });
+ const observation = await hkStopObservation(env, recorded.record);
+ return json(presentHkStop(recorded.record, observation, repository));
+ } catch {
+ const observation = { status: "unknown", request_succeeded: false };
+ return json(presentHkStop({ ...claimed.record, phase: "reserved", dispatch_result: null, persisted: false }, observation, repository));
+ }
+}
+
+export async function dispatchRuntimeStop(request, env) {
+ requireEnv(env, "RUNTIME_SETTINGS_DISPATCH_TOKEN");
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ const raw = await request.json();
+ if (raw && !Array.isArray(raw) && typeof raw === "object" && ["ibkr", "schwab"].includes(raw.platform) && raw.operation === "inspect")
+ return await dispatchPlatformControlReadback(env, raw);
+ if (raw && !Array.isArray(raw) && typeof raw === "object" && ["ibkr", "schwab"].includes(raw.platform) && raw.operation)
+ return await dispatchPlatformRuntimeControl(env, raw);
+ const hkStop = raw && !Array.isArray(raw) && raw.platform === "longbridge" && raw.target_name === "hk";
+ const allowedKeys = hkStop ? ["platform", "target_name", "confirm", "request_id"] : ["platform", "target_name", "confirm"];
+ if (!raw || Array.isArray(raw) || typeof raw !== "object"
+ || Object.keys(raw).some((key) => !allowedKeys.includes(key))
+ || raw.confirm !== "STOP_ONLY") {
+ throw new HttpError("stop accepts only platform, target_name and STOP_ONLY confirmation", 400);
+ }
+ const platform = cleanChoice(raw.platform, SUPPORTED_PLATFORMS, "platform");
+ const targetName = cleanSlug(raw.target_name, "target_name");
+ if (platform === "longbridge" && targetName === "hk") return await dispatchHkRuntimeStop(env, raw);
+ const accountConfig = await loadAccountOptionsConfig(env);
+ const matches = (accountConfig.options?.[platform] || []).filter((item) => item.target_name === targetName);
+ if (matches.length !== 1) throw new HttpError("stop requires one configured target", 400);
+ // Derive routing only from protected account configuration, not form edits.
+ // The workflow independently checks this identity against current variables.
+ const inputs = { ...matches[0], platform, target_name: targetName };
+ inputs.variable_scope = resolvedVariableScope(inputs.variable_scope, inputs);
+ for (const field of ["deployment_selector", "account_scope", "account_selector", "service_name", "github_environment"]) {
+ inputs[field] = inputs[field] || defaultInputValue(field, inputs);
+ }
+ const identity = {
+ platform_id: platform,
+ deployment_selector: inputs.deployment_selector,
+ account_selector: String(inputs.account_selector || "").split(",").map((item) => item.trim()).filter(Boolean),
+ account_scope: inputs.account_scope,
+ service_name: inputs.service_name,
+ };
+ if (!identity.deployment_selector || !identity.account_selector.length || !identity.account_scope || !identity.service_name) {
+ throw new HttpError("stop target identity is incomplete", 400);
+ }
+ const github = { repository: platformRepositories(env)[platform], variable_scope: inputs.variable_scope };
+ if (github.variable_scope === "environment") github.environment = inputs.github_environment;
+ const stopRequest = { target_id: `${platform}/${targetName}`, github, runtime_target: identity };
+ const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
+ const workflow = "manual-runtime-stop.yml";
+ try {
+ const response = await fetchWithTimeout(`https://api.github.com/repos/${repository}/actions/workflows/${workflow}/dispatches`, {
+ method: "POST",
+ headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
+ body: JSON.stringify({
+ ref: env.RUNTIME_SETTINGS_REF || "main",
+ inputs: { stop_request: JSON.stringify(stopRequest), apply: "true", confirm: "STOP_ONLY" },
+ }),
+ });
+ if (!response.ok) throw new Error("dispatch failed");
+ } catch {
+ return json({ ok: false, error: "stop dispatch unverified; check the existing run before retrying" }, 502);
+ }
+ return json({
+ ok: true, configured: false, platform_applied: false,
+ actions_url: `https://github.com/${repository}/actions/workflows/${workflow}`,
+ });
+}
+
+export async function binanceResumeTarget(values, option) {
+ const target = parseJsonObject(values.RUNTIME_TARGET_JSON);
+ const continuity = target?.live_continuity;
+ if (values.RUNTIME_TARGET_ENABLED !== "false" || values.BINANCE_RECOVERY_CONTROL_ENABLED !== "true"
+ || !["", "false"].includes(values.BINANCE_DRY_RUN || "")
+ || !["", "crypto_live_pool_rotation"].includes(values.STRATEGY_PROFILE || "")
+ || values.CLOUD_RUN_SERVICE_TARGETS_JSON
+ || target?.platform_id !== "binance" || target.strategy_profile !== "crypto_live_pool_rotation"
+ || target.execution_mode !== "live" || target.dry_run_only !== false
+ || continuity?.baseline_kind !== "legacy_authorized"
+ || !["RECONCILE_ONLY", "ACTIVE_LKG"].includes(continuity?.state)
+ || typeof continuity.baseline_id !== "string" || !continuity.baseline_id.trim()
+ || typeof continuity.captured_at !== "string" || !continuity.captured_at.trim()
+ || !/^[a-f0-9]{64}$/.test(continuity.baseline_target_sha256 || "")) return null;
+ const inputs = { ...option, platform: "binance" };
+ const identity = { platform_id: "binance" };
+ for (const field of ["deployment_selector", "account_selector", "account_scope", "service_name"]) {
+ const value = inputs[field] || defaultInputValue(field, inputs);
+ identity[field] = field === "account_selector"
+ ? String(value || "").split(",").map((item) => item.trim()).filter(Boolean) : value;
+ if (!value || JSON.stringify(identity[field]) !== JSON.stringify(target[field])) return null;
+ }
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(values.RUNTIME_TARGET_JSON));
+ return {
+ runtime_target: identity,
+ runtime_target_sha256: [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join(""),
+ };
+}
+
+export async function dispatchBinanceResume(request, env) {
+ requireEnv(env, "RUNTIME_SETTINGS_DISPATCH_TOKEN");
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ const raw = await request.json();
+ if (!raw || Array.isArray(raw) || typeof raw !== "object"
+ || Object.keys(raw).some((key) => !["platform", "target_name", "runtime_target_sha256", "confirm"].includes(key))
+ || raw.platform !== "binance" || raw.confirm !== "RESUME_EXISTING"
+ || typeof raw.runtime_target_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(raw.runtime_target_sha256)) {
+ throw new HttpError("resume accepts only the existing Binance target and RESUME_EXISTING confirmation", 400);
+ }
+ const config = await loadAccountOptionsConfig(env);
+ const matches = (config.options?.binance || []).filter((item) => item.target_name === raw.target_name);
+ const repository = platformRepositories(env).binance;
+ if (matches.length !== 1 || repository !== "QuantStrategyLab/BinancePlatform"
+ || resolvedVariableScope(matches[0].variable_scope, { ...matches[0], platform: "binance" }) !== "repository") {
+ throw new HttpError("resume requires one configured Binance repository target", 400);
+ }
+ let target;
+ try {
+ const variables = await fetchGithubVariables(env.RUNTIME_SETTINGS_DISPATCH_TOKEN, repository, "repository", "");
+ target = await binanceResumeTarget(Object.fromEntries(variables), matches[0]);
+ } catch {
+ return json({ ok: false, error: "resume source unavailable; no request submitted" }, 502);
+ }
+ if (!target || target.runtime_target_sha256 !== raw.runtime_target_sha256) {
+ return json({ ok: false, error: "existing recovery configuration changed or unavailable; refresh before continuing" }, 409);
+ }
+ // Only the external switch is requested. The platform's private ACTIVE_LKG
+ // validator remains mandatory; a console confirmation cannot activate it.
+ const resumeRequest = { target_id: `binance/${matches[0].target_name}`,
+ github: { repository, variable_scope: "repository" }, ...target };
+ const settingsRepository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
+ const workflow = "manual-binance-resume.yml";
+ try {
+ const response = await fetchWithTimeout(`https://api.github.com/repos/${settingsRepository}/actions/workflows/${workflow}/dispatches`, {
+ method: "POST", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
+ body: JSON.stringify({ ref: "main", inputs: { resume_request: JSON.stringify(resumeRequest), apply: "true", confirm: "RESUME_EXISTING" } }),
+ });
+ if (!response.ok) throw new Error("dispatch failed");
+ } catch {
+ return json({ ok: false, error: "resume dispatch unverified; check the existing run before retrying" }, 502);
+ }
+ return json({ ok: true, configured: false, platform_applied: false,
+ actions_url: `https://github.com/${settingsRepository}/actions/workflows/${workflow}` });
+}
+
+export async function dispatchSwitch(request, env) {
+ requireEnv(env, "RUNTIME_SETTINGS_DISPATCH_TOKEN");
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+
+ const rawInput = await request.json();
+ const inputs = normalizeSwitchInputs(rawInput);
+ assertSwitchIntent(inputs);
+ if (inputs.live_continuity_state !== "NONE") {
+ return json({
+ ok: false,
+ error: "legacy continuity recovery requires the private reconciliation recovery controller; manual switch cannot restore execution",
+ }, 409);
+ }
+ const accountConfig = await loadAccountOptionsConfig(env);
+ const accountOption = assertConfiguredAccount(inputs, accountConfig.options);
+ assertStrategyAllowedForAccount(inputs, accountOption, await loadStrategyProfilesConfig(env));
+ if (!SWITCH_ACTIVATION_CONNECTED) {
+ return json({
+ ok: false,
+ error: "账户应用尚未接通,系统未提交变更",
+ workflow_dispatched: false,
+ }, 409);
+ }
+ const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
+ const workflow = env.RUNTIME_SETTINGS_WORKFLOW || DEFAULT_WORKFLOW;
+ const apiUrl = `https://api.github.com/repos/${repository}/actions/workflows/${workflow}/dispatches`;
+ const response = await fetchWithTimeout(apiUrl, {
+ method: "POST",
+ headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
+ body: JSON.stringify({
+ ref: env.RUNTIME_SETTINGS_REF || "main",
+ inputs,
+ }),
+ });
+
+ if (!response.ok) {
+ const text = await response.text();
+ return json({ ok: false, error: `GitHub dispatch failed: ${text.slice(0, 600)}` }, 502);
+ }
+
+ return json({
+ ok: true,
+ repository,
+ workflow,
+ actions_url: `https://github.com/${repository}/actions/workflows/${workflow}`,
+ account_options_sync: {
+ synced: false,
+ deferred: true,
+ reason: "workflow_success_required",
+ },
+ inputs,
+ });
+}
+
+export async function syncDefaultStrategyForAccount(env, accountOptions, inputs, session) {
+ if (hasRuntimeInstanceStore(env)) {
+ try {
+ await runtimeInstanceCommand(env, { action: "sync_defaults", actor: session?.login || "github-actions", inputs });
+ return { synced: true, audit_logged: true };
+ } catch (error) {
+ return { synced: false, reason: error instanceof HttpError ? error.message : "runtime_instances_unavailable" };
+ }
+ }
+ if (!hasConfigStore(env)) return { synced: false, reason: "kv_not_bound" };
+ try {
+ const { options, changed } = updateAccountOptionsDefaultStrategy(accountOptions, inputs);
+ let auditLogged = false;
+ if (changed) {
+ await writeConfigJson(env, ACCOUNT_OPTIONS_KEY, validateAccountOptionsSchemaOrThrow(options));
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: session?.login || "",
+ action: "sync_default_strategy",
+ platform: inputs.platform,
+ target_name: inputs.target_name,
+ strategy_profile: inputs.strategy_profile,
+ });
+ auditLogged = true;
+ } catch {
+ auditLogged = false;
+ }
+ }
+ return { synced: true, changed, audit_logged: auditLogged };
+ } catch (error) {
+ return { synced: false, error: error.message || "account option sync failed" };
+ }
+}
+
+export async function syncAccountDefaultResponse(request, env) {
+ requireInternalSyncToken(request, env);
+ let rawInput;
+ try {
+ rawInput = await request.json();
+ } catch {
+ return json({ ok: false, error: "request body must be valid JSON" }, 400);
+ }
+ let inputs;
+ try {
+ inputs = normalizeSwitchInputs(rawInput);
+ } catch (error) {
+ if (isFrozenStrategyProfile({ profile: rawInput?.strategy_profile })) {
+ throw new HttpError("frozen strategy requires valid continuity input", 409);
+ }
+ throw error;
+ }
+ const accountConfig = await loadAccountOptionsConfig(env);
+ const strategyProfiles = await loadStrategyProfilesConfig(env);
+ const strategy = strategyProfiles.find((item) => sameStrategyProfile(item.profile, inputs.strategy_profile));
+ if (!strategy) throw new Error(`strategy ${inputs.strategy_profile} is not configured`);
+
+ let accountOptions = accountConfig.options;
+ let accountOption = configuredAccountForInputs(inputs, accountOptions);
+ let registeredLegacyContinuityAccount = false;
+ if (!accountOption) {
+ if (isFrozenStrategyProfile(strategy)) throw new HttpError(`strategy ${inputs.strategy_profile} is frozen for new selection`, 409);
+ if (hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instance_registration_requires_management", 409);
+ const registration = registerLegacyContinuityAccount(env, accountOptions, inputs, strategy);
+ accountOptions = registration.options;
+ accountOption = registration.account;
+ registeredLegacyContinuityAccount = registration.registered;
+ if (registeredLegacyContinuityAccount) {
+ await writeConfigJson(env, ACCOUNT_OPTIONS_KEY, validateAccountOptionsSchemaOrThrow(accountOptions));
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "github-actions",
+ action: "register_legacy_continuity_account",
+ platform: inputs.platform,
+ target_name: inputs.target_name,
+ strategy_profile: inputs.strategy_profile,
+ live_continuity_state: inputs.live_continuity_state,
+ });
+ } catch {
+ // The routing registration is still valid if its non-critical audit
+ // append fails; callers receive the registration result below.
+ }
+ }
+ }
+ if (!accountOption) throw new Error("switch inputs do not match configured account options");
+ if (isFrozenStrategyProfile(strategy) && !sameStrategyProfile(accountOption.default_strategy_profile, inputs.strategy_profile)) {
+ throw new HttpError(`strategy ${inputs.strategy_profile} requires an existing matching account default`, 409);
+ }
+ assertStrategyAllowedForAccount(inputs, accountOption, strategyProfiles);
+ const result = await syncDefaultStrategyForAccount(env, accountOptions, inputs, {
+ login: "github-actions",
+ });
+ const kvSyncSkipped = result.reason === "kv_not_bound";
+ const accountOptionsSync = kvSyncSkipped ? { ...result, skipped: true } : result;
+ return json(
+ {
+ ok: result.synced || kvSyncSkipped,
+ account_options_sync: accountOptionsSync,
+ legacy_continuity_account_registered: registeredLegacyContinuityAccount,
+ },
+ result.synced || kvSyncSkipped ? 200 : 500,
+ );
+}
+
+export function requireInternalSyncToken(request, env) {
+ const expected = env.STRATEGY_SWITCH_SYNC_TOKEN || env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
+ if (!expected) throw new HttpError("internal sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("internal sync token is invalid", 401);
+}
+
+export async function syncStrategyProfilesResponse(request, env) {
+ requireInternalSyncToken(request, env);
+ const result = await syncStrategyProfilesConfig(env, { login: "github-actions" });
+ const kvSyncSkipped = result.reason === "kv_not_bound";
+ const strategyProfilesSync = kvSyncSkipped ? { ...result, skipped: true } : result;
+ return json(
+ {
+ ok: result.synced || kvSyncSkipped,
+ strategy_profiles_sync: strategyProfilesSync,
+ strategy_profiles_count: result.count,
+ },
+ result.synced || kvSyncSkipped ? 200 : 500,
+ );
+}
+
+export async function syncStrategyHealthResponse(request, env) {
+ requireDedicatedStrategyHealthSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "strategy health KV is not configured" }, 503);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, STRATEGY_HEALTH_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid strategy health payload" }, error.status || 400);
+ }
+
+ let snapshot;
+ try {
+ snapshot = normalizeStrategyHealthSnapshot(raw, "strategy health snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid strategy health payload" }, 400);
+ }
+
+ await writeConfigJson(env, STRATEGY_HEALTH_SNAPSHOT_KEY, snapshot);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "strategy-health-sync",
+ action: "sync_strategy_health",
+ schema_version: snapshot.schema_version,
+ strategy_count: snapshot.summary.strategy_count,
+ data_status: snapshot.data_status,
+ });
+ } catch {
+ // Snapshot delivery remains successful; audit data must never expose the payload.
+ }
+ return json({
+ ok: true,
+ schema_version: snapshot.schema_version,
+ strategy_count: snapshot.summary.strategy_count,
+ generated_at: snapshot.generated_at,
+ });
+}
+
+export async function strategyHealthResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json(emptyStrategyHealthPayload("snapshot_unavailable"));
+
+ let snapshot;
+ try {
+ const stored = await readConfigJson(env, STRATEGY_HEALTH_SNAPSHOT_KEY);
+ if (!stored) return json(emptyStrategyHealthPayload("snapshot_unavailable"));
+ snapshot = normalizeStrategyHealthSnapshot(stored, STRATEGY_HEALTH_SNAPSHOT_KEY);
+ } catch {
+ return json(emptyStrategyHealthPayload("snapshot_invalid"));
+ }
+
+ const ttlSeconds = strategyHealthStaleTtlSeconds(env);
+ const freshnessTimestamps = [snapshot.generated_at, snapshot.computed_at]
+ .filter(Boolean)
+ .map((value) => Date.parse(value));
+ const freshnessAt = freshnessTimestamps.length ? Math.min(...freshnessTimestamps) : Number.NaN;
+ const now = Date.now();
+ const futureBeyondClockSkew = Number.isFinite(freshnessAt) && freshnessAt > now + 5 * 60 * 1000;
+ const ageSeconds = futureBeyondClockSkew
+ ? Number.POSITIVE_INFINITY
+ : Number.isFinite(freshnessAt)
+ ? Math.max(0, (now - freshnessAt) / 1000)
+ : Number.POSITIVE_INFINITY;
+ if (["ready", "partial"].includes(snapshot.data_status) && ageSeconds > ttlSeconds) {
+ snapshot.data_status = "stale";
+ }
+ return json(snapshot);
+}
+
+export async function humanDecisionRequestKey({ requestId, kind, actor, subjectId, materialKey, action, target }) {
+ if (requestId !== undefined && requestId !== null && requestId !== "") {
+ const text = String(requestId).trim();
+ if (!/^[A-Za-z0-9._:-]{1,128}$/.test(text)) throw new HttpError("invalid request_id", 400);
+ return `id:${kind}:${text}`;
+ }
+ const digest = await calculateOwnerDecisionSha256({
+ actor, kind, subject_id: subjectId, material_key: materialKey, action, target: target || null,
+ });
+ return `fp:${digest}`;
+}
+
+export async function researchPromotionMaterialKey(ticket) {
+ return calculateOwnerDecisionSha256({
+ ticket_id: ticket.ticket_id,
+ strategy_profile: ticket.strategy_profile,
+ domain: ticket.domain,
+ proposed_params: ticket.proposed_params,
+ shadow_passed: ticket.shadow_passed,
+ shadow_evidence_kind: ticket.shadow_evidence_kind,
+ });
+}
+
+// The legacy six-field material key remains the durable terminal index. This
+// independent versioned snapshot binds all saved producer review content without
+// rekeying historical records or hashing post-decision/observation-only fields.
+export function researchPromotionReviewMaterial(ticket) {
+ return {
+ schema_version: "qsl_promotion_review_material.v2",
+ ticket_id: ticket.ticket_id, strategy_profile: ticket.strategy_profile, domain: ticket.domain,
+ proposed_params: ticket.proposed_params, shadow_passed: ticket.shadow_passed,
+ shadow_evidence_kind: ticket.shadow_evidence_kind,
+ drift_status: ticket.drift_status, drift_score: ticket.drift_score,
+ budget: ticket.budget, search_iterations: ticket.search_iterations,
+ suggested_risk_profile: ticket.suggested_risk_profile,
+ notification_subject: ticket.notification_subject, notification_body: ticket.notification_body,
+ notes: ticket.notes, research_summary: ticket.research_summary || null,
+ };
+}
+export const RESEARCH_PROMOTION_REVIEW_INVALID = "research_promotion_review_material_invalid";
+export class ResearchPromotionReviewMaterialError extends HttpError {
+ constructor() { super(RESEARCH_PROMOTION_REVIEW_INVALID, 400); }
+}
+export async function researchPromotionReviewBinding(ticket) {
+ let canonical;
+ try {
+ canonical = canonicalResearchTaskJson(researchPromotionReviewMaterial(ticket));
+ } catch (error) {
+ // Only canonical data validation is recoverable per ticket. Hash/storage
+ // failures must not be relabelled as invalid material or a healthy queue.
+ if (error?.message === "research task must use finite JSON values"
+ || error?.message === "research task must use JSON values") throw new ResearchPromotionReviewMaterialError();
+ throw error;
+ }
+ return { schema_version: "qsl_promotion_review_binding.v2", review_sha256: await sha256Hex(canonical) };
+}
+export function promotionReviewBindingsMatch(left, right) {
+ return left?.schema_version === "qsl_promotion_review_binding.v2" && right?.schema_version === left.schema_version
+ && /^[0-9a-f]{64}$/.test(left.review_sha256) && left.review_sha256 === right.review_sha256;
+}
+export function promotionMaterialReviewBinding(row) {
+ try {
+ const binding = JSON.parse(row?.summary_json || "{}").review_binding;
+ return promotionReviewBindingsMatch(binding, binding) ? { schema_version: "qsl_promotion_review_binding.v2", review_sha256: binding.review_sha256 } : null;
+ } catch { return null; }
+}
+
+export async function recoveryDecisionMaterialKey(recovery) {
+ if (recovery.mode === "initial_enrollment") return calculateOwnerDecisionSha256({
+ mode: recovery.mode, recovery_id: recovery.recovery_id,
+ candidate_sha256: recovery.candidate?.candidate_sha256 || recovery.candidate_sha256,
+ facts_sha256: recovery.candidate?.facts_sha256 || recovery.facts_sha256,
+ });
+ return calculateOwnerDecisionSha256({
+ recovery_id: recovery.recovery_id,
+ candidate_sha256: recovery.candidate_sha256,
+ dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
+ });
+}
+
+export async function mirrorConfigJson(env, key, value) {
+ try {
+ await writeConfigJson(env, key, value);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+export async function readLegacyConfig(env, key) {
+ try {
+ return { value: await readConfigJson(env, key), blocked: false, unreadable: false };
+ } catch (error) {
+ if (String(error?.message || "").includes("must be valid JSON")) return { value: null, blocked: true, unreadable: false };
+ return { value: null, blocked: false, unreadable: true };
+ }
+}
+
+export function humanDecisionTimestamp(value) {
+ return String(value || new Date().toISOString()).replace(/\.\d{3}Z$/, "Z");
+}
+
+// Actionable material expires when the evidence that produced it would itself be
+// stale. A missing or future-dated anchor yields null, which callers treat as
+// "not actionable" rather than inventing authority.
+export function controlPlaneDecisionExpiryAt(snapshot, ttlSeconds, now = Date.now()) {
+ const timestamps = [snapshot?.generated_at, snapshot?.computed_at]
+ .filter(Boolean)
+ .map((value) => Date.parse(value))
+ .filter((value) => Number.isFinite(value));
+ if (!timestamps.length) return null;
+ const observedAt = Math.min(...timestamps);
+ if (observedAt > now + 5 * 60 * 1000) return null;
+ return observedAt + ttlSeconds * 1000;
+}
+
+export function reconciliationRecoveryDecisionExpiryAt(recovery, source, ttlSeconds, now = Date.now()) {
+ const sourceExpiry = controlPlaneDecisionExpiryAt(source, ttlSeconds, now);
+ if (sourceExpiry == null) return null;
+ const observedAt = Date.parse(recovery.mode === "initial_enrollment"
+ ? recovery.candidate?.last_observed_at
+ : recovery.last_observed_at);
+ if (!Number.isFinite(observedAt) || observedAt > now + 5 * 60 * 1000) return null;
+ return Math.min(sourceExpiry, observedAt + ttlSeconds * 1000);
+}
+
+export async function publishHumanOwnerMaterials(env, snapshot, sourceId) {
+ const ownerCandidates = (snapshot.candidates || []).filter(isOwnerDecisionCandidate);
+ if (!ownerCandidates.length && !hasRuntimeInstanceStore(env)) return { ok: true, skipped: true };
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const expiresAtMs = controlPlaneDecisionExpiryAt(snapshot, controlPlaneStaleTtlSeconds(env));
+ const grouped = new Map();
+ for (const candidate of ownerCandidates) {
+ const list = grouped.get(candidate.candidate_id) || [];
+ list.push(candidate);
+ grouped.set(candidate.candidate_id, list);
+ }
+ const materials = [];
+ const duplicateSubjectIds = [];
+ for (const [subjectId, list] of grouped) {
+ if (list.length > 1) duplicateSubjectIds.push(subjectId);
+ const candidate = list[0];
+ const materialKey = await ownerDecisionCandidateEvidenceSha256(candidate);
+ const legacyRead = await readLegacyConfig(env, ownerDecisionCurrentKey(subjectId));
+ if (legacyRead.unreadable) throw new HttpError("human_decision_legacy_unreadable", 503);
+ let legacy = null;
+ if (legacyRead.blocked) legacy = { blocked: true };
+ else if (legacyRead.value) {
+ try {
+ const intent = await normalizeOwnerDecisionIntent(legacyRead.value, ownerDecisionCurrentKey(subjectId));
+ if (intent.candidate_id !== subjectId || intent.candidate_evidence_sha256 !== materialKey) legacy = { blocked: true };
+ else {
+ legacy = {
+ record: {
+ action: intent.decision,
+ actor: intent.decided_by,
+ decided_at: intent.decided_at,
+ material_key: materialKey,
+ target_json: canonicalResearchTaskJson({ decision: intent.decision }),
+ payload: intent,
+ },
+ };
+ }
+ } catch {
+ legacy = { blocked: true };
+ }
+ }
+ materials.push({
+ subject_id: subjectId,
+ material_key: materialKey,
+ summary_json: JSON.stringify({ candidate_id: subjectId }),
+ eligible: list.length === 1 && candidate.freshness?.status === "fresh",
+ expires_at_ms: expiresAtMs,
+ legacy,
+ });
+ }
+ return runtimeInstanceCommand(env, {
+ action: "owner_sync_materials",
+ actor: "control-plane-sync",
+ source_id: sourceId,
+ updated_at: humanDecisionTimestamp(),
+ now_ms: Date.now(),
+ replace_source: true,
+ materials,
+ duplicate_subject_ids: duplicateSubjectIds,
+ });
+}
+
+export function recoveryMaterialEligible(recovery, sourceFreshness, evidenceFreshness) {
+ if (recovery.mode === "initial_enrollment") return sourceFreshness?.data_status === "ready" && evidenceFreshness?.data_status === "ready"
+ && Object.values(recovery.candidate.coverage).every(status => status === "complete");
+ return sourceFreshness?.data_status === "ready"
+ && evidenceFreshness?.data_status === "ready"
+ && recovery.readiness === "awaiting_human_confirmation"
+ && recovery.reconciliation_state === "RECONCILE_ONLY"
+ && !recovery.blocker_codes.length
+ && recovery.dual_review.evidence_binding_sha256 === recovery.candidate_sha256
+ && recovery.evidence_sample_count >= 1;
+}
+
+export async function publishHumanRecoveryMaterials(env, source) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const ttlSeconds = reconciliationRecoveryStaleTtlSeconds(env);
+ const now = Date.now();
+ const sourceFreshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
+ const grouped = new Map();
+ for (const recovery of source.recoveries || []) {
+ const list = grouped.get(recovery.recovery_id) || [];
+ list.push(recovery);
+ grouped.set(recovery.recovery_id, list);
+ }
+ const materials = [];
+ const duplicateSubjectIds = [];
+ for (const [subjectId, list] of grouped) {
+ if (list.length > 1) duplicateSubjectIds.push(subjectId);
+ const recovery = list[0];
+ const evidenceFreshness = reconciliationRecoveryEvidenceFreshness(recovery, sourceFreshness, ttlSeconds, now);
+ const materialKey = await recoveryDecisionMaterialKey(recovery);
+ const legacyRead = recovery.mode === "initial_enrollment" ? { unreadable: false, blocked: false, value: null }
+ : await readLegacyConfig(env, reconciliationRecoveryConfirmationCurrentKey(subjectId));
+ if (legacyRead.unreadable) throw new HttpError("human_decision_legacy_unreadable", 503);
+ let legacy = null;
+ if (legacyRead.blocked) legacy = { blocked: true };
+ else if (legacyRead.value) {
+ try {
+ const confirmation = await normalizeReconciliationRecoveryConfirmation(legacyRead.value, reconciliationRecoveryConfirmationCurrentKey(subjectId));
+ if (confirmation.recovery_id !== subjectId || confirmation.candidate_sha256 !== recovery.candidate_sha256 || confirmation.dual_review_binding_sha256 !== recovery.dual_review.evidence_binding_sha256) {
+ legacy = { blocked: true };
+ } else {
+ legacy = {
+ record: {
+ action: "approve",
+ actor: confirmation.confirmed_by,
+ decided_at: confirmation.confirmed_at,
+ material_key: materialKey,
+ target_json: canonicalResearchTaskJson({ decision: "approve" }),
+ payload: confirmation,
+ },
+ };
+ }
+ } catch {
+ legacy = { blocked: true };
+ }
+ }
+ materials.push({
+ subject_id: subjectId,
+ material_key: materialKey,
+ summary_json: JSON.stringify({ recovery_id: subjectId }),
+ eligible: list.length === 1 && recoveryMaterialEligible(recovery, sourceFreshness, evidenceFreshness),
+ expires_at_ms: reconciliationRecoveryDecisionExpiryAt(recovery, source, ttlSeconds, now),
+ legacy,
+ });
+ }
+ return runtimeInstanceCommand(env, {
+ action: "recovery_sync_materials",
+ actor: "reconciliation-recovery-source-sync",
+ source_id: source.source_id,
+ updated_at: humanDecisionTimestamp(),
+ now_ms: Date.now(),
+ replace_source: true,
+ materials,
+ duplicate_subject_ids: duplicateSubjectIds,
+ });
+}
+
+export async function publishHumanPromotionMaterial(env, ticket, existing) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const materialKey = await researchPromotionMaterialKey(ticket);
+ let legacy = null;
+ if (existing && (existing.state === "human_accepted" || existing.state === "human_rejected")) {
+ const existingKey = await researchPromotionMaterialKey(existing);
+ const actor = String(existing.human_decision_actor || "").trim();
+ if (!actor || !existing.human_decided_at || existingKey !== materialKey) legacy = { blocked: true };
+ else {
+ legacy = {
+ record: {
+ action: existing.state === "human_accepted" ? "accept" : "reject",
+ actor,
+ decided_at: existing.human_decided_at,
+ material_key: materialKey,
+ target_json: canonicalResearchTaskJson({
+ selected_account: existing.selected_account || null,
+ confirmation: {
+ target_platform: existing.confirmation_target_platform,
+ execution_mode: existing.confirmation_execution_mode,
+ risk_profile: existing.confirmation_risk_profile,
+ },
+ }),
+ payload: { ticket: existing, selected_account: existing.selected_account || null, proposed_params: existing.proposed_params },
+ },
+ };
+ }
+ }
+ return runtimeInstanceCommand(env, {
+ action: "promotion_sync_materials",
+ actor: "research-promotion-ticket-sync",
+ source_id: "research-promotion",
+ updated_at: humanDecisionTimestamp(),
+ now_ms: Date.now(),
+ replace_source: false,
+ materials: [{
+ subject_id: ticket.ticket_id,
+ material_key: materialKey,
+ summary_json: JSON.stringify({
+ ticket_id: ticket.ticket_id,
+ strategy_profile: ticket.strategy_profile,
+ domain: ticket.domain,
+ review_binding: await researchPromotionReviewBinding(ticket),
+ }),
+ eligible: true,
+ expires_at_ms: Date.now() + controlPlaneStaleTtlSeconds(env) * 1000,
+ legacy,
+ }],
+ });
+}
+
+// A fixed projection of the durable terminal record, never a request echo or KV fallback.
+export async function humanDecisionReceipt(record, expected) {
+ const invalid = () => { throw new HttpError("human_decision_receipt_unavailable", 503); };
+ const text = (value, max) => typeof value === "string" && value.length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
+ const actions = { owner: ["approve_limited_live_canary", "keep_parked"], recovery: ["approve", "reject"], promotion: ["accept", "reject"] };
+ if (!record || !actions[record.kind]?.includes(record.action) || !text(record.subject_id, 256)
+ || !/^[0-9a-f]{64}$/.test(record.material_key) || !text(record.actor, 100)
+ || !text(record.decided_at, 40) || !Number.isFinite(Date.parse(record.decided_at))
+ || record.kind !== expected.kind || record.subject_id !== expected.subject_id || record.material_key !== expected.material_sha256) invalid();
+ let target;
+ try { target = JSON.parse(record.target_json); } catch { invalid(); }
+ let projection;
+ if (record.kind === "promotion") {
+ const account = target?.selected_account;
+ const confirmation = target?.confirmation;
+ if (account != null && (!SUPPORTED_PLATFORMS.includes(account.platform) || !text(account.key, 128))) invalid();
+ if (confirmation != null && (!SUPPORTED_PLATFORMS.includes(confirmation.target_platform)
+ || !["live", "paper", "dry_run"].includes(confirmation.execution_mode)
+ || !RESEARCH_PROMOTION_RISK_PROFILES.includes(confirmation.risk_profile))) invalid();
+ if (record.action === "accept" && (!account || !confirmation || account.platform !== confirmation.target_platform)) invalid();
+ if (record.payload?.ticket?.live_authority_granted !== false || record.payload?.ticket?.human_decision !== record.action
+ || record.payload?.ticket?.ticket_id !== record.subject_id || record.payload.ticket.human_decided_at !== record.decided_at
+ || await researchPromotionMaterialKey(record.payload.ticket) !== record.material_key
+ || canonicalResearchTaskJson(record.payload.selected_account ?? null) !== canonicalResearchTaskJson(account ?? null)
+ || canonicalResearchTaskJson(record.payload.confirmation ?? null) !== canonicalResearchTaskJson(confirmation ?? null)) invalid();
+ projection = {
+ selected_account: account ? { platform: account.platform, key: account.key } : null,
+ confirmation: confirmation ? { target_platform: confirmation.target_platform, execution_mode: confirmation.execution_mode, risk_profile: confirmation.risk_profile } : null,
+ };
+ } else {
+ if (target?.decision !== record.action || record.payload?.no_order !== true || record.payload?.execution_authority_granted !== false) invalid();
+ const payload = record.payload;
+ if (record.kind === "owner") {
+ if (payload.schema_version !== "qsl_owner_decision_intent.v1" || payload.candidate_id !== record.subject_id
+ || payload.candidate_evidence_sha256 !== record.material_key || payload.decision !== record.action
+ || payload.decided_by !== record.actor || payload.decided_at !== record.decided_at
+ || payload.decision_sha256 !== await calculateOwnerDecisionSha256(payload)) invalid();
+ } else if (payload.mode === "initial_enrollment") {
+ const approval = record.action === "approve";
+ if (payload.schema_version !== (approval ? "qsl_initial_enrollment_confirmation.v1" : "qsl_initial_enrollment_rejection.v1")
+ || payload.recovery_id !== record.subject_id || (approval ? payload.confirmed_by : payload.decided_by) !== record.actor
+ || (approval ? payload.confirmed_at : payload.decided_at) !== record.decided_at || (!approval && payload.decision !== "reject")
+ || (approval && payload.confirmation_sha256 !== await calculateReconciliationRecoveryConfirmationSha256(payload))
+ || await recoveryDecisionMaterialKey(payload) !== record.material_key) invalid();
+ } else {
+ const approval = record.action === "approve";
+ if (payload.schema_version !== (approval ? "qsl_reconciliation_recovery_confirmation.v1" : "qsl_reconciliation_recovery_rejection.v1")
+ || payload.recovery_id !== record.subject_id || (approval ? payload.confirmed_by : payload.decided_by) !== record.actor
+ || (approval ? payload.confirmed_at : payload.decided_at) !== record.decided_at || (!approval && payload.decision !== "reject")
+ || await recoveryDecisionMaterialKey({ recovery_id: payload.recovery_id, candidate_sha256: payload.candidate_sha256, dual_review: { evidence_binding_sha256: payload.dual_review_binding_sha256 } }) !== record.material_key) invalid();
+ }
+ projection = { decision: target.decision };
+ }
+ // Extra stored target fields must not be silently dropped into an apparently matching receipt.
+ if (canonicalResearchTaskJson(target) !== canonicalResearchTaskJson(projection)) invalid();
+ let reviewBinding = null;
+ if (record.kind === "promotion" && record.payload?.review_binding !== undefined) {
+ const material = record.payload.review_material;
+ if (material?.schema_version !== "qsl_promotion_review_material.v2" || material.ticket_id !== record.subject_id
+ || await researchPromotionMaterialKey(material) !== record.material_key
+ || !promotionReviewBindingsMatch(record.payload.review_binding, { schema_version: "qsl_promotion_review_binding.v2", review_sha256: await calculateOwnerDecisionSha256(material) })) invalid();
+ reviewBinding = { schema_version: "qsl_promotion_review_binding.v2", review_sha256: record.payload.review_binding.review_sha256 };
+ }
+ const receipt = {
+ schema_version: reviewBinding ? "qsl_human_decision_receipt.v2" : "qsl_human_decision_receipt.v1",
+ ...(reviewBinding ? { review_binding: reviewBinding } : {}),
+ kind: record.kind, subject_id: record.subject_id, material_sha256: record.material_key,
+ action: record.action, target: projection, decided_at: record.decided_at, decided_by: record.actor,
+ no_order: true, execution_authority_granted: false,
+ };
+ return { ...receipt, receipt_sha256: await calculateOwnerDecisionSha256(receipt) };
+}
+
+export async function exactHumanDecisionResponse(request, env, session, kind) {
+ const params = new URL(request.url).searchParams;
+ if (!params.has("decision_subject_id") && !params.has("decision_material_sha256")) return null;
+ requireSameOrigin(request);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ const subjectId = params.get("decision_subject_id");
+ const material = params.get("decision_material_sha256");
+ if (params.getAll("decision_subject_id").length !== 1 || params.getAll("decision_material_sha256").length !== 1
+ || !subjectId || subjectId.length > 256 || /[\u0000-\u001f\u007f]/.test(subjectId) || !/^[0-9a-f]{64}$/.test(material || "")) {
+ return json({ ok: false, error: "human_decision_lookup_invalid" }, 400);
+ }
+ try {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ const result = await runtimeInstanceCommand(env, {
+ action: `${kind}_read`, actor: session.login, subject_id: subjectId, exact_material_key: material, now_ms: Date.now(),
+ });
+ if (result.ok !== true || result.exact_material_key !== material || !Object.prototype.hasOwnProperty.call(result, "decision")) {
+ throw new HttpError("human_decision_receipt_unavailable", 503);
+ }
+ const receipt = result.decision === null ? null : await humanDecisionReceipt(result.decision, { kind, subject_id: subjectId, material_sha256: material });
+ return json({ ok: true, decision_readback: {
+ schema_version: "qsl_human_decision_readback.v1", source: "durable_human_decision_record",
+ kind, subject_id: subjectId, requested_material_sha256: material, observed_at: new Date().toISOString(),
+ lookup_status: receipt ? "found" : "not_found", receipt, current_material: result.current_material,
+ } });
+ } catch {
+ // Unreadable authority is never reported as a completed empty lookup.
+ return json({ ok: false, error: "human_decision_receipt_unavailable" }, 503);
+ }
+}
+
+export async function readHumanDecisionAuthority(env, kind, subjectId) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ return runtimeInstanceCommand(env, { action: `${kind}_read`, actor: `${kind}-decision-read`, subject_id: subjectId });
+}
+
+// A safe projection of durable material authority. It carries only digests and
+// server-side expiry; raw provider payloads and credentials never enter a read model.
+export function humanDecisionAuthorityView(authority) {
+ if (!authority || typeof authority !== "object") return null;
+ const materialKey = /^[0-9a-f]{64}$/.test(authority.material_key || "") ? authority.material_key : null;
+ const expiresAt = typeof authority.expires_at === "string" && Number.isFinite(Date.parse(authority.expires_at))
+ ? authority.expires_at
+ : null;
+ return {
+ material_sha256: materialKey,
+ expires_at: expiresAt,
+ eligible: typeof authority.eligible === "boolean" ? authority.eligible : null,
+ blocked: authority.blocked === true,
+ unavailable: authority.migrated === false,
+ source: "durable_human_decision_material",
+ };
+}
+
+export function overlayPromotionDecision(ticket, authority) {
+ if (!authority || authority.migrated === false) return ticket;
+ const current = authority.eligible === true && authority.blocked !== true ? authority.decision : null;
+ if (current?.payload?.ticket && (current.action === "accept" || current.action === "reject")) {
+ return normalizeResearchPromotionTicket(current.payload.ticket, "human decision ticket");
+ }
+ if (ticket.state !== "human_accepted" && ticket.state !== "human_rejected") return ticket;
+ return normalizeResearchPromotionTicket({
+ ...ticket,
+ state: "awaiting_human",
+ human_decision: "",
+ human_decided_at: "",
+ confirmation_target_platform: "",
+ confirmation_execution_mode: "",
+ confirmation_risk_profile: "",
+ }, "human decision ticket");
+}
+
+export async function promotionTicketWithAuthority(env, ticket) {
+ const authority = await readHumanDecisionAuthority(env, "promotion", ticket.ticket_id);
+ return overlayPromotionDecision(ticket, authority);
+}
+
+export async function syncControlPlaneResponse(request, env) {
+ requireDedicatedControlPlaneSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "control plane KV is not configured" }, 503);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, CONTROL_PLANE_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid control plane payload" }, error.status || 400);
+ }
+
+ let snapshot;
+ try {
+ snapshot = normalizeControlPlaneSnapshot(raw, "control plane snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid control plane payload" }, 400);
+ }
+ try {
+ await publishHumanOwnerMaterials(env, snapshot, "control-plane-snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "owner decision material unavailable" }, error.status || 503);
+ }
+
+ await writeConfigJson(env, CONTROL_PLANE_SNAPSHOT_KEY, snapshot);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "control-plane-sync",
+ action: "sync_control_plane",
+ schema_version: snapshot.schema_version,
+ candidate_count: snapshot.summary.candidate_count,
+ data_status: snapshot.data_status,
+ });
+ } catch {
+ // A successful snapshot must not expose its payload through audit failures.
+ }
+ return json({
+ ok: true,
+ schema_version: snapshot.schema_version,
+ candidate_count: snapshot.summary.candidate_count,
+ generated_at: snapshot.generated_at,
+ });
+}
+
+export async function syncControlPlaneSourceResponse(request, env) {
+ const validationOnly = requireControlPlaneSourceSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "control plane KV is not configured" }, 503);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, CONTROL_PLANE_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid control plane source payload" }, error.status || 400);
+ }
+
+ let source;
+ try {
+ source = normalizeControlPlaneSourceSnapshot(raw, "control plane source snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid control plane source payload" }, 400);
+ }
+
+ if (validationOnly) {
+ const candidate = source.candidates[0];
+ const runId = candidate?.candidate_id?.match(/^soxl_three_asset_mid_weight_validation_([1-9][0-9]*)$/)?.[1];
+ if (
+ source.source_id !== "aiaudit.soxl_manual_validation" ||
+ source.candidates.length !== 1 || !runId ||
+ candidate.candidate_kind !== "individual" || candidate.domain !== "us_equity" ||
+ candidate.lifecycle.stage !== "P3" || candidate.lifecycle.status !== "parked" ||
+ candidate.recommendation.code !== "park" || candidate.evidence.p3_evidence_id !== runId
+ ) {
+ return json({ ok: false, error: "validation publisher scope mismatch" }, 403);
+ }
+ }
+ try {
+ await publishHumanOwnerMaterials(env, source, source.source_id);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "owner decision material unavailable" }, error.status || 503);
+ }
+
+ await writeConfigJson(env, controlPlaneSourceKey(source.source_id), source);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "control-plane-source-sync",
+ action: "sync_control_plane_source",
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ candidate_count: source.candidates.length,
+ data_status: source.data_status,
+ });
+ } catch {
+ // The source snapshot is accepted independently of an optional audit write.
+ }
+ return json({
+ ok: true,
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ candidate_count: source.candidates.length,
+ generated_at: source.generated_at,
+ });
+}
+
+export async function controlPlaneResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ return json(await currentControlPlanePayload(env));
+}
+
+export async function currentControlPlanePayload(env) {
+ if (!hasConfigStore(env)) return emptyControlPlanePayload("snapshot_unavailable");
+
+ const sourceSnapshot = await aggregateControlPlaneSources(env);
+ if (sourceSnapshot) return sourceSnapshot;
+
+ let snapshot;
+ try {
+ const stored = await readConfigJson(env, CONTROL_PLANE_SNAPSHOT_KEY);
+ if (!stored) return emptyControlPlanePayload("snapshot_unavailable");
+ snapshot = normalizeControlPlaneSnapshot(stored, CONTROL_PLANE_SNAPSHOT_KEY);
+ } catch {
+ return emptyControlPlanePayload("snapshot_invalid");
+ }
+
+ const freshness = controlPlaneResearchSnapshotFreshness(
+ snapshot,
+ controlPlaneStaleTtlSeconds(env),
+ Date.now(),
+ );
+ snapshot.data_status = freshness.data_status;
+ return snapshot;
+}
+
+export function isOwnerDecisionCandidate(candidate) {
+ return candidate?.lifecycle?.stage === "P6"
+ && candidate.lifecycle.status === "owner_decision_required"
+ && candidate.recommendation?.code === "owner_live_decision";
+}
+
+export function currentOwnerDecisionCandidate(controlPlane, candidateId) {
+ if (controlPlane?.data_status !== "ready") {
+ throw new HttpError("current control-plane evidence is not ready", 409);
+ }
+ const candidate = controlPlane.candidates.find((item) => item.candidate_id === candidateId);
+ if (!candidate || !isOwnerDecisionCandidate(candidate)) {
+ throw new HttpError("candidate is not awaiting an owner decision", 409);
+ }
+ if (candidate.freshness?.status !== "fresh") {
+ throw new HttpError("candidate evidence is not fresh", 409);
+ }
+ return candidate;
+}
+
+export function normalizeOwnerDecisionRequest(payload) {
+ const value = assertRequiredAndOptionalFields(payload, [
+ "candidate_id", "decision", "candidate_evidence_sha256",
+ ], ["request_id"], "owner decision request");
+ return {
+ candidate_id: normalizeControlPlaneIdentifier(value.candidate_id, "owner decision request.candidate_id", false),
+ decision: cleanChoice(value.decision, OWNER_DECISION_CHOICES, "owner decision request.decision"),
+ candidate_evidence_sha256: normalizeResearchTaskDigest(
+ value.candidate_evidence_sha256,
+ "owner decision request.candidate_evidence_sha256",
+ ),
+ request_id: value.request_id,
+ };
+}
+
+export async function ownerDecisionCandidateEvidenceSha256(candidate) {
+ return await calculateOwnerDecisionSha256({
+ candidate_id: candidate.candidate_id,
+ candidate_kind: candidate.candidate_kind,
+ domain: candidate.domain,
+ lifecycle: candidate.lifecycle,
+ evidence: candidate.evidence,
+ recommendation: { code: candidate.recommendation?.code || "none" },
+ });
+}
+
+export async function buildOwnerDecisionIntent({ candidate, decision, decidedBy, candidateEvidenceSha256, decidedAt }) {
+ const intent = {
+ schema_version: OWNER_DECISION_INTENT_SCHEMA_VERSION,
+ candidate_id: candidate.candidate_id,
+ candidate_kind: candidate.candidate_kind,
+ domain: candidate.domain,
+ decision,
+ decided_at: decidedAt,
+ decided_by: decidedBy,
+ candidate_evidence_sha256: candidateEvidenceSha256,
+ no_order: true,
+ execution_authority_granted: false,
+ decision_sha256: "",
+ };
+ intent.decision_sha256 = await calculateOwnerDecisionSha256(intent);
+ return await normalizeOwnerDecisionIntent(intent, "owner decision intent");
+}
+
+export async function normalizeOwnerDecisionIntent(payload, fieldName) {
+ const value = assertExactFields(payload, [
+ "schema_version", "candidate_id", "candidate_kind", "domain", "decision", "decided_at", "decided_by",
+ "candidate_evidence_sha256", "no_order", "execution_authority_granted", "decision_sha256",
+ ], fieldName);
+ if (value.schema_version !== OWNER_DECISION_INTENT_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const intent = {
+ schema_version: OWNER_DECISION_INTENT_SCHEMA_VERSION,
+ candidate_id: normalizeControlPlaneIdentifier(value.candidate_id, `${fieldName}.candidate_id`, false),
+ candidate_kind: cleanChoice(value.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${fieldName}.candidate_kind`),
+ domain: cleanChoice(value.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.domain`),
+ decision: cleanChoice(value.decision, OWNER_DECISION_CHOICES, `${fieldName}.decision`),
+ decided_at: normalizeResearchTaskTimestamp(value.decided_at, `${fieldName}.decided_at`),
+ decided_by: cleanGithubLogin(value.decided_by, `${fieldName}.decided_by`),
+ candidate_evidence_sha256: normalizeResearchTaskDigest(
+ value.candidate_evidence_sha256,
+ `${fieldName}.candidate_evidence_sha256`,
+ ),
+ no_order: value.no_order,
+ execution_authority_granted: value.execution_authority_granted,
+ decision_sha256: normalizeResearchTaskDigest(value.decision_sha256, `${fieldName}.decision_sha256`),
+ };
+ if (intent.no_order !== true || intent.execution_authority_granted !== false) {
+ throw new Error(`${fieldName} must remain no-order and non-executable`);
+ }
+ if (intent.decision_sha256 !== await calculateOwnerDecisionSha256(intent)) {
+ throw new Error(`${fieldName}.decision_sha256 mismatch`);
+ }
+ return intent;
+}
+
+export async function calculateOwnerDecisionSha256(payload) {
+ const material = { ...payload };
+ delete material.decision_sha256;
+ const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export async function readOwnerDecisionIntent(env, candidateId, materialKey) {
+ let authority;
+ try {
+ authority = await readHumanDecisionAuthority(env, "owner", candidateId);
+ } catch (error) {
+ return { intent: null, authority: null, error: error.message || "runtime_instances_unavailable" };
+ }
+ const authorityView = humanDecisionAuthorityView(authority);
+ if (authority.blocked) return { intent: null, authority: authorityView, error: "owner_decision_legacy_blocked" };
+ if (authority.decision && authority.material_key === materialKey && authority.decision.payload?.no_order === true && authority.decision.payload?.execution_authority_granted === false) {
+ return { intent: authority.decision.payload, authority: authorityView, error: null };
+ }
+ if (authority.migrated === false) {
+ try {
+ const stored = await readConfigJson(env, ownerDecisionCurrentKey(candidateId));
+ if (!stored) return { intent: null, authority: authorityView, error: null };
+ const intent = await normalizeOwnerDecisionIntent(stored, ownerDecisionCurrentKey(candidateId));
+ if (materialKey && intent.candidate_evidence_sha256 !== materialKey) return { intent: null, authority: authorityView, error: null };
+ return { intent, authority: authorityView, error: null, read_only: true };
+ } catch {
+ return { intent: null, authority: authorityView, error: "owner_decision_intent_invalid" };
+ }
+ }
+ return { intent: null, authority: authorityView, error: null };
+}
+
+export function ownerDecisionArchiveKey(candidateId, decisionSha256) {
+ return `${OWNER_DECISION_INTENT_PREFIX}${candidateId}:${decisionSha256}`;
+}
+
+export function ownerDecisionCurrentKey(candidateId) {
+ return `${OWNER_DECISION_CURRENT_PREFIX}${candidateId}`;
+}
+
+export function emptyOwnerDecisionQueue(errorCode, controlPlane = null) {
+ return {
+ schema_version: OWNER_DECISION_QUEUE_SCHEMA_VERSION,
+ data_status: controlPlane?.data_status === "stale" ? "stale" : "unavailable",
+ computed_at: controlPlane?.computed_at || null,
+ candidates: [],
+ policy: {
+ admin_required: true,
+ current_evidence_required: true,
+ execution_authority_granted: false,
+ no_order: true,
+ notice: "网页只记录所有者决定意图;不会下单、变更资金或启用实盘。",
+ },
+ errors: uniqueStrings([...(controlPlane?.errors || []), errorCode]),
+ };
+}
+
+export async function ownerDecisionQueueResponse(request, env) {
+ return ownerDecisionQueueResponseImpl(request, env, {
+ json,
+ readSession,
+ exactHumanDecisionResponse,
+ hasConfigStore,
+ currentControlPlanePayload,
+ isOwnerDecisionCandidate,
+ ownerDecisionCandidateEvidenceSha256,
+ readOwnerDecisionIntent,
+ emptyOwnerDecisionQueue,
+ uniqueStrings,
+ OWNER_DECISION_MAX_CANDIDATES,
+ OWNER_DECISION_QUEUE_SCHEMA_VERSION,
+ });
+}
+
+export async function recordOwnerDecisionResponse(request, env) {
+ return recordOwnerDecisionResponseImpl(request, env, {
+ json,
+ requireSameOrigin,
+ readSession,
+ hasConfigStore,
+ readBoundedJson,
+ normalizeOwnerDecisionRequest,
+ currentControlPlanePayload,
+ currentOwnerDecisionCandidate,
+ ownerDecisionCandidateEvidenceSha256,
+ humanDecisionTimestamp,
+ buildOwnerDecisionIntent,
+ canonicalResearchTaskJson,
+ humanDecisionRequestKey,
+ runtimeInstanceCommand,
+ humanDecisionReceipt,
+ mirrorConfigJson,
+ ownerDecisionArchiveKey,
+ ownerDecisionCurrentKey,
+ appendAuditLog,
+ });
+}
+
+// Recovery snapshots contain digest-bound review metadata. Initial enrollment
+// additionally carries bounded broker facts for the authenticated review;
+// raw receipts remain in the platform's protected source, and confirmation
+// records intent without granting execution authority.
+export async function initialEnrollmentAccountOption(env, item) {
+ if (!await initialEnrollmentBindingsMatch(item.candidate, item.facts)
+ || item.candidate.platform_id.toLowerCase() !== "ibkr"
+ || item.facts.observed_at !== item.candidate.first_observed_at
+ || item.facts.observed_at !== item.candidate.last_observed_at) throw new HttpError("initial_enrollment_invalid", 409);
+ const config = await loadAccountOptionsConfig(env);
+ const configured = await loadAccountFactsBindings(env, { propagateReadErrors: true });
+ const bindings = (configured?.bindings || []).filter(binding => binding.platform === "ibkr" && binding.target_id === item.target_id);
+ const options = (config.options?.ibkr || []).filter(option => bindings.length === 1 && option.key === bindings[0].account_key);
+ if (options.length !== 1 || bindings.length !== 1 || !accountFactsOptionMatchesBinding(options[0], bindings[0])
+ || await initialEnrollmentDigest({ account_ids: [bindings[0].account_selector] }, true) !== item.candidate.account_scope_sha256) {
+ throw new HttpError("initial_enrollment_identity_mismatch", 409);
+ }
+ return options[0];
+}
+
+export async function syncReconciliationRecoverySourceResponse(request, env) {
+ requireDedicatedReconciliationRecoverySyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "reconciliation recovery KV is not configured" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, RECONCILIATION_RECOVERY_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid reconciliation recovery payload" }, error.status || 400);
+ }
+ let source;
+ try {
+ source = normalizeReconciliationRecoverySourceSnapshot(raw, "reconciliation recovery source snapshot");
+ for (const recovery of source.recoveries) if (recovery.mode === "initial_enrollment") await initialEnrollmentAccountOption(env, recovery);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid reconciliation recovery payload" }, 400);
+ }
+ try {
+ await publishHumanRecoveryMaterials(env, source);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "reconciliation recovery material unavailable" }, error.status || 503);
+ }
+ await writeConfigJson(env, reconciliationRecoverySourceKey(source.source_id), source);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "reconciliation-recovery-source-sync",
+ action: "sync_reconciliation_recovery_source",
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ recovery_count: source.recoveries.length,
+ data_status: source.data_status,
+ });
+ } catch {
+ // The source is still safely stored even if the rolling convenience log
+ // cannot be updated.
+ }
+ return json({
+ ok: true,
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ recovery_count: source.recoveries.length,
+ generated_at: source.generated_at,
+ });
+}
+
+export async function reconciliationRecoveryResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ const exact = await exactHumanDecisionResponse(request, env, session, "recovery");
+ if (exact) return exact;
+ if (!hasConfigStore(env)) return json(emptyReconciliationRecoveryPayload("snapshot_unavailable"));
+ return json(decorateQueue(await aggregateReconciliationRecoverySources(env), "recoveries", "reconciliation_recovery"));
+}
+
+export async function syncBinancePrivateScopeResponse(request, env) {
+ requireDedicatedReconciliationRecoverySyncToken(request, env);
+ const store = configStore(env);
+ if (!store) {
+ return json({ ok: false, error: "binance_private_scope_storage_unavailable" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, BINANCE_PRIVATE_SCOPE_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: "invalid_binance_private_scope_payload" }, error.status === 413 ? 413 : 400);
+ }
+ let report;
+ try {
+ report = normalizeBinancePrivateScopeReport(raw, { requireIngestFreshness: true });
+ } catch {
+ return json({ ok: false, error: "invalid_binance_private_scope_payload" }, 400);
+ }
+ try {
+ await store.put(BINANCE_PRIVATE_SCOPE_KEY, JSON.stringify(report), {
+ expirationTtl: BINANCE_PRIVATE_SCOPE_WRITE_TTL_SECONDS,
+ });
+ } catch {
+ return json({ ok: false, error: "binance_private_scope_storage_unavailable" }, 503);
+ }
+ return json({
+ ok: true,
+ observed_at: report.observed_at,
+ source_run_id: report.source_run_id,
+ asset_count: report.assets.length,
+ });
+}
+
+export async function trustedBinanceFactsBinding(env, readiness = null) {
+ const text = String(env.BINANCE_ACCOUNT_FACTS_BINDING_JSON || "");
+ if (!text) return null;
+ let binding;
+ try { binding = normalizeBinanceFactsBinding(JSON.parse(text)); }
+ catch { throw new BinanceFactsError("binance_account_facts_binding_invalid", 503); }
+ await assertBinanceFactsSourceBinding(binding);
+ if (readiness) readiness.binding_valid = true;
+ let config;
+ try { config = await loadAccountOptionsConfig(env); }
+ catch {
+ throw new BinanceFactsError("binance_account_facts_account_options_unavailable", 503);
+ }
+ if (readiness) readiness.account_options_readable = true;
+ const options = config.options?.binance || [];
+ const matchCount = options.filter(option => binanceFactsOptionMatches(option, binding)).length;
+ if (matchCount !== 1) {
+ throw new BinanceFactsError("binance_account_facts_binding_unmatched", 409);
+ }
+ if (readiness) readiness.unique_match = true;
+ return binding;
+}
+
+export function binanceFactsErrorResponse(error) {
+ return json({ ok: false, error: error instanceof BinanceFactsError
+ ? error.code : "binance_account_facts_unavailable" }, error instanceof BinanceFactsError ? error.status : 503);
+}
+
+export function binanceFactsSyncAuthorizationResponse(request, env) {
+ const token = String(env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN || "");
+ const otherTokens = ["ACCOUNT_FACTS_SYNC_TOKEN", "IBKR_ACCOUNT_FACTS_SYNC_TOKEN", "SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN", "FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN",
+ "RECONCILIATION_RECOVERY_SYNC_TOKEN", "RECONCILIATION_RECOVERY_CONTROLLER_TOKEN", "STRATEGY_SWITCH_SYNC_TOKEN"];
+ if (!token || otherTokens.some(name => env[name] && env[name] === token)) {
+ return json({ ok: false, error: "binance_account_facts_token_unavailable" }, 503);
+ }
+ if ((request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] !== token) {
+ return json({ ok: false, error: "binance_account_facts_token_invalid" }, 401);
+ }
+ return null;
+}
+
+export async function binanceDigestSnapshotResponse(request, env, url) {
+ const token = env.BINANCE_DIGEST_READ_TOKEN;
+ const otherTokens = ["BINANCE_ACCOUNT_FACTS_SYNC_TOKEN", "ACCOUNT_FACTS_SYNC_TOKEN", "IBKR_ACCOUNT_FACTS_SYNC_TOKEN",
+ "SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN", "FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN", "RECONCILIATION_RECOVERY_SYNC_TOKEN",
+ "RECONCILIATION_RECOVERY_CONTROLLER_TOKEN", "STRATEGY_SWITCH_SYNC_TOKEN", "SESSION_SECRET"];
+ if (typeof token !== "string" || !/^[A-Za-z0-9_-]{32,256}$/.test(token)
+ || otherTokens.some(name => env[name] === token)) {
+ return json({ ok: false, error: "digest_snapshot_read_unavailable" }, 503);
+ }
+ if (request.headers.get("Authorization") !== `Bearer ${token}`) {
+ return json({ ok: false, error: "digest_snapshot_read_unauthorized" }, 401);
+ }
+ const day = url.searchParams.get("business_day");
+ const start = Date.parse(`${day}T06:00:00+08:00`);
+ const end = start + 86400000;
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(day || "") || !Number.isFinite(start)
+ || new Date(start + 8 * 3600000).toISOString().slice(0, 10) !== day || end > Date.now()) {
+ return json({ ok: false, error: "digest_snapshot_window_invalid" }, 400);
+ }
+ try {
+ const binding = await trustedBinanceFactsBinding(env);
+ if (!binding || !configStore(env)) throw new Error("digest_snapshot_read_unavailable");
+ const retained = await runtimeInstanceCommand(env, {
+ action: "binance_detail_read", binding, date: day, business_day: true,
+ });
+ if (retained?.ok !== true) throw new Error("digest_snapshot_read_unavailable");
+ // The existing latest cache can supply a snapshot from before this
+ // retention path was released, provided it still matches the window.
+ const raw = retained.report ?? await readConfigJson(env, `${BINANCE_FACTS_KEY}:${binding.source_binding.id}`);
+ if (!raw) return json({ ok: false, error: "digest_snapshot_missing" }, 404);
+ const report = normalizeBinanceAccountFacts(raw, binding);
+ const observedFrom = Date.parse(report.observed_started_at);
+ const observedUntil = Date.parse(report.observed_finished_at);
+ if (observedFrom < start || observedUntil >= end) {
+ return json({ ok: false, error: "digest_snapshot_missing" }, 404);
+ }
+ const valuation = report.wallet_valuation;
+ const wallet = url.searchParams.get("include_valuation") === "1" && valuation?.status === "available"
+ ? { wallet_valuation: {
+ amount: valuation.amount, currency: valuation.currency, as_of: valuation.observed_at,
+ } }
+ : {};
+ return json({ ok: true, business_day: day, account_key: binding.account_key,
+ target_id: binding.target_id, as_of: report.observed_finished_at,
+ holdings: report.assets.map(({ asset, quantity }) => ({ asset, quantity })), ...wallet });
+ } catch {
+ return json({ ok: false, error: "digest_snapshot_read_unavailable" }, 503);
+ }
+}
+
+export async function binanceAccountFactsReadinessResponse(request, env) {
+ const authError = binanceFactsSyncAuthorizationResponse(request, env);
+ if (authError) return authError;
+ const readiness = { binding_valid: false, account_options_readable: false, unique_match: false };
+ try {
+ const binding = await trustedBinanceFactsBinding(env, readiness);
+ if (!binding) throw new BinanceFactsError("binance_account_facts_binding_missing", 503);
+ return json({ ok: true, ready: true, ...readiness });
+ } catch (error) {
+ return json({ ok: false, ready: false, ...readiness,
+ error: error instanceof BinanceFactsError ? error.code : "binance_account_facts_unavailable" },
+ error instanceof BinanceFactsError ? error.status : 503);
+ }
+}
+
+export async function syncBinanceAccountFactsResponse(request, env) {
+ const authError = binanceFactsSyncAuthorizationResponse(request, env);
+ if (authError) return authError;
+ try {
+ const binding = await trustedBinanceFactsBinding(env);
+ if (!binding) throw new BinanceFactsError("binance_account_facts_binding_missing", 503);
+ const raw = await readBoundedJson(request, BINANCE_FACTS_MAX_BYTES);
+ const report = normalizeBinanceAccountFacts(raw, binding, { ingest: true });
+ const store = configStore(env);
+ if (!store) throw new BinanceFactsError("binance_account_facts_storage_unavailable", 503);
+ if (!hasRuntimeInstanceStore(env)) throw new BinanceFactsError("binance_account_facts_history_storage_unavailable", 503);
+ const storageKey = `${BINANCE_FACTS_KEY}:${binding.source_binding.id}`;
+ const previous = await readConfigJson(env, storageKey);
+ let unchanged = false;
+ if (previous) {
+ const validPrevious = normalizeBinanceAccountFacts(previous, binding);
+ const incomingTime = Date.parse(report.observed_finished_at);
+ const previousTime = Date.parse(validPrevious.observed_finished_at);
+ if (incomingTime < previousTime || (incomingTime === previousTime
+ && canonicalJson(report) !== canonicalJson(validPrevious))) {
+ throw new BinanceFactsError("binance_account_facts_observation_conflict", 409);
+ }
+ unchanged = incomingTime === previousTime;
+ }
+ try {
+ const detail = await runtimeInstanceCommand(env, {
+ action: "binance_detail_put", binding, report, date: report.observed_finished_at.slice(0, 10),
+ });
+ if (detail.readback_verified !== true) throw new Error("binance_detail_readback_failed");
+ const history = binanceWalletHistoryEntry(report, binding);
+ await runtimeInstanceCommand(env, {
+ action: "binance_wallet_history_put",
+ account_key: binding.account_key,
+ storage_account_key: binanceWalletHistoryStorageKey(binding),
+ target_id: binding.target_id,
+ account_scope: binding.account_scope,
+ source_binding_id: binding.source_binding.id,
+ history,
+ });
+ } catch {
+ throw new BinanceFactsError("binance_account_facts_history_storage_unavailable", 503);
+ }
+ if (unchanged) return json({ ok: true, status: "unchanged" });
+ await store.put(storageKey, JSON.stringify(report), { expirationTtl: 2 * 24 * 60 * 60 });
+ return json({ ok: true, status: "published", observed_finished_at: report.observed_finished_at,
+ asset_count: report.assets.length });
+ } catch (error) {
+ if (error?.status === 413) return json({ ok: false, error: "binance_account_facts_payload_too_large" }, 413);
+ return binanceFactsErrorResponse(error);
+ }
+}
+
+export async function binanceDetailArchiveResponse(request, env, url) {
+ const authError = binanceFactsSyncAuthorizationResponse(request, env);
+ if (authError) return authError;
+ try {
+ const binding = await trustedBinanceFactsBinding(env);
+ if (!binding) throw new Error("binding_missing");
+ const result = await runtimeInstanceCommand(env, {
+ action: "binance_detail_read", binding, date: url.searchParams.get("date"),
+ });
+ return json(result, result.report ? 200 : 404);
+ } catch {
+ return json({ ok: false, error: "binance_detail_archive_unavailable" }, 503);
+ }
+}
+
+export async function binanceWalletHistoryResponse(request, env, url) {
+ if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "account_facts_store_unavailable" }, 503);
+ try {
+ const binding = await trustedBinanceFactsBinding(env);
+ if (!binding) throw new BinanceFactsError("binance_account_facts_binding_missing", 503);
+ if (url.searchParams.get("account_key") !== binding.account_key) {
+ throw new BinanceFactsError("binance_account_facts_binding_unmatched", 409);
+ }
+ let historicalBindings;
+ try {
+ const encoded = String(env.BINANCE_ACCOUNT_FACTS_HISTORY_BINDINGS_JSON || "[]");
+ historicalBindings = await assertBinanceFactsHistoryBindings(JSON.parse(encoded), binding);
+ } catch {
+ throw new BinanceFactsError("binance_account_facts_history_bindings_invalid", 503);
+ }
+ const buckets = [];
+ for (const sourceBinding of [binding, ...historicalBindings]) {
+ const stored = await runtimeInstanceCommand(env, {
+ action: "binance_wallet_history_read",
+ account_key: binding.account_key,
+ storage_account_key: binanceWalletHistoryStorageKey(sourceBinding),
+ target_id: binding.target_id,
+ account_scope: binding.account_scope,
+ source_binding_id: sourceBinding.source_binding.id,
+ });
+ buckets.push({ binding: sourceBinding, days: Array.isArray(stored.days) ? stored.days : [] });
+ }
+ return json(projectBinanceWalletHistoryFromSources(buckets, binding, historicalBindings));
+ } catch (error) {
+ const allowedErrors = new Set([
+ "binance_account_facts_binding_invalid", "binance_account_facts_account_options_unavailable",
+ "binance_account_facts_binding_unmatched", "binance_account_facts_binding_missing",
+ "binance_wallet_history_identity_mismatch", "binance_wallet_history_stored_invalid",
+ "binance_wallet_history_conflict", "binance_account_facts_history_bindings_invalid",
+ ]);
+ const code = allowedErrors.has(error?.code || error?.message)
+ ? (error.code || error.message) : "binance_wallet_history_unavailable";
+ return json({ ok: false, error: code }, error?.status || 503);
+ }
+}
+
+export async function binanceAccountFactsResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ try {
+ const binding = await trustedBinanceFactsBinding(env);
+ if (!binding) return json({ ok: true, report_status: "unavailable", report: null });
+ const raw = await readConfigJson(env, `${BINANCE_FACTS_KEY}:${binding.source_binding.id}`);
+ if (!raw) return json({ ok: true, report_status: "missing", report: null });
+ const report = projectBinanceAccountFacts(raw, binding);
+ if (!report) return json({ ok: true, report_status: "expired", report: null });
+ return json({ ok: true, report_status: "available", report });
+ } catch { return json({ ok: true, report_status: "unavailable", report: null }); }
+}
+
+export async function binancePrivateScopeResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session) return json({ ok: false, error: "login required" }, 401);
+ if (!session.allowed || !session.admin) return json({ ok: false, error: "admin required" }, 403);
+ if (!hasConfigStore(env)) return json({ ok: true, report: null });
+ try {
+ const raw = await readConfigJson(env, BINANCE_PRIVATE_SCOPE_KEY);
+ if (!raw) return json({ ok: true, report: null });
+ const report = normalizeBinancePrivateScopeReport(raw);
+ const ageMs = Date.now() - Date.parse(report.observed_at);
+ if (ageMs > BINANCE_PRIVATE_SCOPE_READ_MAX_AGE_MS || ageMs < -BINANCE_PRIVATE_SCOPE_FUTURE_SKEW_MS) {
+ return json({ ok: true, report: null });
+ }
+ return json({ ok: true, report });
+ } catch {
+ return json({ ok: true, report: null });
+ }
+}
+
+// This is a least-privilege service-to-service read for a platform-owned
+// controller. It deliberately returns only the current, redacted digest
+// binding and immutable human receipt; broker state remains in the platform.
+export async function reconciliationRecoveryControllerReadResponse(request, env, url) {
+ requireDedicatedReconciliationRecoveryControllerToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "reconciliation recovery KV is not configured" }, 503);
+ }
+ let recoveryId;
+ try {
+ recoveryId = normalizeControlPlaneIdentifier(
+ url.searchParams.get("recovery_id") || "",
+ "reconciliation recovery controller recovery_id",
+ false,
+ );
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid recovery_id" }, 400);
+ }
+ const dashboard = await aggregateReconciliationRecoverySources(env);
+ let recovery;
+ try {
+ recovery = currentReconciliationRecoveryRequest(dashboard, recoveryId);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "reconciliation recovery is unavailable" }, error.status || 409);
+ }
+ const entry = dashboard.recoveries.find((item) => item.recovery?.recovery_id === recoveryId);
+ if (!entry?.confirmation) {
+ return json({ ok: false, error: "reconciliation recovery has no current confirmation" }, 404);
+ }
+ if (recovery.mode === "initial_enrollment") return json({ ok: true, schema_version: "qsl_initial_enrollment_controller_read.v1",
+ recovery: { mode: recovery.mode, recovery_id: recovery.recovery_id, candidate_sha256: recovery.candidate_sha256, facts_sha256: recovery.facts_sha256 },
+ confirmation: entry.confirmation, policy: { no_order: true, execution_authority_granted: false, controller_must_reverify: true } });
+ return json({
+ ok: true,
+ schema_version: RECONCILIATION_RECOVERY_CONTROLLER_READ_SCHEMA_VERSION,
+ recovery: {
+ recovery_id: recovery.recovery_id,
+ platform: recovery.platform,
+ strategy_profile: recovery.strategy_profile,
+ environment: recovery.environment,
+ reconciliation_state: recovery.reconciliation_state,
+ candidate_sha256: recovery.candidate_sha256,
+ dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
+ evidence_sample_count: recovery.evidence_sample_count,
+ first_observed_at: recovery.first_observed_at,
+ last_observed_at: recovery.last_observed_at,
+ },
+ confirmation: entry.confirmation,
+ policy: {
+ no_order: true,
+ execution_authority_granted: false,
+ controller_must_reverify: true,
+ },
+ });
+}
+
+export function currentReconciliationRecoveryRequest(dashboard, recoveryId) {
+ const entry = dashboard?.recoveries?.find((item) => item.recovery?.recovery_id === recoveryId);
+ if (entry?.recovery?.mode !== "initial_enrollment" && dashboard?.data_status !== "ready") {
+ throw new HttpError("current reconciliation recovery evidence is not ready", 409);
+ }
+ if (!entry || entry.freshness?.data_status !== "ready") {
+ throw new HttpError("reconciliation recovery request is not fresh", 409);
+ }
+ const recovery = entry.recovery;
+ if (recovery.mode === "initial_enrollment") {
+ if (recovery.readiness !== "awaiting_human_confirmation" || recovery.blocker_codes.length) throw new HttpError("initial_enrollment_incomplete", 409);
+ return recovery;
+ }
+ if (
+ recovery.readiness !== "awaiting_human_confirmation" ||
+ recovery.reconciliation_state !== "RECONCILE_ONLY" ||
+ recovery.blocker_codes.length ||
+ recovery.dual_review.evidence_binding_sha256 !== recovery.candidate_sha256 ||
+ recovery.evidence_sample_count < 1
+ ) {
+ throw new HttpError("reconciliation recovery request is not eligible for confirmation", 409);
+ }
+ return recovery;
+}
+
+export function normalizeReconciliationRecoveryConfirmationRequest(payload) {
+ if (payload?.mode === "initial_enrollment") {
+ const value = assertRequiredAndOptionalFields(payload, ["mode", "recovery_id", "candidate_sha256", "facts_sha256"], ["decision", "request_id"], "initial enrollment confirmation request");
+ const decision = value.decision ?? "approve";
+ if (!["approve", "reject"].includes(decision)) throw new Error("initial enrollment decision unsupported");
+ return { mode: "initial_enrollment", recovery_id: normalizeControlPlaneIdentifier(value.recovery_id, "recovery_id", false),
+ candidate_sha256: normalizeResearchTaskDigest(value.candidate_sha256, "candidate_sha256"),
+ facts_sha256: normalizeResearchTaskDigest(value.facts_sha256, "facts_sha256"), decision, request_id: value.request_id };
+ }
+ const value = assertRequiredAndOptionalFields(payload, [
+ "recovery_id", "candidate_sha256", "dual_review_binding_sha256",
+ ], ["decision", "request_id"], "reconciliation recovery confirmation request");
+ const decision = Object.prototype.hasOwnProperty.call(value, "decision") ? value.decision : "approve";
+ if (decision !== "approve" && decision !== "reject") {
+ throw new Error("reconciliation recovery confirmation request.decision is unsupported");
+ }
+ return {
+ recovery_id: normalizeControlPlaneIdentifier(value.recovery_id, "reconciliation recovery confirmation request.recovery_id", false),
+ candidate_sha256: normalizeResearchTaskDigest(
+ value.candidate_sha256,
+ "reconciliation recovery confirmation request.candidate_sha256",
+ ),
+ dual_review_binding_sha256: normalizeResearchTaskDigest(
+ value.dual_review_binding_sha256,
+ "reconciliation recovery confirmation request.dual_review_binding_sha256",
+ ),
+ decision,
+ request_id: value.request_id,
+ };
+}
+
+export async function calculateReconciliationRecoveryConfirmationSha256(payload) {
+ const material = { ...payload };
+ delete material.confirmation_sha256;
+ const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export async function buildReconciliationRecoveryConfirmation({ recovery, confirmedBy, confirmedAt }) {
+ const confirmation = {
+ schema_version: RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION,
+ recovery_id: recovery.recovery_id,
+ candidate_sha256: recovery.candidate_sha256,
+ dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
+ confirmed_at: confirmedAt,
+ confirmed_by: confirmedBy,
+ no_order: true,
+ execution_authority_granted: false,
+ confirmation_sha256: "",
+ };
+ confirmation.confirmation_sha256 = await calculateReconciliationRecoveryConfirmationSha256(confirmation);
+ return await normalizeReconciliationRecoveryConfirmation(confirmation, "reconciliation recovery confirmation");
+}
+
+export async function normalizeReconciliationRecoveryConfirmation(payload, fieldName) {
+ const value = assertExactFields(payload, [
+ "schema_version", "recovery_id", "candidate_sha256", "dual_review_binding_sha256", "confirmed_at", "confirmed_by",
+ "no_order", "execution_authority_granted", "confirmation_sha256",
+ ], fieldName);
+ if (value.schema_version !== RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const confirmation = {
+ schema_version: RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION,
+ recovery_id: normalizeControlPlaneIdentifier(value.recovery_id, `${fieldName}.recovery_id`, false),
+ candidate_sha256: normalizeResearchTaskDigest(value.candidate_sha256, `${fieldName}.candidate_sha256`),
+ dual_review_binding_sha256: normalizeResearchTaskDigest(
+ value.dual_review_binding_sha256,
+ `${fieldName}.dual_review_binding_sha256`,
+ ),
+ confirmed_at: normalizeResearchTaskTimestamp(value.confirmed_at, `${fieldName}.confirmed_at`),
+ confirmed_by: cleanGithubLogin(value.confirmed_by, `${fieldName}.confirmed_by`),
+ no_order: value.no_order,
+ execution_authority_granted: value.execution_authority_granted,
+ confirmation_sha256: normalizeResearchTaskDigest(value.confirmation_sha256, `${fieldName}.confirmation_sha256`),
+ };
+ if (confirmation.no_order !== true || confirmation.execution_authority_granted !== false) {
+ throw new Error(`${fieldName} must remain no-order and non-executable`);
+ }
+ if (confirmation.confirmation_sha256 !== await calculateReconciliationRecoveryConfirmationSha256(confirmation)) {
+ throw new Error(`${fieldName}.confirmation_sha256 mismatch`);
+ }
+ return confirmation;
+}
+
+export function reconciliationRecoveryConfirmationArchiveKey(recoveryId, confirmationSha256) {
+ return `${RECONCILIATION_RECOVERY_CONFIRMATION_PREFIX}${recoveryId}:${confirmationSha256}`;
+}
+
+export function reconciliationRecoveryConfirmationCurrentKey(recoveryId) {
+ return `${RECONCILIATION_RECOVERY_CURRENT_PREFIX}${recoveryId}`;
+}
+
+export async function readReconciliationRecoveryConfirmation(env, recoveryId) {
+ let authority;
+ try {
+ authority = await readHumanDecisionAuthority(env, "recovery", recoveryId);
+ } catch (error) {
+ return { confirmation: null, rejection: null, authority: null, error: error.message || "runtime_instances_unavailable" };
+ }
+ const authorityView = humanDecisionAuthorityView(authority);
+ if (authority.migrated === false) {
+ try {
+ const stored = await readConfigJson(env, reconciliationRecoveryConfirmationCurrentKey(recoveryId));
+ if (!stored) return { confirmation: null, rejection: null, authority: authorityView, error: null };
+ return {
+ confirmation: await normalizeReconciliationRecoveryConfirmation(
+ stored,
+ reconciliationRecoveryConfirmationCurrentKey(recoveryId),
+ ),
+ rejection: null,
+ authority: authorityView,
+ error: null,
+ read_only: true,
+ };
+ } catch {
+ return { confirmation: null, rejection: null, authority: authorityView, error: "reconciliation_recovery_confirmation_invalid" };
+ }
+ }
+ if (authority.blocked) return { confirmation: null, rejection: null, authority: authorityView, error: "reconciliation_recovery_legacy_blocked" };
+ if (authority.eligible !== true) return { confirmation: null, rejection: null, authority: authorityView, error: null };
+ if (authority.decision?.action === "reject") {
+ const payload = authority.decision.payload;
+ if (payload?.decision === "reject" && payload?.no_order === true && payload?.execution_authority_granted === false) {
+ return { confirmation: null, rejection: payload, authority: authorityView, error: null };
+ }
+ return { confirmation: null, rejection: null, authority: authorityView, error: null };
+ }
+ if (authority.decision?.action === "approve" && authority.decision.payload?.no_order === true && authority.decision.payload?.execution_authority_granted === false) {
+ return { confirmation: authority.decision.payload, rejection: null, authority: authorityView, error: null };
+ }
+ return { confirmation: null, rejection: null, authority: authorityView, error: null };
+}
+
+export async function recordInitialEnrollmentDecision(env, session, requested, recovery) {
+ if (recovery.mode !== "initial_enrollment" || requested.candidate_sha256 !== recovery.candidate_sha256
+ || requested.facts_sha256 !== recovery.facts_sha256) return json({ ok: false, error: "initial_enrollment_changed" }, 409);
+ const decidedAt = humanDecisionTimestamp();
+ const materialKey = await recoveryDecisionMaterialKey(recovery);
+ const base = { mode: "initial_enrollment", recovery_id: recovery.recovery_id,
+ candidate_sha256: recovery.candidate_sha256, facts_sha256: recovery.facts_sha256,
+ no_order: true, execution_authority_granted: false };
+ const payload = requested.decision === "approve"
+ ? { schema_version: "qsl_initial_enrollment_confirmation.v1", ...base, confirmed_at: decidedAt, confirmed_by: session.login }
+ : { schema_version: "qsl_initial_enrollment_rejection.v1", ...base, decision: "reject", decided_at: decidedAt, decided_by: session.login };
+ if (requested.decision === "approve") payload.confirmation_sha256 = await calculateReconciliationRecoveryConfirmationSha256(payload);
+ const target = { decision: requested.decision };
+ try {
+ const requestKey = await humanDecisionRequestKey({ requestId: requested.request_id, kind: "recovery", actor: session.login,
+ subjectId: recovery.recovery_id, materialKey, action: requested.decision, target });
+ const recorded = await runtimeInstanceCommand(env, { action: "recovery_decide", actor: session.login,
+ subject_id: recovery.recovery_id, material_key: materialKey, action_name: requested.decision,
+ request_key: requestKey, target_json: canonicalResearchTaskJson(target), decided_at: decidedAt, now_ms: Date.now(), payload });
+ const decisionReceipt = await humanDecisionReceipt(recorded.record, { kind: "recovery", subject_id: recovery.recovery_id, material_sha256: materialKey });
+ return json({ ok: true, confirmation: recorded.record?.action === "approve" ? recorded.record.payload : null,
+ rejection: recorded.record?.action === "reject" ? recorded.record.payload : null, decision_receipt: decisionReceipt, replayed: recorded.replayed === true });
+ } catch (error) { return json({ ok: false, error: error.message || "initial_enrollment_unavailable" }, error.status || 503); }
+}
+
+export async function recordReconciliationRecoveryConfirmationResponse(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "STRATEGY_SWITCH_CONFIG KV binding is required" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, 4 * 1024);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid reconciliation recovery confirmation" }, error.status || 400);
+ }
+ let requested;
+ try {
+ requested = normalizeReconciliationRecoveryConfirmationRequest(raw);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid reconciliation recovery confirmation" }, 400);
+ }
+ const dashboard = await aggregateReconciliationRecoverySources(env);
+ let recovery;
+ try {
+ recovery = currentReconciliationRecoveryRequest(dashboard, requested.recovery_id);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "reconciliation recovery confirmation is unavailable" }, error.status || 409);
+ }
+ if (requested.mode === "initial_enrollment") return recordInitialEnrollmentDecision(env, session, requested, recovery);
+ if (recovery.mode === "initial_enrollment" ||
+ requested.candidate_sha256 !== recovery.candidate_sha256 ||
+ requested.dual_review_binding_sha256 !== recovery.dual_review.evidence_binding_sha256
+ ) {
+ return json({ ok: false, error: "reconciliation evidence changed; reload the review before confirming" }, 409);
+ }
+ const decidedAt = humanDecisionTimestamp();
+ const materialKey = await recoveryDecisionMaterialKey(recovery);
+ const confirmation = requested.decision === "approve"
+ ? await buildReconciliationRecoveryConfirmation({ recovery, confirmedBy: session.login, confirmedAt: decidedAt })
+ : null;
+ const rejection = requested.decision === "reject" ? {
+ schema_version: "qsl_reconciliation_recovery_rejection.v1",
+ recovery_id: recovery.recovery_id,
+ candidate_sha256: recovery.candidate_sha256,
+ dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
+ decision: "reject",
+ decided_at: decidedAt,
+ decided_by: session.login,
+ no_order: true,
+ execution_authority_granted: false,
+ } : null;
+ const target = { decision: requested.decision };
+ let requestKey;
+ try {
+ requestKey = await humanDecisionRequestKey({
+ requestId: requested.request_id,
+ kind: "recovery",
+ actor: session.login,
+ subjectId: recovery.recovery_id,
+ materialKey,
+ action: requested.decision,
+ target,
+ });
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid reconciliation recovery confirmation" }, error.status || 400);
+ }
+ let recorded;
+ try {
+ recorded = await runtimeInstanceCommand(env, {
+ action: "recovery_decide",
+ actor: session.login,
+ subject_id: recovery.recovery_id,
+ material_key: materialKey,
+ action_name: requested.decision,
+ request_key: requestKey,
+ target_json: canonicalResearchTaskJson(target),
+ decided_at: decidedAt,
+ now_ms: Date.now(),
+ payload: confirmation || rejection,
+ });
+ } catch (error) {
+ return json({ ok: false, error: error.message || "reconciliation recovery confirmation is unavailable" }, error.status || 503);
+ }
+ const decisionReceipt = await humanDecisionReceipt(recorded.record, { kind: "recovery", subject_id: recovery.recovery_id, material_sha256: materialKey });
+ const recordedPayload = recorded.record.payload;
+ if (recorded.record?.action === "approve") {
+ await mirrorConfigJson(env, reconciliationRecoveryConfirmationArchiveKey(recovery.recovery_id, recordedPayload.confirmation_sha256), recordedPayload);
+ await mirrorConfigJson(env, reconciliationRecoveryConfirmationCurrentKey(recovery.recovery_id), recordedPayload);
+ }
+ let auditLogged = false;
+ try {
+ await appendAuditLog(env, {
+ ts: recorded.record?.decided_at || decidedAt,
+ login: session.login,
+ action: "record_reconciliation_recovery_confirmation",
+ recovery_id: recovery.recovery_id,
+ candidate_sha256: recovery.candidate_sha256,
+ dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
+ confirmation_sha256: recordedPayload.confirmation_sha256 || "",
+ decision: recorded.record?.action || requested.decision,
+ no_order: true,
+ execution_authority_granted: false,
+ });
+ auditLogged = true;
+ } catch {
+ // The immutable confirmation remains available to a future private
+ // controller even if the rolling audit log is unavailable.
+ }
+ return json({
+ ok: true,
+ confirmation: recorded.record?.action === "approve" ? recordedPayload : null,
+ rejection: recorded.record?.action === "reject" ? recordedPayload : null,
+ decision_receipt: decisionReceipt,
+ audit_logged: auditLogged,
+ replayed: recorded.replayed === true,
+ });
+}
+
+export async function aggregateReconciliationRecoverySources(env) {
+ const sources = await readReconciliationRecoverySources(env);
+ if (!sources.length) return emptyReconciliationRecoveryPayload("snapshot_unavailable");
+ const ttlSeconds = reconciliationRecoveryStaleTtlSeconds(env);
+ const now = Date.now();
+ const recoveries = [];
+ const recoveryIds = new Set();
+ const duplicateRecoveryIds = new Set();
+ const errors = [];
+ const timestamps = [];
+ let hasReadySource = false;
+ let hasStaleSource = false;
+ let hasStaleRecoveryEvidence = false;
+ for (const source of sources) {
+ const sourceFreshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
+ if (source.generated_at) timestamps.push(source.generated_at);
+ if (source.computed_at) timestamps.push(source.computed_at);
+ if (sourceFreshness.data_status === "ready") hasReadySource = true;
+ if (sourceFreshness.data_status === "stale") {
+ hasStaleSource = true;
+ errors.push("reconciliation_recovery_source_stale");
+ }
+ for (const recovery of source.recoveries) {
+ if (recoveryIds.has(recovery.recovery_id)) {
+ duplicateRecoveryIds.add(recovery.recovery_id);
+ errors.push("reconciliation_recovery_duplicate_recovery");
+ continue;
+ }
+ recoveryIds.add(recovery.recovery_id);
+ const freshness = reconciliationRecoveryEvidenceFreshness(recovery, sourceFreshness, ttlSeconds, now);
+ if (freshness.data_status === "stale") {
+ hasStaleRecoveryEvidence = true;
+ errors.push("reconciliation_recovery_evidence_stale");
+ }
+ const result = await readReconciliationRecoveryConfirmation(env, recovery.recovery_id);
+ if (result.error) errors.push(result.error);
+ if (recovery.mode === "initial_enrollment") {
+ const option = await initialEnrollmentAccountOption(env, recovery);
+ const incomplete = Object.entries(recovery.candidate.coverage).filter(([, status]) => status !== "complete").map(([name]) => `initial_enrollment_${name}_incomplete`);
+ const view = { ...recovery, platform: "ibkr", strategy_profile: recovery.candidate.strategy_profile,
+ target_name: option.target_name, account_key: option.key, candidate_sha256: recovery.candidate.candidate_sha256,
+ facts_sha256: recovery.candidate.facts_sha256, first_observed_at: recovery.candidate.first_observed_at,
+ last_observed_at: recovery.candidate.last_observed_at,
+ readiness: incomplete.length ? "blocked" : "awaiting_human_confirmation", blocker_codes: incomplete };
+ const matches = decision => decision?.mode === "initial_enrollment"
+ && decision.candidate_sha256 === view.candidate_sha256 && decision.facts_sha256 === view.facts_sha256;
+ const confirmation = matches(result.confirmation) ? result.confirmation : null;
+ const rejection = matches(result.rejection) ? result.rejection : null;
+ const presentation = recoveryMaterialPresentation({ source, recovery: view, confirmation, rejection, decisionError: result.error });
+ presentation.label = { zh: "首次登记确认", en: "Initial enrollment" };
+ presentation.material_kind = "initial_enrollment";
+ recoveries.push({ source_id: source.source_id, freshness, recovery: view, confirmation, rejection, presentation,
+ decision_authority: result.authority || null,
+ decision_binding: { kind: "recovery", subject_id: view.recovery_id, material_sha256: await recoveryDecisionMaterialKey(recovery) } });
+ continue;
+ }
+ const confirmation = result.confirmation
+ && result.confirmation.candidate_sha256 === recovery.candidate_sha256
+ && result.confirmation.dual_review_binding_sha256 === recovery.dual_review.evidence_binding_sha256
+ ? result.confirmation
+ : null;
+ const rejection = result.rejection
+ && result.rejection.candidate_sha256 === recovery.candidate_sha256
+ && result.rejection.dual_review_binding_sha256 === recovery.dual_review.evidence_binding_sha256
+ ? result.rejection
+ : null;
+ recoveries.push({ source_id: source.source_id, freshness, recovery, confirmation, rejection,
+ presentation: recoveryMaterialPresentation({ source, recovery, confirmation, rejection, decisionError: result.error }),
+ decision_authority: result.authority || null,
+ decision_binding: { kind: "recovery", subject_id: recovery.recovery_id, material_sha256: await recoveryDecisionMaterialKey(recovery) },
+ });
+ }
+ errors.push(...source.errors);
+ }
+ const uniqueRecoveries = recoveries
+ .filter((entry) => !duplicateRecoveryIds.has(entry.recovery.recovery_id))
+ .sort((left, right) => left.recovery.recovery_id.localeCompare(right.recovery.recovery_id));
+ const dataStatus = hasStaleSource || hasStaleRecoveryEvidence
+ ? "stale"
+ : (hasReadySource ? "ready" : "unavailable");
+ return {
+ schema_version: RECONCILIATION_RECOVERY_DASHBOARD_SCHEMA_VERSION,
+ generated_at: earliestControlPlaneTimestamp(timestamps),
+ computed_at: earliestControlPlaneTimestamp(timestamps),
+ data_status: dataStatus,
+ summary: {
+ recovery_count: uniqueRecoveries.length,
+ awaiting_human_confirmation: uniqueRecoveries.filter((entry) =>
+ entry.freshness.data_status === "ready" &&
+ entry.recovery.readiness === "awaiting_human_confirmation" &&
+ !entry.confirmation &&
+ !entry.rejection,
+ ).length,
+ blocked: uniqueRecoveries.filter((entry) => entry.recovery.readiness === "blocked").length,
+ confirmed: uniqueRecoveries.filter((entry) => Boolean(entry.confirmation)).length,
+ },
+ recoveries: uniqueRecoveries,
+ current_reconciliation_observation: currentReconciliationObservationPresentation(),
+ policy: {
+ human_confirmation_required: true,
+ current_evidence_required: true,
+ no_order: true,
+ execution_authority_granted: false,
+ notice: "恢复确认只记录与双审摘要绑定的人工意图;私有控制器仍须重新核验后才可恢复既有执行。",
+ },
+ errors: uniqueStrings(errors),
+ };
+}
+
+export async function readReconciliationRecoverySources(env) {
+ const store = configStore(env);
+ if (!store) return [];
+ let listing;
+ try {
+ listing = await directoryList(env, RECONCILIATION_RECOVERY_SOURCE_PREFIX, RECONCILIATION_RECOVERY_MAX_SOURCES);
+ } catch (error) {
+ return [emptyReconciliationRecoverySourceSnapshot(sourceListFailure(error, "reconciliation_recovery_source_list_unavailable"))];
+ }
+ const keys = Array.isArray(listing?.keys) ? listing.keys : [];
+ const sources = [];
+ for (const entry of keys.slice(0, RECONCILIATION_RECOVERY_MAX_SOURCES)) {
+ const key = typeof entry?.name === "string" ? entry.name : "";
+ if (!key.startsWith(RECONCILIATION_RECOVERY_SOURCE_PREFIX)) continue;
+ try {
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new Error("indexed_record_unavailable");
+ const source = normalizeReconciliationRecoverySourceSnapshot(stored, key);
+ for (const recovery of source.recoveries) if (recovery.mode === "initial_enrollment") await initialEnrollmentAccountOption(env, recovery);
+ sources.push(source);
+ } catch {
+ sources.push(emptyReconciliationRecoverySourceSnapshot("reconciliation_recovery_source_invalid"));
+ }
+ }
+ return sources;
+}
+
+export function reconciliationRecoverySourceKey(sourceId) {
+ return `${RECONCILIATION_RECOVERY_SOURCE_PREFIX}${sourceId}`;
+}
+
+export function runtimeDailyReadModelEnabled(env) {
+ return String(env.RUNTIME_DAILY_READ_MODEL_ENABLED || "") === "true";
+}
+
+export function runtimeDailyDisabledResponse() {
+ return json({ ok: false, error: "runtime_daily_disabled" }, 404);
+}
+
+export function runtimeDailyKey(businessDate, target = RUNTIME_DAILY_TARGET) {
+ return `${RUNTIME_DAILY_KEY_PREFIX}${target.target_key}:${businessDate}`;
+}
+
+export function runtimeDailyToday(now = Date.now()) {
+ return runtimeDailyBusinessDate(now);
+}
+
+export function runtimeDailyCalendarDate(value) {
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return null;
+ const [year, month, day] = value.split("-").map(Number);
+ const utc = new Date(Date.UTC(year, month - 1, day));
+ if (utc.getUTCFullYear() !== year || utc.getUTCMonth() !== month - 1 || utc.getUTCDate() !== day) return null;
+ return value;
+}
+
+export function runtimeDailyInstant(value) {
+ if (typeof value !== "string") return null;
+ const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,9})?(Z|[+-](\d{2}):(\d{2}))$/.exec(value);
+ if (!match) return null;
+ const year = Number(match[1]);
+ const month = Number(match[2]);
+ const day = Number(match[3]);
+ const hour = Number(match[4]);
+ const minute = Number(match[5]);
+ const second = Number(match[6]);
+ if (hour > 23 || minute > 59 || second > 59) return null;
+ if (match[7] !== "Z" && (Number(match[8]) > 23 || Number(match[9]) > 59)) return null;
+ const utc = new Date(Date.UTC(year, month - 1, day));
+ if (utc.getUTCFullYear() !== year || utc.getUTCMonth() !== month - 1 || utc.getUTCDate() !== day) return null;
+ const parsed = Date.parse(value);
+ return Number.isFinite(parsed) ? parsed : null;
+}
+
+export function runtimeDailyExactKeys(value, keys) {
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
+ const present = Object.keys(value);
+ return present.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
+}
+
+export function runtimeDailyBoundedText(value, max) {
+ if (typeof value !== "string" || !value || value.length > max) return false;
+ if (/[\u0000-\u001f\u007f]/.test(value)) return false;
+ const lowered = value.toLowerCase();
+ return !["secret", "token", "password", "bearer", "traceback", "/users/", "/home/"].some((marker) => lowered.includes(marker));
+}
+
+export function runtimeDailyChoice(value, allowed) {
+ return typeof value === "string" && allowed.includes(value);
+}
+
+export function runtimeDailyReject(code) {
+ throw new HttpError(code, 400);
+}
+
+export function runtimeDailyOptionalInstant(value, observedMs) {
+ if (value === null) return null;
+ const parsed = runtimeDailyInstant(value);
+ if (parsed === null) runtimeDailyReject("invalid_runtime_daily_time");
+ if (parsed > observedMs + RUNTIME_DAILY_FUTURE_SKEW_MS) runtimeDailyReject("runtime_daily_future_observation");
+ return parsed;
+}
+
+export function runtimeDailyScheduleInstants(schedule, observedMs) {
+ const latest = schedule.latest_due_at === null ? null : runtimeDailyInstant(schedule.latest_due_at);
+ const next = schedule.next_due_at === null ? null : runtimeDailyInstant(schedule.next_due_at);
+ const grace = schedule.grace_ends_at === null ? null : runtimeDailyInstant(schedule.grace_ends_at);
+ if (schedule.latest_due_at !== null && latest === null) runtimeDailyReject("invalid_runtime_daily_time");
+ if (schedule.next_due_at !== null && next === null) runtimeDailyReject("invalid_runtime_daily_time");
+ if (schedule.grace_ends_at !== null && grace === null) runtimeDailyReject("invalid_runtime_daily_time");
+ // latest_due is the last cron time already reached. next_due and grace_ends are plans.
+ if (latest !== null && latest > observedMs + RUNTIME_DAILY_FUTURE_SKEW_MS) runtimeDailyReject("invalid_runtime_daily_time");
+ if (next !== null && next <= observedMs) runtimeDailyReject("invalid_runtime_daily_time");
+ if (latest !== null && next !== null && next <= latest) runtimeDailyReject("invalid_runtime_daily_time");
+ if (latest !== null && grace !== null && grace < latest) runtimeDailyReject("invalid_runtime_daily_time");
+}
+
+// These additional constraints describe only the merged Schwab projector. The
+// original LongBridge key sets, time tolerance and receipt protocol stay intact.
+export function validateSchwabRuntimeDailyRun(run, observedMs, started, finished) {
+ const evidence = run.evidence;
+ const confirmations = {
+ not_due: ["not_applicable"], no_action: ["not_applicable"], no_signal: ["not_applicable"], no_rebalance: ["not_applicable"],
+ risk_blocked: ["not_applicable"], submitted: ["not_observed"], broker_acknowledged: ["acknowledged"],
+ partially_filled: ["partially_filled"], filled: ["filled"], reconciliation_required: ["reconciliation_required"],
+ failed: ["not_applicable", "not_observed", "reconciliation_required"],
+ };
+ if ((run.run_id !== null && !/^run\.[0-9a-f]{32}$/.test(run.run_id))
+ || run.source_object !== null || run.source_objects.length !== 0 || run.object_updated_at !== null
+ || run.execution_lane === "paper" || run.run_time_known !== (started !== null || finished !== null)) runtimeDailyReject("invalid_runtime_daily_run");
+ if ((started !== null && started > observedMs) || (finished !== null && finished > observedMs)) runtimeDailyReject("invalid_runtime_daily_time");
+ if (run.report_status !== null && !["ok", "skipped", "success", "completed", "no_action", "error", "failed", "failure", "cancelled", "canceled", "timed_out"].includes(run.report_status)) runtimeDailyReject("invalid_runtime_daily_run");
+ if (evidence.execution_status !== null && !["no_op", "no_action", "no_signal", "no_rebalance", "skipped", "outside_market_hours", "submitted", "pending_reconciliation", "reconciliation_required", "unknown", "unknown_order", "blocked", "risk_blocked", "error", "failed", "failure", "dry_run", "previewed", "partial", "partially_filled", "filled", "completed"].includes(evidence.execution_status)) runtimeDailyReject("invalid_runtime_daily_run");
+ if (!runtimeDailyChoice(evidence.receipt_state, ["valid", "missing", "invalid"])) runtimeDailyReject("invalid_runtime_daily_run");
+ if (evidence.receipt_state === "valid") {
+ if (typeof evidence.receipt_id !== "string" || !/^execution-receipt\.[0-9a-f]{32}$/.test(evidence.receipt_id)
+ || started === null || finished === null
+ || !Object.prototype.hasOwnProperty.call(confirmations, evidence.receipt_outcome)
+ || !confirmations[evidence.receipt_outcome].includes(evidence.receipt_broker_confirmation)) runtimeDailyReject("invalid_runtime_daily_run");
+ } else if (evidence.receipt_id !== null || evidence.receipt_outcome !== null || evidence.receipt_broker_confirmation !== null) runtimeDailyReject("invalid_runtime_daily_run");
+ const completedReceipt = { no_submission: "no_action", no_signal: "no_signal", no_rebalance: "no_rebalance", filled: "filled" };
+ if (Object.prototype.hasOwnProperty.call(completedReceipt, run.activity)
+ && (evidence.receipt_state !== "valid" || evidence.receipt_outcome !== completedReceipt[run.activity]
+ || !["ok", "skipped", "success", "completed", "no_action"].includes(run.report_status)
+ || run.execution_lane !== "live" || runtimeDailyRunIssue(run) !== null)) runtimeDailyReject("runtime_daily_summary_conflict");
+ if (["no_submission", "no_signal", "no_rebalance"].includes(run.activity)
+ && (evidence.broker_submission_done !== false || evidence.action_done === true || evidence.orders_pending_count !== 0
+ || (evidence.execution_status !== null && !["no_op", "no_action", "no_signal", "no_rebalance", "skipped", "outside_market_hours", "completed"].includes(evidence.execution_status)))) runtimeDailyReject("runtime_daily_summary_conflict");
+}
+
+export function validateSchwabRuntimeDailySummary(raw, record, runs, observedMs) {
+ if (raw.completeness !== (record.completeness === "complete" ? "complete" : "incomplete")) runtimeDailyReject("runtime_daily_summary_conflict");
+ const runSignatures = new Map();
+ for (const run of runs) {
+ if (run.run_id === null) continue;
+ const signature = canonicalResearchTaskJson(run);
+ const previous = runSignatures.get(run.run_id);
+ if (previous !== undefined && previous !== signature && !record.conflicts.includes(run.run_id)) runtimeDailyReject("runtime_daily_summary_conflict");
+ runSignatures.set(run.run_id, signature);
+ }
+ const incomplete = raw.read_errors.length > 0 || record.conflicts.length > 0 || record.schedule.state === "unevaluable"
+ || record.excluded_reports.some(item => item.reason !== "other_business_date")
+ || runs.some(run => run.run_id === null || run.evidence.receipt_state !== "valid" || !run.run_time_known);
+ if (record.completeness === "complete" && incomplete) runtimeDailyReject("runtime_daily_summary_conflict");
+ // A run that only finishes after the due time cannot prove that due cycle.
+ // This is a receiver invariant of the existing producer, not a new scheduler.
+ const latest = runtimeDailyInstant(record.schedule.latest_due_at);
+ const covering = latest === null ? [] : runs.filter(run => {
+ const started = runtimeDailyInstant(run.started_at), finished = runtimeDailyInstant(run.finished_at);
+ return started !== null && finished !== null && started >= latest && finished <= observedMs
+ && runtimeDailyToday(started) === record.business_date;
+ });
+ const quiet = ["no_submission", "no_signal", "no_rebalance"];
+ if ([...quiet, "filled", ...RUNTIME_DAILY_SCHEDULE_ONLY].includes(record.status)
+ && record.completeness !== "complete") runtimeDailyReject("runtime_daily_summary_conflict");
+ if ([...quiet, "filled"].includes(record.status)) {
+ if (record.kind !== "run" || covering.length === 0 || covering.some(run => run.execution_lane !== "live")) runtimeDailyReject("runtime_daily_summary_conflict");
+ if (quiet.includes(record.status) && (!['due', 'within_grace'].includes(record.schedule.state)
+ || covering.some(run => run.activity !== record.status))) runtimeDailyReject("runtime_daily_summary_conflict");
+ if (record.status === "filled" && !covering.some(run => run.activity === "filled")) runtimeDailyReject("runtime_daily_summary_conflict");
+ }
+ if (RUNTIME_DAILY_SCHEDULE_ONLY.includes(record.status)
+ && (record.kind !== "schedule" || record.schedule.state !== record.status || covering.length > 0)) runtimeDailyReject("runtime_daily_summary_conflict");
+}
+
+export function validateSchwabRuntimeDailySchedule(schedule, observedMs) {
+ const { state, reason, publication_grace_ended: ended, expected_window: window } = schedule;
+ const latest = schedule.latest_due_at === null ? null : runtimeDailyInstant(schedule.latest_due_at);
+ const next = schedule.next_due_at === null ? null : runtimeDailyInstant(schedule.next_due_at);
+ const grace = schedule.grace_ends_at === null ? null : runtimeDailyInstant(schedule.grace_ends_at);
+ const reasons = { due: ["publication_grace_ended"], within_grace: ["publication_grace_open"],
+ not_due: ["before_schedule", "no_cron_on_business_date"], market_closed: ["market_closed"],
+ outside_window: ["outside_expected_window"], unevaluable: ["schedule_missing", "schedule_invalid"] };
+ if (!reasons[state]?.includes(reason)
+ || (latest !== null && (latest > observedMs || runtimeDailyToday(latest) !== schedule.business_date))
+ || (next !== null && (next <= observedMs || runtimeDailyToday(next) !== schedule.business_date))) runtimeDailyReject("invalid_runtime_daily_projection");
+ let valid;
+ if (state === "unevaluable") valid = latest === null && next === null && grace === null && ended === null && window === "unspecified";
+ else if (state === "due" || state === "within_grace") valid = latest !== null && grace !== null && next === null && window !== "outside"
+ && (state === "due" ? ended === true && grace <= observedMs : ended === false && grace > observedMs);
+ else if (state === "not_due") valid = latest === null && grace === null && ended === null && window !== "outside"
+ && ((reason === "before_schedule") === (next !== null));
+ else if (state === "market_closed") valid = latest !== null && grace === null && ended === null;
+ else valid = window === "outside" && ended === null && ((latest === null) === (grace === null)) && !(grace !== null && next !== null);
+ if (!valid) runtimeDailyReject("invalid_runtime_daily_projection");
+}
+
+export function normalizeRuntimeDailyRun(run, observedMs, target) {
+ if (!runtimeDailyExactKeys(run, [
+ "run_id", "source_object", "source_objects", "started_at", "finished_at", "object_updated_at",
+ "report_status", "execution_lane", "activity", "run_time_known", "evidence",
+ ])) runtimeDailyReject("invalid_runtime_daily_run");
+ if (run.run_id !== null && !runtimeDailyBoundedText(run.run_id, 120)) runtimeDailyReject("invalid_runtime_daily_run");
+ if (run.source_object !== null && !runtimeDailyBoundedText(run.source_object, 512)) runtimeDailyReject("invalid_runtime_daily_run");
+ if (!Array.isArray(run.source_objects) || run.source_objects.length > 8 || run.source_objects.some((item) => !runtimeDailyBoundedText(item, 512))) {
+ runtimeDailyReject("invalid_runtime_daily_run");
+ }
+ const started = runtimeDailyOptionalInstant(run.started_at, observedMs);
+ const finished = runtimeDailyOptionalInstant(run.finished_at, observedMs);
+ runtimeDailyOptionalInstant(run.object_updated_at, observedMs);
+ if (started !== null && finished !== null && finished < started) runtimeDailyReject("invalid_runtime_daily_time");
+ if (run.report_status !== null && !runtimeDailyBoundedText(run.report_status, 64)) runtimeDailyReject("invalid_runtime_daily_run");
+ if (!runtimeDailyChoice(run.execution_lane, RUNTIME_DAILY_LANES) || !runtimeDailyChoice(run.activity, RUNTIME_DAILY_ACTIVITIES)) {
+ runtimeDailyReject("invalid_runtime_daily_run");
+ }
+ if (typeof run.run_time_known !== "boolean") runtimeDailyReject("invalid_runtime_daily_run");
+ const evidenceKeys = [
+ "execution_status", "broker_submission_done", "action_done", "orders_pending_count", "errors_present",
+ "receipt_outcome", "receipt_broker_confirmation",
+ ];
+ if (target.platform === "schwab") evidenceKeys.push("receipt_state", "receipt_id");
+ if (!runtimeDailyExactKeys(run.evidence, evidenceKeys)) runtimeDailyReject("invalid_runtime_daily_run");
+ const evidence = run.evidence;
+ if (evidence.execution_status !== null && !runtimeDailyBoundedText(evidence.execution_status, 64)) runtimeDailyReject("invalid_runtime_daily_run");
+ for (const field of ["broker_submission_done", "action_done"]) {
+ if (evidence[field] !== null && typeof evidence[field] !== "boolean") runtimeDailyReject("invalid_runtime_daily_run");
+ }
+ if (evidence.orders_pending_count !== null && (!Number.isInteger(evidence.orders_pending_count) || evidence.orders_pending_count < 0 || evidence.orders_pending_count > 100000)) {
+ runtimeDailyReject("invalid_runtime_daily_run");
+ }
+ if (typeof evidence.errors_present !== "boolean") runtimeDailyReject("invalid_runtime_daily_run");
+ for (const field of ["receipt_outcome", "receipt_broker_confirmation"]) {
+ if (evidence[field] !== null && !runtimeDailyBoundedText(evidence[field], 64)) runtimeDailyReject("invalid_runtime_daily_run");
+ }
+ if (target.platform === "schwab") validateSchwabRuntimeDailyRun(run, observedMs, started, finished);
+ return {
+ run_id: run.run_id,
+ source_object: run.source_object,
+ source_objects: [...run.source_objects],
+ started_at: run.started_at,
+ finished_at: run.finished_at,
+ object_updated_at: run.object_updated_at,
+ report_status: run.report_status,
+ execution_lane: run.execution_lane,
+ activity: run.activity,
+ run_time_known: run.run_time_known,
+ evidence: { ...evidence },
+ };
+}
+
+export function normalizeRuntimeDailyProjection(raw, now = Date.now(), registeredTarget = null) {
+ if (!runtimeDailyExactKeys(raw, ["platform", "observed_at", "completeness", "read_errors", "records", "unmatched_reports"])) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ const target = registeredTarget || runtimeDailyTarget(raw.platform);
+ if (target && raw.platform !== target.platform) runtimeDailyReject("invalid_runtime_daily_target");
+ if (!target || !runtimeDailyChoice(raw.completeness, ["complete", "incomplete"])) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ const observedMs = runtimeDailyInstant(raw.observed_at);
+ if (observedMs === null) runtimeDailyReject("invalid_runtime_daily_time");
+ if (observedMs > now + RUNTIME_DAILY_FUTURE_SKEW_MS) runtimeDailyReject("runtime_daily_future_observation");
+ if (!Array.isArray(raw.read_errors) || raw.read_errors.length > RUNTIME_DAILY_MAX_LIST || raw.read_errors.some((item) => !runtimeDailyBoundedText(item, 120))) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (!Array.isArray(raw.records) || raw.records.length !== 1) runtimeDailyReject("invalid_runtime_daily_target");
+ if (!Array.isArray(raw.unmatched_reports) || raw.unmatched_reports.length > RUNTIME_DAILY_MAX_LIST) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ const record = raw.records[0];
+ if (!runtimeDailyExactKeys(record, [
+ "platform", "target_key", "target", "business_date", "timezone", "observed_at", "status", "kind",
+ "completeness", "execution_lane", "schedule", "runs", "excluded_reports", "conflicts", "fills",
+ ])) runtimeDailyReject("invalid_runtime_daily_projection");
+ if (record.platform !== target.platform || record.target_key !== target.target_key || record.timezone !== RUNTIME_DAILY_TIMEZONE) {
+ runtimeDailyReject(record.timezone === RUNTIME_DAILY_TIMEZONE ? "invalid_runtime_daily_target" : "invalid_runtime_daily_timezone");
+ }
+ if (!runtimeDailyExactKeys(record.target, ["service", "strategy_profile", "account_scope"])) runtimeDailyReject("invalid_runtime_daily_target");
+ if (record.target.service !== target.service || record.target.strategy_profile !== target.strategy_profile || record.target.account_scope !== target.account_scope) {
+ runtimeDailyReject("invalid_runtime_daily_target");
+ }
+ const businessDate = runtimeDailyCalendarDate(record.business_date);
+ if (!businessDate || businessDate > runtimeDailyToday(now)) runtimeDailyReject("invalid_runtime_daily_date");
+ if (target.platform === "schwab" && businessDate > runtimeDailyToday(observedMs)) runtimeDailyReject("invalid_runtime_daily_date");
+ if (record.observed_at !== raw.observed_at) runtimeDailyReject("invalid_runtime_daily_time");
+ if (!runtimeDailyChoice(record.status, RUNTIME_DAILY_STATUSES) || !runtimeDailyChoice(record.kind, RUNTIME_DAILY_KINDS)) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (!runtimeDailyChoice(record.completeness, ["complete", "incomplete", "insufficient"]) || !runtimeDailyChoice(record.execution_lane, RUNTIME_DAILY_LANES)) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (!runtimeDailyExactKeys(record.schedule, [
+ "state", "business_date", "timezone", "latest_due_at", "next_due_at", "grace_ends_at",
+ "publication_grace_ended", "expected_window", "reason",
+ ])) runtimeDailyReject("invalid_runtime_daily_projection");
+ const schedule = record.schedule;
+ if (!runtimeDailyChoice(schedule.state, RUNTIME_DAILY_SCHEDULE_STATES) || schedule.business_date !== businessDate || schedule.timezone !== RUNTIME_DAILY_TIMEZONE) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ runtimeDailyScheduleInstants(schedule, observedMs);
+ if (schedule.publication_grace_ended !== null && typeof schedule.publication_grace_ended !== "boolean") {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (!runtimeDailyChoice(schedule.expected_window, ["unspecified", "inside", "outside"])) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (schedule.reason !== null && !runtimeDailyBoundedText(schedule.reason, 120)) runtimeDailyReject("invalid_runtime_daily_projection");
+ if (target.platform === "schwab") validateSchwabRuntimeDailySchedule(schedule, observedMs);
+ if (!Array.isArray(record.runs) || record.runs.length > RUNTIME_DAILY_MAX_RUNS) runtimeDailyReject("runtime_daily_run_limit");
+ const runs = record.runs.map((run) => normalizeRuntimeDailyRun(run, observedMs, target));
+ if (!Array.isArray(record.excluded_reports) || record.excluded_reports.length > RUNTIME_DAILY_MAX_LIST) runtimeDailyReject("invalid_runtime_daily_projection");
+ const excluded = record.excluded_reports.map((item) => {
+ const keys = Object.keys(item || {});
+ const allowed = keys.length === 3 ? ["run_id", "reason", "business_date"] : ["run_id", "reason"];
+ if (!runtimeDailyExactKeys(item, allowed) || !runtimeDailyBoundedText(item.reason, 64)) runtimeDailyReject("invalid_runtime_daily_projection");
+ if (item.run_id !== null && !runtimeDailyBoundedText(item.run_id, 120)) runtimeDailyReject("invalid_runtime_daily_projection");
+ if (allowed.length === 3 && runtimeDailyCalendarDate(item.business_date) === null) runtimeDailyReject("invalid_runtime_daily_date");
+ if (target.platform === "schwab" && (allowed.length !== 2
+ || !runtimeDailyChoice(item.reason, ["missing_run_time", "invalid_run_time", "inverted_run_time", "future_run_time", "other_business_date"])
+ || (item.run_id !== null && !/^run\.[0-9a-f]{32}$/.test(item.run_id)))) runtimeDailyReject("invalid_runtime_daily_projection");
+ return allowed.length === 3
+ ? { run_id: item.run_id, reason: item.reason, business_date: item.business_date }
+ : { run_id: item.run_id, reason: item.reason };
+ });
+ if (!Array.isArray(record.conflicts) || record.conflicts.length > RUNTIME_DAILY_MAX_LIST || record.conflicts.some((item) => !runtimeDailyBoundedText(item, 160))) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (["no_submission", "no_signal", "no_rebalance", "filled", ...RUNTIME_DAILY_SCHEDULE_ONLY].includes(record.status)
+ && (record.conflicts.length || runs.some(run => runtimeDailyRunIssue(run) !== null))) {
+ runtimeDailyReject("runtime_daily_summary_conflict");
+ }
+ if (!runtimeDailyExactKeys(record.fills, ["source", "records", "count"]) || record.fills.source !== "not_connected" || record.fills.count !== null || !Array.isArray(record.fills.records) || record.fills.records.length !== 0) {
+ runtimeDailyReject("invalid_runtime_daily_fills");
+ }
+ const unmatched = raw.unmatched_reports.map((item) => {
+ if (target.platform === "schwab") {
+ if (!runtimeDailyExactKeys(item, ["reason"]) || !runtimeDailyChoice(item.reason, ["invalid_report", "wrong_platform", "wrong_target", "invalid_source_object"])) runtimeDailyReject("invalid_runtime_daily_projection");
+ return { reason: item.reason };
+ }
+ if (!runtimeDailyExactKeys(item, ["run_id", "platform", "service", "strategy_profile", "account_scope", "reason"])) {
+ runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ for (const field of ["platform", "service", "strategy_profile", "account_scope", "reason"]) {
+ if (item[field] !== null && !runtimeDailyBoundedText(item[field], 120)) runtimeDailyReject("invalid_runtime_daily_projection");
+ }
+ if (item.run_id !== null && !runtimeDailyBoundedText(item.run_id, 120)) runtimeDailyReject("invalid_runtime_daily_projection");
+ return { ...item };
+ });
+ if (target.platform === "schwab") {
+ if (raw.read_errors.some(item => !["report_read_error", "coverage_unconfirmed", "report_rejected"].includes(item))
+ || record.conflicts.some(item => !/^run\.[0-9a-f]{32}$/.test(item))
+ || record.execution_lane === "paper") runtimeDailyReject("invalid_runtime_daily_projection");
+ const lanes = new Set(runs.map(run => run.execution_lane));
+ if (record.execution_lane !== (lanes.size === 1 ? runs[0].execution_lane : "insufficient")) runtimeDailyReject("invalid_runtime_daily_projection");
+ validateSchwabRuntimeDailySummary(raw, record, runs, observedMs);
+ }
+ return {
+ platform: target.platform,
+ observed_at: raw.observed_at,
+ completeness: raw.completeness,
+ read_errors: [...raw.read_errors],
+ records: [{
+ platform: target.platform,
+ target_key: target.target_key,
+ target: { ...record.target },
+ business_date: businessDate,
+ timezone: RUNTIME_DAILY_TIMEZONE,
+ observed_at: raw.observed_at,
+ status: record.status,
+ kind: record.kind,
+ completeness: record.completeness,
+ execution_lane: record.execution_lane,
+ schedule: { ...schedule },
+ runs,
+ excluded_reports: excluded,
+ conflicts: [...record.conflicts],
+ fills: { source: "not_connected", records: [], count: null },
+ }],
+ unmatched_reports: unmatched,
+ };
+}
+
+export async function runtimeDailyTrustedBinding(env, target, accountOptions = null) {
+ const config = accountOptions ? { options: accountOptions } : await loadAccountOptionsConfig(env);
+ const accountKey = runtimeDailyBoundAccountKey(config?.options, target.platform);
+ if (!accountKey) return null;
+ if (target.platform === "longbridge") return { accountKey, fingerprint: null };
+ // The payload never supplies this identity. Reuse the protected account-facts
+ // contract rather than inferring a physical account from service/live labels.
+ const bindings = await loadAccountFactsBindings(env, { propagateReadErrors: true });
+ const matches = (bindings?.bindings || []).filter(item => item.platform === target.platform
+ && item.service_name === target.service && item.account_scope === target.account_scope);
+ const option = config.options.schwab.find(item => item.key === accountKey);
+ if (matches.length !== 1 || !accountFactsOptionMatchesBinding(option, matches[0])) return null;
+ return { accountKey, sourceBindingId: matches[0].source_binding.id,
+ fingerprint: await sha256Hex(canonicalResearchTaskJson({ target, binding: matches[0] })) };
+}
+
+// A protected registration opts an account into this read model; account-facts
+// bindings alone do not register a daily source or authorize a publisher.
+export async function runtimeDailyRegisteredBindings(env, accountOptions) {
+ if (!hasConfigStore(env)) throw Error("runtime_daily_bindings_store_unavailable");
+ const registry = await readConfigJson(env, "runtime_daily_bindings");
+ if (registry === null) return [];
+ if (!runtimeDailyExactKeys(registry, ["schema_version", "bindings"])
+ || registry.schema_version !== "qsl_runtime_daily_bindings.v1" || !Array.isArray(registry.bindings) || registry.bindings.length > 64)
+ throw Error("runtime_daily_bindings_invalid");
+ if (!registry.bindings.length) return [];
+ const facts = await loadAccountFactsBindings(env, { propagateReadErrors: true });
+ const entries = registry.bindings.map(item => {
+ const platform = item?.platform || "ibkr";
+ const keys = ["account_key", "target_id", "source_binding_id", "strategy_profile", "target_key", ...(Object.hasOwn(item || {}, "platform") ? ["platform"] : [])];
+ if (!runtimeDailyExactKeys(item, keys) || !["ibkr", "longbridge", "firstrade", "binance"].includes(platform)
+ || !runtimeDailyBoundedText(item.account_key, 120) || !runtimeDailyBoundedText(item.target_id, 120)
+ || typeof item.source_binding_id !== "string" || !/^[a-f0-9]{64}$/.test(item.source_binding_id)
+ || !runtimeDailyBoundedText(item.strategy_profile, 120)) throw Error("runtime_daily_bindings_invalid");
+ const target = parseRuntimeDailyTargetKey(item.target_key, platform);
+ if (!target || (platform === "ibkr" && item.target_key.split("|").length !== 4)
+ || target.strategy_profile !== item.strategy_profile
+ || ![target.service, target.strategy_profile, target.account_scope].every(value => /^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/.test(value)))
+ throw Error("runtime_daily_bindings_invalid");
+ return { item, target, platform };
+ });
+ let binance = null, binanceReadFailed = false;
+ if (entries.some(entry => entry.platform === "binance")) {
+ try { binance = await trustedBinanceFactsBinding(env); }
+ catch { binanceReadFailed = true; }
+ }
+ return Promise.all(entries.map(async ({ item, target, platform }) => {
+ if (platform === "binance" && binanceReadFailed) return { platform, target_key: item.target_key, account_key: item.account_key, status: "read_failed" };
+ const collision = entries.some(other => other.item !== item && (other.item.account_key === item.account_key && other.platform === platform
+ || other.item.target_key === item.target_key || other.item.target_id === item.target_id
+ || other.item.source_binding_id === item.source_binding_id));
+ const resolved = platform === "binance" ? {ok: Boolean(binance), binding: binance}
+ : resolveTrustedAccountFactsBinding(facts, item.target_id, item.source_binding_id);
+ const options = (accountOptions?.[platform] || []).filter(option => option.key === item.account_key);
+ const b = resolved.binding;
+ const optionMatches = Boolean(b) && (platform === "binance" ? options.length === 1 && binanceFactsOptionMatches(options[0], b)
+ : options.length === 1 && accountFactsOptionMatchesBinding(options[0], b));
+ const binding = resolved.ok && b.platform === platform && b.account_key === item.account_key
+ && b.target_id === item.target_id && b.source_binding.id === item.source_binding_id && optionMatches
+ && (target.service === b.service_name || (platform === "binance" && b.service_name === ""))
+ && (target.account_scope === b.account_scope || (platform === "longbridge" && target.account_scope === "hk" && b.account_scope === "HK")) ? b : null;
+ const sharedPhysicalAccount = platform === "ibkr" && binding && entries.some(other => other.platform === "ibkr" && other.item !== item && other.item.account_key !== item.account_key
+ && facts?.bindings.some(otherBinding => otherBinding.platform === "ibkr" && otherBinding.account_key === other.item.account_key
+ && otherBinding.account_selector === binding.account_selector));
+ if (collision || !binding || sharedPhysicalAccount) return { platform, target_key: item.target_key, account_key: item.account_key, status: "conflict" };
+ return { platform, target_key: item.target_key, account_key: item.account_key, status: "bound", target,
+ sourceBindingId: item.source_binding_id,
+ fingerprint: await sha256Hex(canonicalResearchTaskJson({ target, registration: item, binding })) };
+ }));
+}
+
+export async function runtimeDailyPublicBindings(env, accountOptions, readRegistered = () => runtimeDailyRegisteredBindings(env, accountOptions)) {
+ const legacy = await Promise.all(Object.values(RUNTIME_DAILY_TARGETS).map(async target => {
+ try {
+ const binding = await runtimeDailyTrustedBinding(env, target, accountOptions);
+ return { platform: target.platform, target_key: target.target_key, account_key: binding?.accountKey || null,
+ status: binding ? "bound" : "unresolved" };
+ } catch {
+ return { platform: target.platform, target_key: target.target_key, account_key: null, status: "read_failed" };
+ }
+ }));
+ try {
+ const registered = await readRegistered();
+ return [...legacy, ...registered.map(({ platform, target_key, account_key, status }) => ({ platform, target_key, account_key, status }))];
+ } catch {
+ return [...legacy, { platform: "ibkr", target_key: "", account_key: null, status: "read_failed" }];
+ }
+}
+
+export function runtimeDailyStoredProjection(raw, target, binding) {
+ if (target.platform === "longbridge" && !binding.fingerprint) return raw;
+ if (!runtimeDailyExactKeys(raw, ["binding_fingerprint", "projection"])) throw new HttpError("runtime_daily_record_invalid", 503);
+ if (raw.binding_fingerprint !== binding.fingerprint) throw new HttpError("runtime_daily_binding_changed", 409);
+ return raw.projection;
+}
+
+export function runtimeDailyUnattributedResponse() {
+ return json({ ok: false, error: "runtime_daily_account_unattributed" }, 409);
+}
+
+export function runtimeDailyPublicRecord(record) {
+ return {
+ target_key: record.target_key,
+ service: record.target.service,
+ strategy_profile: record.target.strategy_profile,
+ account_scope: record.target.account_scope,
+ business_date: record.business_date,
+ timezone: record.timezone,
+ observed_at: record.observed_at,
+ status: record.status,
+ kind: record.kind,
+ completeness: record.completeness,
+ execution_lane: record.execution_lane,
+ schedule: {
+ state: record.schedule.state,
+ business_date: record.schedule.business_date,
+ timezone: record.schedule.timezone,
+ latest_due_at: record.schedule.latest_due_at,
+ next_due_at: record.schedule.next_due_at,
+ grace_ends_at: record.schedule.grace_ends_at,
+ publication_grace_ended: record.schedule.publication_grace_ended,
+ expected_window: record.schedule.expected_window,
+ // Only Schwab's validated, fixed closed-session facts may reach health UI.
+ // Legacy LongBridge reasons remain private bounded diagnostic text.
+ ...(record.platform === "schwab" && ["no_cron_on_business_date", "market_closed"].includes(record.schedule.reason)
+ ? { reason: record.schedule.reason } : {}),
+ },
+ runs: record.runs.map((run) => ({
+ run_id: run.run_id,
+ started_at: run.started_at,
+ finished_at: run.finished_at,
+ activity: run.activity,
+ execution_lane: run.execution_lane,
+ errors_present: run.evidence.errors_present,
+ ...(record.platform === "schwab" ? { issue: runtimeDailyRunIssue(run) } : {}),
+ })),
+ conflict_count: record.conflicts.length,
+ excluded_count: record.excluded_reports.length,
+ };
+}
+
+// The directory contains only successfully discovered or registered record keys.
+// Unknown coverage remains null; it must never look like an empty history.
+export async function runtimeDailyHistory(env, target) {
+ const prefix = `${RUNTIME_DAILY_KEY_PREFIX}${target.target_key}:`;
+ try {
+ const listing = await directoryList(env, prefix, RUNTIME_DAILY_HISTORY_PAGE * RUNTIME_DAILY_HISTORY_MAX_PAGES);
+ const dates = listing.keys.map(entry => runtimeDailyCalendarDate(entry.name.slice(prefix.length))).filter(Boolean).sort();
+ return { available_from: dates[0] || null, available_through: dates.at(-1) || null,
+ stored_days: dates.length, truncated: false };
+ } catch {
+ return null;
+ }
+}
+
+export function runtimeDailyReadSummary(status, reason, observedRunCount = null) {
+ return {
+ source: "stored_runtime_daily_projection", status, reason,
+ observed_run_count: observedRunCount,
+ total_run_count: status === "complete" ? observedRunCount : null,
+ };
+}
+
+export function runtimeDailyReadStatus(stored, now) {
+ const record = stored.records[0];
+ // Preserve partial observations without turning their length into a day total.
+ // Read completeness and execution outcome/freshness are separate facts.
+ const complete = stored.completeness === "complete" && record.completeness === "complete"
+ && !stored.read_errors.length && !stored.unmatched_reports.length && !record.conflicts.length
+ && record.kind !== "incomplete" && !["read_incomplete", "missing_report", "insufficient", "conflict"].includes(record.status);
+ const observedMs = runtimeDailyInstant(stored.observed_at);
+ const today = record.business_date === runtimeDailyToday(now);
+ let dataStatus = "historical";
+ if (today) {
+ const fresh = observedMs !== null && observedMs <= now + RUNTIME_DAILY_FUTURE_SKEW_MS && now - observedMs <= RUNTIME_DAILY_STALE_MS;
+ dataStatus = fresh ? "fresh" : "stale";
+ }
+ return {
+ data_status: dataStatus,
+ read_summary: runtimeDailyReadSummary(complete ? "complete" : "partial",
+ complete ? null : "runtime_daily_incomplete", record.runs.length),
+ read_error_count: stored.read_errors.length,
+ // These producer codes contain no object paths, identities or exception text.
+ // Unknown legacy diagnostics remain private and retain an explicit error.
+ read_error_codes: stored.read_errors.map(error => {
+ if (["report_read_error", "coverage_unconfirmed", "report_rejected", "read_failed", "read_truncated", "list_failed"].includes(error)) return error;
+ if (error === "listing truncated") return "listing_truncated";
+ if (error === "runtime_target_enabled_schedule_unverified") return "schedule_unverified";
+ if (error === "runtime_target_disabled") return "target_disabled";
+ return "source_read_error";
+ }),
+ unmatched_count: stored.unmatched_reports.length,
+ record: runtimeDailyPublicRecord(record),
+ fills: { source: "not_connected", records: [], count: null },
+ };
+}
+
+export async function syncRuntimeDailyResponse(request, env) {
+ if (!runtimeDailyReadModelEnabled(env)) return runtimeDailyDisabledResponse();
+ const ibkrToken = String(env.IBKR_RUNTIME_DAILY_SYNC_TOKEN || "");
+ const supplied = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ const isIbkr = !!ibkrToken && supplied === ibkrToken && supplied !== String(env.EXECUTION_EVIDENCE_SYNC_TOKEN || "");
+ if (isIbkr && [env.ACCOUNT_FACTS_SYNC_TOKEN,
+ env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN, env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN, env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.STRATEGY_SWITCH_SYNC_TOKEN, env.RECONCILIATION_RECOVERY_SYNC_TOKEN,
+ env.RECONCILIATION_RECOVERY_CONTROLLER_TOKEN, env.CYCLE_HEALTH_PROVISIONER_TOKEN]
+ .some(value => value && String(value) === ibkrToken)) {
+ throw new HttpError("runtime_daily_token_ambiguous", 503);
+ }
+ if (!isIbkr) requireDedicatedExecutionEvidenceSyncToken(request, env);
+ if (!hasConfigStore(env)) return json({ ok: false, error: "runtime daily KV is not configured" }, 503);
+ let raw;
+ try {
+ raw = await readBoundedJson(request, RUNTIME_DAILY_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid_runtime_daily_projection" }, error.status || 400);
+ }
+ let target, binding, projection;
+ try {
+ const configured = String(env.IBKR_RUNTIME_DAILY_TARGET_KEY || "");
+ let authorized;
+ try { authorized = configured.startsWith("[") || configured.startsWith("{") ? JSON.parse(configured) : [configured]; }
+ catch { throw new HttpError("runtime_daily_target_unauthorized", 403); }
+ const isGroups = authorized && !Array.isArray(authorized) && typeof authorized === "object";
+ if (isGroups && !runtimeDailyExactKeys(authorized, ["ibkr", "execution"])) throw new HttpError("runtime_daily_target_unauthorized", 403);
+ const allowed = isGroups ? authorized[isIbkr ? "ibkr" : "execution"] : isIbkr ? authorized : [];
+ if (!Array.isArray(allowed) || allowed.length > 64 || new Set(allowed).size !== allowed.length
+ || allowed.some(key => typeof key !== "string" || !parseRuntimeDailyTargetKey(key, isIbkr ? "ibkr" : "longbridge")
+ || (isIbkr && key.split("|").length !== 4))) throw new HttpError("runtime_daily_target_unauthorized", 403);
+ const registeredRequest = raw?.records?.length === 1 && allowed.includes(raw.records[0]?.target_key);
+ if (isIbkr || registeredRequest) {
+ if (!registeredRequest || (isIbkr ? raw?.platform !== "ibkr" : raw?.platform === "ibkr")) throw new HttpError("runtime_daily_target_unauthorized", 403);
+ const options = (await loadAccountOptionsConfig(env)).options;
+ const matches = (await runtimeDailyRegisteredBindings(env, options)).filter(item => item.target_key === raw.records[0].target_key && item.platform === raw.platform);
+ if (matches.length !== 1 || matches[0].status !== "bound") return runtimeDailyUnattributedResponse();
+ target = matches[0].target;
+ binding = { accountKey: matches[0].account_key, fingerprint: matches[0].fingerprint, sourceBindingId: matches[0].sourceBindingId };
+ } else {
+ projection = normalizeRuntimeDailyProjection(raw);
+ target = runtimeDailyTarget(projection.platform);
+ binding = await runtimeDailyTrustedBinding(env, target);
+ }
+ }
+ catch (error) {
+ if (error instanceof HttpError) throw error;
+ return json({ ok: false, error: "runtime_daily_read_failed" }, 503);
+ }
+ if (!binding) return runtimeDailyUnattributedResponse();
+ if (!projection) projection = normalizeRuntimeDailyProjection(raw, Date.now(), target);
+ if (target.platform === "schwab" || binding.sourceBindingId) {
+ // Reuse the existing protected source_binding.id, not a new identity or a
+ // body-supplied account. This also guards a new day with no cached fingerprint.
+ const sourceBindingId = request.headers.get("X-QSL-Source-Binding-ID");
+ if (typeof sourceBindingId !== "string" || !/^[0-9a-f]{64}$/.test(sourceBindingId)) {
+ return json({ ok: false, error: "runtime_daily_source_binding_invalid" }, 400);
+ }
+ if (sourceBindingId !== binding.sourceBindingId) {
+ return json({ ok: false, error: "runtime_daily_source_binding_mismatch" }, 409);
+ }
+ }
+ const accountKey = binding.accountKey;
+ const businessDate = projection.records[0].business_date;
+ const store = configStore(env);
+ const key = runtimeDailyKey(businessDate, target);
+ const storedText = await store.get(key);
+ if (storedText !== null && storedText !== undefined) {
+ let storedRaw;
+ let storedProjection;
+ try {
+ storedRaw = JSON.parse(storedText);
+ storedProjection = normalizeRuntimeDailyProjection(runtimeDailyStoredProjection(storedRaw, target, binding), Date.now(), target);
+ } catch (error) {
+ if (error.message === "runtime_daily_binding_changed") return json({ ok: false, error: error.message }, 409);
+ return json({ ok: false, error: "runtime_daily_existing_record_invalid" }, 409);
+ }
+ if (storedProjection.records[0].business_date !== businessDate || storedProjection.platform !== target.platform
+ || storedProjection.records[0].target_key !== target.target_key) {
+ return json({ ok: false, error: "runtime_daily_existing_record_invalid" }, 409);
+ }
+ const storedObservedAt = runtimeDailyInstant(storedProjection.observed_at);
+ const incomingObservedAt = runtimeDailyInstant(projection.observed_at);
+ if (storedObservedAt === null || incomingObservedAt === null) {
+ return json({ ok: false, error: "runtime_daily_existing_record_invalid" }, 409);
+ }
+ if (incomingObservedAt < storedObservedAt) {
+ return json({ ok: false, error: "runtime_daily_stale_observation" }, 409);
+ }
+ if (incomingObservedAt === storedObservedAt) {
+ if (canonicalResearchTaskJson(projection) === canonicalResearchTaskJson(storedProjection)) {
+ return json({
+ ok: true,
+ stored: true,
+ business_date: businessDate,
+ platform: target.platform,
+ target_key: target.target_key,
+ account_key: accountKey,
+ ...(binding.fingerprint && target.platform !== "schwab" ? { observed_at: projection.observed_at } : {}),
+ });
+ }
+ return json({ ok: false, error: "runtime_daily_observation_conflict" }, 409);
+ }
+ }
+ await writeConfigJson(env, key, binding.fingerprint
+ ? { binding_fingerprint: binding.fingerprint, projection } : projection);
+ return json({
+ ok: true,
+ stored: true,
+ business_date: businessDate,
+ platform: target.platform,
+ target_key: target.target_key,
+ account_key: accountKey,
+ ...(binding.fingerprint && target.platform !== "schwab" ? { observed_at: projection.observed_at } : {}),
+ });
+}
+
+export async function runtimeDailyResponse(request, env, url, context = null) {
+ if (!runtimeDailyReadModelEnabled(env)) return runtimeDailyDisabledResponse();
+ const session = await (context ? context.readSession() : readSession(request, env));
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json({ ok: false, error: "runtime daily KV is not configured" }, 503);
+ const platforms = url.searchParams.getAll("platform");
+ const accounts = url.searchParams.getAll("account_key");
+ if (platforms.length > 1 || accounts.length > 1 || url.searchParams.getAll("date").length !== 1
+ || (platforms.length !== accounts.length)) return json({ ok: false, error: "invalid_runtime_daily_selection" }, 400);
+ // Legacy date-only reads always mean PAPER, never the first configured target.
+ let target = platforms.length ? runtimeDailyTarget(platforms[0]) : RUNTIME_DAILY_TARGET;
+ if ((!target && !["ibkr", "firstrade", "binance"].includes(platforms[0])) || (accounts.length && !runtimeDailyBoundedText(accounts[0], 120))) return json({ ok: false, error: "invalid_runtime_daily_selection" }, 400);
+ const historyOptions = url.searchParams.getAll("include_history");
+ if (historyOptions.length > 1 || historyOptions.some(value => !["true", "false"].includes(value)))
+ return json({ ok: false, error: "invalid_runtime_daily_selection" }, 400);
+ const includeHistory = historyOptions[0] !== "false";
+ const businessDate = runtimeDailyCalendarDate(url.searchParams.get("date"));
+ if (!businessDate || businessDate > runtimeDailyToday()) return json({ ok: false, error: "invalid_runtime_daily_date" }, 400);
+ let binding;
+ try {
+ const config = await (context ? context.readOptions() : loadAccountOptionsConfig(env));
+ const matches = accounts.length ? (await (context ? context.readRegistered() : runtimeDailyRegisteredBindings(env, config.options)))
+ .filter(item => item.platform === platforms[0] && item.account_key === accounts[0]) : [];
+ if (matches.length) {
+ if (matches.length !== 1 || matches[0].status !== "bound") return runtimeDailyUnattributedResponse();
+ binding = { accountKey: matches[0].account_key, fingerprint: matches[0].fingerprint };
+ target = matches[0].target;
+ } else if (platforms[0] === "ibkr" || !target) return runtimeDailyUnattributedResponse();
+ else binding = await runtimeDailyTrustedBinding(env, target, config.options);
+ }
+ catch { return json({ ok: false, error: "runtime_daily_read_failed" }, 503); }
+ if (!binding || (accounts.length && accounts[0] !== binding.accountKey)) return runtimeDailyUnattributedResponse();
+ const accountKey = binding.accountKey;
+ let stored;
+ try {
+ stored = await readConfigJson(env, runtimeDailyKey(businessDate, target));
+ } catch {
+ return json({ ok: false, error: "runtime_daily_read_failed",
+ read_summary: runtimeDailyReadSummary("read_failed", "runtime_daily_read_failed") }, 503);
+ }
+ const base = {
+ ok: true,
+ date: businessDate,
+ timezone: RUNTIME_DAILY_TIMEZONE,
+ account_key: accountKey,
+ platform: target.platform,
+ target_key: target.target_key,
+ history: includeHistory ? await runtimeDailyHistory(env, target) : null,
+ };
+ if (stored === null || stored === undefined) {
+ return json({ ...base, data_status: "unavailable", record: null, fills: null, read_error_count: 0, unmatched_count: 0,
+ read_summary: runtimeDailyReadSummary("no_data", "runtime_daily_record_missing") });
+ }
+ let projection;
+ try {
+ projection = normalizeRuntimeDailyProjection(runtimeDailyStoredProjection(stored, target, binding), Date.now(), target);
+ } catch (error) {
+ if (error.message === "runtime_daily_binding_changed") return json({ ok: false, error: error.message }, 409);
+ return json({ ok: false, error: "runtime_daily_record_invalid",
+ read_summary: runtimeDailyReadSummary("read_failed", "runtime_daily_record_invalid") }, 503);
+ }
+ if (projection.records[0].business_date !== businessDate || projection.platform !== target.platform
+ || projection.records[0].target_key !== target.target_key) {
+ return json({ ok: false, error: "runtime_daily_record_invalid",
+ read_summary: runtimeDailyReadSummary("read_failed", "runtime_daily_record_invalid") }, 503);
+ }
+ return json({ ...base, ...runtimeDailyReadStatus(projection, Date.now()) });
+}
+
+export async function syncExecutionEvidenceSourceResponse(request, env) {
+ requireDedicatedExecutionEvidenceSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "execution evidence KV is not configured" }, 503);
+ }
+
+ const receiptId = request.headers.get("X-QSL-Execution-Evidence-Receipt");
+ if (receiptId !== null && !/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(receiptId)) {
+ return json({ ok: false, error: "invalid execution evidence receipt identifier" }, 400);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, EXECUTION_EVIDENCE_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid execution evidence payload" }, error.status || 400);
+ }
+
+ let source;
+ try {
+ source = normalizeExecutionEvidenceSourceSnapshot(raw, "execution evidence source snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid execution evidence payload" }, 400);
+ }
+
+ await writeConfigJson(env, executionEvidenceSourceKey(source.source_id), source);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "execution-evidence-source-sync",
+ action: "sync_execution_evidence_source",
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ deployment_count: source.deployments.length,
+ data_status: source.data_status,
+ ...(receiptId === null ? {} : { receipt_id: receiptId }),
+ });
+ } catch {
+ // The source snapshot is accepted independently of optional audit retention.
+ }
+ return json({
+ ok: true,
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ deployment_count: source.deployments.length,
+ generated_at: source.generated_at,
+ ...(receiptId === null ? {} : { receipt_id: receiptId }),
+ });
+}
+
+export async function executionEvidenceResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json(emptyExecutionEvidencePayload("snapshot_unavailable"));
+ return json(await aggregateExecutionEvidenceSources(env));
+}
+
+export async function aggregateExecutionEvidenceSources(env) {
+ const sources = await readExecutionEvidenceSources(env);
+ if (!sources.length) return emptyExecutionEvidencePayload("snapshot_unavailable");
+
+ const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
+ const now = Date.now();
+ const deployments = [];
+ const deploymentIds = new Set();
+ const duplicateDeploymentIds = new Set();
+ const errors = [];
+ const timestamps = [];
+ let hasReadySource = false;
+ let hasStaleSource = false;
+
+ for (const source of sources) {
+ const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
+ if (source.generated_at) timestamps.push(source.generated_at);
+ if (source.computed_at) timestamps.push(source.computed_at);
+ if (freshness.data_status === "ready") hasReadySource = true;
+ if (freshness.data_status === "stale") {
+ hasStaleSource = true;
+ errors.push("execution_evidence_source_stale");
+ }
+ for (const deployment of source.deployments) {
+ if (deploymentIds.has(deployment.deployment_id)) {
+ duplicateDeploymentIds.add(deployment.deployment_id);
+ errors.push("execution_evidence_duplicate_deployment");
+ continue;
+ }
+ deploymentIds.add(deployment.deployment_id);
+ deployments.push({ source_id: source.source_id, freshness, deployment });
+ }
+ errors.push(...source.errors);
+ }
+
+ const uniqueDeployments = deployments.filter((entry) => !duplicateDeploymentIds.has(entry.deployment.deployment_id));
+ const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
+ return {
+ schema_version: EXECUTION_EVIDENCE_DASHBOARD_SCHEMA_VERSION,
+ generated_at: earliestControlPlaneTimestamp(timestamps),
+ computed_at: earliestControlPlaneTimestamp(timestamps),
+ data_status: dataStatus,
+ summary: normalizeExecutionEvidenceSummary(uniqueDeployments.map((entry) => entry.deployment)),
+ deployments: uniqueDeployments,
+ policy: {
+ execution_evidence_read_only: true,
+ p6_owner_decision_required: true,
+ limited_live_canary_active: false,
+ notice: "执行证据按策略、平台和执行通道分别记录;它不授权订单或实盘。",
+ },
+ errors: uniqueStrings(errors),
+ };
+}
+
+export async function readExecutionEvidenceSources(env) {
+ const store = configStore(env);
+ if (!store) return [];
+ let listing;
+ try {
+ listing = await directoryList(env, EXECUTION_EVIDENCE_SOURCE_PREFIX, EXECUTION_EVIDENCE_MAX_SOURCES);
+ } catch {
+ return [emptyExecutionEvidenceSourceSnapshot("execution_evidence_source_list_unavailable")];
+ }
+ const keys = Array.isArray(listing?.keys) ? listing.keys : [];
+ const sources = [];
+ for (const entry of keys.slice(0, EXECUTION_EVIDENCE_MAX_SOURCES)) {
+ const key = typeof entry?.name === "string" ? entry.name : "";
+ if (!key.startsWith(EXECUTION_EVIDENCE_SOURCE_PREFIX)) continue;
+ try {
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new Error("indexed_record_unavailable");
+ sources.push(normalizeExecutionEvidenceSourceSnapshot(stored, key));
+ } catch {
+ sources.push(emptyExecutionEvidenceSourceSnapshot("execution_evidence_source_invalid"));
+ }
+ }
+ return sources;
+}
+
+export function executionEvidenceSourceKey(sourceId) {
+ return `${EXECUTION_EVIDENCE_SOURCE_PREFIX}${sourceId}`;
+}
+
+export function runtimeTargetLifecycleAuditState(source, ttlSeconds, now) {
+ if (!source) return null;
+ const state = structuredClone(source);
+ state.freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now).data_status;
+ delete state.generated_at;
+ delete state.computed_at;
+ for (const target of state.targets) {
+ if (target.deployment?.observed_at) {
+ target.deployment.observed_at = controlPlaneSnapshotFreshness({
+ data_status: "ready", computed_at: target.deployment.observed_at,
+ }, ttlSeconds, now).data_status;
+ }
+ }
+ return JSON.stringify(state);
+}
+
+export async function syncRuntimeTargetLifecycleSourceResponse(request, env) {
+ // This publisher has the same narrow scope as execution evidence: sanitized
+ // platform status only, never credentials, accounts, orders, or commands.
+ requireDedicatedExecutionEvidenceSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "runtime target lifecycle KV is not configured" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, RUNTIME_TARGET_LIFECYCLE_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid runtime target lifecycle payload" }, error.status || 400);
+ }
+ let source;
+ try {
+ source = normalizeRuntimeTargetLifecycleSourceSnapshot(raw, "runtime target lifecycle source snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid runtime target lifecycle payload" }, 400);
+ }
+ const sourceKey = runtimeTargetLifecycleSourceKey(source.source_id);
+ let previous = null;
+ try {
+ previous = normalizeRuntimeTargetLifecycleSourceSnapshot(await readConfigJson(env, sourceKey));
+ } catch {
+ // Missing/unreadable history must not prevent a fresh, valid observation.
+ }
+ // Always retain the new evidence timestamps. Only the optional rolling audit
+ // skips unchanged polling records; operator actions are audited separately.
+ await writeConfigJson(env, sourceKey, source);
+ try {
+ const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
+ const now = Date.now();
+ if (runtimeTargetLifecycleAuditState(previous, ttlSeconds, now) !== runtimeTargetLifecycleAuditState(source, ttlSeconds, now)) {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "runtime-target-lifecycle-source-sync",
+ action: "sync_runtime_target_lifecycle_source",
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ target_count: source.targets.length,
+ data_status: source.data_status,
+ });
+ }
+ } catch {
+ // A valid no-order snapshot remains useful when convenience audit retention fails.
+ }
+ await maybeAutoDispatchAccountDiagnosis(env, source);
+ return json({
+ ok: true,
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ target_count: source.targets.length,
+ generated_at: source.generated_at,
+ });
+}
+
+export async function runtimeReadbackResponse(request, env, url) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
+ if ([...url.searchParams.keys()].some(key => key !== "scope") || url.searchParams.getAll("scope").length !== 1
+ || !/^[a-z0-9_-]+:[a-zA-Z0-9_.-]+$/.test(url.searchParams.get("scope") || ""))
+ return json({ ok: false, error: "invalid_runtime_scope" }, 400);
+ const scope = url.searchParams.get("scope");
+ try {
+ const config = await loadAccountOptionsConfig(env);
+ const accounts = Object.entries(config.options || {}).flatMap(([platform, rows]) => rows.map(row => ({ ...row, platform })));
+ const matches = accounts.filter(row => `${row.platform}:${row.key}` === scope);
+ if (!matches.length) return json({ ok: false, error: "runtime_scope_not_found" }, 404);
+ if (matches.length !== 1) return json({ ok: false, error: "runtime_binding_conflict" }, 409);
+ if (!hasConfigStore(env)) return json({ ok: false, error: "runtime_readback_unavailable" }, 503);
+ const snapshot = await aggregateRuntimeTargetLifecycleSources(env);
+ if (snapshot.errors?.some(code => /source_list_unavailable|source_invalid/.test(code)))
+ return json({ ok: false, error: "runtime_readback_failed" }, 503);
+ return json(runtimeReadbackProjection(matches[0], accounts, snapshot));
+ } catch {
+ return json({ ok: false, error: "runtime_readback_failed" }, 503);
+ }
+}
+
+export async function runtimeTargetLifecycleResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json(emptyRuntimeTargetLifecyclePayload("snapshot_unavailable"));
+ return json(await aggregateRuntimeTargetLifecycleSources(env));
+}
+
+export function requireAccountDiagnosisToken(request, env) {
+ const expected = String(env.ACCOUNT_DIAGNOSIS_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("account diagnosis sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("account diagnosis sync token is invalid", 401);
+}
+
+export function accountDiagnosisRequestId(value) {
+ const text = String(value || "").trim().toLowerCase();
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(text)) {
+ throw new HttpError("invalid_account_diagnosis_request_id", 400);
+ }
+ return text;
+}
+
+export function accountDiagnosisChecks(entry, dataStatus) {
+ const target = entry?.target?.target || {};
+ const monitoring = entry?.target?.monitoring || {};
+ const deployment = entry?.target?.deployment || {};
+ return {
+ configured_state: ["enabled", "disabled"].includes(target.configured_state) ? target.configured_state : "unknown",
+ runtime_enabled: typeof deployment.runtime_enabled === "boolean" ? deployment.runtime_enabled : null,
+ scheduler_state: ["enabled", "paused"].includes(deployment.scheduler_state) ? deployment.scheduler_state : "unknown",
+ runtime_guard: ["pass", "attention", "unavailable"].includes(monitoring.runtime_guard) ? monitoring.runtime_guard : "unavailable",
+ execution_heartbeat: ["pass", "attention", "unavailable", "not_due", "not_applicable"].includes(monitoring.execution_heartbeat)
+ ? monitoring.execution_heartbeat : "unavailable",
+ freshness: ["ready", "stale", "unavailable"].includes(entry?.freshness?.data_status)
+ ? entry.freshness.data_status : (dataStatus === "ready" ? "unavailable" : dataStatus),
+ };
+}
+
+export function accountDiagnosisHasConfirmedAttention(checks) {
+ return ["ready", "stale"].includes(checks.freshness)
+ && (checks.freshness === "stale" || (checks.configured_state !== "disabled" && checks.runtime_enabled === false)
+ || (checks.configured_state === "enabled" && checks.scheduler_state === "paused")
+ || checks.runtime_guard === "attention" || checks.execution_heartbeat === "attention");
+}
+
+export function accountDiagnosisStateFingerprint(targetId, checks) {
+ return `${targetId}:${JSON.stringify(checks)}`;
+}
+
+export function accountDiagnosisTargetSpec(platform, targetId) {
+ const spec = ACCOUNT_DIAGNOSIS_TARGETS[String(targetId || "").trim()];
+ return spec && (platform == null || spec.platform === platform) ? spec : null;
+}
+
+export async function accountDiagnosisAccount(env, platform, key) {
+ let config;
+ try {
+ config = await loadAccountOptionsConfig(env);
+ } catch {
+ throw accountDiagnosisConflict("account_diagnosis_config_unavailable");
+ }
+ const options = Array.isArray(config.options?.[platform])
+ ? config.options[platform].filter(item => item?.key === key) : [];
+ if (options.length === 0) throw accountDiagnosisConflict("account_diagnosis_account_not_found");
+ if (options.length !== 1) throw accountDiagnosisConflict("account_diagnosis_account_not_unique");
+ const account = options[0];
+ const targetId = String(account.runtime_status_target_id || "").trim();
+ if (!accountDiagnosisTargetSpec(platform, targetId)) throw accountDiagnosisConflict("account_diagnosis_target_not_admitted");
+ const allIdentityMatches = Object.entries(config.options || {}).flatMap(([itemPlatform, items]) =>
+ (Array.isArray(items) ? items : []).filter(item => String(item?.runtime_status_target_id || "").trim() === targetId)
+ .map(item => ({ platform: itemPlatform, key: item.key })));
+ if (allIdentityMatches.length !== 1 || allIdentityMatches[0].platform !== platform || allIdentityMatches[0].key !== key) {
+ throw accountDiagnosisConflict("account_diagnosis_identity_conflict");
+ }
+ return { platform, key, account, targetId, config };
+}
+
+export async function accountDiagnosisContext(env, platform, key) {
+ const identity = await accountDiagnosisAccount(env, platform, key);
+ if (!hasConfigStore(env)) throw accountDiagnosisConflict("account_diagnosis_lifecycle_store_unavailable");
+ const sources = await readRuntimeTargetLifecycleSources(env);
+ const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
+ const matches = [];
+ for (const source of sources) {
+ const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, Date.now());
+ for (const target of source.targets) {
+ if (target.target_id === identity.targetId && target.target.platform === identity.platform) {
+ matches.push({ target, freshness, observedAt: source.computed_at || source.generated_at });
+ }
+ }
+ }
+ if (matches.length === 0) {
+ throw accountDiagnosisConflict("account_diagnosis_lifecycle_match_missing");
+ }
+ if (matches.length !== 1) {
+ throw accountDiagnosisConflict("account_diagnosis_lifecycle_match_ambiguous");
+ }
+ const entry = matches[0];
+ let checks;
+ try {
+ checks = accountDiagnosisChecks(entry, entry.freshness.data_status);
+ } catch {
+ throw accountDiagnosisConflict("account_diagnosis_schema_incompatible");
+ }
+ if (!checks || typeof checks !== "object") {
+ throw accountDiagnosisConflict("account_diagnosis_schema_incompatible");
+ }
+ if (!["ready", "stale"].includes(checks.freshness)) throw accountDiagnosisConflict("account_diagnosis_source_unavailable");
+ const observedAt = entry.observedAt;
+ if (!observedAt) throw accountDiagnosisConflict("account_diagnosis_observation_missing");
+ return {
+ platform, key, targetId: identity.targetId, checks, observedAt,
+ stateFingerprint: accountDiagnosisStateFingerprint(identity.targetId, checks),
+ attention: accountDiagnosisHasConfirmedAttention(checks),
+ };
+}
+
+export function accountDiagnosisPublicTask(task, recheckStatus = task?.recheck_dispatch_state) {
+ if (!task) return null;
+ return {
+ request_id: task.request_id,
+ platform: task.platform,
+ key: task.key,
+ target_id: task.target_id,
+ trigger: task.trigger,
+ status: task.status,
+ summary: task.summary || "",
+ reason_code: task.reason_code || "",
+ dispatch_state: task.dispatch_state,
+ recheck_status: recheckStatus,
+ created_at: task.created_at,
+ updated_at: task.updated_at,
+ };
+}
+
+export async function accountDiagnosisRecheckStatus(env, task) {
+ if (!task || task.status !== "succeeded" || task.recheck_dispatch_state !== "sent") {
+ return task?.recheck_dispatch_state || "not_requested";
+ }
+ const resultAt = Date.parse(task.updated_at);
+ if (!Number.isFinite(resultAt)) return "sent";
+ try {
+ const sources = await readRuntimeTargetLifecycleSources(env);
+ const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
+ const matches = [];
+ for (const source of sources) {
+ const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, Date.now());
+ const observedAt = source.computed_at || source.generated_at;
+ if (freshness.data_status !== "ready" || !observedAt || Date.parse(observedAt) <= resultAt) continue;
+ for (const target of source.targets) {
+ if (target.target_id === task.target_id && target.target.platform === task.platform) {
+ matches.push({ target, freshness, observedAt });
+ }
+ }
+ }
+ if (matches.length !== 1) return "sent";
+ const checks = accountDiagnosisChecks(matches[0], matches[0].freshness.data_status);
+ if (checks.freshness !== "ready" || checks.runtime_guard === "unavailable" || checks.execution_heartbeat === "unavailable"
+ || checks.runtime_enabled === null || checks.scheduler_state === "unknown") return "unavailable";
+ if (checks.configured_state === "enabled") {
+ return checks.runtime_enabled === true && checks.scheduler_state === "enabled"
+ && checks.runtime_guard === "pass" && ["pass", "not_due"].includes(checks.execution_heartbeat) ? "passed" : "attention";
+ }
+ if (checks.configured_state === "disabled") {
+ return checks.runtime_enabled === false && checks.scheduler_state === "paused"
+ && checks.runtime_guard === "pass" && checks.execution_heartbeat === "not_applicable" ? "passed" : "attention";
+ }
+ return "unavailable";
+ } catch {
+ return "sent";
+ }
+}
+
+export function accountDiagnosisInternalTask(task) {
+ return {
+ request_id: task.request_id,
+ platform: task.platform,
+ key: task.key,
+ target_id: task.target_id,
+ trigger: task.trigger,
+ observed_at: task.observed_at,
+ checks: task.checks,
+ status: task.status,
+ };
+}
+
+export function accountDiagnosisNativeContext(env) {
+ try {
+ const binding = JSON.parse(env.ACCOUNT_DIAGNOSIS_NATIVE_BINDING_JSON || "null");
+ const expected = ["schema_version", "project", "resource", "audience", "provider", "profile", "model", "worker"];
+ if (!binding || Object.keys(binding).sort().join() !== expected.sort().join()
+ || binding.schema_version !== "qrs.account-diagnosis-native.v1"
+ || binding.project !== "QuantStrategyLab/QuantRuntimeSettings"
+ || expected.filter(key => key !== "schema_version").some(key => typeof binding[key] !== "string"
+ || !binding[key] || binding[key].length > 200 || /\s/.test(binding[key]))
+ || binding.profile.length > 100 || binding.profile.includes(":")) throw Error();
+ const url = new URL(binding.resource);
+ if (url.protocol !== "https:" || !url.hostname || url.username || url.password || url.search || url.hash
+ || binding.resource.endsWith("/")) throw Error();
+ const transport = env.ACCOUNT_DIAGNOSIS_NATIVE_TRANSPORT;
+ // This seam carries existing approved submit/read authentication. Neither
+ // an old GitHub dispatch token nor the QRS callback token can substitute it.
+ if (!transport || typeof transport.fetch !== "function") throw Error();
+ return { binding, transport };
+ } catch {
+ throw new HttpError("account_diagnosis_native_not_configured", 503);
+ }
+}
+
+export function accountDiagnosisNativeRequest(task, binding) {
+ const input = accountDiagnosisInternalTask(task);
+ const properties = { status: { enum: ["succeeded", "failed", "unknown"] },
+ summary: { type: "string", minLength: 1, maxLength: ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS },
+ reason_code: { enum: ACCOUNT_DIAGNOSIS_REASON_CODES }, advisory_only: { const: true },
+ execution_authority_granted: { const: false } };
+ return { mode: "agent", profile: binding.profile, model: binding.model,
+ objective: "Diagnose only the supplied account/runtime availability checks. Return an advisory report, not a health or execution approval. Do not access accounts, change configuration, repair, trade, deploy, publish, or notify.",
+ materials: [input], timeout_seconds: 600,
+ output_schema: { type: "object", additionalProperties: false, required: Object.keys(properties), properties } };
+}
+
+export async function accountDiagnosisNativeIO(context, method, path, body, headers = {}) {
+ const controller = new AbortController();
+ const timer = setTimeout(() => controller.abort(), 10000);
+ try {
+ const response = await context.transport.fetch(new Request(context.binding.resource + path, {
+ method, redirect: "manual", signal: controller.signal,
+ headers: { "Content-Type": "application/json", ...headers },
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
+ }));
+ if (!response.ok || !response.body) throw Error();
+ const reader = response.body.getReader();
+ const chunks = [];
+ let length = 0;
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+ length += value.length;
+ if (length > 64 * 1024) { await reader.cancel(); throw Error(); }
+ chunks.push(value);
+ }
+ const bytes = new Uint8Array(length);
+ let offset = 0;
+ for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.length; }
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
+ } catch {
+ throw new HttpError("account_diagnosis_native_outcome_unknown", 502);
+ } finally {
+ clearTimeout(timer);
+ }
+}
+
+export async function accountDiagnosisNativeStop(env, context, task) {
+ const reserved = await runtimeInstanceCommand(env, { action: "diagnosis_native_cancel", actor: "native-diagnosis-caller",
+ request_id: task.request_id, updated_at: new Date().toISOString() });
+ if (reserved.send_cancel) {
+ try { await accountDiagnosisNativeIO(context, "POST", `/v1/tasks/${encodeURIComponent(reserved.task.native.task_id)}/cancel`, {}); } catch { /* Unknown cancellation is never retried. */ }
+ }
+ return reserved;
+}
+
+export async function accountDiagnosisNativeReadback(env, context, task, record, cancelRequested = false) {
+ const native = task.native;
+ if (!native || canonicalResearchTaskJson(native.binding) !== canonicalResearchTaskJson(context.binding)) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ const taskId = record?.id;
+ const validId = typeof taskId === "string" && /^[A-Za-z0-9_-]{1,200}$/.test(taskId);
+ if (!validId || (native.task_id && taskId !== native.task_id)
+ || record.owner !== native.binding.project || record.provider !== native.binding.provider
+ || record.result_kind !== "advisory" || record.revision !== 1
+ || !Number.isFinite(record.deadline) || (native.task_deadline !== null && native.task_deadline !== record.deadline)
+ || await sha256Hex(canonicalResearchTaskJson(record.request ?? null)) !== native.request_sha256) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ const next = structuredClone(native);
+ next.task_id = taskId;
+ next.task_deadline = record.deadline;
+ if (record.worker !== null && record.worker !== undefined || record.attempt !== null && record.attempt !== undefined) {
+ if (record.worker !== native.binding.worker || typeof record.attempt !== "string" || !record.attempt || record.attempt.length > 200) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ const claim = [record.worker, record.attempt, record.revision];
+ if (native.claim && canonicalResearchTaskJson(native.claim) !== canonicalResearchTaskJson(claim)) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ next.claim = claim;
+ } else if (native.claim) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ const expired = Date.now() / 1000 >= Math.min(native.deadline, record.deadline);
+ let status = "queued", summary = "", reason = "", terminal = false;
+ const negativeTerminal = ["failed", "invalid_output", "cancelled"].includes(record.status);
+ if (((cancelRequested || expired || native.cancel_requested || native.cancel_sent) && !negativeTerminal)
+ || record.status === "cancel_requested" || record.status === "outcome_unknown") {
+ status = "unknown";
+ next.phase = "hold";
+ } else if (["queued", "submitting", "running"].includes(record.status)) {
+ status = record.status === "running" ? "running" : "queued";
+ if (status === "running" && !next.claim) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ next.phase = "pending";
+ } else if (record.status === "completed") {
+ const output = record.output;
+ if (!next.claim || !output || Object.keys(output).sort().join() !== "advisory_only,execution_authority_granted,reason_code,status,summary"
+ || !["succeeded", "failed", "unknown"].includes(output.status)
+ || typeof output.summary !== "string" || !output.summary.trim() || output.summary.length > ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS
+ || !ACCOUNT_DIAGNOSIS_REASON_CODES.includes(output.reason_code)
+ || output.advisory_only !== true || output.execution_authority_granted !== false) {
+ throw new HttpError("invalid_account_diagnosis_result", 400);
+ }
+ next.output_sha256 = await sha256Hex(canonicalResearchTaskJson(output));
+ next.phase = "terminal";
+ status = output.status; summary = output.summary.trim(); reason = output.reason_code;
+ terminal = true;
+ } else if (["failed", "invalid_output", "cancelled"].includes(record.status)) {
+ next.phase = "terminal"; status = "failed"; terminal = true;
+ summary = "Native diagnosis did not produce an accepted advisory result."; reason = "invalid_response";
+ } else {
+ throw new HttpError("invalid_account_diagnosis_result", 400);
+ }
+ // All terminal adoption is still bounded by the original operation deadline.
+ if (terminal && status === "succeeded" && Date.now() / 1000 >= Math.min(native.deadline, record.deadline)) {
+ return accountDiagnosisNativeStop(env, context, { ...task, native: next });
+ }
+ if (terminal) next.receipt = await sha256Hex(canonicalResearchTaskJson({ task_id: taskId, claim: next.claim,
+ revision: record.revision, request_sha256: next.request_sha256, output_sha256: next.output_sha256,
+ native_status: record.status, status, summary, reason }));
+ const saved = await runtimeInstanceCommand(env, { action: "diagnosis_native_save", actor: "native-diagnosis-caller",
+ request_id: task.request_id, native: next, status, summary, reason_code: reason, updated_at: new Date().toISOString() });
+ if ((cancelRequested || native.cancel_requested || expired) && !terminal) return accountDiagnosisNativeStop(env, context, saved.task);
+ if (terminal && status === "succeeded" && saved.changed) {
+ // Durable result persistence may itself cross expiry; no recheck then.
+ if (Date.now() / 1000 >= Math.min(native.deadline, record.deadline)) {
+ return accountDiagnosisNativeStop(env, context, saved.task);
+ }
+ try {
+ await dispatchAccountDiagnosisRecheck(env, saved.task);
+ await runtimeInstanceCommand(env, { action: "diagnosis_mark_recheck", actor: "native-diagnosis-caller",
+ request_id: task.request_id, recheck_dispatch_state: "sent", updated_at: new Date().toISOString() });
+ } catch {
+ await runtimeInstanceCommand(env, { action: "diagnosis_mark_recheck", actor: "native-diagnosis-caller",
+ request_id: task.request_id, recheck_dispatch_state: "unknown", updated_at: new Date().toISOString() });
+ }
+ }
+ return saved;
+}
+
+export async function reconcileAccountDiagnosis(env, requestId, cancel = false) {
+ const context = accountDiagnosisNativeContext(env);
+ const current = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "native-diagnosis-caller", request_id: requestId });
+ let task = current.task;
+ if (!task?.native) throw new HttpError("account_diagnosis_legacy_retired", 409);
+ if (canonicalResearchTaskJson(task.native.binding) !== canonicalResearchTaskJson(context.binding)) {
+ throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ }
+ if (task.native.phase === "terminal") return { ...current, changed: false };
+ if (cancel) {
+ const stopped = await accountDiagnosisNativeStop(env, context, task);
+ task = stopped.task;
+ if (task.native.receipt || task.native.task_id) return stopped;
+ }
+ if (task.native.task_id && (Date.now() / 1000 >= Math.min(task.native.deadline, task.native.task_deadline ?? Infinity)
+ || (task.native.cancel_requested && !task.native.cancel_sent))) return accountDiagnosisNativeStop(env, context, task);
+ try {
+ let taskId = task.native.task_id;
+ if (!taskId) {
+ const found = await accountDiagnosisNativeIO(context, "GET", "/v1/tasks/lookup", undefined,
+ { "Idempotency-Key": task.native.operation_key, "X-Request-SHA256": task.native.request_sha256 });
+ if (!found || Object.keys(found).join() !== "id" || typeof found.id !== "string" || !/^[A-Za-z0-9_-]{1,200}$/.test(found.id)) {
+ throw new HttpError("account_diagnosis_native_outcome_unknown", 502);
+ }
+ taskId = found.id;
+ }
+ const record = await accountDiagnosisNativeIO(context, "GET", `/v1/tasks/${encodeURIComponent(taskId)}`);
+ if (record.id !== taskId) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
+ return accountDiagnosisNativeReadback(env, context, task, record, cancel);
+ } catch (error) {
+ // A read/validation failure retains the original obligation beyond24h.
+ try {
+ await runtimeInstanceCommand(env, { action: "diagnosis_native_save", actor: "native-diagnosis-caller",
+ request_id: requestId, native: { ...task.native, phase: "hold" }, status: "unknown", summary: "", reason_code: "",
+ updated_at: new Date().toISOString() });
+ } catch { /* Never overwrite a concurrently accepted immutable terminal receipt. */ }
+ throw error;
+ }
+}
+
+export async function dispatchAccountDiagnosis(env, requestId) {
+ const context = accountDiagnosisNativeContext(env);
+ const current = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "native-diagnosis-caller", request_id: requestId });
+ const request = accountDiagnosisNativeRequest(current.task, context.binding);
+ const native = { version: "qrs.native-diagnosis.v1", binding: context.binding, request,
+ input_sha256: await sha256Hex(canonicalResearchTaskJson(request.materials)),
+ request_sha256: await sha256Hex(canonicalResearchTaskJson(request)), operation_key: "qrs-account-diagnosis:" + requestId,
+ deadline: Date.now() / 1000 + 600, task_id: null, task_deadline: null, claim: null,
+ output_sha256: null, receipt: null, cancel_requested: false, cancel_sent: false, phase: "intent" };
+ const intent = await runtimeInstanceCommand(env, { action: "diagnosis_native_intent", actor: "native-diagnosis-caller",
+ request_id: requestId, native, updated_at: new Date().toISOString() });
+ if (!intent.created) return intent; // Never replay POST, even after a lost reply.
+ if (Date.now() / 1000 >= intent.task.native.deadline) return accountDiagnosisNativeStop(env, context, intent.task);
+ const record = await accountDiagnosisNativeIO(context, "POST", "/v1/tasks", request,
+ { "Idempotency-Key": native.operation_key });
+ return accountDiagnosisNativeReadback(env, context, intent.task, record);
+}
+
+export function accountDiagnosisAutoEnabled(env) {
+ return String(env[ACCOUNT_DIAGNOSIS_AUTO_ENABLED_ENV] || "").toLowerCase() === "true";
+}
+
+export async function accountDiagnosisIdentityForTarget(env, targetId) {
+ const spec = accountDiagnosisTargetSpec(null, targetId);
+ if (!spec) return null;
+ let config;
+ try {
+ config = await loadAccountOptionsConfig(env);
+ } catch {
+ return null;
+ }
+ const matches = Object.entries(config.options || {}).flatMap(([platform, items]) =>
+ (Array.isArray(items) ? items : [])
+ .filter(item => String(item?.runtime_status_target_id || "").trim() === targetId)
+ .map(item => ({ platform, key: item.key })));
+ if (matches.length !== 1 || matches[0].platform !== spec.platform) return null;
+ try {
+ return await accountDiagnosisAccount(env, matches[0].platform, matches[0].key);
+ } catch {
+ return null;
+ }
+}
+
+export async function maybeAutoDispatchAccountDiagnosis(env, source) {
+ if (!accountDiagnosisAutoEnabled(env)) return;
+ try { accountDiagnosisNativeContext(env); } catch { return; }
+ const now = Date.now();
+ const freshness = controlPlaneSnapshotFreshness(source, executionEvidenceStaleTtlSeconds(env), now);
+ if (freshness.data_status !== "ready") return;
+ const observedAt = source.computed_at || source.generated_at;
+ if (!observedAt) return;
+ for (const [targetId, spec] of Object.entries(ACCOUNT_DIAGNOSIS_TARGETS)) {
+ try {
+ const matchingTargets = source.targets.filter(item =>
+ item.target_id === targetId && item.target?.platform === spec.platform);
+ if (matchingTargets.length !== 1) continue;
+ const target = matchingTargets[0];
+ const checks = accountDiagnosisChecks({ target, freshness }, freshness.data_status);
+ if (checks.configured_state !== "enabled" || !accountDiagnosisHasConfirmedAttention(checks)) continue;
+ const identity = await accountDiagnosisIdentityForTarget(env, targetId);
+ if (!identity) continue;
+ const createdAt = new Date().toISOString();
+ const requestId = crypto.randomUUID();
+ const created = await runtimeInstanceCommand(env, {
+ action: "diagnosis_create", actor: "runtime-target-lifecycle-source-sync", request_id: requestId,
+ platform: identity.platform, key: identity.key, target_id: identity.targetId, trigger: "incident",
+ observed_at: observedAt, checks, state_fingerprint: accountDiagnosisStateFingerprint(identity.targetId, checks),
+ created_at: createdAt, now, auto_source: "source_sync",
+ });
+ if (!created.created) continue;
+ try {
+ await dispatchAccountDiagnosis(env, requestId);
+ await runtimeInstanceCommand(env, {
+ action: "diagnosis_mark_dispatch", actor: "runtime-target-lifecycle-source-sync",
+ request_id: requestId, dispatch_state: "sent", updated_at: new Date().toISOString(),
+ });
+ } catch {
+ await runtimeInstanceCommand(env, {
+ action: "diagnosis_mark_dispatch", actor: "runtime-target-lifecycle-source-sync",
+ request_id: requestId, dispatch_state: "unknown", updated_at: new Date().toISOString(),
+ });
+ }
+ } catch {
+ // One target's unavailable identity or dispatch must not affect the other targets.
+ }
+ }
+}
+
+export async function dispatchAccountDiagnosisRecheck(env, task) {
+ const token = String(env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
+ if (!token) throw new HttpError("account_diagnosis_recheck_unavailable", 503);
+ const spec = accountDiagnosisTargetSpec(task?.platform, task?.target_id);
+ if (!spec) throw accountDiagnosisConflict("account_diagnosis_target_not_admitted");
+ const url = `https://api.github.com/repos/${spec.recheckRepository}/actions/workflows/${spec.recheckWorkflow}/dispatches`;
+ const body = task.platform === "longbridge"
+ ? { ref: "main", inputs: { target: task.target_id.slice("longbridge.".length) } }
+ : { ref: "main" };
+ const response = await fetchWithTimeout(url, {
+ method: "POST",
+ headers: githubHeaders(token),
+ body: JSON.stringify(body),
+ });
+ if (!response.ok) throw new HttpError("account_diagnosis_recheck_unverified", 502);
+}
+
+export async function accountDiagnosisResponse(request, env, url) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "account_diagnosis_storage_unavailable" }, 503);
+ if (request.method === "GET") {
+ const params = [...url.searchParams.keys()].sort();
+ if (params.join(",") !== "key,platform") return json({ ok: false, error: "account_diagnosis_query_required" }, 400);
+ try {
+ const identity = await accountDiagnosisAccount(env, url.searchParams.get("platform"), url.searchParams.get("key"));
+ const result = await runtimeInstanceCommand(env, { action: "diagnosis_latest", actor: session.login, platform: identity.platform, key: identity.key });
+ const recheckStatus = await accountDiagnosisRecheckStatus(env, result.task);
+ return json({ ok: true, account: { platform: identity.platform, key: identity.key, target_id: identity.targetId }, task: accountDiagnosisPublicTask(result.task, recheckStatus) });
+ } catch (error) {
+ if (error instanceof HttpError) return json(accountDiagnosisErrorPayload(error), error.status);
+ return json({ ok: false, error: "account_diagnosis_unavailable", reason_code: "account_diagnosis_unavailable" }, 503);
+ }
+ }
+ if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
+ try { requireSameOrigin(request, { requireOrigin: true }); } catch (error) { return json({ ok: false, error: error.message }, error.status || 403); }
+ let raw;
+ try { raw = await readBoundedJson(request, ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES); } catch (error) {
+ return json({ ok: false, error: error.message || "invalid_account_diagnosis_request" }, error.status || 400);
+ }
+ if (!raw || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).sort().join(",") !== "key,platform,trigger") {
+ return json({ ok: false, error: "invalid_account_diagnosis_request" }, 400);
+ }
+ if (!ACCOUNT_DIAGNOSIS_TRIGGERS.includes(raw.trigger)) return json({ ok: false, error: "invalid_account_diagnosis_trigger" }, 400);
+ try { accountDiagnosisNativeContext(env); } catch { return json({ ok: false, error: "account_diagnosis_native_not_configured" }, 503); }
+ try {
+ const context = await accountDiagnosisContext(env, raw.platform, raw.key);
+ if (raw.trigger === "incident" && !context.attention) {
+ return json(accountDiagnosisErrorPayload(accountDiagnosisConflict("account_diagnosis_incident_requires_attention")), 409);
+ }
+ const requestId = crypto.randomUUID();
+ const createdAt = new Date().toISOString();
+ const created = await runtimeInstanceCommand(env, {
+ action: "diagnosis_create", actor: session.login, request_id: requestId,
+ platform: context.platform, key: context.key, target_id: context.targetId, trigger: raw.trigger,
+ observed_at: context.observedAt, checks: context.checks, state_fingerprint: context.stateFingerprint, created_at: createdAt, now: Date.now(),
+ });
+ if (!created.created) return json({ ok: true, deduplicated: true, request_id: created.task.request_id, status: created.task.status, task: accountDiagnosisPublicTask(created.task) }, 200);
+ try {
+ await dispatchAccountDiagnosis(env, requestId);
+ await runtimeInstanceCommand(env, { action: "diagnosis_mark_dispatch", actor: session.login, request_id: requestId, dispatch_state: "sent", updated_at: new Date().toISOString() });
+ } catch (error) {
+ await runtimeInstanceCommand(env, { action: "diagnosis_mark_dispatch", actor: session.login, request_id: requestId, dispatch_state: "unknown", updated_at: new Date().toISOString() });
+ const latest = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: session.login, request_id: requestId });
+ return json({ ok: false, error: error.message || "account_diagnosis_dispatch_unverified", request_id: latest.task.request_id, status: latest.task.status, task: accountDiagnosisPublicTask(latest.task) }, error.status || 502);
+ }
+ const latest = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: session.login, request_id: requestId });
+ return json({ ok: true, status: "queued", request_id: latest.task.request_id, task: accountDiagnosisPublicTask(latest.task) }, 202);
+ } catch (error) {
+ if (error instanceof HttpError) return json(accountDiagnosisErrorPayload(error), error.status);
+ return json({ ok: false, error: "account_diagnosis_unavailable", reason_code: "account_diagnosis_unavailable" }, 503);
+ }
+}
+
+export async function accountDiagnosisInternalResponse(request, env, url) {
+ try { requireAccountDiagnosisToken(request, env); } catch (error) { return json({ ok: false, error: error.message }, error.status || 401); }
+ if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "account_diagnosis_storage_unavailable" }, 503);
+ if (url.search) return json({ ok: false, error: "invalid_account_diagnosis_request" }, 400);
+ let requestId;
+ try { requestId = accountDiagnosisRequestId(url.pathname.slice(ACCOUNT_DIAGNOSIS_INTERNAL_PREFIX.length)); } catch (error) {
+ return json({ ok: false, error: error.message }, error.status || 400);
+ }
+ if (request.method === "GET") {
+ try {
+ const result = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "aab-account-diagnosis", request_id: requestId });
+ return json(accountDiagnosisInternalTask(result.task));
+ } catch (error) {
+ return json({ ok: false, error: error.message || "account_diagnosis_request_not_found" }, error.status || 404);
+ }
+ }
+ if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
+ let raw;
+ try { raw = await readBoundedJson(request, ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES); } catch (error) {
+ return json({ ok: false, error: error.message || "invalid_account_diagnosis_request" }, error.status || 400);
+ }
+ if (!raw || typeof raw !== "object" || Array.isArray(raw) || raw.request_id !== requestId) {
+ return json({ ok: false, error: "invalid_account_diagnosis_request" }, 400);
+ }
+ try {
+ if (Object.keys(raw).sort().join() !== "action,request_id" || !["readback", "cancel"].includes(raw.action)) {
+ throw new HttpError("invalid_account_diagnosis_result", 400);
+ }
+ const result = await reconcileAccountDiagnosis(env, requestId, raw.action === "cancel");
+ const latest = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "native-diagnosis-caller", request_id: requestId });
+ return json({ ok: true, replayed: !result.changed, recheck_status: latest.task.recheck_dispatch_state,
+ task: accountDiagnosisPublicTask(latest.task) });
+ } catch (error) {
+ if (error instanceof HttpError) return json(accountDiagnosisErrorPayload(error), error.status);
+ return json({ ok: false, error: "account_diagnosis_native_outcome_unknown" }, 502);
+ }
+}
+
+export function projectRuntimeAccountState(entry) {
+ const base = { scope: "monitoring_only", limit: "not_trading_or_books" };
+ const target = entry?.target || {};
+ const monitoring = target.monitoring || {};
+ const disposition = target.disposition || {};
+ const deployment = target.deployment;
+ const sourceFresh = entry?.freshness?.data_status === "ready";
+ const deploymentFresh = Boolean(deployment?.observed_at) && entry?.deployment_freshness?.data_status === "ready";
+ let activation = "unknown";
+ if (deploymentFresh && deployment.runtime_enabled === true && deployment.scheduler_state === "enabled") activation = "enabled";
+ else if (deploymentFresh && deployment.runtime_enabled === false && deployment.scheduler_state === "paused") activation = "disabled";
+ const configured = target.target?.configured_state;
+ const retainedFault = monitoring.runtime_guard === "attention"
+ || monitoring.execution_heartbeat === "attention"
+ || disposition.code === "parked";
+ if (retainedFault) return { ...base, health: "abnormal", activation, reason: "retained_attention" };
+ if ((configured === "enabled" && activation === "disabled") || (configured === "disabled" && activation === "enabled")) {
+ return { ...base, health: "abnormal", activation, reason: "config_inconsistent" };
+ }
+ if (monitoring.execution_heartbeat === "not_due") {
+ return { ...base, health: "unknown", activation, reason: "check_not_due" };
+ }
+ const enabledAgrees = configured === "enabled"
+ && activation === "enabled"
+ && monitoring.runtime_guard === "pass"
+ && monitoring.execution_heartbeat === "pass"
+ && disposition.code === "continue_enabled_monitoring";
+ const disabledAgrees = configured === "disabled"
+ && activation === "disabled"
+ && monitoring.runtime_guard === "pass"
+ && monitoring.execution_heartbeat === "not_applicable"
+ && disposition.code === "continue_disabled_validation";
+ if (sourceFresh && (enabledAgrees || disabledAgrees)) {
+ return { ...base, health: "normal", activation, reason: "monitoring_agrees" };
+ }
+ let reason = "evidence_insufficient";
+ if (!sourceFresh) reason = "source_not_fresh";
+ else if (!deployment) reason = "deployment_missing";
+ else if (!deploymentFresh) reason = "deployment_not_fresh";
+ else if (activation === "unknown") reason = "activation_unconfirmed";
+ return { ...base, health: "unknown", activation, reason };
+}
+
+export async function aggregateRuntimeTargetLifecycleSources(env) {
+ const sources = await readRuntimeTargetLifecycleSources(env);
+ if (!sources.length) return emptyRuntimeTargetLifecyclePayload("snapshot_unavailable");
+ const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
+ const now = Date.now();
+ const targets = [];
+ const targetIds = new Set();
+ const duplicateTargetIds = new Set();
+ const errors = [];
+ const timestamps = [];
+ let hasReadySource = false;
+ let hasStaleSource = false;
+ for (const source of sources) {
+ const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
+ if (source.generated_at) timestamps.push(source.generated_at);
+ if (source.computed_at) timestamps.push(source.computed_at);
+ if (freshness.data_status === "ready") hasReadySource = true;
+ if (freshness.data_status === "stale") {
+ hasStaleSource = true;
+ errors.push("runtime_target_lifecycle_source_stale");
+ }
+ for (const target of source.targets) {
+ if (targetIds.has(target.target_id)) {
+ duplicateTargetIds.add(target.target_id);
+ errors.push("runtime_target_lifecycle_duplicate_target");
+ continue;
+ }
+ targetIds.add(target.target_id);
+ const entry = {
+ source_id: source.source_id,
+ observed_at: earliestControlPlaneTimestamp([source.generated_at, source.computed_at].filter(Boolean)),
+ evidence_valid_for_seconds: ttlSeconds,
+ freshness,
+ target,
+ // A lifecycle source is deliberately no-order. Keep this derived
+ // observation separate from the monitoring checks so a green check
+ // cannot be mistaken for a broker submission or fill receipt.
+ execution_observation: runtimeTargetLifecycleExecutionObservation(target),
+ ...(target.deployment ? {deployment_freshness: target.deployment.observed_at
+ ? controlPlaneSnapshotFreshness({data_status:"ready", computed_at:target.deployment.observed_at}, ttlSeconds, now)
+ : freshness} : {}),
+ };
+ entry.account_state = projectRuntimeAccountState(entry);
+ targets.push(entry);
+ }
+ errors.push(...source.errors);
+ }
+ const uniqueTargets = targets.filter((entry) => !duplicateTargetIds.has(entry.target.target_id));
+ const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
+ return {
+ schema_version: RUNTIME_TARGET_LIFECYCLE_DASHBOARD_SCHEMA_VERSION,
+ generated_at: earliestControlPlaneTimestamp(timestamps),
+ computed_at: earliestControlPlaneTimestamp(timestamps),
+ data_status: dataStatus,
+ summary: {
+ target_count: uniqueTargets.length,
+ enabled: uniqueTargets.filter((entry) => entry.target.target.configured_state === "enabled").length,
+ disabled: uniqueTargets.filter((entry) => entry.target.target.configured_state === "disabled").length,
+ attention: uniqueTargets.filter((entry) => entry.target.disposition.code === "parked").length,
+ },
+ targets: uniqueTargets,
+ policy: {
+ lifecycle_status_read_only: true,
+ execution_observation_read_only: true,
+ no_order: true,
+ order_or_fill_evidence: "not_collected",
+ notice: "已启用目标持续监控;已停用目标持续进行无执行验证。运行或心跳通过只说明监测正常,不代表已提交订单或已成交。",
+ },
+ errors: uniqueStrings(errors),
+ };
+}
+
+export function runtimeTargetLifecycleExecutionObservation(target) {
+ const monitoring = target?.monitoring || {};
+ const configuredState = target?.target?.configured_state;
+ let code = "unavailable";
+ if (monitoring.runtime_guard === "attention" || monitoring.execution_heartbeat === "attention") {
+ code = "attention";
+ } else if (monitoring.runtime_guard === "unavailable" || monitoring.execution_heartbeat === "unavailable") {
+ code = "unavailable";
+ } else if (configuredState === "disabled") {
+ code = "not_applicable";
+ } else if (monitoring.execution_heartbeat === "not_due") {
+ code = "not_due";
+ } else if (monitoring.execution_heartbeat === "pass") {
+ code = "monitoring_only";
+ }
+ return {
+ code: cleanChoice(code, RUNTIME_TARGET_LIFECYCLE_EXECUTION_OBSERVATIONS, "runtime target lifecycle execution observation"),
+ // The source contract always declares no_order=true. Only the separate
+ // execution-receipt chain may later provide an order/fill attestation.
+ order_or_fill_evidence: "not_collected",
+ };
+}
+
+export async function readRuntimeTargetLifecycleSources(env) {
+ const store = configStore(env);
+ if (!store) return [];
+ let listing;
+ try {
+ listing = await directoryList(env, RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX, RUNTIME_TARGET_LIFECYCLE_MAX_SOURCES);
+ } catch {
+ return [emptyRuntimeTargetLifecycleSourceSnapshot("runtime_target_lifecycle_source_list_unavailable")];
+ }
+ const keys = Array.isArray(listing?.keys) ? listing.keys : [];
+ const sources = [];
+ for (const entry of keys.slice(0, RUNTIME_TARGET_LIFECYCLE_MAX_SOURCES)) {
+ const key = typeof entry?.name === "string" ? entry.name : "";
+ if (!key.startsWith(RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX)) continue;
+ try {
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new Error("indexed_record_unavailable");
+ sources.push(normalizeRuntimeTargetLifecycleSourceSnapshot(stored, key));
+ } catch {
+ sources.push(emptyRuntimeTargetLifecycleSourceSnapshot("runtime_target_lifecycle_source_invalid"));
+ }
+ }
+ return sources;
+}
+
+export function runtimeTargetLifecycleSourceKey(sourceId) {
+ return `${RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX}${sourceId}`;
+}
+
+export async function syncResearchTaskSourceResponse(request, env) {
+ requireDedicatedResearchTaskSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "research task KV is not configured" }, 503);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, RESEARCH_TASK_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research task source payload" }, error.status || 400);
+ }
+
+ let source;
+ try {
+ source = await normalizeResearchTaskSourceSnapshot(raw, "research task source snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research task source payload" }, 400);
+ }
+
+ await writeConfigJson(env, researchTaskSourceKey(source.source_id), source);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "research-task-source-sync",
+ action: "sync_research_task_source",
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ task_count: source.tasks.length,
+ data_status: source.data_status,
+ });
+ } catch {
+ // A valid no-order task index does not depend on optional audit retention.
+ }
+ return json({
+ ok: true,
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ task_count: source.tasks.length,
+ generated_at: source.generated_at,
+ });
+}
+
+export async function researchTaskResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json(emptyResearchTaskPayload("snapshot_unavailable"));
+ return json(await aggregateResearchTaskSources(env));
+}
+
+export async function aggregateResearchTaskSources(env) {
+ const sources = await readResearchTaskSources(env);
+ if (!sources.length) return emptyResearchTaskPayload("snapshot_unavailable");
+
+ const ttlSeconds = researchTaskStaleTtlSeconds(env);
+ const now = Date.now();
+ const taskIds = new Set();
+ const duplicateTaskIds = new Set();
+ const tasks = [];
+ const errors = [];
+ const timestamps = [];
+ let hasReadySource = false;
+ let hasStaleSource = false;
+
+ for (const source of sources) {
+ const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
+ if (source.generated_at) timestamps.push(source.generated_at);
+ if (source.computed_at) timestamps.push(source.computed_at);
+ if (freshness.data_status === "ready") hasReadySource = true;
+ if (freshness.data_status === "stale") {
+ hasStaleSource = true;
+ errors.push("research_task_source_stale");
+ }
+ for (const task of source.tasks) {
+ if (taskIds.has(task.task_id)) {
+ duplicateTaskIds.add(task.task_id);
+ errors.push("research_task_duplicate_task");
+ continue;
+ }
+ taskIds.add(task.task_id);
+ tasks.push({ source_id: source.source_id, freshness, task });
+ }
+ errors.push(...source.errors);
+ }
+
+ const uniqueTasks = tasks.filter((entry) => !duplicateTaskIds.has(entry.task.task_id));
+ const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
+ return {
+ schema_version: RESEARCH_TASK_DASHBOARD_SCHEMA_VERSION,
+ generated_at: earliestControlPlaneTimestamp(timestamps),
+ computed_at: earliestControlPlaneTimestamp(timestamps),
+ data_status: dataStatus,
+ summary: { task_count: uniqueTasks.length },
+ tasks: uniqueTasks,
+ policy: {
+ research_only: true,
+ no_order: true,
+ size_zero_required: true,
+ p4_p5_p6_authorized: false,
+ notice: "研究任务只用于离线、零仓位实验;不会调参、改代码、部署或下单。",
+ },
+ errors: uniqueStrings(errors),
+ };
+}
+
+export async function readResearchTaskSources(env) {
+ const store = configStore(env);
+ if (!store) return [];
+ let listing;
+ try {
+ listing = await directoryList(env, RESEARCH_TASK_SOURCE_PREFIX, RESEARCH_TASK_MAX_SOURCES);
+ } catch {
+ return [emptyResearchTaskSourceSnapshot("research_task_source_list_unavailable")];
+ }
+ const keys = Array.isArray(listing?.keys) ? listing.keys : [];
+ const sources = [];
+ for (const entry of keys.slice(0, RESEARCH_TASK_MAX_SOURCES)) {
+ const key = typeof entry?.name === "string" ? entry.name : "";
+ if (!key.startsWith(RESEARCH_TASK_SOURCE_PREFIX)) continue;
+ try {
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new Error("indexed_record_unavailable");
+ sources.push(await normalizeResearchTaskSourceSnapshot(stored, key));
+ } catch {
+ sources.push(emptyResearchTaskSourceSnapshot("research_task_source_invalid"));
+ }
+ }
+ return sources;
+}
+
+export function researchTaskSourceKey(sourceId) {
+ return `${RESEARCH_TASK_SOURCE_PREFIX}${sourceId}`;
+}
+
+export async function aggregateControlPlaneSources(env) {
+ const now = Date.now();
+ let retirements;
+ try {
+ const stored = await configStore(env).get(CONTROL_PLANE_SOURCE_RETIREMENTS_KEY);
+ retirements = stored === null || stored === undefined
+ ? new Map()
+ : normalizeControlPlaneSourceRetirements(JSON.parse(stored), now);
+ } catch {
+ return emptyControlPlanePayload("control_plane_source_retirements_invalid");
+ }
+ const sources = await readControlPlaneSources(env);
+ // A legacy aggregate has no source identity and cannot honor a retirement.
+ if (!sources?.length && !retirements.size) return null;
+
+ const ttlSeconds = controlPlaneStaleTtlSeconds(env);
+ const candidates = [];
+ const historicalSources = [];
+ const candidateIds = new Set();
+ const duplicateCandidateIds = new Set();
+ const errors = [];
+ const timestamps = [];
+ let hasReadySource = false;
+ let hasStaleSource = false;
+
+ for (const source of sources || []) {
+ const sourceFreshness = controlPlaneResearchSnapshotFreshness(source, ttlSeconds, now);
+ const retirement = retirements.get(source.source_id);
+ if (retirement) {
+ historicalSources.push({ retirement, snapshot: source, freshness: sourceFreshness });
+ continue;
+ }
+ if (source.generated_at) timestamps.push(source.generated_at);
+ if (source.computed_at) timestamps.push(source.computed_at);
+ if (sourceFreshness.data_status === "ready") hasReadySource = true;
+ if (sourceFreshness.data_status === "stale") {
+ hasStaleSource = true;
+ errors.push("control_plane_source_stale");
+ }
+ for (const candidate of source.candidates) {
+ if (candidateIds.has(candidate.candidate_id)) {
+ duplicateCandidateIds.add(candidate.candidate_id);
+ errors.push("control_plane_duplicate_candidate");
+ continue;
+ }
+ candidateIds.add(candidate.candidate_id);
+ candidates.push({
+ ...candidate,
+ source_id: source.source_id,
+ freshness: mergeControlPlaneFreshness(candidate.freshness, sourceFreshness),
+ });
+ }
+ errors.push(...source.errors);
+ }
+
+ const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
+ const uniqueCandidates = candidates.filter((candidate) => !duplicateCandidateIds.has(candidate.candidate_id));
+ const uniqueErrors = uniqueStrings(errors);
+ return {
+ schema_version: "qsl_control_plane_dashboard.v1",
+ generated_at: earliestControlPlaneTimestamp(timestamps),
+ computed_at: earliestControlPlaneTimestamp(timestamps),
+ data_status: dataStatus,
+ summary: normalizeControlPlaneSummary(uniqueCandidates),
+ attention: normalizeControlPlaneAttention({
+ dataStatus,
+ candidates: uniqueCandidates,
+ errors: uniqueErrors,
+ }),
+ candidates: uniqueCandidates,
+ ...(retirements.size ? { historical_sources: historicalSources } : {}),
+ policy: normalizeControlPlanePolicy({
+ p4_p5_automation: "not_configured",
+ p6_owner_decision_required: true,
+ notice: "P1–P3 自动研究已接入;P4/P5 尚未配置,live 仍需所有者明确决定。",
+ }, "aggregated control plane policy"),
+ errors: uniqueErrors,
+ };
+}
+
+export function normalizeControlPlaneSourceRetirements(payload, now) {
+ const value = assertExactFields(payload, ["schema_version", "retirements"], CONTROL_PLANE_SOURCE_RETIREMENTS_KEY);
+ if (value.schema_version !== "qsl_control_plane_source_retirements.v1"
+ || !Array.isArray(value.retirements) || value.retirements.length > CONTROL_PLANE_MAX_SOURCES) {
+ throw new Error("invalid control plane source retirements");
+ }
+ const retirements = new Map();
+ for (const entry of value.retirements) {
+ const item = assertExactFields(entry, ["source_id", "retired_at", "reason"], "source retirement");
+ const sourceId = normalizeControlPlaneIdentifier(item.source_id, "source retirement.source_id", false);
+ const retiredAt = normalizeStrategyHealthTimestamp(item.retired_at, "source retirement.retired_at");
+ const reason = typeof item.reason === "string"
+ ? sanitizeStrategyHealthText(item.reason, "source retirement.reason", 240, false, null) : null;
+ // "unavailable" is the diagnostic identity for unreadable source records.
+ if (sourceId === "unavailable" || retirements.has(sourceId) || Date.parse(retiredAt) > now || !reason) {
+ throw new Error("invalid control plane source retirement");
+ }
+ retirements.set(sourceId, { source_id: sourceId, retired_at: retiredAt, reason });
+ }
+ return retirements;
+}
+
+export async function readControlPlaneSources(env) {
+ const store = configStore(env);
+ if (!store) return null;
+ let listing;
+ try {
+ listing = await directoryList(env, CONTROL_PLANE_SOURCE_PREFIX, CONTROL_PLANE_MAX_SOURCES);
+ } catch (error) {
+ return [emptyControlPlaneSourceSnapshot(sourceListFailure(error, "control_plane_source_list_unavailable"))];
+ }
+ const keys = Array.isArray(listing?.keys) ? listing.keys : [];
+ const sources = [];
+ for (const entry of keys.slice(0, CONTROL_PLANE_MAX_SOURCES)) {
+ const key = typeof entry?.name === "string" ? entry.name : "";
+ if (!key.startsWith(CONTROL_PLANE_SOURCE_PREFIX)) continue;
+ try {
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new Error("indexed_record_unavailable");
+ const source = normalizeControlPlaneSourceSnapshot(stored, key);
+ if (key !== controlPlaneSourceKey(source.source_id)) throw new Error("control plane source identity mismatch");
+ sources.push(source);
+ } catch {
+ sources.push(emptyControlPlaneSourceSnapshot("control_plane_source_invalid"));
+ }
+ }
+ return sources;
+}
+
+export function controlPlaneSourceKey(sourceId) {
+ return `${CONTROL_PLANE_SOURCE_PREFIX}${sourceId}`;
+}
+
+export async function syncAdaptiveSelectionSourceResponse(request, env) {
+ requireDedicatedAdaptiveSelectionSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "adaptive selection KV is not configured" }, 503);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, ADAPTIVE_SELECTION_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid adaptive selection payload" }, error.status || 400);
+ }
+
+ let source;
+ try {
+ source = await normalizeAdaptiveSelectionSourceSnapshot(raw, "adaptive selection source snapshot");
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid adaptive selection payload" }, 400);
+ }
+
+ await writeConfigJson(env, adaptiveSelectionSourceKey(source.source_id), source);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "adaptive-selection-source-sync",
+ action: "sync_adaptive_selection_source",
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ candidate_count: source.decision?.candidates.length || 0,
+ data_status: source.data_status,
+ no_order: true,
+ });
+ } catch {
+ // This source remains safe and usable if the rolling convenience log fails.
+ }
+ return json({
+ ok: true,
+ source_id: source.source_id,
+ schema_version: source.schema_version,
+ candidate_count: source.decision?.candidates.length || 0,
+ generated_at: source.generated_at,
+ no_order: true,
+ });
+}
+
+export async function syncM0ResearchLedgerResponse(request, env) {
+ requireDedicatedM0ResearchSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "M0 research ledger KV is not configured" }, 503);
+ }
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, M0_RESEARCH_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid M0 research ledger payload" }, error.status || 400);
+ }
+
+ let envelope;
+ try {
+ envelope = await normalizeM0ResearchLedgerTransport(raw, "M0 research ledger transport");
+ } catch (error) {
+ // Validation deliberately completes before any KV write. A malformed,
+ // over-scoped, or digest-mismatched payload can therefore never replace
+ // the last known-good current ledger.
+ return json({ ok: false, error: error.message || "invalid M0 research ledger payload" }, 400);
+ }
+
+ const current = await readCurrentM0ResearchLedgerRecord(env);
+ if (current) {
+ // A retry for the exact immutable source is not a new decision or a
+ // second write. Acknowledge it so a lost response cannot make a valid
+ // no-order publication look failed, while retaining the guards below.
+ if (envelope.source_artifact.sha256 === current.envelope.source_artifact.sha256) {
+ return json({
+ ok: true,
+ schema_version: current.envelope.schema_version,
+ source_repository: current.envelope.source_artifact.repository,
+ source_revision: current.envelope.source_artifact.revision,
+ source_run_id: current.envelope.source_artifact.run_id,
+ artifact_id: current.envelope.source_artifact.artifact_id,
+ ledger_sha256: current.envelope.ledger_sha256,
+ replayed: true,
+ no_order: true,
+ expires_at: current.expires_at,
+ });
+ }
+ const replayError = m0ResearchLedgerReplayError(current.envelope, envelope);
+ if (replayError) return json({ ok: false, error: replayError }, 409);
+ }
+
+ // Capture once so the persisted interval is exactly the requested physical
+ // retention even when the request crosses a wall-clock second boundary.
+ const storedNow = new Date();
+ const storedAt = utcTimestampSeconds(storedNow);
+ const expiresAt = utcTimestampSeconds(new Date(storedNow.getTime() + M0_RESEARCH_RETENTION_SECONDS * 1000));
+ const record = {
+ schema_version: M0_RESEARCH_STORAGE_SCHEMA_VERSION,
+ stored_at: storedAt,
+ expires_at: expiresAt,
+ envelope,
+ };
+ try {
+ // Archive first: an archive failure must not advance the current pointer.
+ // The archive identity is derived exclusively from the verified digest;
+ // callers never choose a KV key.
+ await writeM0ResearchLedgerRecord(env, m0ResearchLedgerArchiveKey(envelope.ledger_sha256), record);
+ await writeM0ResearchLedgerRecord(env, M0_RESEARCH_CURRENT_KEY, record);
+ } catch {
+ return json({ ok: false, error: "M0 research ledger persistence failed" }, 503);
+ }
+
+ try {
+ await appendAuditLog(env, {
+ ts: storedAt,
+ login: "m0-research-ledger-sync",
+ action: "sync_m0_research_ledger",
+ source_repository: envelope.source_artifact.repository,
+ source_revision: envelope.source_artifact.revision,
+ source_run_id: envelope.source_artifact.run_id,
+ artifact_id: envelope.source_artifact.artifact_id,
+ ledger_sha256: envelope.ledger_sha256,
+ no_order: true,
+ });
+ } catch {
+ // Retention of an optional convenience log must not change a valid,
+ // already persisted no-order research ledger.
+ }
+ return json({
+ ok: true,
+ schema_version: envelope.schema_version,
+ source_repository: envelope.source_artifact.repository,
+ source_revision: envelope.source_artifact.revision,
+ source_run_id: envelope.source_artifact.run_id,
+ artifact_id: envelope.source_artifact.artifact_id,
+ ledger_sha256: envelope.ledger_sha256,
+ replayed: false,
+ no_order: true,
+ expires_at: expiresAt,
+ });
+}
+
+export async function m0ResearchLedgerResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json(emptyM0ResearchDashboardPayload("m0_research_ledger_unavailable"));
+ const record = await readCurrentM0ResearchLedgerRecord(env);
+ return json(record
+ ? projectM0ResearchDashboardForRead(record.envelope.ledger, record.envelope.ledger_sha256)
+ : emptyM0ResearchDashboardPayload("m0_research_ledger_unavailable"));
+}
+
+export function m0ResearchLedgerReplayError(current, incoming) {
+ if (!current || !incoming) return null;
+ if (incoming.ledger_sha256 === current.ledger_sha256
+ || incoming.source_artifact.sha256 === current.source_artifact.sha256) {
+ return "M0 research ledger current replay rejected";
+ }
+ // Run IDs are closed identifiers rather than an assumed numeric sequence.
+ // An equal source/run identity is a replay; ledger time is the portable
+ // ordering guard for a different run identifier.
+ if (incoming.source_artifact.repository === current.source_artifact.repository
+ && incoming.source_artifact.run_id === current.source_artifact.run_id) {
+ return "M0 research ledger current replay rejected";
+ }
+ const incomingTime = Date.parse(incoming.ledger.computed_at);
+ const currentTime = Date.parse(current.ledger.computed_at);
+ if (Number.isFinite(incomingTime) && Number.isFinite(currentTime) && incomingTime <= currentTime) {
+ return "M0 research ledger time rollback rejected";
+ }
+ return null;
+}
+
+export function m0ResearchLedgerArchiveKey(ledgerSha256) {
+ return `${M0_RESEARCH_ARCHIVE_PREFIX}${ledgerSha256}`;
+}
+
+export async function writeM0ResearchLedgerRecord(env, key, record) {
+ const store = configStore(env);
+ if (!store) throw new Error("M0 research ledger KV is not configured");
+ await store.put(key, JSON.stringify(record), { expirationTtl: M0_RESEARCH_RETENTION_SECONDS });
+}
+
+export async function readCurrentM0ResearchLedgerRecord(env) {
+ if (!hasConfigStore(env)) return null;
+ let stored;
+ try {
+ stored = await readConfigJson(env, M0_RESEARCH_CURRENT_KEY);
+ } catch {
+ return null;
+ }
+ if (!stored) return null;
+ try {
+ return await normalizeM0ResearchLedgerStorageRecord(stored, "M0 research ledger current record");
+ } catch {
+ return null;
+ }
+}
+
+export async function adaptiveSelectionResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!hasConfigStore(env)) return json(emptyAdaptiveSelectionPayload("adaptive_selection_source_unavailable"));
+ return json(await aggregateAdaptiveSelectionSources(env));
+}
+
+export async function aggregateAdaptiveSelectionSources(env) {
+ const sources = await readAdaptiveSelectionSources(env);
+ if (!sources.length) return emptyAdaptiveSelectionPayload("adaptive_selection_source_unavailable");
+
+ const ttlSeconds = adaptiveSelectionStaleTtlSeconds(env);
+ const now = Date.now();
+ const selections = [];
+ const errors = [];
+ const timestamps = [];
+ let hasReadySource = false;
+ let hasStaleSource = false;
+
+ for (const source of sources) {
+ const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
+ if (source.generated_at) timestamps.push(source.generated_at);
+ if (source.computed_at) timestamps.push(source.computed_at);
+ if (freshness.data_status === "ready") hasReadySource = true;
+ if (freshness.data_status === "stale") {
+ hasStaleSource = true;
+ errors.push("adaptive_selection_source_stale");
+ }
+ if (source.decision) selections.push({ source_id: source.source_id, freshness, decision: source.decision });
+ errors.push(...source.errors);
+ }
+
+ return {
+ schema_version: ADAPTIVE_SELECTION_DASHBOARD_SCHEMA_VERSION,
+ generated_at: earliestControlPlaneTimestamp(timestamps),
+ computed_at: earliestControlPlaneTimestamp(timestamps),
+ data_status: hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable"),
+ summary: normalizeAdaptiveSelectionSummary(selections),
+ selections: selections.sort((left, right) => left.source_id.localeCompare(right.source_id)),
+ policy: {
+ authority: ADAPTIVE_SELECTION_AUTHORITY,
+ no_order: true,
+ execution_authority_granted: false,
+ notice: "M1 仅展示 Shadow 建议和拒绝原因;不会修改策略、平台、资金、运行状态或订单。",
+ },
+ errors: uniqueStrings(errors),
+ };
+}
+
+export async function readAdaptiveSelectionSources(env) {
+ const store = configStore(env);
+ if (!store) return [];
+ let listing;
+ try {
+ listing = await directoryList(env, ADAPTIVE_SELECTION_SOURCE_PREFIX, ADAPTIVE_SELECTION_MAX_SOURCES);
+ } catch {
+ return [emptyAdaptiveSelectionSourceSnapshot("adaptive_selection_source_list_unavailable")];
+ }
+ const keys = Array.isArray(listing?.keys) ? listing.keys : [];
+ const sources = [];
+ for (const entry of keys.slice(0, ADAPTIVE_SELECTION_MAX_SOURCES)) {
+ const key = typeof entry?.name === "string" ? entry.name : "";
+ if (!key.startsWith(ADAPTIVE_SELECTION_SOURCE_PREFIX)) continue;
+ try {
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new Error("indexed_record_unavailable");
+ sources.push(await normalizeAdaptiveSelectionSourceSnapshot(stored, key));
+ } catch {
+ sources.push(emptyAdaptiveSelectionSourceSnapshot("adaptive_selection_source_invalid"));
+ }
+ }
+ return sources;
+}
+
+export function adaptiveSelectionSourceKey(sourceId) {
+ return `${ADAPTIVE_SELECTION_SOURCE_PREFIX}${sourceId}`;
+}
+
+export function controlPlaneSnapshotFreshness(snapshot, ttlSeconds, now) {
+ const timestamps = [snapshot.generated_at, snapshot.computed_at]
+ .filter(Boolean)
+ .map((value) => Date.parse(value));
+ const freshnessAt = timestamps.length ? Math.min(...timestamps) : Number.NaN;
+ const futureBeyondClockSkew = Number.isFinite(freshnessAt) && freshnessAt > now + 5 * 60 * 1000;
+ const ageSeconds = futureBeyondClockSkew
+ ? Number.POSITIVE_INFINITY
+ : Number.isFinite(freshnessAt)
+ ? Math.max(0, Math.round((now - freshnessAt) / 1000))
+ : Number.POSITIVE_INFINITY;
+ const dataStatus = snapshot.data_status === "ready" && ageSeconds > ttlSeconds
+ ? "stale"
+ : snapshot.data_status;
+ return { data_status: dataStatus, age_seconds: Number.isFinite(ageSeconds) ? ageSeconds : null };
+}
+
+export function controlPlaneResearchSnapshotFreshness(snapshot, ttlSeconds, now) {
+ if (snapshot.data_status !== "ready") {
+ return controlPlaneSnapshotFreshness(snapshot, ttlSeconds, now);
+ }
+ const timestamps = [snapshot.generated_at, snapshot.computed_at]
+ .filter(Boolean)
+ .map((value) => Date.parse(value));
+ const freshnessAt = timestamps.length ? Math.min(...timestamps) : Number.NaN;
+ const futureBeyondClockSkew = Number.isFinite(freshnessAt) && freshnessAt > now + 5 * 60 * 1000;
+ const ageSeconds = futureBeyondClockSkew
+ ? Number.POSITIVE_INFINITY
+ : Number.isFinite(freshnessAt)
+ ? Math.max(0, Math.round((now - freshnessAt) / 1000))
+ : Number.POSITIVE_INFINITY;
+ if (!Number.isFinite(freshnessAt) || futureBeyondClockSkew) {
+ return { data_status: "stale", age_seconds: null };
+ }
+
+ const ttlDeadline = freshnessAt + ttlSeconds * 1000;
+ const nextScheduledRefresh = nextControlPlaneResearchScheduleAfter(freshnessAt);
+ const scheduledDeadline = nextScheduledRefresh + CONTROL_PLANE_RESEARCH_DELIVERY_GRACE_MS;
+ const staleDeadline = Math.max(ttlDeadline, scheduledDeadline);
+ return {
+ data_status: now > staleDeadline ? "stale" : "ready",
+ age_seconds: ageSeconds,
+ };
+}
+
+export function nextControlPlaneResearchScheduleAfter(freshnessAt) {
+ const scheduled = new Date(freshnessAt);
+ scheduled.setUTCMinutes(0, 0, 0);
+ scheduled.setUTCHours(CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_HOUR);
+ if (scheduled.getTime() <= freshnessAt) scheduled.setUTCDate(scheduled.getUTCDate() + 1);
+ while (!CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_DAYS.has(scheduled.getUTCDay())) {
+ scheduled.setUTCDate(scheduled.getUTCDate() + 1);
+ }
+ return scheduled.getTime();
+}
+
+// A recently published source must not be able to re-advertise an old
+// reconciliation candidate as current. The private controller independently
+// verifies raw receipts, but the human console also fails closed here.
+export function reconciliationRecoveryEvidenceFreshness(recovery, sourceFreshness, ttlSeconds, now) {
+ const observedAt = Date.parse(recovery.mode === "initial_enrollment" ? recovery.candidate.last_observed_at : recovery.last_observed_at);
+ const futureBeyondClockSkew = Number.isFinite(observedAt) && observedAt > now + 5 * 60 * 1000;
+ const evidenceAgeSeconds = futureBeyondClockSkew
+ ? Number.POSITIVE_INFINITY
+ : Number.isFinite(observedAt)
+ ? Math.max(0, Math.round((now - observedAt) / 1000))
+ : Number.POSITIVE_INFINITY;
+ const ageSeconds = sourceFreshness.age_seconds === null
+ ? evidenceAgeSeconds
+ : Math.max(sourceFreshness.age_seconds, evidenceAgeSeconds);
+ const dataStatus = sourceFreshness.data_status === "ready" && evidenceAgeSeconds <= ttlSeconds
+ ? "ready"
+ : "stale";
+ return { data_status: dataStatus, age_seconds: Number.isFinite(ageSeconds) ? ageSeconds : null };
+}
+
+export function mergeControlPlaneFreshness(candidateFreshness, sourceFreshness) {
+ const sourceAgeSeconds = sourceFreshness.age_seconds;
+ const candidateAge = candidateFreshness.age_seconds;
+ const ageSeconds = sourceAgeSeconds === null
+ ? candidateAge
+ : (candidateAge === null ? sourceAgeSeconds : Math.max(candidateAge, sourceAgeSeconds));
+ const status = candidateFreshness.status === "stale" || sourceFreshness.data_status !== "ready"
+ ? "stale"
+ : candidateFreshness.status;
+ return { status, age_seconds: ageSeconds };
+}
+
+export function earliestControlPlaneTimestamp(values) {
+ const timestamps = values
+ .filter(Boolean)
+ .map((value) => ({ value, timestamp: Date.parse(value) }))
+ .filter((item) => Number.isFinite(item.timestamp))
+ .sort((left, right) => left.timestamp - right.timestamp);
+ return timestamps[0]?.value || null;
+}
+
+export async function readBoundedJson(request, maxBytes) {
+ const declaredLength = Number(request.headers.get("Content-Length") || 0);
+ if (declaredLength > maxBytes) throw new HttpError("request body is too large", 413);
+ const bytes = await request.arrayBuffer();
+ if (bytes.byteLength > maxBytes) throw new HttpError("request body is too large", 413);
+ try {
+ return JSON.parse(new TextDecoder().decode(bytes));
+ } catch {
+ throw new HttpError("request body must be valid JSON", 400);
+ }
+}
+
+export function requireDedicatedStrategyHealthSyncToken(request, env) {
+ const expected = String(env.STRATEGY_HEALTH_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("strategy health sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("strategy health sync token is invalid", 401);
+}
+
+export function requireDedicatedControlPlaneSyncToken(request, env) {
+ const expected = String(env.CONTROL_PLANE_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("control plane sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("control plane sync token is invalid", 401);
+}
+
+export function requireControlPlaneSourceSyncToken(request, env) {
+ const validationToken = String(env.AAB_VALIDATION_SYNC_TOKEN || "");
+ const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ // Check the narrower credential first, including accidental equal bindings.
+ if (validationToken && token === validationToken) return true;
+ if (validationToken && !env.CONTROL_PLANE_SYNC_TOKEN) {
+ throw new HttpError("control plane source sync token is invalid", 401);
+ }
+ requireDedicatedControlPlaneSyncToken(request, env);
+ return false;
+}
+
+export function requireDedicatedAdaptiveSelectionSyncToken(request, env) {
+ const expected = String(env.ADAPTIVE_SELECTION_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("adaptive selection sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("adaptive selection sync token is invalid", 401);
+}
+
+export function requireDedicatedExecutionEvidenceSyncToken(request, env) {
+ const expected = String(env.EXECUTION_EVIDENCE_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("execution evidence sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("execution evidence sync token is invalid", 401);
+}
+
+export function requireDedicatedAccountFactsSyncToken(request, env) {
+ const configured = [
+ ["longbridge", String(env.ACCOUNT_FACTS_SYNC_TOKEN || "")],
+ [IBKR_ACCOUNT_FACTS_PLATFORM, String(env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN || "")],
+ [SCHWAB_ACCOUNT_FACTS_PLATFORM, String(env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN || "")],
+ [FIRSTRADE_ACCOUNT_FACTS_PLATFORM, String(env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN || "")],
+ ].filter(([, token]) => token);
+ const firstradeToken = String(env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN || "");
+ if (firstradeToken && [env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN, env.EXECUTION_EVIDENCE_SYNC_TOKEN,
+ env.STRATEGY_SWITCH_SYNC_TOKEN, env.RECONCILIATION_RECOVERY_SYNC_TOKEN,
+ env.RECONCILIATION_RECOVERY_CONTROLLER_TOKEN, env.CYCLE_HEALTH_PROVISIONER_TOKEN]
+ .some(other => other && String(other) === firstradeToken)) {
+ throw new HttpError("account_facts_sync_token_ambiguous", 503);
+ }
+ if (new Set(configured.map(([, token]) => token)).size !== configured.length) {
+ throw new HttpError("account_facts_sync_token_ambiguous", 503);
+ }
+ if (!configured.length) throw new HttpError("account_facts_sync_token_not_configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ const match = configured.find(([, expected]) => token === expected);
+ if (match) return match[0];
+ throw new HttpError("account_facts_sync_token_invalid", 401);
+}
+
+export function accountFactsDisabledResponse() {
+ return json({ ok: false, error: "account_facts_disabled" }, 404);
+}
+
+// Sync producers keep only the HTTP status, so a refused push is undiagnosable
+// from their logs. Publish the refusal code, tagged with a fixed endpoint literal
+// from the caller; free-form exception text is classified to "unknown" so payload
+// content, identities and credentials cannot enter the log stream. The response
+// body and status are exactly what this helper already returned.
+export function accountFactsErrorResponse(error, endpoint = "read") {
+ const code = error instanceof AccountFactsError ? error.code
+ : error instanceof HttpError ? error.message
+ : error?.message || "invalid_account_facts_history";
+ const status = error?.status || 400;
+ console.warn("account_facts_refused", {
+ endpoint,
+ http_status: status,
+ error_category: typeof code === "string" && /^[a-z][a-z0-9_]{2,63}$/.test(code) ? code : "unknown",
+ });
+ return json({ ok: false, error: code }, status);
+}
+
+export function requireCycleHealthProvisionToken(request, env) {
+ const expected = String(env.STRATEGY_SWITCH_SYNC_TOKEN || env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
+ if (!expected) throw new HttpError("cycle_health_provisioner_unavailable", 503);
+ const sourceTokens = [
+ env.ACCOUNT_FACTS_SYNC_TOKEN, env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN, env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN, env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.EXECUTION_EVIDENCE_SYNC_TOKEN,
+ ].filter(Boolean).map(String);
+ if (sourceTokens.includes(expected)) throw new HttpError("cycle_health_provisioner_token_alias", 503);
+ const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("cycle_health_provisioner_token_invalid", 401);
+}
+
+export async function resolveCycleHealthBindingFingerprint(env, targetId, bindingId) {
+ const config = await loadAccountOptionsConfig(env);
+ const options = Array.isArray(config?.options?.longbridge) ? config.options.longbridge : [];
+ const matches = options.filter(o => o.runtime_status_target_id === targetId);
+ const allMatches = Object.entries(config.options || {}).flatMap(([platform, items]) =>
+ (Array.isArray(items) ? items : []).filter(o => o.runtime_status_target_id === targetId).map(o => ({ platform, key: o.key })));
+ if (matches.length !== 1 || allMatches.length !== 1 || allMatches[0].platform !== "longbridge"
+ || options.filter(o => o.key === matches[0]?.key).length !== 1) throw new HttpError("cycle_health_option_not_unique", 409);
+ const bindings = await loadAccountFactsBindings(env);
+ const bound = bindings?.bindings?.filter(b => b.platform === "longbridge" && b.account_key === matches[0].key) || [];
+ if (bound.length !== 1 || bound[0].account_scope !== "paper" || bound[0].source_binding.id !== bindingId
+ || !accountFactsOptionMatchesBinding(matches[0], bound[0])) throw new HttpError("cycle_health_binding_mismatch", 409);
+ return cycleHealthSha256({ binding: bound[0], runtime_status_target_id: targetId });
+}
+
+export async function runtimeCycleHealthAdmissionResponse(request, env) {
+ try {
+ requireCycleHealthProvisionToken(request, env);
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("cycle_health_store_unavailable", 503);
+ const raw = await readBoundedJson(request, 8192);
+ const fields = ["source_id", "target_id", "configuration_sha256", "required_from", "expected_authority_revision"];
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)
+ || Object.keys(raw).length !== fields.length || fields.some(field => !Object.hasOwn(raw, field))) {
+ throw new HttpError("cycle_health_admission_request_invalid", 400);
+ }
+ const sourceId = normalizeControlPlaneIdentifier(raw.source_id, "source_id", false);
+ const targetId = raw.target_id;
+ if (targetId !== "longbridge.paper" || !/^[a-f0-9]{64}$/.test(raw.configuration_sha256 || "")
+ || !Number.isSafeInteger(raw.expected_authority_revision) || raw.expected_authority_revision < 0) {
+ throw new HttpError("cycle_health_admission_request_invalid", 400);
+ }
+ const requiredFrom = normalizeCycleInstant(raw.required_from);
+ const bindingId = request.headers.get("X-QSL-Source-Binding-ID") || "";
+ if (!/^[a-f0-9]{64}$/.test(bindingId)) throw new HttpError("cycle_health_binding_required", 409);
+ const bindingFingerprint = await resolveCycleHealthBindingFingerprint(env, targetId, bindingId);
+ return json(await runtimeInstanceCommand(env, {
+ action: "cycle_health_provision", source_id: sourceId, target_id: targetId,
+ binding_fingerprint: bindingFingerprint, configuration_sha256: raw.configuration_sha256,
+ required_from: requiredFrom, expected_authority_revision: raw.expected_authority_revision,
+ }));
+ } catch (error) {
+ return json({ ok: false, error: error instanceof HttpError || error instanceof CycleHealthError
+ ? error.message : "cycle_health_admission_unavailable" }, error.status || 400);
+ }
+}
+
+export async function runtimeCycleHealthSourceResponse(request, env) {
+ try {
+ const platform = requireDedicatedAccountFactsSyncToken(request, env);
+ if (platform !== "longbridge") throw new HttpError("cycle_health_token_platform_mismatch", 403);
+ const dedicated = String(env.ACCOUNT_FACTS_SYNC_TOKEN || "");
+ if ([env.EXECUTION_EVIDENCE_SYNC_TOKEN, env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN].some(t => t && String(t) === dedicated)) {
+ throw new HttpError("cycle_health_token_alias", 503);
+ }
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("cycle_health_store_unavailable", 503);
+ const url = new URL(request.url);
+ let source, targetId, sourceId, historyCursor = null;
+ const bindingId = request.headers.get("X-QSL-Source-Binding-ID") || "";
+ if (!/^[a-f0-9]{64}$/.test(bindingId)) throw new HttpError("cycle_health_binding_required", 409);
+ if (request.method === "GET") {
+ if ([...url.searchParams.keys()].some(k => !["source_id", "target_id", "history_cursor"].includes(k))
+ || url.searchParams.getAll("source_id").length !== 1 || url.searchParams.getAll("target_id").length !== 1
+ || url.searchParams.getAll("history_cursor").length > 1) throw new HttpError("cycle_health_invalid_query", 400);
+ sourceId = normalizeControlPlaneIdentifier(url.searchParams.get("source_id"), "source_id", false);
+ targetId = url.searchParams.get("target_id");
+ historyCursor = url.searchParams.get("history_cursor");
+ if (historyCursor !== null) {
+ if (historyCursor.length > 512) throw new HttpError("cycle_health_history_cursor_invalid", 400);
+ }
+ } else {
+ const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
+ if (!Array.isArray(raw?.targets) || raw.targets.length !== 1) throw new HttpError("cycle_health_one_target_required", 400);
+ const { cycle_health: health, ...legacyTarget } = raw.targets[0];
+ if (!health) throw new HttpError("cycle_health_extension_required", 400);
+ // Reuse the lifecycle shape with the companion member removed. The legacy
+ // normalizer and legacy POST still reject this extension as before.
+ source = normalizeRuntimeTargetLifecycleSourceSnapshot({ ...raw, targets: [legacyTarget] });
+ normalizeCycleInstant(raw.generated_at); normalizeCycleInstant(raw.computed_at);
+ if (raw.generated_at !== raw.computed_at || source.data_status !== "ready") throw new HttpError("cycle_health_observation_time_mismatch", 400);
+ source.generated_at = raw.generated_at; source.computed_at = raw.computed_at;
+ if (legacyTarget.deployment?.observed_at !== undefined) {
+ source.targets[0].deployment.observed_at = normalizeCycleInstant(legacyTarget.deployment.observed_at);
+ if (compareCycleInstants(legacyTarget.deployment.observed_at, raw.computed_at) > 0) throw new HttpError("cycle_health_deployment_chronology", 400);
+ }
+ const age = Date.now() - Date.parse(source.computed_at);
+ if (age > ACCOUNT_FACTS_STALE_MS || age < -ACCOUNT_FACTS_FUTURE_SKEW_MS) throw new HttpError("cycle_health_observation_age", 409);
+ targetId = source.targets[0].target_id; sourceId = source.source_id;
+ source.targets[0].cycle_health = await normalizeCycleHealth(health, {
+ target_id: targetId, source_binding_id: bindingId, observed_at: source.computed_at,
+ });
+ }
+ if (targetId !== "longbridge.paper" || (source && (source.targets[0].target.platform !== "longbridge" || source.targets[0].target.execution_mode !== "paper"))) throw new HttpError("cycle_health_paper_target_required", 403);
+ const bindingFingerprint = await resolveCycleHealthBindingFingerprint(env, targetId, bindingId);
+ const identity = { source_id: sourceId, target_id: targetId, binding_fingerprint: bindingFingerprint, source_binding_id: bindingId };
+ const admission = await runtimeInstanceCommand(env, { ...identity, action: "cycle_health_admission" });
+ if (source && source.targets[0].cycle_health.configuration_sha256 !== admission.configuration_sha256) throw new HttpError("cycle_health_configuration_not_admitted", 409);
+ const command = { ...identity, ...admission, action: source ? "cycle_health_put" : "cycle_health_read",
+ ...(historyCursor ? { history_cursor: historyCursor } : {}) };
+ if (source) {
+ command.observation = source;
+ command.observation_json = canonicalCycleJson(source);
+ command.observation_sha256 = await cycleHealthSha256(source);
+ command.received_at = new Date().toISOString();
+ }
+ return json(await runtimeInstanceCommand(env, command));
+ } catch (error) {
+ return json({ ok: false, error: error instanceof HttpError || error instanceof CycleHealthError ? error.message : "cycle_health_invalid_source" }, error.status || 400);
+ }
+}
+
+export async function loadAccountFactsBindings(env, { propagateReadErrors = false } = {}) {
+ if (!hasConfigStore(env)) {
+ if (propagateReadErrors) throw new Error("account_facts_bindings_store_unavailable");
+ return null;
+ }
+ let raw;
+ try {
+ raw = await readConfigJson(env, ACCOUNT_FACTS_BINDINGS_KEY);
+ } catch (error) {
+ if (propagateReadErrors) throw error;
+ return null;
+ }
+ if (!raw) return null;
+ return normalizeAccountFactsBindings(raw);
+}
+
+export async function loadStoredAccountFactsMap(env, accountOptions, bindings) {
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
+ const accounts = [];
+ const bindingByAccount = new Map(
+ (bindings?.bindings || []).map((item) => [`${item.platform}:${item.account_key}`, item]),
+ );
+ for (const [platform, options] of Object.entries(accountOptions || {})) {
+ if (!Array.isArray(options)) continue;
+ for (const option of options) {
+ if (!option || typeof option.key !== "string" || !option.key) continue;
+ const binding = bindingByAccount.get(`${platform}:${option.key}`);
+ if (!binding || !accountFactsOptionMatchesBinding(option, binding)) continue;
+ accounts.push({
+ platform,
+ account_key: option.key,
+ account_scope: binding.account_scope,
+ account_selector: binding.account_selector,
+ ...(platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
+ ? { broker_account_hash: binding.broker_account_hash }
+ : {}),
+ ...(platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? { broker_account_id: binding.broker_account_id } : {}),
+ target_id: binding.target_id,
+ source_binding_id: binding.source_binding.id,
+ });
+ }
+ }
+ const listed = await runtimeInstanceCommand(env, {
+ action: "account_facts_list",
+ accounts,
+ });
+ const storedByAccount = new Map();
+ for (const row of listed.observations || []) {
+ if (!row?.platform || !row?.account_key || !row?.payload) continue;
+ storedByAccount.set(`${row.platform}:${row.account_key}`, row.payload);
+ }
+ return storedByAccount;
+}
+
+export function periodReturnCommand(binding, action) {
+ return { action, platform: "ibkr", account_key: binding.account_key, account_scope: binding.account_scope,
+ account_selector: binding.account_selector, target_id: binding.target_id, source_binding_id: binding.source_binding.id,
+ ...(binding.history_source_binding_ids ? { history_source_binding_ids: binding.history_source_binding_ids } : {}) };
+}
+
+export async function readBoundAccountExecutions(option, env) {
+ if (option.platform !== "ibkr" || !accountFactsReadModelEnabled(env)) return null;
+ const bindings = await loadAccountFactsBindings(env);
+ const matches = (bindings?.bindings || []).filter(binding => binding.platform === option.platform
+ && binding.account_key === option.key);
+ if (!matches.length) return null;
+ if (matches.length !== 1 || !accountFactsOptionMatchesBinding(option, matches[0])) {
+ throw new HttpError("execution_account_unattributed", 409);
+ }
+ const stored = await runtimeInstanceCommand(env, periodReturnCommand(matches[0], "account_executions_read"));
+ if (!stored.ok) throw new HttpError("execution_store_unavailable", 503);
+ return stored.executions;
+}
+
+export async function syncAccountExternalFlowResponse(request, env) {
+ if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
+ try {
+ const platform = requireDedicatedAccountFactsSyncToken(request, env);
+ if (!hasConfigStore(env) || !hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
+ const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
+ const fields = ["schema_version", "target_id", "source_binding_id", "account_scope", "account_selector", "externalFlow"];
+ if (!raw || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).length !== fields.length
+ || fields.some(key => !Object.hasOwn(raw, key)) || raw.schema_version !== "account_external_flow.v1") {
+ throw new HttpError("invalid_external_flow", 400);
+ }
+ const bindings = await loadAccountFactsBindings(env);
+ const resolved = resolveTrustedAccountFactsBinding(bindings, raw.target_id, raw.source_binding_id);
+ if (!resolved.ok || resolved.binding.platform !== platform) throw new HttpError("account_facts_identity_mismatch", 409);
+ const binding = resolved.binding;
+ if (raw.account_scope !== binding.account_scope || raw.account_selector !== binding.account_selector) {
+ throw new HttpError("account_facts_identity_mismatch", 409);
+ }
+ const config = await loadAccountOptionsConfig(env);
+ const options = (config.options?.[platform] || []).filter(item => item.key === binding.account_key);
+ if (options.length !== 1 || !accountFactsOptionMatchesBinding(options[0], binding)) throw new HttpError("account_facts_account_unattributed", 409);
+ const flow = normalizeExternalFlow(raw.externalFlow);
+ if (!externalFlowEnabled(env) && !dateOnlyExternalFlow(flow)) throw new HttpError("external_flow_disabled", 409);
+ const source = { ibkr: "ibkr_flex", schwab: "schwab_transactions", longbridge: "longbridge_cashflow" }[platform];
+ if (!source || flow.windows.some(w => w.source !== source)) throw new HttpError("external_flow_source_mismatch", 409);
+ const stored = await runtimeInstanceCommand(env, { action: "account_external_flow_put", platform,
+ account_key: binding.account_key, account_scope: binding.account_scope, account_selector: binding.account_selector,
+ target_id: binding.target_id, source_binding_id: binding.source_binding.id,
+ ...(platform === SCHWAB_ACCOUNT_FACTS_PLATFORM ? { broker_account_hash: binding.broker_account_hash } : {}),
+ ...(platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? { broker_account_id: binding.broker_account_id } : {}),
+ externalFlow: flow });
+ return json({ ok: true, stored: true, unchanged: stored.unchanged === true, readback_verified: stored.readback_verified === true,
+ account_key: binding.account_key, window_count: flow.windows.length,
+ record_count: new Set(flow.windows.flatMap(w => w.records.map(r => r.source_ref))).size });
+ } catch (error) {
+ if (error instanceof AccountFactsError || error instanceof HttpError || error?.code?.startsWith("external_flow")
+ || error?.code === "invalid_external_flow") return accountFactsErrorResponse(error, "external_flow_sync");
+ return json({ ok: false, error: "account_external_flow_unavailable" }, 503);
+ }
+}
+
+export async function syncAccountExecutionsResponse(request, env) {
+ if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
+ try {
+ if (requireDedicatedAccountFactsSyncToken(request, env) !== "ibkr") throw new HttpError("account_facts_sync_token_platform_mismatch", 403);
+ if (!hasConfigStore(env) || !hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
+ const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
+ const bindings = await loadAccountFactsBindings(env);
+ const resolved = resolveTrustedAccountFactsBinding(bindings, raw?.target_id, raw?.source_binding_id);
+ if (!resolved.ok || resolved.binding.platform !== "ibkr") throw new HttpError("account_facts_identity_mismatch", 409);
+ const binding = resolved.binding;
+ const config = await loadAccountOptionsConfig(env);
+ const options = (config.options?.ibkr || []).filter(item => item.key === binding.account_key);
+ if (options.length !== 1 || !accountFactsOptionMatchesBinding(options[0], binding)) throw new HttpError("account_facts_account_unattributed", 409);
+ const payload = normalizeExecutions(raw, { binding });
+ if (payload.records.some(row => row.report_ref !== payload.source_ref)) throw new HttpError("invalid_broker_executions", 400);
+ const stored = await runtimeInstanceCommand(env, { ...periodReturnCommand(binding, "account_executions_put"), payload });
+ return json({ ok: true, stored: true, unchanged: stored.unchanged === true,
+ account_key: binding.account_key, period: payload.period, record_count: payload.records.length });
+ } catch (error) {
+ if (error instanceof AccountFactsError || error instanceof HttpError || error?.code?.startsWith("execution_")
+ || error?.code === "invalid_broker_executions") return accountFactsErrorResponse(error, "executions_sync");
+ return json({ ok: false, error: "account_executions_unavailable" }, 503);
+ }
+}
+
+export async function syncAccountPeriodReturnResponse(request, env) {
+ if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
+ try {
+ if (requireDedicatedAccountFactsSyncToken(request, env) !== "ibkr") throw new HttpError("account_facts_sync_token_platform_mismatch", 403);
+ if (!hasConfigStore(env) || !hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
+ const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
+ const bindings = await loadAccountFactsBindings(env);
+ const resolved = resolveTrustedAccountFactsBinding(bindings, raw?.target_id, raw?.source_binding_id);
+ if (!resolved.ok || resolved.binding.platform !== "ibkr") throw new HttpError("account_facts_identity_mismatch", 409);
+ const binding = resolved.binding;
+ const config = await loadAccountOptionsConfig(env);
+ const options = (config.options?.ibkr || []).filter(item => item.key === binding.account_key);
+ if (options.length !== 1 || !accountFactsOptionMatchesBinding(options[0], binding)) throw new HttpError("account_facts_account_unattributed", 409);
+ const payload = normalizeIbkrPeriodReturn(raw, { binding });
+ const stored = await runtimeInstanceCommand(env, { ...periodReturnCommand(binding, "account_period_return_put"), payload,
+ historical: new URL(request.url).searchParams.get("historical") === "true" });
+ return json({ ok: true, stored: true, unchanged: stored.unchanged === true, account_key: binding.account_key,
+ period: payload.period, currency: payload.currency, method: payload.method });
+ } catch (error) {
+ if (error instanceof AccountFactsError || error instanceof HttpError) return accountFactsErrorResponse(error, "period_return_sync");
+ return json({ ok: false, error: "account_period_return_unavailable" }, 503);
+ }
+}
+
+export async function syncAccountFactsResponse(request, env, options) {
+ return syncAccountFactsResponseImpl(request, env, {
+ json,
+ hasConfigStore,
+ hasRuntimeInstanceStore,
+ loadAccountOptionsConfig,
+ loadAccountFactsBindings,
+ runtimeInstanceCommand,
+ readBoundedJson,
+ requireDedicatedAccountFactsSyncToken,
+ accountFactsErrorResponse: (error) => accountFactsErrorResponse(
+ error, options?.historical ? "history_sync" : "current_sync"),
+ }, options);
+}
+
+export async function accountFactsResponse(request, env) {
+ return accountFactsResponseImpl(request, env, {
+ json,
+ readSession,
+ hasConfigStore,
+ hasRuntimeInstanceStore,
+ loadAccountOptionsConfig,
+ loadAccountFactsBindings: (env) => loadAccountFactsBindings(env, { propagateReadErrors: true }),
+ loadStoredAccountFactsMap,
+ runtimeInstanceCommand,
+ periodReturnCommand,
+ accountFactsErrorResponse,
+ });
+}
+
+export async function accountFactsHistoryResponse(request, env, url) {
+ return accountFactsHistoryResponseImpl(request, env, url, {
+ json,
+ readSession,
+ hasConfigStore,
+ hasRuntimeInstanceStore,
+ loadAccountOptionsConfig,
+ loadAccountFactsBindings: (env) => loadAccountFactsBindings(env, { propagateReadErrors: true }),
+ runtimeInstanceCommand,
+ accountFactsErrorResponse,
+ sha256Hex,
+ });
+}
+
+export function requireDedicatedReconciliationRecoverySyncToken(request, env) {
+ const expected = String(env.RECONCILIATION_RECOVERY_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("reconciliation recovery sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("reconciliation recovery sync token is invalid", 401);
+}
+
+export function requireDedicatedReconciliationRecoveryControllerToken(request, env) {
+ const expected = String(env.RECONCILIATION_RECOVERY_CONTROLLER_TOKEN || "");
+ if (!expected) throw new HttpError("reconciliation recovery controller token is not configured", 500);
+ if (expected === String(env.RECONCILIATION_RECOVERY_SYNC_TOKEN || "")) {
+ throw new HttpError("reconciliation recovery controller token must differ from the source sync token", 500);
+ }
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("reconciliation recovery controller token is invalid", 401);
+}
+
+
+
+export function requireDedicatedResearchPromotionSyncToken(request, env) {
+ const expected = String(env.RESEARCH_PROMOTION_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("research promotion sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("research promotion sync token is invalid", 401);
+}
+
+export function researchPromotionTicketKey(ticketId) {
+ return `${RESEARCH_PROMOTION_TICKET_PREFIX}${ticketId}`;
+}
+
+export function platformSupportsBrokerPaperMode(platform) {
+ // Broker paper/sim is distinct from the local dry_run adapter. LongBridge's
+ // paper account is currently the only configured broker simulation route.
+ return platform === "longbridge";
+}
+
+export function supportedBrokerEnvironmentsForPlatform(platform) {
+ return platformSupportsBrokerPaperMode(platform) ? [...BROKER_ENVIRONMENTS] : ["live"];
+}
+
+export function normalizeBrokerEnvironment(value, fieldName = "broker_environment") {
+ const environment = String(value || "").trim();
+ if (!BROKER_ENVIRONMENTS.includes(environment)) {
+ throw new Error(`${fieldName} must be live or paper`);
+ }
+ return environment;
+}
+
+export function normalizeResearchPromotionRiskProfile(value, fieldName) {
+ const profile = String(value || "").trim().toUpperCase();
+ if (!RESEARCH_PROMOTION_RISK_PROFILES.includes(profile)) {
+ throw new Error(
+ `${fieldName} must be CAPITAL_PRESERVATION, BALANCED_COMPOUNDING, or GROWTH_COMPOUNDING`,
+ );
+ }
+ return profile;
+}
+
+export function normalizePromotionConfirmation(value, fieldName, { paperSupported }) {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ // Keep exact QPK PromotionConfirmation.to_dict() fields.
+ assertExactFields(value, ["target_platform", "execution_mode", "risk_profile"], fieldName);
+ const targetPlatform = String(value.target_platform || "").trim();
+ const executionMode = String(value.execution_mode || "").trim().toLowerCase();
+ const riskProfile = normalizeResearchPromotionRiskProfile(
+ value.risk_profile,
+ `${fieldName}.risk_profile`,
+ );
+ if (!targetPlatform) throw new Error(`${fieldName}.target_platform is required`);
+ if (!RESEARCH_PROMOTION_EXECUTION_MODES.includes(executionMode)) {
+ throw new Error(`${fieldName}.execution_mode must be live or paper`);
+ }
+ if (executionMode === "paper" && !paperSupported) {
+ throw new Error("paper is unavailable for this platform; synthetic matching is not supported");
+ }
+ return {
+ target_platform: targetPlatform,
+ execution_mode: executionMode,
+ risk_profile: riskProfile,
+ };
+}
+
+export function validateResearchPromotionSelectedAccount({
+ ticket,
+ selectedAccount,
+ confirmation,
+ accountOptions,
+ strategyProfiles,
+}) {
+ assertExactFields(selectedAccount, ["platform", "key"], "selected_account");
+ const platform = cleanChoice(selectedAccount.platform, SUPPORTED_PLATFORMS, "selected_account.platform");
+ const key = cleanSlug(selectedAccount.key, "selected_account.key");
+ const targetPlatform = String(confirmation?.target_platform || "").trim();
+ if (targetPlatform !== platform) {
+ throw new HttpError("selected_account platform does not match confirmation target_platform", 409);
+ }
+ const option = (accountOptions?.[platform] || []).find((item) => item.key === key);
+ if (!option) throw new HttpError("selected_account does not match configured account", 409);
+ const brokerEnvironment = String(option.broker_environment || "").trim();
+ if (!BROKER_ENVIRONMENTS.includes(brokerEnvironment)) {
+ throw new HttpError("selected account broker environment is unknown", 409);
+ }
+ if (!supportedBrokerEnvironmentsForPlatform(platform).includes(brokerEnvironment)) {
+ throw new HttpError(`${platform} does not support broker environment ${brokerEnvironment}`, 400);
+ }
+ if (String(confirmation?.execution_mode || "").trim().toLowerCase() !== brokerEnvironment) {
+ throw new HttpError("selected account broker environment does not match confirmation execution_mode", 409);
+ }
+ const strategy = (Array.isArray(strategyProfiles) ? strategyProfiles : [])
+ .find((item) => item.profile === ticket?.strategy_profile);
+ if (!strategy) throw new HttpError("selected candidate strategy profile is not configured", 409);
+ if (strategy.domain !== ticket?.domain) {
+ throw new HttpError("selected candidate strategy domain does not match ticket domain", 409);
+ }
+ if (!supportedDomainsForAccount(platform, option).includes(ticket.domain)) {
+ throw new HttpError("selected account does not support candidate domain", 409);
+ }
+ if (PLATFORM_CONFIG[platform]?.dry_run_only) {
+ throw new HttpError(`${platform} does not support broker execution`, 400);
+ }
+ assertDcaPlatform(platform, ticket.strategy_profile);
+ if (!(strategy.allowed_execution_modes || []).includes(brokerEnvironment)) {
+ throw new HttpError(`strategy ${strategy.profile} does not support broker environment ${brokerEnvironment}`, 400);
+ }
+ // A broker paper/live selection still needs the real adapter path. The
+ // account's dry_run default is not an implicit paper capability.
+ const adapterMode = cleanExecutionMode(
+ option.default_execution_mode || PLATFORM_CONFIG[platform]?.default_execution_mode || "live",
+ );
+ if (adapterMode !== "live") {
+ throw new HttpError("selected account adapter is not configured for broker execution", 400);
+ }
+ return { platform, key, broker_environment: brokerEnvironment };
+}
+
+export function researchPromotionCandidateIdentity(ticket) {
+ return {
+ strategy_profile: String(ticket?.strategy_profile || ""),
+ domain: String(ticket?.domain || ""),
+ proposed_params:
+ ticket?.proposed_params && typeof ticket.proposed_params === "object" && !Array.isArray(ticket.proposed_params)
+ ? ticket.proposed_params
+ : {},
+ search_iterations: Number(ticket?.search_iterations || 0),
+ shadow_evidence_kind: String(ticket?.shadow_evidence_kind || ""),
+ };
+}
+
+export function researchPromotionCandidatesMatch(left, right) {
+ return (
+ canonicalResearchTaskJson(researchPromotionCandidateIdentity(left))
+ === canonicalResearchTaskJson(researchPromotionCandidateIdentity(right))
+ );
+}
+
+export function assertResearchPromotionExpectedCandidate(ticket, raw, { requireExpectedParams = false } = {}) {
+ if (requireExpectedParams && !Object.prototype.hasOwnProperty.call(raw || {}, "expected_proposed_params")) {
+ throw new HttpError("accept requires expected_proposed_params", 400);
+ }
+ if (!Object.prototype.hasOwnProperty.call(raw || {}, "expected_proposed_params")) return;
+ const expected = raw.expected_proposed_params;
+ if (!expected || typeof expected !== "object" || Array.isArray(expected)) {
+ throw new HttpError("expected_proposed_params must be an object", 400);
+ }
+ const stored = ticket.proposed_params || {};
+ if (canonicalResearchTaskJson(expected) !== canonicalResearchTaskJson(stored)) {
+ throw new HttpError("expected_proposed_params does not match stored ticket candidate", 409);
+ }
+ if (raw.expected_strategy_profile != null) {
+ if (String(raw.expected_strategy_profile).trim() !== ticket.strategy_profile) {
+ throw new HttpError("expected_strategy_profile does not match stored ticket", 409);
+ }
+ }
+ if (raw.expected_domain != null) {
+ if (String(raw.expected_domain).trim() !== ticket.domain) {
+ throw new HttpError("expected_domain does not match stored ticket", 409);
+ }
+ }
+}
+
+export const RESEARCH_SUMMARY_HAN = /[\u4e00-\u9fff]/;
+export const RESEARCH_SUMMARY_LATIN = /[A-Za-z]/;
+export const RESEARCH_SUMMARY_DIGIT = /[0-9\uff10-\uff19]/;
+export const RESEARCH_SUMMARY_LOCALE_FIELDS = ["question", "basis", "limits", "suggestion"];
+const RESEARCH_SUMMARY_BINDING_FIELDS = [
+ "ticket_id", "strategy_profile", "domain", "proposed_params", "comparison",
+ "shadow_evidence_kind", "shadow_passed", "notes",
+];
+export const RESEARCH_SUMMARY_NEW_KEYS = ["status", "provider", "model", "scope", "locales", "binding"];
+export const RESEARCH_SUMMARY_OLD_KEYS = ["status", "provider", "model", "text"];
+export const RESEARCH_SUMMARY_HIDDEN = { status: "unavailable", text: "", provider: "", model: "" };
+
+export function researchSummaryExactKeys(value, keys) {
+ if (!value || Array.isArray(value) || typeof value !== "object") return false;
+ const present = Object.keys(value);
+ return present.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
+}
+
+export function researchSummaryCodePointLength(text) {
+ return Array.from(text).length;
+}
+
+export function researchSummarySegment(text, chinese) {
+ if (typeof text !== "string" || !text.trim() || researchSummaryCodePointLength(text) > 240) return null;
+ if (RESEARCH_SUMMARY_DIGIT.test(text)) return null;
+ const hasHan = RESEARCH_SUMMARY_HAN.test(text);
+ if (chinese) return hasHan ? text : null;
+ if (hasHan || !RESEARCH_SUMMARY_LATIN.test(text)) return null;
+ return text;
+}
+
+export function sameResearchSummaryMaterial(left, right) {
+ return canonicalResearchTaskJson(left) === canonicalResearchTaskJson(right);
+}
+
+export function readBilingualResearchPromotionExplanation(ai, material) {
+ if (ai.status !== "available" || (ai.provider !== "codex" && ai.provider !== "cursor")) return null;
+ if (typeof ai.model !== "string" || !ai.model.trim() || ai.scope !== "candidate") return null;
+ const locales = ai.locales;
+ if (!researchSummaryExactKeys(locales, ["zh-CN", "en"])) return null;
+ const savedLocales = {};
+ for (const [name, chinese] of [["zh-CN", true], ["en", false]]) {
+ const section = locales[name];
+ if (!researchSummaryExactKeys(section, RESEARCH_SUMMARY_LOCALE_FIELDS)) return null;
+ const saved = {};
+ for (const field of RESEARCH_SUMMARY_LOCALE_FIELDS) {
+ const segment = researchSummarySegment(section[field], chinese);
+ if (segment == null) return null;
+ saved[field] = segment;
+ }
+ savedLocales[name] = saved;
+ }
+ if (!researchSummaryExactKeys(ai.binding, RESEARCH_SUMMARY_BINDING_FIELDS)) return null;
+ if (!sameResearchSummaryMaterial(ai.binding, material)) return null;
+ return {
+ status: "available",
+ provider: ai.provider,
+ model: ai.model,
+ scope: "candidate",
+ locales: savedLocales,
+ binding: JSON.parse(canonicalResearchTaskJson(material)),
+ };
+}
+
+export function readLegacyResearchPromotionExplanation(ai) {
+ const status = String(ai.status || "").trim();
+ if (status !== "available" && status !== "unavailable") return null;
+ if (typeof ai.text !== "string" || typeof ai.provider !== "string" || typeof ai.model !== "string") return null;
+ if (ai.text.length > 2000 || ai.model.length > 120) return null;
+ if (status === "available" && (ai.provider !== "codex" || !ai.text.trim())) return null;
+ if (status === "unavailable" && ai.provider !== "") return null;
+ return {
+ status,
+ text: ai.text.trim(),
+ provider: ai.provider,
+ model: ai.model.trim(),
+ };
+}
+
+export function normalizeSavedResearchPromotionExplanation(ai, material) {
+ try {
+ if (ai == null) return { ...RESEARCH_SUMMARY_HIDDEN };
+ if (researchSummaryExactKeys(ai, RESEARCH_SUMMARY_NEW_KEYS)) {
+ return readBilingualResearchPromotionExplanation(ai, material) || { ...RESEARCH_SUMMARY_HIDDEN };
+ }
+ if (researchSummaryExactKeys(ai, RESEARCH_SUMMARY_OLD_KEYS)) {
+ return readLegacyResearchPromotionExplanation(ai) || { ...RESEARCH_SUMMARY_HIDDEN };
+ }
+ return { ...RESEARCH_SUMMARY_HIDDEN };
+ } catch {
+ return { ...RESEARCH_SUMMARY_HIDDEN };
+ }
+}
+
+export function normalizeResearchPromotionSummary(raw, ticket, fieldName = "research_summary") {
+ if (raw == null) return null;
+ if (!raw || Array.isArray(raw) || typeof raw !== "object") return null;
+ try {
+ const comparisonForBinding = raw.comparison;
+ const identity = raw.identity;
+ if (!identity || Array.isArray(identity) || typeof identity !== "object") return null;
+ const identityParams = identity.proposed_params;
+ if (
+ String(identity.strategy_profile || "").trim() !== ticket.strategy_profile
+ || String(identity.domain || "").trim() !== ticket.domain
+ || !identityParams || Array.isArray(identityParams)
+ || canonicalResearchTaskJson(identityParams) !== canonicalResearchTaskJson(ticket.proposed_params || {})
+ ) return null;
+
+ if (raw.strategy_description != null && typeof raw.strategy_description !== "string") return null;
+ const strategyDescription = String(raw.strategy_description || "").trim();
+ if (strategyDescription.length > 500) return null;
+
+ let plugins = null;
+ if (raw.plugins === null) {
+ plugins = null;
+ } else if (Array.isArray(raw.plugins)) {
+ plugins = raw.plugins.map((plugin, index) => {
+ if (!plugin || Array.isArray(plugin) || typeof plugin !== "object") {
+ throw new Error(`${fieldName}.plugins[${index}] must be an object`);
+ }
+ if (typeof plugin.id !== "string" || typeof plugin.description !== "string") {
+ throw new Error(`${fieldName}.plugins[${index}] must include text fields`);
+ }
+ const id = plugin.id.trim();
+ const description = plugin.description.trim();
+ if (id.length > 120 || description.length > 300) throw new Error(`${fieldName}.plugins[${index}] is too long`);
+ return { id, description };
+ });
+ } else if (raw.plugins == null) {
+ plugins = null;
+ } else {
+ return null;
+ }
+
+ const comparison = raw.comparison == null ? { status: "unavailable" } : raw.comparison;
+ if (!comparison || Array.isArray(comparison) || typeof comparison !== "object") return null;
+ const comparisonStatus = String(comparison.status || "").trim();
+ if (comparisonStatus !== "comparable" && comparisonStatus !== "unavailable") return null;
+ const optionalText = (value, name) => {
+ if (value == null) return null;
+ if (typeof value !== "string") throw new Error(`${fieldName}.${name} must be text or null`);
+ const text = value.trim();
+ if (text.length > 120) throw new Error(`${fieldName}.${name} is too long`);
+ return text;
+ };
+ const exactCostModel = (value, name) => {
+ if (value == null) return null;
+ if (typeof value !== "string") throw new Error(`${fieldName}.${name} must be text or null`);
+ if (value.length > 120) throw new Error(`${fieldName}.${name} is too long`);
+ return value;
+ };
+ const normalizeMetrics = (value, name) => {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName}.${name} must be an object`);
+ }
+ const cagr = value.cagr;
+ const maxDrawdown = value.max_drawdown;
+ if (typeof cagr !== "number" || typeof maxDrawdown !== "number"
+ || !Number.isFinite(cagr) || !Number.isFinite(maxDrawdown)
+ || cagr < -1 || maxDrawdown < -1 || maxDrawdown > 0) {
+ throw new Error(`${fieldName}.${name} must use finite numbers`);
+ }
+ return { cagr, max_drawdown: maxDrawdown };
+ };
+ const normalizedComparison = {
+ status: comparisonStatus,
+ start_date: optionalText(comparison.start_date, "comparison.start_date"),
+ end_date: optionalText(comparison.end_date, "comparison.end_date"),
+ cost_model: exactCostModel(comparison.cost_model, "comparison.cost_model"),
+ baseline: null,
+ candidate: null,
+ };
+ if (comparisonStatus === "comparable") {
+ if (!normalizedComparison.start_date || !normalizedComparison.end_date || !normalizedComparison.cost_model?.trim()) return null;
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(normalizedComparison.start_date)
+ || !/^\d{4}-\d{2}-\d{2}$/.test(normalizedComparison.end_date)) return null;
+ const startMillis = Date.parse(`${normalizedComparison.start_date}T00:00:00Z`);
+ const endMillis = Date.parse(`${normalizedComparison.end_date}T00:00:00Z`);
+ if (!Number.isFinite(startMillis) || !Number.isFinite(endMillis) || startMillis > endMillis) return null;
+ normalizedComparison.baseline = normalizeMetrics(comparison.baseline, "comparison.baseline");
+ normalizedComparison.candidate = normalizeMetrics(comparison.candidate, "comparison.candidate");
+ } else {
+ if (comparison.baseline != null) normalizeMetrics(comparison.baseline, "comparison.baseline");
+ if (comparison.candidate != null) normalizeMetrics(comparison.candidate, "comparison.candidate");
+ }
+
+ if (!Array.isArray(raw.limitations) || raw.limitations.length > 8 || raw.limitations.some((item) => typeof item !== "string" || item.length > 300)) return null;
+ const aiExplanation = normalizeSavedResearchPromotionExplanation(raw.ai_explanation, {
+ ticket_id: ticket.ticket_id,
+ strategy_profile: ticket.strategy_profile,
+ domain: ticket.domain,
+ proposed_params: ticket.proposed_params || {},
+ comparison: comparisonForBinding,
+ shadow_evidence_kind: ticket.shadow_evidence_kind,
+ shadow_passed: ticket.shadow_passed,
+ notes: Array.isArray(ticket.notes) ? ticket.notes : [],
+ });
+
+ return {
+ identity: {
+ strategy_profile: ticket.strategy_profile,
+ domain: ticket.domain,
+ proposed_params: ticket.proposed_params || {},
+ },
+ strategy_description: strategyDescription,
+ plugins,
+ comparison: normalizedComparison,
+ limitations: raw.limitations.map((item) => item.trim()),
+ ai_explanation: aiExplanation,
+ };
+ } catch {
+ return null;
+ }
+}
+
+export function normalizeResearchPromotionTicket(raw, fieldName = "research promotion ticket") {
+ if (!raw || Array.isArray(raw) || typeof raw !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ const ticketId = String(raw.ticket_id || "").trim();
+ const strategyProfile = String(raw.strategy_profile || "").trim();
+ const domain = String(raw.domain || "").trim();
+ const state = String(raw.state || "").trim();
+ if (!ticketId) throw new Error(`${fieldName}.ticket_id is required`);
+ if (!strategyProfile) throw new Error(`${fieldName}.strategy_profile is required`);
+ if (!domain) throw new Error(`${fieldName}.domain is required`);
+ if (!RESEARCH_PROMOTION_STATES.includes(state)) {
+ throw new Error(`${fieldName}.state is unsupported`);
+ }
+ if (raw.live_authority_granted === true) {
+ throw new Error(`${fieldName}.live_authority_granted must remain false`);
+ }
+ const suggested = normalizeResearchPromotionRiskProfile(
+ raw.suggested_risk_profile || DEFAULT_RESEARCH_PROMOTION_RISK_PROFILE,
+ `${fieldName}.suggested_risk_profile`,
+ );
+ const driftStatus = String(raw.drift_status || "");
+ const normalizedTicket = {
+ schema: RESEARCH_PROMOTION_TICKET_SCHEMA,
+ ticket_id: ticketId,
+ strategy_profile: strategyProfile,
+ domain,
+ state,
+ drift_status: driftStatus,
+ drift_score: driftStatus === "new_research" && raw.drift_score === null
+ ? null
+ : Number(raw.drift_score || 0),
+ created_at: String(raw.created_at || ""),
+ updated_at: String(raw.updated_at || ""),
+ budget: raw.budget && typeof raw.budget === "object" && !Array.isArray(raw.budget) ? raw.budget : {},
+ proposed_params:
+ raw.proposed_params && typeof raw.proposed_params === "object" && !Array.isArray(raw.proposed_params)
+ ? raw.proposed_params
+ : {},
+ search_iterations: Number(raw.search_iterations || 0),
+ shadow_evidence_kind: String(raw.shadow_evidence_kind || ""),
+ // Qualification must never treat string values such as "false" as a
+ // passed observation. Keep malformed legacy values unknown and let the
+ // application gate reject them.
+ shadow_passed: raw.shadow_passed === true ? true : raw.shadow_passed === false ? false : null,
+ notification_subject: String(raw.notification_subject || ""),
+ notification_body: String(raw.notification_body || ""),
+ human_decision: String(raw.human_decision || ""),
+ human_decided_at: String(raw.human_decided_at || ""),
+ live_authority_granted: false,
+ suggested_risk_profile: suggested,
+ confirmation_target_platform: String(raw.confirmation_target_platform || ""),
+ confirmation_execution_mode: String(raw.confirmation_execution_mode || ""),
+ confirmation_risk_profile: String(raw.confirmation_risk_profile || ""),
+ notes: Array.isArray(raw.notes) ? raw.notes.map((item) => String(item)) : [],
+ };
+ const researchSummary = normalizeResearchPromotionSummary(raw.research_summary, normalizedTicket, `${fieldName}.research_summary`);
+ if (researchSummary) normalizedTicket.research_summary = researchSummary;
+ return normalizedTicket;
+}
+
+export function applyResearchPromotionDecision(
+ ticket,
+ {
+ decision,
+ confirmation = null,
+ paperSupported = false,
+ selectedAccount = null,
+ accountOptions = null,
+ strategyProfiles = null,
+ decidedAt = null,
+ expectedRaw = null,
+ },
+) {
+ if (ticket.state !== "awaiting_human") {
+ throw new HttpError(`ticket ${ticket.ticket_id} is not awaiting human (state=${ticket.state})`, 409);
+ }
+ const normalized = String(decision || "").trim().toLowerCase();
+ if (normalized !== "accept" && normalized !== "reject") {
+ throw new HttpError("decision must be accept or reject", 400);
+ }
+ assertResearchPromotionExpectedCandidate(ticket, expectedRaw || {}, {
+ requireExpectedParams: normalized === "accept",
+ });
+ const stamp = decidedAt || new Date().toISOString();
+ const next = {
+ ...ticket,
+ human_decision: normalized,
+ human_decided_at: stamp,
+ live_authority_granted: false,
+ updated_at: stamp,
+ notes: [...(ticket.notes || [])],
+ };
+ if (normalized === "accept") {
+ if (!confirmation) {
+ throw new HttpError(
+ "accept requires confirmation (target_platform, execution_mode, risk_profile)",
+ 400,
+ );
+ }
+ const confirmed = normalizePromotionConfirmation(confirmation, "confirmation", {
+ paperSupported: Boolean(paperSupported),
+ });
+ if (!selectedAccount) {
+ throw new HttpError("accept requires selected_account", 400);
+ }
+ validateResearchPromotionSelectedAccount({
+ ticket,
+ selectedAccount,
+ confirmation: confirmed,
+ accountOptions,
+ strategyProfiles,
+ });
+ next.confirmation_target_platform = confirmed.target_platform;
+ next.confirmation_execution_mode = confirmed.execution_mode;
+ next.confirmation_risk_profile = confirmed.risk_profile;
+ next.state = "human_accepted";
+ next.notes.push(
+ "human_accepted_intent_only_no_live_authority",
+ `confirmation_platform=${confirmed.target_platform}`,
+ `confirmation_mode=${confirmed.execution_mode}`,
+ `confirmation_risk_profile=${confirmed.risk_profile}`,
+ );
+ } else {
+ next.state = "human_rejected";
+ next.notes.push("human_rejected");
+ }
+ return next;
+}
+
+export async function syncResearchPromotionTicketResponse(request, env) {
+ requireDedicatedResearchPromotionSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "research promotion KV is not configured" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, RESEARCH_PROMOTION_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research promotion ticket" }, error.status || 400);
+ }
+ let ticket;
+ try {
+ ticket = normalizeResearchPromotionTicket(raw);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research promotion ticket" }, 400);
+ }
+ if (ticket.state !== "awaiting_human") {
+ return json(
+ { ok: false, error: "research promotion sync only accepts awaiting_human tickets" },
+ 400,
+ );
+ }
+ const existingRaw = await readConfigJson(env, researchPromotionTicketKey(ticket.ticket_id));
+ let existing = null;
+ if (existingRaw) {
+ try {
+ existing = normalizeResearchPromotionTicket(existingRaw, "stored research promotion ticket");
+ } catch (error) {
+ return json(
+ { ok: false, error: error.message || "invalid stored research promotion ticket" },
+ 400,
+ );
+ }
+ }
+ let material;
+ try {
+ material = await publishHumanPromotionMaterial(env, ticket, existing);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "research promotion material unavailable" }, error.status || 503);
+ }
+ if (material.identity_conflict) {
+ return json(
+ { ok: false, error: "refusing to overwrite awaiting_human research promotion ticket with mismatched candidate identity" },
+ 409,
+ );
+ }
+ if (material.terminal || material.legacy_blocked) {
+ return json(
+ { ok: false, error: `refusing to overwrite terminal research promotion ticket state=${material.terminal_state || existing?.state || "human_accepted"}` },
+ 409,
+ );
+ }
+ await writeConfigJson(env, researchPromotionTicketKey(ticket.ticket_id), ticket);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: "research-promotion-ticket-sync",
+ action: "sync_research_promotion_ticket",
+ ticket_id: ticket.ticket_id,
+ state: ticket.state,
+ suggested_risk_profile: ticket.suggested_risk_profile,
+ live_authority_granted: false,
+ });
+ } catch {
+ // Intent sync must not depend on optional audit retention.
+ }
+ return json({
+ ok: true,
+ ticket_id: ticket.ticket_id,
+ state: ticket.state,
+ suggested_risk_profile: ticket.suggested_risk_profile,
+ live_authority_granted: false,
+ });
+}
+
+export async function fetchResearchPromotionTicketResponse(request, env) {
+ requireDedicatedResearchPromotionSyncToken(request, env);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "research promotion KV is not configured" }, 503);
+ }
+ const ticketId = String(new URL(request.url).searchParams.get("ticket_id") || "").trim();
+ if (!ticketId) return json({ ok: false, error: "ticket_id is required" }, 400);
+ const stored = await readConfigJson(env, researchPromotionTicketKey(ticketId));
+ if (!stored) return json({ ok: false, error: "research promotion ticket not found" }, 404);
+ let ticket;
+ try {
+ ticket = normalizeResearchPromotionTicket(stored);
+ ticket = await promotionTicketWithAuthority(env, ticket);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid stored research promotion ticket" }, error.status || 400);
+ }
+ if (ticket.live_authority_granted) {
+ return json({ ok: false, error: "refusing to expose live_authority_granted=true" }, 500);
+ }
+ return json({
+ ok: true,
+ ticket: attachRiskEnvelopeView(ticket),
+ live_authority_granted: false,
+ });
+}
+
+export async function listResearchPromotionTickets(env) {
+ if (!hasConfigStore(env)) return [];
+ const store = configStore(env);
+ let listing;
+ try {
+ listing = await directoryList(env, RESEARCH_PROMOTION_TICKET_PREFIX, RESEARCH_PROMOTION_MAX_TICKETS);
+ } catch (error) {
+ throw new HttpError(sourceListFailure(error, "research_promotion_source_list_unavailable"), 503);
+ }
+ const keys = listing?.keys || [];
+ const tickets = [];
+ for (const entry of keys) {
+ const key = entry.name || entry;
+ if (!String(key).startsWith(RESEARCH_PROMOTION_TICKET_PREFIX)) continue;
+ const stored = await readConfigJson(env, key);
+ if (!stored) throw new HttpError("kv_directory_record_unavailable", 503);
+ try {
+ const record = normalizeResearchPromotionTicket(stored, key);
+ const authority = await readHumanDecisionAuthority(env, "promotion", record.ticket_id);
+ const ticket = attachPromotionQueueReadMetadata(record, overlayPromotionDecision(record, authority), authority);
+ if (ticket.live_authority_granted) continue;
+ if (ticket.state === "awaiting_human") {
+ // Project the same durable observation used by the decision metadata.
+ ticket.decision_authority = humanDecisionAuthorityView(authority);
+ }
+ tickets.push(ticket);
+ } catch (error) {
+ if (error instanceof HttpError && error.status === 503) throw error;
+ // Skip corrupt tickets rather than failing the whole queue.
+ }
+ }
+ tickets.sort((left, right) => String(right.updated_at).localeCompare(String(left.updated_at)));
+ return tickets.slice(0, RESEARCH_PROMOTION_MAX_TICKETS);
+}
+
+export function attachPromotionQueueReadMetadata(record, ticket, authority) {
+ // Reuse the queue's existing material observation. Unknown is not permission;
+ // these fixed reasons describe stored intent material flags, not full decision
+ // permission, ticket-hash validation, or account application gates.
+ const migrated = typeof authority?.migrated === "boolean" ? authority.migrated : null;
+ const eligible = migrated === true && typeof authority?.eligible === "boolean" ? authority.eligible : null;
+ const blocked = migrated === true && typeof authority?.blocked === "boolean" ? authority.blocked : null;
+ const blockerCodes = migrated !== true ? null
+ : blocked === true ? ["human_decision_legacy_blocked"]
+ : eligible === false ? ["human_decision_material_conflict"]
+ : eligible === true && blocked === false ? [] : null;
+ return {
+ ...ticket,
+ decision_material: { migrated, eligible, blocked, blocker_codes: blockerCodes },
+ decision_review_binding: authority?.review_binding || null,
+ // Timestamps of the already-read KV ticket record, not producer-observed
+ // time, freshness, a validity window, or evidence of actual execution.
+ ticket_record_timestamps: {
+ created_at: typeof record?.created_at === "string" && record.created_at ? record.created_at : null,
+ updated_at: typeof record?.updated_at === "string" && record.updated_at ? record.updated_at : null,
+ },
+ };
+}
+
+export async function researchPromotionTicketsResponse(request, env) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ const exact = await exactHumanDecisionResponse(request, env, session, "promotion");
+ if (exact) return exact;
+ const tickets = [];
+ const invalidTickets = [];
+ for (const ticket of await listResearchPromotionTickets(env)) {
+ let reviewBinding;
+ try {
+ reviewBinding = await researchPromotionReviewBinding(ticket);
+ } catch (error) {
+ if (!(error instanceof ResearchPromotionReviewMaterialError)) throw error;
+ // Keep a bounded, explicit non-actionable diagnosis; never serialize the
+ // invalid numbers as fake zero/null or certify this ticket with a digest.
+ invalidTickets.push({
+ ticket_id: ticket.ticket_id, strategy_profile: ticket.strategy_profile, state: ticket.state,
+ decision_material: { eligible: false, blocked: true, blocker_codes: [RESEARCH_PROMOTION_REVIEW_INVALID] },
+ decision_binding: null, live_authority_granted: false, no_order: true,
+ });
+ continue;
+ }
+ tickets.push({ ...ticket, decision_binding: {
+ kind: "promotion", subject_id: ticket.ticket_id, material_sha256: await researchPromotionMaterialKey(ticket),
+ review_binding: promotionReviewBindingsMatch(reviewBinding, ticket.decision_review_binding) ? reviewBinding : null,
+ } });
+ }
+ const awaiting = tickets.filter((ticket) => ticket.state === "awaiting_human");
+ const applicationTickets = tickets.filter((ticket) =>
+ ticket.state === "awaiting_human" || ticket.state === "human_accepted");
+ const accountConfig = await loadAccountOptionsConfig(env);
+ const strategyProfiles = await loadStrategyProfilesConfig(env);
+ const applications = [];
+ for (const ticket of applicationTickets) {
+ const preparation = attachResearchPromotionApplicationPreparation(ticket, accountConfig.options, strategyProfiles);
+ let application = null;
+ if (hasRuntimeInstanceStore(env)) {
+ try {
+ const stored = await runtimeInstanceCommand(env, { action: "application_latest", actor: session.login, ticket_id: ticket.ticket_id });
+ application = publicResearchPromotionApplication(stored.application);
+ } catch {
+ // Application storage is optional for the research-only queue view.
+ }
+ }
+ applications.push({ ...preparation, application });
+ }
+ return json({
+ schema_version: RESEARCH_PROMOTION_QUEUE_SCHEMA,
+ data_status: hasConfigStore(env) ? (invalidTickets.length ? "partial" : "ready") : "unavailable",
+ computed_at: new Date().toISOString(),
+ tickets: decorateQueue({ tickets: awaiting.map(attachRiskEnvelopeView) }, "tickets", "strategy_promotion").tickets,
+ applications,
+ ...(invalidTickets.length ? { invalid_tickets: invalidTickets } : {}),
+ summary: {
+ ticket_count: awaiting.length,
+ awaiting_human: awaiting.length,
+ application_count: applications.length,
+ ...(invalidTickets.length ? { invalid_review_count: invalidTickets.length } : {}),
+ },
+ policy: {
+ admin_required_to_decide: true,
+ live_authority_granted: false,
+ no_order: true,
+ application_dispatch_allowed: false,
+ activation_status: "not_connected",
+ notice: "网页只记录晋级人工意图;确认不授予实盘权限,也不下单。",
+ },
+ errors: invalidTickets.length ? [RESEARCH_PROMOTION_REVIEW_INVALID] : [],
+ });
+}
+
+const DECISION_POLICY = Object.freeze({
+ no_order: true,
+ execution_authority_granted: false,
+ current_evidence_required: true,
+ human_confirmation_required: true,
+ notice: "只记录人工决定意图;不会下单、变更资金或启用实盘。",
+});
+
+export function decisionInboxSources() {
+ return {
+ owner: ownerDecisionQueueResponse,
+ promotion: researchPromotionTicketsResponse,
+ recovery: reconciliationRecoveryResponse,
+ credential: (request, env) => credentialMaintenanceResponse(
+ request, env, new URL("/api/credential-maintenance", request.url),
+ ),
+ };
+}
+
+export function decodeDecisionApiId(raw) {
+ let id;
+ try {
+ id = decodeURIComponent(String(raw || ""));
+ } catch {
+ return null;
+ }
+ const parts = decisionCategoryPart(id);
+ if (parts) return { id, category: parts.category, subject_id: parts.subject_id };
+ const legacyCredential = /^credential:(.+)$/.exec(id);
+ if (!legacyCredential || legacyCredential[1].length > 256 || /[\u0000-\u001f\u007f]/.test(legacyCredential[1])) return null;
+ return { id, category: "credential_maintenance", subject_id: legacyCredential[1] };
+}
+
+export function decodeOperationApiId(raw) {
+ let id;
+ try {
+ id = decodeURIComponent(String(raw || ""));
+ } catch {
+ return null;
+ }
+ const match = /^operation:(owner_decision|strategy_promotion|paper_account_application|reconciliation_recovery|credential_maintenance):(.+)$/.exec(id);
+ if (!match || match[2].length > 256 || /[\u0000-\u001f\u007f]/.test(match[2])) return null;
+ return { id, category: match[1], subject_id: match[2] };
+}
+
+const DECISION_SOURCE_BY_CATEGORY = Object.freeze({
+ owner_decision: "owner",
+ strategy_promotion: "promotion",
+ paper_account_application: "promotion",
+ reconciliation_recovery: "recovery",
+ credential_maintenance: "credential",
+});
+
+/**
+ * Absence is only proven when the owning source was read. A failed or
+ * unavailable source stays a 503 so a missing id never masks a broken read.
+ */
+export function decisionSourceUnreadable(queue, category) {
+ const name = DECISION_SOURCE_BY_CATEGORY[category];
+ const source = (queue?.sources || []).find((entry) => entry.source === name);
+ if (!source) return true;
+ return ["read_failed", "unavailable"].includes(source.status);
+}
+
+// The durable record keeps the operation id in its request key. The id names the
+// recorded intent; a legacy fingerprint key carries no client operation id.
+export function recordedDecisionOperationId(record) {
+ const match = /^id:(?:owner|promotion|recovery):(.+)$/.exec(
+ typeof record?.request_key === "string" ? record.request_key : "",
+ );
+ return match ? match[1] : null;
+}
+
+// The recorded intent's canonical target: accepted selection for promotion, action elsewhere.
+export function decisionIntentTargetJson(category, action, selection) {
+ if (category === "strategy_promotion" || category === "paper_account_application") {
+ const accepted = action === "accept" ? selection : null;
+ return canonicalResearchTaskJson({
+ selected_account: accepted?.selected_account ?? null,
+ confirmation: accepted?.confirmation ?? null,
+ });
+ }
+ return canonicalResearchTaskJson({ decision: action });
+}
+
+// A terminal item synthesized from the durable record. It keeps the original
+// decision id resolvable after the pending projection drops or recategorizes it.
+export function durableDecisionItem(record, parsed, kind, aliasItem = null) {
+ const material = /^[0-9a-f]{64}$/.test(record.material_key || "") ? record.material_key : null;
+ const reviewSha = /^[0-9a-f]{64}$/.test(record.payload?.review_binding?.review_sha256 || "")
+ ? record.payload.review_binding.review_sha256 : null;
+ const binding = {
+ kind,
+ subject_id: record.subject_id,
+ material_sha256: material,
+ ...(reviewSha ? { review_binding: { schema_version: "qsl_promotion_review_binding.v2", review_sha256: reviewSha } } : {}),
+ };
+ return {
+ id: parsed.id,
+ short_id: shortId(parsed.id),
+ decision_id: parsed.id,
+ category: parsed.category,
+ title_key: `decisions.${parsed.category}`,
+ revision: decisionRevision(binding, parsed.id),
+ actionable: false,
+ blocking_reason_codes: ["decision_already_decided"],
+ allowed_actions: [],
+ request_id_required: false,
+ action_endpoint: null,
+ decision_state: {
+ status: "decided",
+ action: record.action,
+ decided_at: typeof record.decided_at === "string" ? record.decided_at : null,
+ },
+ decision_binding: binding,
+ operation_reference: aliasItem?.operation_reference
+ || decisionOperationReference({}, parsed.category, parsed.subject_id),
+ source: "durable_human_decision_record",
+ };
+}
+
+export async function loadDecisionById(request, env, parsed) {
+ // Detail and action routes address one decision by id. Reading the unpaged
+ // projection keeps them independent of the presentation page a client last saw.
+ const queue = await inbox(request, env, decisionInboxSources(), { paginate: false });
+ const item = queue.items.find((entry) => entry.id === parsed.id) || null;
+ if (item) return { queue, item, authorityRaw: undefined };
+ // A terminal record outlives the pending projection: accepted paper tickets are
+ // recategorized and rejected tickets leave the queue, so resolve them durably.
+ const kind = decisionKind(parsed.category);
+ if (!kind || !hasRuntimeInstanceStore(env)) return { queue, item: null, authorityRaw: undefined };
+ let authorityRaw;
+ try {
+ authorityRaw = await readHumanDecisionAuthority(env, kind, parsed.subject_id);
+ } catch {
+ throw new HttpError("decision_authority_unavailable", 503);
+ }
+ const record = authorityRaw?.migrated === false ? null : authorityRaw?.decision;
+ if (!record || record.kind !== kind || record.subject_id !== parsed.subject_id)
+ return { queue, item: null, authorityRaw };
+ const alias = queue.items.find((entry) => entry.decision_binding?.subject_id === parsed.subject_id
+ && entry.decision_binding?.kind === kind);
+ return { queue, item: durableDecisionItem(record, parsed, kind, alias || null), authorityRaw };
+}
+
+export async function readDecisionAuthorityOrNull(env, kind, subjectId) {
+ if (!kind) return null;
+ if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
+ return readHumanDecisionAuthority(env, kind, subjectId);
+}
+
+export async function decisionReviewResponse(request, env, rawId) {
+ if (request.method !== "GET") return json({ ok: false, error: "method_not_allowed" }, 405);
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
+ const parsed = decodeDecisionApiId(rawId);
+ if (!parsed) return json({ ok: false, error: "decision_id_invalid" }, 400);
+ const { queue, item, authorityRaw: loadedAuthority } = await loadDecisionById(request, env, parsed);
+ if (!item) {
+ if (decisionSourceUnreadable(queue, parsed.category))
+ return json({ ok: false, error: "decision_source_unavailable", error_state: queue.error_state || null }, 503);
+ return json({ ok: false, error: "decision_not_found" }, 404);
+ }
+ const kind = decisionKind(parsed.category);
+ let authorityRaw;
+ try {
+ authorityRaw = loadedAuthority !== undefined
+ ? loadedAuthority
+ : await readDecisionAuthorityOrNull(env, kind, parsed.subject_id);
+ } catch {
+ return json({ ok: false, error: "decision_authority_unavailable" }, 503);
+ }
+ const authority = authorityRaw ? humanDecisionAuthorityView(authorityRaw) : null;
+ const now = Date.now();
+ let receipt = null;
+ const errors = [];
+ if (authorityRaw?.decision) {
+ try {
+ receipt = await humanDecisionReceipt(authorityRaw.decision, {
+ kind,
+ subject_id: parsed.subject_id,
+ material_sha256: authorityRaw.decision.material_key,
+ });
+ } catch {
+ errors.push("decision_receipt_unavailable");
+ }
+ }
+ if (authorityRaw?.migrated === false) errors.push("decision_authority_unavailable");
+ if (queue.status !== "ok") errors.push("decision_source_partial");
+ return json({
+ schema_version: DECISION_REVIEW_SCHEMA_VERSION,
+ server_time: new Date(now).toISOString(),
+ data_status: errors.length ? "partial" : "ready",
+ decision_id: item.id,
+ decision: item,
+ current_eligibility: decisionCurrentEligibility(item, authority, now),
+ decision_authority: authority,
+ decision_receipt: receipt,
+ operation: item.operation_reference,
+ policy: DECISION_POLICY,
+ tier_policies: riskTierPolicyCatalog(),
+ errors: [...new Set(errors)],
+ });
+}
+
+export function decisionSelection(raw) {
+ const selection = raw?.selection;
+ if (!selection || Array.isArray(selection) || typeof selection !== "object") return null;
+ return {
+ confirmation: selection.confirmation && typeof selection.confirmation === "object" && !Array.isArray(selection.confirmation)
+ ? selection.confirmation : null,
+ selected_account: selection.selected_account && typeof selection.selected_account === "object" && !Array.isArray(selection.selected_account)
+ ? selection.selected_account : null,
+ };
+}
+
+export async function decisionActionResponse(request, env, rawId) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ const parsed = decodeDecisionApiId(rawId);
+ if (!parsed) return json({ ok: false, error: "decision_id_invalid" }, 400);
+ const supported = DECISION_ACTIONS[parsed.category] || [];
+ const kind = decisionKind(parsed.category);
+ if (!kind || !supported.length) return json({ ok: false, error: "decision_not_actionable" }, 409);
+
+ let raw;
+ try {
+ raw = await readBoundedJson(request, DECISION_ACTION_MAX_BODY_BYTES);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid decision action" }, error.status || 400);
+ }
+ if (!raw || Array.isArray(raw) || typeof raw !== "object")
+ return json({ ok: false, error: "decision_action_request_invalid" }, 400);
+ if (Object.keys(raw).some((key) => !["action", "expected_revision", "expected_expires_at", "request_id", "operation_id", "selection"].includes(key)))
+ return json({ ok: false, error: "decision_action_request_invalid" }, 400);
+ const action = typeof raw.action === "string" ? raw.action.trim() : "";
+ if (!supported.includes(action))
+ return json({ ok: false, error: "decision_action_invalid" }, 400);
+ if (typeof raw.expected_revision !== "string" || !/^rev[0-9]-[0-9a-z-]{1,64}$/.test(raw.expected_revision))
+ return json({ ok: false, error: "decision_revision_required" }, 400);
+ const requestId = typeof raw.request_id === "string" ? raw.request_id.trim() : "";
+ // The operation id names the intent. It is the durable idempotency key, so a
+ // retry with the same id replays and a new intent needs a new id.
+ const operationId = decisionOperationId(raw);
+ if (!operationId) {
+ if (requestId && !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId))
+ return json({ ok: false, error: "invalid request_id" }, 400);
+ return json({ ok: false, error: "decision_operation_id_invalid" }, 400);
+ }
+ const operationSha256 = await decisionOperationSha256(parsed.id, raw);
+ const selection = decisionSelection(raw);
+ if ((parsed.category === "strategy_promotion" || parsed.category === "paper_account_application")
+ && action === "accept" && (!selection?.confirmation || !selection?.selected_account))
+ return json({ ok: false, error: "decision_selection_required" }, 400);
+
+ const { queue, item } = await loadDecisionById(request, env, parsed);
+ if (!item) {
+ if (decisionSourceUnreadable(queue, parsed.category))
+ return json({ ok: false, error: "decision_source_unavailable", error_state: queue.error_state || null }, 503);
+ return json({ ok: false, error: "decision_not_found" }, 404);
+ }
+ const now = Date.now();
+ const serverTime = new Date(now).toISOString();
+ let authorityRaw;
+ try {
+ authorityRaw = await readHumanDecisionAuthority(env, kind, parsed.subject_id);
+ } catch {
+ return json({ ok: false, error: "decision_authority_unavailable", server_time: serverTime }, 503);
+ }
+ const authority = humanDecisionAuthorityView(authorityRaw);
+ const materialKey = item.decision_binding?.material_sha256 || null;
+ const existing = authorityRaw?.decision;
+ if (existing && materialKey && existing.material_key === materialKey) {
+ // The durable request key keeps the operation id that produced the record.
+ const recordedOperationId = recordedDecisionOperationId(existing);
+ // A retry replays only when the recorded operation id and the complete
+ // canonical intent match. Any other intent on the same material conflicts,
+ // whether it reuses the id or presents a new one with the same action.
+ let recordedTarget = null;
+ try {
+ recordedTarget = canonicalResearchTaskJson(JSON.parse(existing.target_json || "{}"));
+ } catch {
+ recordedTarget = null;
+ }
+ const intentMatches = recordedOperationId !== null && recordedOperationId === operationId
+ && recordedTarget !== null
+ && recordedTarget === decisionIntentTargetJson(parsed.category, action, selection);
+ if (existing.kind !== kind || existing.subject_id !== parsed.subject_id || existing.action !== action
+ || !intentMatches) {
+ return json({
+ ok: false,
+ error: "decision_operation_conflict",
+ decision_id: item.id,
+ operation_id: operationId,
+ recorded_operation_id: recordedOperationId,
+ server_time: serverTime,
+ }, 409);
+ }
+ const receipt = await humanDecisionReceipt(existing, {
+ kind, subject_id: parsed.subject_id, material_sha256: materialKey,
+ });
+ return json({
+ schema_version: DECISION_ACTION_SCHEMA_VERSION,
+ ok: true,
+ replayed: true,
+ decision_id: item.id,
+ revision: item.revision,
+ action,
+ operation_id: operationId,
+ operation_sha256: operationSha256,
+ decision_receipt: receipt,
+ decided_at: existing.decided_at,
+ decision_state: { status: "decided", action, decided_at: existing.decided_at },
+ operation: item.operation_reference,
+ policy: DECISION_POLICY,
+ server_time: serverTime,
+ });
+ }
+ if (raw.expected_revision !== item.revision)
+ return json({ ok: false, error: "decision_revision_conflict", decision_id: item.id, server_time: serverTime }, 409);
+ if (raw.expected_expires_at !== undefined && raw.expected_expires_at !== item.expires_at)
+ return json({ ok: false, error: "decision_expiry_changed", decision_id: item.id, server_time: serverTime }, 409);
+ if (decisionExpiryState(item.expires_at, now) !== "active")
+ return json({ ok: false, error: "decision_expired", decision_id: item.id, server_time: serverTime }, 409);
+ if (decisionExpiryState(authority?.expires_at, now) !== "active")
+ return json({ ok: false, error: "decision_expired", decision_id: item.id, server_time: serverTime }, 409);
+ if (authority?.blocked === true)
+ return json({ ok: false, error: "decision_legacy_blocked", decision_id: item.id, server_time: serverTime }, 409);
+ if (authority?.eligible === false)
+ return json({ ok: false, error: "decision_material_ineligible", decision_id: item.id, server_time: serverTime }, 409);
+ if (item.actionable !== true)
+ return json({
+ ok: false, error: "decision_not_actionable", decision_id: item.id,
+ blocking_reason_codes: item.blocking_reason_codes || [], server_time: serverTime,
+ }, 409);
+ if (!(item.allowed_actions || []).some((entry) => entry.action === action))
+ return json({ ok: false, error: "decision_action_not_allowed", decision_id: item.id, server_time: serverTime }, 409);
+ if (!materialKey)
+ return json({ ok: false, error: "decision_evidence_unavailable", decision_id: item.id, server_time: serverTime }, 409);
+
+ let targetPath;
+ let innerBody;
+ if (parsed.category === "owner_decision") {
+ targetPath = "/api/owner-decisions";
+ innerBody = {
+ candidate_id: parsed.subject_id,
+ decision: action,
+ candidate_evidence_sha256: materialKey,
+ request_id: operationId,
+ };
+ } else if (parsed.category === "reconciliation_recovery") {
+ targetPath = "/api/reconciliation-recovery-confirmations";
+ if (item.initial_enrollment) {
+ innerBody = {
+ mode: "initial_enrollment",
+ recovery_id: parsed.subject_id,
+ candidate_sha256: item.initial_enrollment.candidate_sha256,
+ facts_sha256: item.initial_enrollment.facts_sha256,
+ decision: action,
+ request_id: operationId,
+ };
+ } else {
+ innerBody = {
+ recovery_id: parsed.subject_id,
+ candidate_sha256: item.evidence_summary?.candidate_sha256,
+ dual_review_binding_sha256: item.evidence_summary?.dual_review_binding_sha256,
+ decision: action,
+ request_id: operationId,
+ };
+ }
+ } else {
+ targetPath = "/api/research-promotion-decisions";
+ let ticket;
+ try {
+ ticket = await loadStoredResearchPromotionTicket(env, parsed.subject_id);
+ } catch (error) {
+ return json({
+ ok: false, error: error.message || "research promotion ticket unavailable",
+ decision_id: item.id, server_time: serverTime,
+ }, error.status || 503);
+ }
+ innerBody = {
+ ticket_id: parsed.subject_id,
+ decision: action,
+ expected_proposed_params: ticket.proposed_params,
+ expected_material_sha256: materialKey,
+ ...(item.decision_binding?.review_binding?.review_sha256
+ ? { expected_review_sha256: item.decision_binding.review_binding.review_sha256 } : {}),
+ ...(action === "accept" && selection ? {
+ confirmation: selection.confirmation,
+ selected_account: selection.selected_account,
+ } : {}),
+ request_id: operationId,
+ };
+ }
+
+ const innerResponse = await ({
+ "/api/owner-decisions": recordOwnerDecisionResponse,
+ "/api/reconciliation-recovery-confirmations": recordReconciliationRecoveryConfirmationResponse,
+ "/api/research-promotion-decisions": recordResearchPromotionDecisionResponse,
+ })[targetPath](new Request(new URL(targetPath, request.url), {
+ method: "POST",
+ headers: new Headers(request.headers),
+ body: JSON.stringify(innerBody),
+ }), env);
+ let payload = null;
+ try {
+ payload = await innerResponse.json();
+ } catch {
+ payload = null;
+ }
+ if (!innerResponse.ok || payload?.ok !== true) {
+ return json({
+ ...(payload && typeof payload === "object" ? payload : { ok: false, error: "decision_action_unavailable" }),
+ schema_version: DECISION_ACTION_SCHEMA_VERSION,
+ decision_id: item.id,
+ action,
+ server_time: serverTime,
+ }, innerResponse.status || 503);
+ }
+ const decidedAt = payload.intent?.decided_at
+ || payload.confirmation?.confirmed_at
+ || payload.ticket?.human_decided_at
+ || null;
+ return json({
+ schema_version: DECISION_ACTION_SCHEMA_VERSION,
+ ok: true,
+ replayed: payload.replayed === true,
+ decision_id: item.id,
+ revision: item.revision,
+ action,
+ operation_id: operationId,
+ operation_sha256: operationSha256,
+ decision_receipt: payload.decision_receipt || null,
+ decided_at: decidedAt,
+ decision_state: { status: "decided", action, decided_at: decidedAt },
+ operation: item.operation_reference,
+ policy: DECISION_POLICY,
+ server_time: serverTime,
+ });
+}
+
+export function operationDecisionStatus(category, decision, application) {
+ const promoted = category === "strategy_promotion" || category === "paper_account_application";
+ if (promoted && application) {
+ return { status: operationStatusFromApplication(application), reason_code: application.reason_code || null };
+ }
+ if (!decision) return { status: "unaccepted", reason_code: "decision_pending" };
+ // The operation records the human decision; it never implies activation.
+ if (promoted) return decision.action === "accept"
+ ? { status: "accepted", reason_code: "application_not_created" }
+ : { status: "failed", reason_code: "decision_rejected" };
+ return { status: "accepted", reason_code: "operation_not_connected" };
+}
+
+export async function operationResponse(request, env, rawId) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
+ const parsed = decodeOperationApiId(rawId);
+ if (!parsed) return json({ ok: false, error: "operation_not_found" }, 404);
+ const now = Date.now();
+ const serverTime = new Date(now).toISOString();
+ const kind = decisionKind(parsed.category);
+ if (kind && !hasRuntimeInstanceStore(env))
+ return json({ ok: false, error: "runtime_instances_not_bound", server_time: serverTime }, 503);
+
+ let authorityRaw = null;
+ let ticket = null;
+ if (kind) {
+ try {
+ if (parsed.category === "strategy_promotion" || parsed.category === "paper_account_application") {
+ ticket = await loadStoredResearchPromotionTicket(env, parsed.subject_id);
+ }
+ authorityRaw = await readHumanDecisionAuthority(env, kind, parsed.subject_id);
+ } catch (error) {
+ return json({
+ ok: false, error: error.message || "operation_unavailable",
+ operation_id: parsed.id, server_time: serverTime,
+ }, error.status || 503);
+ }
+ }
+ let application = null;
+ if (kind === "promotion") {
+ try {
+ const stored = await runtimeInstanceCommand(env, {
+ action: "application_latest", actor: session.login, ticket_id: parsed.subject_id,
+ });
+ application = stored.application || null;
+ } catch {
+ return json({ ok: false, error: "operation_unavailable", operation_id: parsed.id, server_time: serverTime }, 503);
+ }
+ }
+ const decision = authorityRaw?.decision || null;
+ const status = operationDecisionStatus(parsed.category, decision, application);
+ const publicApplication = application ? publicResearchPromotionApplication(application) : null;
+ return json({
+ schema_version: OPERATION_SCHEMA_VERSION,
+ server_time: serverTime,
+ data_status: "ready",
+ operation: {
+ id: parsed.id,
+ decision_id: `${parsed.category}:${parsed.subject_id}`,
+ kind: kind || parsed.category,
+ subject_id: parsed.subject_id,
+ status: status.status,
+ reason_code: status.reason_code,
+ activation_status: "not_connected",
+ updated_at: publicApplication?.updated_at || decision?.decided_at || ticket?.updated_at || null,
+ dispatch: publicApplication ? {
+ status: publicApplication.dispatch_state || "unknown",
+ workflow_run_id: publicApplication.workflow_run_id || null,
+ updated_at: publicApplication.updated_at || null,
+ } : null,
+ application: publicApplication,
+ },
+ decision: decision ? {
+ material_sha256: /^[0-9a-f]{64}$/.test(decision.material_key || "") ? decision.material_key : null,
+ action: decision.action,
+ decided_at: decision.decided_at,
+ } : null,
+ policy: DECISION_POLICY,
+ errors: [],
+ });
+}
+
+// Event type by normalized projection source. Comparing the normalized source
+// keeps a promotion application from being reported as an account-settings approval.
+export function auditEventAction(source, kind) {
+ if (source === "durable_human_decision") return `record_${kind}_decision`;
+ if (source === "research_promotion_application") return "research_promotion_application";
+ if (source === "account_settings_application") return "account_settings_approval";
+ return null;
+}
+
+export function auditEventSubjectId(row) {
+ if (typeof row.ticket_id === "string" && row.ticket_id) return { kind: "strategy_promotion", id: row.ticket_id };
+ if (typeof row.recovery_id === "string" && row.recovery_id) return { kind: "reconciliation_recovery", id: row.recovery_id };
+ if (typeof row.candidate_id === "string" && row.candidate_id) return { kind: "owner_decision", id: row.candidate_id };
+ if (typeof row.platform === "string" && typeof row.key === "string") return { kind: "account_settings", id: `${row.platform}:${row.key}` };
+ return null;
+}
+
+export async function auditEventsResponse(request, env, url) {
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
+ let page;
+ try {
+ page = auditPageQuery(url);
+ } catch {
+ return json({ ok: false, error: "invalid_pagination" }, 400);
+ }
+ const now = Date.now();
+ const serverTime = new Date(now).toISOString();
+ if (!hasRuntimeInstanceStore(env))
+ return json({ ok: false, error: "runtime_instances_not_bound", server_time: serverTime }, 503);
+ let rows;
+ try {
+ const result = await runtimeInstanceCommand(env, {
+ action: "console_audit_events", actor: session.login, limit: page.limit + 1, snapshot: page.snapshot, before: page.before,
+ });
+ if (!Array.isArray(result.rows)) throw Error("invalid_audit_rows");
+ rows = result.rows;
+ } catch {
+ return json({ ok: false, error: "audit_projection_unavailable", server_time: serverTime }, 503);
+ }
+ const events = [];
+ for (const row of rows) {
+ const occurredAt = typeof row.occurred_at === "string" && Number.isFinite(Date.parse(row.occurred_at))
+ ? row.occurred_at : null;
+ if (!occurredAt) return json({ ok: false, error: "audit_projection_invalid" }, 503);
+ if (row.source === "credential_rotation") {
+ events.push({ id: row.event_id, event_id: row.event_id, occurred_at: occurredAt,
+ actor_alias: await actorAlias(row.actor || null), action: row.action,
+ subject: { kind: "credential", id: "ibkr_flex" }, operation_id: row.ref ?? null, outcome: row.status });
+ continue;
+ }
+ const source = row.source === "decision" ? "durable_human_decision"
+ : row.source === "promotion_application" ? "research_promotion_application"
+ : row.source === "account_settings_application" ? "account_settings_application"
+ : null;
+ if (!source) return json({ ok: false, error: "audit_projection_invalid" }, 503);
+ const subject = source === "durable_human_decision"
+ ? { kind: `${row.kind}_decision`, id: row.subject_id }
+ : source === "research_promotion_application"
+ ? { kind: "strategy_promotion", id: row.subject_id }
+ : { kind: "account_settings", id: row.subject_id };
+ if (typeof subject.id !== "string" || !subject.id || subject.id.length > 256) return json({ ok: false, error: "audit_projection_invalid" }, 503);
+ const revision = /^[0-9a-f]{64}$/.test(row.revision || "") ? row.revision : null;
+ events.push({
+ id: `${source}:${row.ref}`,
+ source,
+ occurred_at: occurredAt,
+ action: auditEventAction(source, row.kind),
+ actor_alias: await actorAlias(row.actor || null),
+ subject,
+ revision,
+ outcome: typeof row.status === "string" && row.status.length <= 40 ? row.status : null,
+ ref: source === "durable_human_decision"
+ ? `/api/decisions/${encodeURIComponent(`${row.kind === "promotion" ? "strategy_promotion" : row.kind === "owner" ? "owner_decision" : "reconciliation_recovery"}:${row.subject_id}`)}`
+ : source === "research_promotion_application"
+ ? `/api/operations/${encodeURIComponent(`operation:strategy_promotion:${row.subject_id}`)}`
+ : null,
+ });
+ }
+ try {
+ if (!hasConfigStore(env)) throw Error("audit_log_unavailable");
+ const storedLog = await readConfigJson(env, AUDIT_LOG_KEY);
+ if (storedLog !== null && !Array.isArray(storedLog)) throw Error("audit_log_invalid");
+ const log = storedLog || [];
+ const ids = await Promise.all(log.map(row => cycleHealthSha256(row)));
+ const occurrences = new Map();
+ const aliases = await Promise.all(log.map((row) =>
+ actorAlias(typeof row?.login === "string" ? row.login : null)));
+ log.forEach((row, index) => {
+ if (!row || typeof row !== "object" || Array.isArray(row)) throw Error("audit_log_invalid");
+ const occurredAt = typeof row.ts === "string" && Number.isFinite(Date.parse(row.ts)) ? row.ts : null;
+ const action = typeof row.action === "string" && row.action.length <= 64 ? row.action : null;
+ if (!occurredAt || !action) throw Error("audit_log_invalid");
+ const subject = auditEventSubjectId(row);
+ const occurrence = occurrences.get(ids[index]) || 0;
+ occurrences.set(ids[index], occurrence + 1);
+ events.push({
+ id: `bounded_audit_log:${ids[index]}:${occurrence}`,
+ source: "bounded_audit_log",
+ occurred_at: new Date(occurredAt).toISOString(),
+ action,
+ actor_alias: aliases[index] || null,
+ subject,
+ revision: null,
+ outcome: "recorded",
+ ref: null,
+ });
+ });
+ } catch {
+ return json({ ok: false, error: "audit_log_unavailable", server_time: serverTime }, 503);
+ }
+ const seen = new Set();
+ const unique = events
+ .filter((event) => {
+ if (seen.has(event.id)) return false;
+ seen.add(event.id);
+ return true;
+ })
+ .filter(event => auditEventInPage(event, page))
+ .sort(auditEventOrder);
+ const pageEvents = unique.slice(0, page.limit);
+ return json({
+ schema_version: AUDIT_EVENTS_SCHEMA_VERSION,
+ server_time: serverTime,
+ data_status: "ready",
+ events: pageEvents.map(event => { if (!event.event_id) return event; const { id, ...safe } = event; return safe; }),
+ next_cursor: unique.length > page.limit ? auditNextCursor(pageEvents.at(-1), page) : null,
+ coverage: "durable_human_decisions_and_application_records_and_bounded_audit_log",
+ policy: DECISION_POLICY,
+ errors: [],
+ });
+}
+
+export function attachResearchPromotionApplicationPreparation(ticket, accountOptions, strategyProfiles) {
+ const blockers = new Set(["activation_not_connected"]);
+ if (ticket?.shadow_passed !== true || !String(ticket?.shadow_evidence_kind || "").trim()) {
+ blockers.add("research_evidence_unverified");
+ }
+ const params = ticket?.proposed_params;
+ const strategy = (Array.isArray(strategyProfiles) ? strategyProfiles : [])
+ .find((item) => item.profile === ticket.strategy_profile);
+ const candidateIdentity = researchCandidateIdentityForStrategy(strategy);
+ const applicationAdapter = researchCandidateApplicationAdapter(strategy);
+ const candidateParamsBound = candidateIdentity
+ ? Boolean(
+ params
+ && !Array.isArray(params)
+ && typeof params === "object"
+ && canonicalResearchTaskJson(params) === canonicalResearchTaskJson(candidateIdentity),
+ )
+ : Boolean(params && !Array.isArray(params) && typeof params === "object" && !Object.keys(params).length);
+ if (!candidateParamsBound) {
+ blockers.add("candidate_params_unbound");
+ }
+ if (!strategy) blockers.add("strategy_not_configured");
+ if (candidateIdentity && !applicationAdapter) blockers.add("paper_application_adapter_unavailable");
+
+ const confirmedPlatform = String(ticket.confirmation_target_platform || "").trim();
+ const platforms = confirmedPlatform ? [confirmedPlatform] : SUPPORTED_PLATFORMS;
+ const accounts = [];
+ for (const platform of strategy ? platforms : []) {
+ const options = Array.isArray(accountOptions?.[platform]) ? accountOptions[platform] : [];
+ for (const option of options) {
+ if (!supportedDomainsForAccount(platform, option).includes(ticket.domain)) continue;
+ const accountBlockers = [];
+ const configuredExecutionMode = cleanExecutionMode(
+ option.default_execution_mode || PLATFORM_CONFIG[platform]?.default_execution_mode || "live",
+ );
+ if (strategy) {
+ try {
+ const brokerEnvironment = normalizeBrokerEnvironment(
+ option.broker_environment,
+ `account_options.${platform}.${option.key}.broker_environment`,
+ );
+ if (!supportedBrokerEnvironmentsForPlatform(platform).includes(brokerEnvironment)) {
+ throw new HttpError(`${platform} does not support broker environment ${brokerEnvironment}`, 400);
+ }
+ const executionMode = String(
+ ticket.confirmation_execution_mode || brokerEnvironment,
+ ).trim().toLowerCase();
+ validateResearchPromotionSelectedAccount({
+ ticket,
+ selectedAccount: { platform, key: option.key },
+ confirmation: {
+ target_platform: platform,
+ execution_mode: executionMode,
+ risk_profile: ticket.confirmation_risk_profile || ticket.suggested_risk_profile,
+ },
+ accountOptions,
+ strategyProfiles,
+ });
+ } catch (error) {
+ accountBlockers.push(researchPromotionApplicationBlocker(error));
+ }
+ }
+ if (accountBlockers.length) continue;
+ accounts.push({
+ platform,
+ key: option.key,
+ label: option.label,
+ configured_execution_mode: configuredExecutionMode,
+ broker_environment: option.broker_environment,
+ preflight_status: accountBlockers.length ? "blocked" : (strategy ? "ready" : "blocked"),
+ blocker_codes: [...new Set(accountBlockers)],
+ });
+ }
+ }
+ if (!accounts.length) blockers.add("configured_account_missing");
+ if (strategy && accounts.length && accounts.every((account) => account.preflight_status !== "ready")) {
+ blockers.add("account_preflight_failed");
+ }
+ const candidateBlockers = [...blockers].filter((code) => code !== "activation_not_connected");
+ const previewAccounts = (
+ ticket?.state === "human_accepted"
+ && ticket?.shadow_passed === true
+ && String(ticket?.shadow_evidence_kind || "").trim()
+ && candidateIdentity
+ && applicationAdapter
+ && strategy?.domain === "us_equity"
+ && candidateParamsBound
+ && candidateBlockers.length === 0
+ )
+ ? accounts.filter((account) => {
+ const option = (accountOptions?.[account.platform] || [])
+ .find((item) => item.key === account.key);
+ return (
+ account.platform === "longbridge"
+ && account.broker_environment === "paper"
+ && account.configured_execution_mode === "live"
+ && String(option?.account_selector || "").trim()
+ );
+ })
+ : [];
+ const previewRequest = previewAccounts.length === 1
+ ? {
+ platform_id: previewAccounts[0].platform,
+ account_scope: String(
+ (accountOptions?.[previewAccounts[0].platform] || [])
+ .find((item) => item.key === previewAccounts[0].key)?.account_selector || "",
+ ).trim(),
+ strategy_profile: ticket.strategy_profile,
+ candidate_id: params.candidate_id,
+ config_sha256: params.config_sha256,
+ }
+ : null;
+ return {
+ ...attachRiskEnvelopeView(ticket),
+ application_preparation: {
+ status: "blocked",
+ preflight_status: candidateBlockers.length ? "blocked" : "ready",
+ activation_status: "not_connected",
+ dispatch_allowed: false,
+ blocker_codes: [...blockers].sort(),
+ account_options: accounts,
+ preview_request: previewRequest,
+ },
+ };
+}
+
+export function researchCandidateIdentityForStrategy(strategy) {
+ const identity = strategy?.research_candidate_identity;
+ return identity && typeof identity === "object" && !Array.isArray(identity) ? identity : null;
+}
+
+export function researchCandidateApplicationAdapter(strategy) {
+ if (strategy?.profile !== V7_PAPER_PREVIEW_PROFILE) return null;
+ return {
+ platform: "longbridge",
+ account_key: V7_PAPER_APPLICATION_ACCOUNT_KEY,
+ workflow_repository: V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY,
+ workflow: V7_PAPER_APPLICATION_WORKFLOW,
+ };
+}
+
+export function researchPromotionApplicationBlocker(error) {
+ const message = String(error?.message || error || "").toLowerCase();
+ if (message.includes("broker environment is unknown")) return "broker_environment_unknown";
+ if (message.includes("does not support broker environment")) return "broker_environment_unsupported";
+ if (message.includes("not configured")) return "strategy_not_configured";
+ if (message.includes("domain") && message.includes("not supported")) return "strategy_domain_not_supported";
+ if (message.includes("live-enabled") || message.includes("blocked for live") || message.includes("does not allow")) {
+ return "strategy_execution_not_allowed";
+ }
+ if (message.includes("configured account")) return "configured_account_mismatch";
+ return "account_preflight_failed";
+}
+
+export async function recordResearchPromotionDecisionResponse(request, env) {
+ requireSameOrigin(request, { requireOrigin: true });
+ const session = await readSession(request, env);
+ if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
+ if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
+ if (!hasConfigStore(env)) {
+ return json({ ok: false, error: "STRATEGY_SWITCH_CONFIG KV binding is required" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, 8 * 1024);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
+ }
+ const ticketId = String(raw?.ticket_id || "").trim();
+ const decision = String(raw?.decision || "").trim().toLowerCase();
+ if (!ticketId) return json({ ok: false, error: "ticket_id is required" }, 400);
+ const stored = await readConfigJson(env, researchPromotionTicketKey(ticketId));
+ if (!stored) return json({ ok: false, error: "research promotion ticket not found" }, 404);
+ let ticket;
+ try {
+ ticket = normalizeResearchPromotionTicket(stored);
+ assertResearchPromotionExpectedCandidate(ticket, raw, { requireExpectedParams: decision === "accept" });
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
+ }
+ const materialKey = await researchPromotionMaterialKey(ticket);
+ // Keep the legacy material index stable; the separate review digest binds the complete producer review.
+ if (Object.prototype.hasOwnProperty.call(raw, "expected_material_sha256") && raw.expected_material_sha256 !== materialKey) {
+ return json({ ok: false, error: "human_decision_material_conflict" }, 409);
+ }
+ const reviewMaterial = researchPromotionReviewMaterial(ticket);
+ const reviewBinding = await researchPromotionReviewBinding(ticket);
+ const selectedAccount = raw?.selected_account || null;
+ const confirmation = raw?.confirmation || null;
+ const target = { selected_account: selectedAccount, confirmation };
+ const targetJson = canonicalResearchTaskJson(target);
+ let authority;
+ try {
+ authority = await readHumanDecisionAuthority(env, "promotion", ticket.ticket_id);
+ } catch (error) {
+ return json({ ok: false, error: error.message || "research promotion decision unavailable" }, error.status || 503);
+ }
+ if (authority.migrated !== false) {
+ if (authority.blocked) return json({ ok: false, error: "human_decision_legacy_blocked" }, 409);
+ if (authority.eligible !== true || authority.material_key !== materialKey) {
+ return json({ ok: false, error: "human_decision_material_conflict" }, 409);
+ }
+ const existing = authority.decision;
+ if (existing && existing.action === decision && existing.target_json === targetJson && existing.payload?.ticket) {
+ if (Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256")
+ && (existing.payload.review_binding?.schema_version !== "qsl_promotion_review_binding.v2"
+ || raw.expected_review_sha256 !== existing.payload.review_binding.review_sha256)) {
+ return json({ ok: false, error: "human_decision_review_binding_unqualified" }, 409);
+ }
+ return json({
+ ok: true,
+ ticket: attachRiskEnvelopeView(existing.payload.ticket),
+ live_authority_granted: false,
+ replayed: true,
+ actor: existing.actor,
+ decision_receipt: await humanDecisionReceipt(existing, { kind: "promotion", subject_id: ticket.ticket_id, material_sha256: materialKey }),
+ });
+ }
+ if (existing) return json({ ok: false, error: "human_decision_conflict" }, 409);
+ }
+ if (Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256") && raw.expected_review_sha256 !== reviewBinding.review_sha256) {
+ return json({ ok: false, error: "human_decision_review_material_conflict" }, 409);
+ }
+ const targetPlatform = String(
+ raw?.confirmation?.target_platform || ticket.confirmation_target_platform || "",
+ ).trim();
+ const paperSupported = platformSupportsBrokerPaperMode(targetPlatform);
+ const accountConfig = decision === "accept" ? await loadAccountOptionsConfig(env) : null;
+ const serverAccountRevision = accountConfig?.source === "durable_object" && Number.isSafeInteger(accountConfig.revision)
+ ? accountConfig.revision
+ : null;
+ const strategyProfiles = decision === "accept" ? await loadStrategyProfilesConfig(env) : null;
+ let decided;
+ try {
+ decided = applyResearchPromotionDecision(ticket, {
+ decision,
+ confirmation,
+ paperSupported,
+ selectedAccount,
+ accountOptions: accountConfig?.options,
+ strategyProfiles,
+ decidedAt: new Date().toISOString(),
+ expectedRaw: raw,
+ });
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
+ }
+ if (decided.live_authority_granted) {
+ return json({ ok: false, error: "refusing to persist live_authority_granted=true" }, 500);
+ }
+ const preflightRevision = decision === "accept" ? serverAccountRevision : null;
+ if (decision === "accept" && Object.prototype.hasOwnProperty.call(raw, "expected_account_revision")
+ && Number(raw.expected_account_revision) !== serverAccountRevision) {
+ return json({ ok: false, error: "runtime_instance_revision_conflict" }, 409);
+ }
+ const decidedAt = decided.human_decided_at || humanDecisionTimestamp();
+ let requestKey;
+ try {
+ requestKey = await humanDecisionRequestKey({
+ requestId: raw?.request_id,
+ kind: "promotion",
+ actor: session.login,
+ subjectId: ticket.ticket_id,
+ materialKey,
+ action: decision,
+ target,
+ });
+ } catch (error) {
+ return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
+ }
+ let recorded;
+ try {
+ recorded = await runtimeInstanceCommand(env, {
+ action: "promotion_decide",
+ ...(Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256") ? { review_binding: reviewBinding } : {}),
+ actor: session.login,
+ subject_id: ticket.ticket_id,
+ material_key: materialKey,
+ action_name: decision,
+ request_key: requestKey,
+ target_json: canonicalResearchTaskJson(target),
+ decided_at: decidedAt,
+ now_ms: Date.now(),
+ preflight_revision: preflightRevision,
+ payload: {
+ ticket: decided,
+ ...(Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256") ? { review_binding: reviewBinding, review_material: reviewMaterial } : {}),
+ selected_account: selectedAccount,
+ confirmation,
+ proposed_params: ticket.proposed_params,
+ },
+ });
+ } catch (error) {
+ return json({ ok: false, error: error.message || "research promotion decision unavailable" }, error.status || 503);
+ }
+ const decisionReceipt = await humanDecisionReceipt(recorded.record, { kind: "promotion", subject_id: ticket.ticket_id, material_sha256: materialKey });
+ const recordedTicket = recorded.record.payload.ticket;
+ await mirrorConfigJson(env, researchPromotionTicketKey(recordedTicket.ticket_id), recordedTicket);
+ try {
+ await appendAuditLog(env, {
+ ts: recordedTicket.updated_at,
+ login: session.login,
+ action: "research_promotion_decision",
+ ticket_id: recordedTicket.ticket_id,
+ decision: recordedTicket.human_decision,
+ confirmation_target_platform: recordedTicket.confirmation_target_platform,
+ confirmation_execution_mode: recordedTicket.confirmation_execution_mode,
+ confirmation_risk_profile: recordedTicket.confirmation_risk_profile,
+ suggested_risk_profile: recordedTicket.suggested_risk_profile,
+ live_authority_granted: false,
+ });
+ } catch {
+ // Decision persistence must not depend on optional audit retention.
+ }
+ return json({
+ ok: true,
+ ticket: attachRiskEnvelopeView(recordedTicket),
+ decision_receipt: decisionReceipt,
+ live_authority_granted: false,
+ replayed: recorded.replayed === true,
+ });
+}
+
+export function v7PaperApplicationCandidate(strategy, ticket) {
+ if (!researchCandidateApplicationAdapter(strategy)) {
+ throw new HttpError("paper application adapter is not configured for candidate", 409);
+ }
+ if (ticket?.shadow_evidence_kind !== "v7_nonlive_shadow_and_simulated_paper") {
+ throw new HttpError("v7_shadow_evidence_kind_not_qualified", 409);
+ }
+ const notes = Array.isArray(ticket?.notes) ? ticket.notes : [];
+ const requiredEvidence = [
+ "frozen_v7_forward_financial_gates_passed_research_only",
+ "forward_record_sha256",
+ "financial_evidence_sha256",
+ "p1_manifest_sha256",
+ "p4_policy_sha256",
+ "baseline_p3_evidence_sha256",
+ ];
+ if (notes[0] !== requiredEvidence[0] || requiredEvidence.slice(1).some((prefix) =>
+ !notes.some((note) => new RegExp(`^${prefix}=[0-9a-f]{64}$`).test(String(note))))) {
+ throw new HttpError("v7_shadow_evidence_provenance_incomplete", 409);
+ }
+ const identity = researchCandidateIdentityForStrategy(strategy);
+ if (!identity || ticket?.domain !== "us_equity") {
+ throw new HttpError("research_candidate_not_eligible_for_paper_application", 409);
+ }
+ const params = ticket?.proposed_params;
+ if (!params || Array.isArray(params) || typeof params !== "object"
+ || canonicalResearchTaskJson(params) !== canonicalResearchTaskJson(identity)) {
+ throw new HttpError("candidate_params_unbound", 409);
+ }
+ return {
+ candidate_id: String(identity.candidate_id || ""),
+ config_sha256: String(identity.config_sha256 || ""),
+ };
+}
+
+export async function loadStoredResearchPromotionTicket(env, ticketId) {
+ if (!hasConfigStore(env)) throw new HttpError("research promotion KV is not configured", 503);
+ const stored = await readConfigJson(env, researchPromotionTicketKey(ticketId));
+ if (!stored) throw new HttpError("research promotion ticket not found", 404);
+ let ticket;
+ try {
+ ticket = normalizeResearchPromotionTicket(stored, "stored research promotion ticket");
+ } catch (error) {
+ throw new HttpError(error.message || "invalid stored research promotion ticket", 409);
+ }
+ return promotionTicketWithAuthority(env, ticket);
+}
+
+export async function qualifyV7PaperApplication(env, { ticketId, selectedAccount, expectedRevision }) {
+ assertExactFields(selectedAccount, ["platform", "key"], "selected_account");
+ const platform = cleanChoice(selectedAccount.platform, SUPPORTED_PLATFORMS, "selected_account.platform");
+ const key = cleanSlug(selectedAccount.key, "selected_account.key");
+ if (platform !== "longbridge" || key !== V7_PAPER_APPLICATION_ACCOUNT_KEY) {
+ throw new HttpError("only the configured LongBridge paper account is supported", 409);
+ }
+ if (!V7_PAPER_APPLICATION_TICKET_RE.test(String(ticketId || ""))) {
+ throw new HttpError("research promotion ticket is not from the V7 producer", 409);
+ }
+ if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
+ throw new HttpError("runtime instance revision is required", 400);
+ }
+ const ticket = await loadStoredResearchPromotionTicket(env, ticketId);
+ const promotionMaterialKey = await researchPromotionMaterialKey(ticket);
+ const promotionAuthority = await readHumanDecisionAuthority(env, "promotion", ticket.ticket_id);
+ if (promotionAuthority.blocked || promotionAuthority.eligible !== true || promotionAuthority.decision?.action !== "accept" || promotionAuthority.material_key !== promotionMaterialKey) {
+ throw new HttpError("research candidate is not human_accepted", 409);
+ }
+ const boundAccount = promotionAuthority.decision.payload?.selected_account || {};
+ if (boundAccount.platform !== platform || boundAccount.key !== key) {
+ throw new HttpError("promotion_account_binding_conflict", 409);
+ }
+ if (ticket.state !== "human_accepted") throw new HttpError("research candidate is not human_accepted", 409);
+ if (ticket.live_authority_granted !== false || ticket.shadow_passed !== true || !String(ticket.shadow_evidence_kind || "").trim()) {
+ throw new HttpError("research candidate evidence is not qualified", 409);
+ }
+ const strategyProfiles = await loadStrategyProfilesConfig(env);
+ const strategy = (Array.isArray(strategyProfiles) ? strategyProfiles : [])
+ .find((item) => item.profile === ticket.strategy_profile);
+ if (!strategy) throw new HttpError("selected candidate strategy profile is not configured", 409);
+ const candidate = v7PaperApplicationCandidate(strategy, ticket);
+ const state = await runtimeInstanceCommand(env);
+ if (!state.initialized) throw new HttpError("runtime instances are not initialized", 409);
+ if (state.revision !== expectedRevision) throw new HttpError("runtime instance revision conflict", 409);
+ const instance = (state.instances || []).find((item) => item.kind === "existing" && item.platform === platform && item.key === key && item.retirement_status === "none");
+ const config = instance?.config;
+ if (!config) throw new HttpError("selected LongBridge paper account is unavailable", 409);
+ if (String(config.broker_environment || "") !== "paper"
+ || String(config.account_selector || "") !== V7_PAPER_APPLICATION_ACCOUNT_SCOPE
+ || String(config.service_name || "") !== V7_PAPER_APPLICATION_SERVICE
+ || String(config.runtime_status_target_id || "") !== "longbridge.paper"
+ || String(config.default_execution_mode || "") !== "live") {
+ throw new HttpError("selected LongBridge paper account binding is incomplete", 409);
+ }
+ const expectedStrategyProfile = String(config.default_strategy_profile || "").trim();
+ if (!expectedStrategyProfile) throw new HttpError("selected account strategy profile is unknown", 409);
+ validateResearchPromotionSelectedAccount({
+ ticket,
+ selectedAccount: { platform, key },
+ confirmation: {
+ target_platform: ticket.confirmation_target_platform,
+ execution_mode: ticket.confirmation_execution_mode,
+ risk_profile: ticket.confirmation_risk_profile,
+ },
+ accountOptions: { longbridge: [config] },
+ strategyProfiles,
+ });
+ return {
+ ticket,
+ strategy,
+ candidate,
+ promotionMaterialKey,
+ revision: state.revision,
+ account: {
+ platform_id: platform,
+ account_key: key,
+ account_scope: V7_PAPER_APPLICATION_ACCOUNT_SCOPE,
+ account_selector: V7_PAPER_APPLICATION_ACCOUNT_SCOPE,
+ service_name: V7_PAPER_APPLICATION_SERVICE,
+ broker_environment: "paper",
+ expected_strategy_profile: expectedStrategyProfile,
+ },
+ };
+}
+
+export function publicResearchPromotionApplication(application) {
+ if (!application) return null;
+ const { claim_token: _claimToken, ...publicApplication } = application;
+ return publicApplication;
+}
+
+export async function dispatchV7PaperApplication(env, applicationId) {
+ const token = String(env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
+ if (!token) throw new HttpError("paper application dispatch unavailable", 503);
+ const url = `https://api.github.com/repos/${V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY}/actions/workflows/${V7_PAPER_APPLICATION_WORKFLOW}/dispatches`;
+ const response = await fetchWithTimeout(url, {
+ method: "POST",
+ headers: githubHeaders(token),
+ body: JSON.stringify({ ref: "main", inputs: { application_id: applicationId } }),
+ });
+ if (!response.ok) throw new HttpError("paper application dispatch unverified", 502);
+}
+
+export function applicationIdFromPath(pathname) {
+ const value = String(pathname || "").slice("/api/internal/research-promotion-application/".length);
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
+ throw new HttpError("invalid application_id", 400);
+ }
+ return value;
+}
+
+export async function researchPromotionApplicationResponse(request, env, url) {
+ return researchPromotionApplicationResponseImpl(request, env, url, {
+ json,
+ readSession,
+ requireSameOrigin,
+ readBoundedJson,
+ runtimeInstanceCommand,
+ assertExactFields,
+ randomToken,
+ qualifyV7PaperApplication,
+ dispatchV7PaperApplication,
+ publicResearchPromotionApplication,
+ isUnsupportedApplicationActionError: (error) => (
+ error instanceof HttpError
+ && error.message === "unsupported_research_promotion_application_action"
+ ),
+ V7_PAPER_APPLICATION_MAX_BODY_BYTES,
+ V7_PAPER_APPLICATION_SOURCE_COMMIT,
+ V7_PAPER_APPLICATION_UES_REVISION,
+ });
+}
+
+export function validateV7PaperApplicationReadback(application, readback) {
+ if (!readback || typeof readback !== "object" || Array.isArray(readback)) return false;
+ return readback.application_id === application.application_id
+ && readback.platform_id === application.platform_id
+ && readback.account_scope === application.account_scope
+ && readback.service_name === application.service_name
+ && readback.strategy_profile === application.strategy_profile
+ && readback.candidate_id === application.candidate_id
+ && readback.config_sha256 === application.config_sha256
+ && readback.source_commit === application.source_commit
+ && readback.ues_revision === application.approved_ues_revision
+ && readback.runtime_target_enabled === false
+ && typeof readback.revision_name === "string" && readback.revision_name.trim() !== "";
+}
+
+export async function researchPromotionApplicationInternalResponse(request, env, url) {
+ return researchPromotionApplicationInternalResponseImpl(request, env, url, {
+ json,
+ requireDedicatedExecutionEvidenceSyncToken,
+ hasRuntimeInstanceStore,
+ applicationIdFromPath,
+ readBoundedJson,
+ runtimeInstanceCommand,
+ assertExactFields,
+ qualifyV7PaperApplication,
+ validateV7PaperApplicationReadback,
+ V7_PAPER_APPLICATION_MAX_BODY_BYTES,
+ V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY,
+ V7_PAPER_APPLICATION_WORKFLOW,
+ });
+}
+
+export function requireDedicatedResearchTaskSyncToken(request, env) {
+ const expected = String(env.RESEARCH_TASK_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("research task sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("research task sync token is invalid", 401);
+}
+
+export function assertExactFields(value, fields, fieldName) {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ const actual = Object.keys(value).sort();
+ const expected = [...fields].sort();
+ if (actual.length !== expected.length || actual.some((item, index) => item !== expected[index])) {
+ throw new Error(`${fieldName} has invalid fields`);
+ }
+ return value;
+}
+
+export function assertRequiredAndOptionalFields(value, requiredFields, optionalFields, fieldName) {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ const allowed = new Set([...requiredFields, ...optionalFields]);
+ const actual = Object.keys(value);
+ if (
+ requiredFields.some((field) => !Object.prototype.hasOwnProperty.call(value, field))
+ || actual.some((field) => !allowed.has(field))
+ ) {
+ throw new Error(`${fieldName} has invalid fields`);
+ }
+ return value;
+}
+
+export function normalizeResearchTaskIdentity(value, fieldName) {
+ const text = String(value || "").trim();
+ if (!/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(text)) {
+ throw new Error(`${fieldName} must be a stable identity`);
+ }
+ return text;
+}
+
+export function normalizeResearchTaskDigest(value, fieldName, nullable = false) {
+ if ((value === null || value === undefined || value === "") && nullable) return null;
+ const text = String(value || "").trim();
+ if (!/^[0-9a-f]{64}$/.test(text)) throw new Error(`${fieldName} must be a lowercase SHA-256`);
+ return text;
+}
+
+export function normalizeResearchTaskRevision(value, fieldName) {
+ const text = String(value || "").trim();
+ if (!/^[0-9a-f]{40}$/.test(text)) throw new Error(`${fieldName} must be a 40-character revision`);
+ return text;
+}
+
+export function normalizeResearchTaskTimestamp(value, fieldName) {
+ const text = String(value || "").trim();
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(text) || Number.isNaN(Date.parse(text))) {
+ throw new Error(`${fieldName} must be a UTC timestamp`);
+ }
+ return text;
+}
+
+export function normalizeResearchTaskText(value, fieldName, maxLength) {
+ const text = String(value || "").trim();
+ if (!text || text.length > maxLength || /[<>\\]/.test(text)) throw new Error(`${fieldName} is invalid`);
+ if (/\b(?:token|secret|password|credential|api[_ -]?key)\s*[:=]/i.test(text)) {
+ throw new Error(`${fieldName} contains sensitive material`);
+ }
+ return text;
+}
+
+export function assertResearchTaskHasNoUnsafeMaterial(value, fieldName = "research task") {
+ if (Array.isArray(value)) {
+ value.forEach((item, index) => assertResearchTaskHasNoUnsafeMaterial(item, `${fieldName}[${index}]`));
+ return;
+ }
+ if (!value || typeof value !== "object") return;
+ for (const [key, nested] of Object.entries(value)) {
+ if (key !== "no_order" && /(?:secret|token|password|credential|api[_-]?key|order|fill|capital|account|broker)/i.test(key)) {
+ throw new Error(`${fieldName} contains forbidden execution or secret material`);
+ }
+ assertResearchTaskHasNoUnsafeMaterial(nested, `${fieldName}.${key}`);
+ }
+}
+
+export function canonicalResearchTaskJson(value) {
+ if (value === null) return "null";
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
+ if (typeof value === "number") {
+ if (!Number.isFinite(value)) throw new Error("research task must use finite JSON values");
+ return JSON.stringify(value);
+ }
+ if (Array.isArray(value)) return `[${value.map(canonicalResearchTaskJson).join(",")}]`;
+ if (!value || typeof value !== "object") throw new Error("research task must use JSON values");
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalResearchTaskJson(value[key])}`).join(",")}}`;
+}
+
+export async function sha256Hex(text) {
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export async function calculateResearchTaskSha256(payload) {
+ const material = { ...payload };
+ delete material.task_sha256;
+ const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export async function normalizeResearchTask(payload, fieldName) {
+ const task = assertExactFields(payload, [
+ "schema", "task_id", "created_at", "digest_algorithm", "task_type", "target", "evidence", "experiment", "authority", "task_sha256",
+ ], fieldName);
+ assertResearchTaskHasNoUnsafeMaterial(task, fieldName);
+ if (task.schema !== RESEARCH_TASK_SCHEMA_VERSION) throw new Error(`${fieldName}.schema is unsupported`);
+ if (task.digest_algorithm !== "sha256") throw new Error(`${fieldName}.digest_algorithm must be sha256`);
+ const target = assertExactFields(task.target, ["candidate_id", "candidate_kind", "domain", "repository", "strategy_revision"], `${fieldName}.target`);
+ const evidence = assertExactFields(task.evidence, ["p1_input_digest", "p2_config_digest", "p3_evidence_id", "producer_revision"], `${fieldName}.evidence`);
+ const experiment = assertExactFields(task.experiment, ["objective", "hypothesis", "parameter_bounds_sha256", "max_runs", "max_wall_seconds"], `${fieldName}.experiment`);
+ const authority = assertExactFields(task.authority, ["research_only", "no_order", "size_zero_required", "p4_p5_p6_authorized"], `${fieldName}.authority`);
+ const normalized = {
+ schema: RESEARCH_TASK_SCHEMA_VERSION,
+ task_id: normalizeResearchTaskIdentity(task.task_id, `${fieldName}.task_id`),
+ created_at: normalizeResearchTaskTimestamp(task.created_at, `${fieldName}.created_at`),
+ digest_algorithm: "sha256",
+ task_type: cleanChoice(task.task_type, RESEARCH_TASK_TYPES, `${fieldName}.task_type`),
+ target: {
+ candidate_id: normalizeResearchTaskIdentity(target.candidate_id, `${fieldName}.target.candidate_id`),
+ candidate_kind: cleanChoice(target.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${fieldName}.target.candidate_kind`),
+ domain: cleanChoice(target.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.target.domain`),
+ repository: normalizeResearchTaskRepository(target.repository, `${fieldName}.target.repository`),
+ strategy_revision: normalizeResearchTaskRevision(target.strategy_revision, `${fieldName}.target.strategy_revision`),
+ },
+ evidence: {
+ p1_input_digest: normalizeResearchTaskDigest(evidence.p1_input_digest, `${fieldName}.evidence.p1_input_digest`, true),
+ p2_config_digest: normalizeResearchTaskDigest(evidence.p2_config_digest, `${fieldName}.evidence.p2_config_digest`, true),
+ p3_evidence_id: normalizeResearchTaskDigest(evidence.p3_evidence_id, `${fieldName}.evidence.p3_evidence_id`, true),
+ producer_revision: normalizeResearchTaskRevision(evidence.producer_revision, `${fieldName}.evidence.producer_revision`),
+ },
+ experiment: {
+ objective: cleanChoice(experiment.objective, RESEARCH_TASK_OBJECTIVES, `${fieldName}.experiment.objective`),
+ hypothesis: normalizeResearchTaskText(experiment.hypothesis, `${fieldName}.experiment.hypothesis`, 800),
+ parameter_bounds_sha256: normalizeResearchTaskDigest(experiment.parameter_bounds_sha256, `${fieldName}.experiment.parameter_bounds_sha256`, true),
+ max_runs: normalizeResearchTaskBound(experiment.max_runs, `${fieldName}.experiment.max_runs`, 100),
+ max_wall_seconds: normalizeResearchTaskBound(experiment.max_wall_seconds, `${fieldName}.experiment.max_wall_seconds`, 86400),
+ },
+ authority: {
+ research_only: authority.research_only,
+ no_order: authority.no_order,
+ size_zero_required: authority.size_zero_required,
+ p4_p5_p6_authorized: authority.p4_p5_p6_authorized,
+ },
+ task_sha256: normalizeResearchTaskDigest(task.task_sha256, `${fieldName}.task_sha256`),
+ };
+ if (JSON.stringify(normalized.authority) !== JSON.stringify({ research_only: true, no_order: true, size_zero_required: true, p4_p5_p6_authorized: false })) {
+ throw new Error(`${fieldName}.authority must be fixed to offline research only`);
+ }
+ if (normalized.task_sha256 !== await calculateResearchTaskSha256(normalized)) {
+ throw new Error(`${fieldName}.task_sha256 mismatch`);
+ }
+ return normalized;
+}
+
+export function normalizeResearchTaskRepository(value, fieldName) {
+ const text = String(value || "").trim();
+ if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*\/[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(text)) {
+ throw new Error(`${fieldName} is invalid`);
+ }
+ return text;
+}
+
+export function normalizeResearchTaskBound(value, fieldName, maximum) {
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > maximum) {
+ throw new Error(`${fieldName} is outside its safe bound`);
+ }
+ return value;
+}
+
+export async function normalizeResearchTaskSourceSnapshot(payload, fieldName = "research task source snapshot") {
+ const source = assertExactFields(payload, ["schema_version", "source_id", "generated_at", "computed_at", "data_status", "tasks", "errors"], fieldName);
+ if (source.schema_version !== RESEARCH_TASK_SOURCE_SCHEMA_VERSION) throw new Error(`${fieldName}.schema_version is unsupported`);
+ const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ if (!Array.isArray(source.tasks) || source.tasks.length > 100) {
+ throw new Error(`${fieldName}.tasks must be an array with at most 100 items`);
+ }
+ const tasks = [];
+ const seen = new Set();
+ for (const [index, item] of source.tasks.entries()) {
+ const task = await normalizeResearchTask(item, `${fieldName}.tasks[${index}]`);
+ if (seen.has(task.task_id)) throw new Error(`${fieldName}.tasks contains duplicate task_id`);
+ seen.add(task.task_id);
+ tasks.push(task);
+ }
+ if (dataStatus === "unavailable" && tasks.length) throw new Error(`${fieldName}.tasks must be empty when unavailable`);
+ return {
+ schema_version: RESEARCH_TASK_SOURCE_SCHEMA_VERSION,
+ source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
+ generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
+ data_status: dataStatus,
+ tasks,
+ errors: normalizeStrategyHealthErrors(source.errors),
+ };
+}
+
+export function emptyResearchTaskSourceSnapshot(errorCode) {
+ return {
+ schema_version: RESEARCH_TASK_SOURCE_SCHEMA_VERSION,
+ source_id: "unavailable",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ tasks: [],
+ errors: [errorCode],
+ };
+}
+
+export function emptyResearchTaskPayload(errorCode) {
+ return {
+ schema_version: RESEARCH_TASK_DASHBOARD_SCHEMA_VERSION,
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { task_count: 0 },
+ tasks: [],
+ policy: {
+ research_only: true,
+ no_order: true,
+ size_zero_required: true,
+ p4_p5_p6_authorized: false,
+ notice: "研究任务只用于离线、零仓位实验;不会调参、改代码、部署或下单。",
+ },
+ errors: [errorCode],
+ };
+}
+
+export function researchTaskStaleTtlSeconds(env) {
+ const configured = Number(env.RESEARCH_TASK_STALE_TTL_SECONDS);
+ if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
+ return RESEARCH_TASK_DEFAULT_STALE_TTL_SECONDS;
+ }
+ return Math.floor(configured);
+}
+
+export function normalizeStrategyHealthSnapshot(payload, fieldName = "strategy health snapshot") {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ if (payload.schema_version !== "strategy_health_dashboard.v1") {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const status = cleanChoice(payload.data_status || "unavailable", [...STRATEGY_HEALTH_DATA_STATUSES, "partial"], `${fieldName}.data_status`);
+ const strategies = status === "unavailable"
+ ? []
+ : normalizeStrategyHealthStrategies(payload.strategies, fieldName);
+ const summary = normalizeStrategyHealthSummary(payload.summary, strategies);
+ const errors = normalizeStrategyHealthErrors(payload.errors);
+ return {
+ schema_version: "strategy_health_dashboard.v1",
+ generated_at: normalizeStrategyHealthTimestamp(payload.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(payload.computed_at, `${fieldName}.computed_at`, true),
+ data_status: status,
+ summary,
+ strategies,
+ policy: normalizeStrategyHealthPolicy(payload.policy),
+ errors,
+ };
+}
+
+export function normalizeStrategyHealthStrategies(value, fieldName) {
+ if (!Array.isArray(value) || value.length > 100) {
+ throw new Error(`${fieldName}.strategies must be an array with at most 100 items`);
+ }
+ const seen = new Set();
+ return value.map((item, index) => {
+ if (!item || Array.isArray(item) || typeof item !== "object") {
+ throw new Error(`${fieldName}.strategies[${index}] must be an object`);
+ }
+ const profile = cleanSlug(item.profile, `${fieldName}.strategies[${index}].profile`).toLowerCase();
+ if (seen.has(profile)) throw new Error(`${fieldName}.strategies contains duplicate profile`);
+ seen.add(profile);
+ return {
+ profile,
+ domain: cleanChoice(item.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.strategies[${index}].domain`),
+ as_of: sanitizeStrategyHealthText(item.as_of, `${fieldName}.strategies[${index}].as_of`, 64, true),
+ status: cleanChoice(item.status, STRATEGY_HEALTH_STATUSES, `${fieldName}.strategies[${index}].status`),
+ score: normalizeStrategyHealthScore(item.score, `${fieldName}.strategies[${index}].score`),
+ components: normalizeStrategyHealthComponents(item.components, `${fieldName}.strategies[${index}].components`),
+ decision: normalizeStrategyHealthDecision(item.decision, `${fieldName}.strategies[${index}].decision`),
+ review: normalizeStrategyHealthReview(item.review, `${fieldName}.strategies[${index}].review`),
+ freshness: normalizeStrategyHealthFreshness(item.freshness, `${fieldName}.strategies[${index}].freshness`),
+ source_revision: sanitizeStrategyHealthText(item.source_revision, `${fieldName}.strategies[${index}].source_revision`, 120, true),
+ };
+ });
+}
+
+export function normalizeStrategyHealthSummary(value, strategies) {
+ const counts = Object.fromEntries(STRATEGY_HEALTH_STATUSES.map((status) => [status, 0]));
+ for (const item of strategies) counts[item.status] += 1;
+ return { strategy_count: strategies.length, ...counts };
+}
+
+export function normalizeStrategyHealthComponents(value, fieldName) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ performance: normalizeStrategyHealthScore(source.performance, `${fieldName}.performance`),
+ risk: normalizeStrategyHealthScore(source.risk, `${fieldName}.risk`),
+ decay: normalizeStrategyHealthScore(source.decay, `${fieldName}.decay`),
+ stability: normalizeStrategyHealthScore(source.stability, `${fieldName}.stability`),
+ operations: normalizeStrategyHealthScore(source.operations, `${fieldName}.operations`),
+ };
+}
+
+export function normalizeStrategyHealthDecision(value, fieldName) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ code: cleanSlug(source.code || "evidence_missing", `${fieldName}.code`).toLowerCase(),
+ label: sanitizeStrategyHealthText(source.label, `${fieldName}.label`, 120, false, "证据不足,保持研究态"),
+ reason: sanitizeStrategyHealthText(source.reason, `${fieldName}.reason`, 240, false, "没有可用的机器检查结果。"),
+ };
+}
+
+export function normalizeStrategyHealthReview(value, fieldName) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ requested_stage: sanitizeStrategyHealthText(source.requested_stage, `${fieldName}.requested_stage`, 80, true),
+ evidence_package_id: sanitizeStrategyHealthText(source.evidence_package_id, `${fieldName}.evidence_package_id`, 120, true),
+ validation: normalizeStrategyHealthSummaryObject(source.validation),
+ risk: normalizeStrategyHealthSummaryObject(source.risk),
+ kelly_readiness: normalizeStrategyHealthSummaryObject(source.kelly_readiness),
+ };
+}
+
+export function normalizeStrategyHealthSummaryObject(value) {
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
+ const result = {};
+ for (const [key, raw] of Object.entries(value).slice(0, 12)) {
+ if (!/^[A-Za-z0-9_.-]{1,48}$/.test(key)) continue;
+ if (/(token|secret|password|cookie|private|path|key)/i.test(key)) continue;
+ if (typeof raw === "boolean") result[key] = raw;
+ else if (typeof raw === "number" && Number.isFinite(raw)) result[key] = raw;
+ else if (typeof raw === "string") {
+ const safe = sanitizeStrategyHealthText(raw, "summary.value", 120, true);
+ if (safe !== null) result[key] = safe;
+ }
+ }
+ return result;
+}
+
+export function normalizeStrategyHealthFreshness(value, fieldName) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ status: cleanChoice(source.status || "unknown", ["fresh", "stale", "unknown"], `${fieldName}.status`),
+ age_seconds: normalizeStrategyHealthAge(source.age_seconds, `${fieldName}.age_seconds`),
+ };
+}
+
+export function normalizeStrategyHealthAge(value, fieldName) {
+ if (value === null || value === undefined || value === "") return null;
+ const number = Number(value);
+ if (!Number.isFinite(number) || number < 0 || number > 315360000) throw new Error(`${fieldName} is invalid`);
+ return Math.round(number);
+}
+
+export function normalizeStrategyHealthScore(value, fieldName) {
+ if (value === null || value === undefined || value === "") return null;
+ const number = Number(value);
+ if (!Number.isFinite(number) || number < 0 || number > 100) throw new Error(`${fieldName} must be between 0 and 100`);
+ return number;
+}
+
+export function normalizeStrategyHealthTimestamp(value, fieldName, nullable = false) {
+ if ((value === null || value === undefined || value === "") && nullable) return null;
+ const text = normalizeStrategyHealthText(value, fieldName, 64);
+ if (!/^\d{4}-\d{2}-\d{2}T.+(?:Z|[+-]\d{2}:\d{2})$/.test(text) || Number.isNaN(Date.parse(text))) {
+ throw new Error(`${fieldName} must be an ISO timestamp`);
+ }
+ return text;
+}
+
+export function normalizeStrategyHealthText(value, fieldName, maxLength, nullable = false) {
+ if ((value === null || value === undefined || value === "") && nullable) return null;
+ const text = String(value || "").trim();
+ if (
+ !text ||
+ text.length > maxLength ||
+ /[<>\\]/.test(text) ||
+ text.startsWith("/") ||
+ /^[A-Za-z]:[\\/]/.test(text)
+ ) throw new Error(`${fieldName} is invalid`);
+ return text;
+}
+
+export function sanitizeStrategyHealthText(value, fieldName, maxLength, nullable = false, fallback = null) {
+ if (value === null || value === undefined || value === "") return nullable ? null : fallback;
+ let text;
+ try {
+ text = normalizeStrategyHealthText(value, fieldName, maxLength);
+ } catch {
+ return nullable ? null : fallback;
+ }
+ if (
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/i.test(text) ||
+ /\b(?:token|secret|password|api[_ -]?key|private[_ -]?key|cookie)\s*[:=]\s*[^\s,;]{8,}/i.test(text) ||
+ /\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|sk-[A-Za-z0-9_-]{20,}|eyJ[A-Za-z0-9_-]{20,})\b/.test(text) ||
+ /(?:^|[\s(])(?:\/Users\/|\/home\/|[A-Za-z]:[\\/])/.test(text)
+ ) return nullable ? null : fallback;
+ return text;
+}
+
+export function normalizeStrategyHealthErrors(value) {
+ if (!Array.isArray(value)) return [];
+ return uniqueStrings(value.slice(0, 20).filter((item) => /^[a-z][a-z0-9_.-]{0,63}$/.test(String(item || ""))));
+}
+
+export function normalizeStrategyHealthPolicy(value) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ const list = (raw) => Array.isArray(raw)
+ ? raw.slice(0, 20).map((item) => sanitizeStrategyHealthText(item, "policy.item", 120, true)).filter(Boolean)
+ : [];
+ return {
+ mode: sanitizeStrategyHealthText(source.mode, "policy.mode", 40, false, "read_only"),
+ automatic_stages: list(source.automatic_stages),
+ automatic_modes: list(source.automatic_modes),
+ human_gate_stages: list(source.human_gate_stages),
+ canary_requirements: list(source.canary_requirements),
+ human_actions: list(source.human_actions),
+ machine_checks: list(source.machine_checks),
+ notice: sanitizeStrategyHealthText(source.notice, "policy.notice", 240, false, "健康不等于已批准 live。"),
+ };
+}
+
+export function emptyStrategyHealthPayload(errorCode) {
+ return {
+ schema_version: "strategy_health_dashboard.v1",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { strategy_count: 0, healthy: 0, watch: 0, review: 0, critical: 0 },
+ strategies: [],
+ policy: normalizeStrategyHealthPolicy({}),
+ errors: [errorCode],
+ };
+}
+
+export function strategyHealthStaleTtlSeconds(env) {
+ const configured = Number(env.STRATEGY_HEALTH_STALE_TTL_SECONDS);
+ if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
+ return STRATEGY_HEALTH_DEFAULT_STALE_TTL_SECONDS;
+ }
+ return Math.floor(configured);
+}
+
+export function normalizeControlPlaneSnapshot(payload, fieldName = "control plane snapshot") {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ if (payload.schema_version !== "qsl_control_plane_dashboard.v1") {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ for (const required of ["generated_at", "computed_at", "data_status", "summary", "candidates", "policy", "errors"]) {
+ if (!(required in payload)) throw new Error(`${fieldName}.${required} is required`);
+ }
+ if (!payload.summary || Array.isArray(payload.summary) || typeof payload.summary !== "object") {
+ throw new Error(`${fieldName}.summary must be an object`);
+ }
+ const dataStatus = cleanChoice(payload.data_status || "unavailable", STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ const candidates = dataStatus === "unavailable" ? [] : normalizeControlPlaneCandidates(payload.candidates, fieldName);
+ const errors = normalizeStrategyHealthErrors(payload.errors);
+ return {
+ schema_version: "qsl_control_plane_dashboard.v1",
+ generated_at: normalizeStrategyHealthTimestamp(payload.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(payload.computed_at, `${fieldName}.computed_at`, true),
+ data_status: dataStatus,
+ summary: normalizeControlPlaneSummary(candidates),
+ attention: normalizeControlPlaneAttention({ dataStatus, candidates, errors }),
+ candidates,
+ policy: normalizeControlPlanePolicy(payload.policy, fieldName),
+ errors,
+ };
+}
+
+export function normalizeControlPlaneSourceSnapshot(payload, fieldName = "control plane source snapshot") {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ if (payload.schema_version !== CONTROL_PLANE_SOURCE_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ for (const required of ["source_id", "generated_at", "computed_at", "data_status", "candidates", "errors"]) {
+ if (!(required in payload)) throw new Error(`${fieldName}.${required} is required`);
+ }
+ const dataStatus = cleanChoice(payload.data_status || "unavailable", STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ return {
+ schema_version: CONTROL_PLANE_SOURCE_SCHEMA_VERSION,
+ source_id: normalizeControlPlaneIdentifier(payload.source_id, `${fieldName}.source_id`, false),
+ generated_at: normalizeStrategyHealthTimestamp(payload.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(payload.computed_at, `${fieldName}.computed_at`, true),
+ data_status: dataStatus,
+ candidates: dataStatus === "unavailable" ? [] : normalizeControlPlaneCandidates(payload.candidates, fieldName),
+ errors: normalizeStrategyHealthErrors(payload.errors),
+ };
+}
+
+export function emptyControlPlaneSourceSnapshot(errorCode) {
+ return {
+ schema_version: CONTROL_PLANE_SOURCE_SCHEMA_VERSION,
+ source_id: "unavailable",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ candidates: [],
+ errors: [errorCode],
+ };
+}
+
+export function requireDedicatedM0ResearchSyncToken(request, env) {
+ const expected = String(env.M0_RESEARCH_SYNC_TOKEN || "");
+ if (!expected) throw new HttpError("M0 research sync token is not configured", 500);
+ const header = request.headers.get("Authorization") || "";
+ const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (token !== expected) throw new HttpError("M0 research sync token is invalid", 401);
+}
+
+export async function normalizeM0ResearchLedgerTransport(payload, fieldName = "M0 research ledger transport") {
+ const source = assertExactFields(payload, [
+ "schema_version", "producer", "source_artifact", "ledger_sha256", "ledger",
+ ], fieldName);
+ if (source.schema_version !== M0_RESEARCH_TRANSPORT_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const normalized = {
+ schema_version: M0_RESEARCH_TRANSPORT_SCHEMA_VERSION,
+ producer: normalizeM0ResearchProducer(source.producer, `${fieldName}.producer`),
+ source_artifact: normalizeM0ResearchSourceArtifact(source.source_artifact, `${fieldName}.source_artifact`),
+ ledger_sha256: normalizeResearchTaskDigest(source.ledger_sha256, `${fieldName}.ledger_sha256`),
+ ledger: normalizeM0ResearchLedger(source.ledger, `${fieldName}.ledger`),
+ };
+ // The ledger digest binds the closed embedded ledger. source_artifact.sha256
+ // intentionally remains a distinct immutable declaration about the QAR
+ // source artifact; it is not a hash of this derived ledger.
+ const recomputed = await calculateM0ResearchLedgerSha256(normalized.ledger);
+ if (normalized.ledger_sha256 !== recomputed) {
+ throw new Error(`${fieldName}.ledger_sha256 mismatch`);
+ }
+ const computedAt = Date.parse(normalized.ledger.computed_at);
+ if (!Number.isFinite(computedAt) || computedAt > Date.now() + 5 * 60 * 1000) {
+ throw new Error(`${fieldName}.ledger.computed_at is in the future`);
+ }
+ if (computedAt < Date.now() - M0_RESEARCH_RETENTION_SECONDS * 1000) {
+ throw new Error(`${fieldName}.ledger is expired`);
+ }
+ return normalized;
+}
+
+export async function normalizeM0ResearchLedgerStorageRecord(payload, fieldName) {
+ const record = assertExactFields(payload, ["schema_version", "stored_at", "expires_at", "envelope"], fieldName);
+ if (record.schema_version !== M0_RESEARCH_STORAGE_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const storedAt = normalizeM0ResearchTimestamp(record.stored_at, `${fieldName}.stored_at`);
+ const expiresAt = normalizeM0ResearchTimestamp(record.expires_at, `${fieldName}.expires_at`);
+ const storedMillis = Date.parse(storedAt);
+ const expiresMillis = Date.parse(expiresAt);
+ if (expiresMillis - storedMillis !== M0_RESEARCH_RETENTION_SECONDS * 1000 || expiresMillis <= Date.now()) {
+ throw new Error(`${fieldName} is expired`);
+ }
+ return {
+ schema_version: M0_RESEARCH_STORAGE_SCHEMA_VERSION,
+ stored_at: storedAt,
+ expires_at: expiresAt,
+ envelope: await normalizeM0ResearchLedgerTransport(record.envelope, `${fieldName}.envelope`),
+ };
+}
+
+export function normalizeM0ResearchLedger(payload, fieldName) {
+ const ledger = assertExactFields(payload, [
+ "schema_version", "generated_at", "computed_at", "data_status", "summary", "subjects", "policy", "errors",
+ ], fieldName);
+ if (ledger.schema_version !== M0_RESEARCH_LEDGER_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const generatedAt = normalizeM0ResearchTimestamp(ledger.generated_at, `${fieldName}.generated_at`);
+ const computedAt = normalizeM0ResearchTimestamp(ledger.computed_at, `${fieldName}.computed_at`);
+ if (generatedAt !== computedAt || /\./.test(generatedAt)) {
+ throw new Error(`${fieldName} timestamps must be the same canonical second`);
+ }
+ const dataStatus = cleanChoice(ledger.data_status, ["ready", "unavailable", "stale"], `${fieldName}.data_status`);
+ if (!Array.isArray(ledger.subjects) || ledger.subjects.length > 50000) {
+ throw new Error(`${fieldName}.subjects must be a bounded array`);
+ }
+ const subjects = ledger.subjects.map((subject, index) => normalizeM0ResearchSubject(
+ subject, `${fieldName}.subjects[${index}]`, computedAt,
+ ));
+ assertM0ResearchSortedUnique(subjects, (subject) => `${subject.subject.kind}\u0000${subject.subject.identifier}`, `${fieldName}.subjects`);
+ const summary = normalizeM0ResearchLedgerSummary(ledger.summary, `${fieldName}.summary`);
+ const calculatedSummary = summarizeM0ResearchSubjects(subjects);
+ if (!m0ResearchSummariesEqual(summary, calculatedSummary)) {
+ throw new Error(`${fieldName}.summary does not match subjects`);
+ }
+ const expectedStatus = summary.fresh_observation_count > 0
+ ? "ready"
+ : (summary.observation_count > 0 ? "stale" : "unavailable");
+ if (dataStatus !== expectedStatus) throw new Error(`${fieldName}.data_status does not match subjects`);
+ if (dataStatus === "unavailable" && subjects.length) throw new Error(`${fieldName}.subjects must be empty when unavailable`);
+ return {
+ schema_version: M0_RESEARCH_LEDGER_SCHEMA_VERSION,
+ generated_at: generatedAt,
+ computed_at: computedAt,
+ data_status: dataStatus,
+ summary,
+ subjects,
+ policy: normalizeM0ResearchLedgerPolicy(ledger.policy, `${fieldName}.policy`),
+ errors: normalizeM0ResearchErrorCodes(ledger.errors, `${fieldName}.errors`),
+ };
+}
+
+export function normalizeM0ResearchLedgerSummary(value, fieldName) {
+ const summary = assertExactFields(value, M0_RESEARCH_SUMMARY_FIELDS, fieldName);
+ const result = {};
+ for (const key of M0_RESEARCH_SUMMARY_FIELDS) {
+ result[key] = normalizeM0ResearchCount(summary[key], `${fieldName}.${key}`);
+ }
+ return result;
+}
+
+export function m0ResearchSummariesEqual(left, right) {
+ return M0_RESEARCH_SUMMARY_FIELDS.every((field) => left[field] === right[field]);
+}
+
+export function normalizeM0ResearchLedgerPolicy(value, fieldName) {
+ const policy = assertExactFields(value, ["authority", "no_order", "permitted_next_step", "notice"], fieldName);
+ if (policy.authority !== "research_only" || policy.no_order !== true || policy.permitted_next_step !== "research_validation_only") {
+ throw new Error(`${fieldName} must remain research-only and no-order`);
+ }
+ return {
+ authority: "research_only",
+ no_order: true,
+ permitted_next_step: "research_validation_only",
+ notice: normalizeM0ResearchText(policy.notice, `${fieldName}.notice`, 240),
+ };
+}
+
+export function normalizeM0ResearchSubject(value, fieldName, ledgerComputedAt) {
+ const item = assertExactFields(value, ["subject", "observations", "horizon_conflict", "historical_stale_horizon_drift"], fieldName);
+ const subject = assertExactFields(item.subject, ["kind", "identifier"], `${fieldName}.subject`);
+ const normalizedSubject = {
+ kind: cleanChoice(subject.kind, M0_RESEARCH_SUBJECT_KINDS, `${fieldName}.subject.kind`),
+ identifier: normalizeM0ResearchIdentifier(subject.identifier, `${fieldName}.subject.identifier`),
+ };
+ if (!Array.isArray(item.observations) || !item.observations.length || item.observations.length > 100) {
+ throw new Error(`${fieldName}.observations must be a non-empty bounded array`);
+ }
+ const observations = item.observations.map((observation, index) => normalizeM0ResearchObservation(
+ observation, `${fieldName}.observations[${index}]`, ledgerComputedAt,
+ ));
+ assertM0ResearchSortedUnique(observations, (observation) => (
+ `${observation.source_report_digest}\u0000${observation.source_entry_digest}`
+ ), `${fieldName}.observations`);
+ const expectedHorizonView = calculateM0ResearchHorizonViews(observations);
+ const horizonConflict = normalizeM0ResearchHorizonView(
+ item.horizon_conflict, `${fieldName}.horizon_conflict`, ["none", "conflict"], expectedHorizonView.horizon_conflict,
+ );
+ const historicalStaleHorizonDrift = normalizeM0ResearchHorizonView(
+ item.historical_stale_horizon_drift, `${fieldName}.historical_stale_horizon_drift`,
+ ["none", "drift", "unavailable"], expectedHorizonView.historical_stale_horizon_drift,
+ );
+ return {
+ subject: normalizedSubject,
+ observations,
+ horizon_conflict: horizonConflict,
+ historical_stale_horizon_drift: historicalStaleHorizonDrift,
+ };
+}
+
+export function normalizeM0ResearchObservation(value, fieldName, ledgerComputedAt) {
+ const item = assertExactFields(value, [
+ "source_ids", "source_report_digest", "source_entry_digest", "hypothesis_id", "as_of", "generated_at", "expires_at",
+ "research_context", "freshness",
+ ], fieldName);
+ if (!Array.isArray(item.source_ids) || !item.source_ids.length || item.source_ids.length > 100) {
+ throw new Error(`${fieldName}.source_ids must be a non-empty bounded array`);
+ }
+ const sourceIds = item.source_ids.map((sourceId, index) => normalizeM0ResearchIdentifier(sourceId, `${fieldName}.source_ids[${index}]`));
+ assertM0ResearchSortedUnique(sourceIds, (sourceId) => sourceId, `${fieldName}.source_ids`);
+ const generatedAt = normalizeM0ResearchTimestamp(item.generated_at, `${fieldName}.generated_at`);
+ const expiresAt = normalizeM0ResearchTimestamp(item.expires_at, `${fieldName}.expires_at`);
+ const generatedMillis = Date.parse(generatedAt);
+ const expiresMillis = Date.parse(expiresAt);
+ if (expiresMillis - generatedMillis !== 7 * 24 * 60 * 60 * 1000) {
+ throw new Error(`${fieldName} must have the fixed seven-day M0 expiry`);
+ }
+ const asOf = normalizeM0ResearchDate(item.as_of, `${fieldName}.as_of`);
+ if (asOf > generatedAt.slice(0, 10)) throw new Error(`${fieldName}.as_of cannot be after generated_at`);
+ const context = normalizeM0ResearchContext(item.research_context, `${fieldName}.research_context`);
+ const freshness = normalizeM0ResearchFreshness(
+ item.freshness, `${fieldName}.freshness`, generatedMillis, expiresMillis, Date.parse(ledgerComputedAt),
+ );
+ return {
+ source_ids: sourceIds,
+ source_report_digest: normalizeResearchTaskDigest(item.source_report_digest, `${fieldName}.source_report_digest`),
+ source_entry_digest: normalizeResearchTaskDigest(item.source_entry_digest, `${fieldName}.source_entry_digest`),
+ hypothesis_id: normalizeM0ResearchIdentifier(item.hypothesis_id, `${fieldName}.hypothesis_id`),
+ as_of: asOf,
+ generated_at: generatedAt,
+ expires_at: expiresAt,
+ research_context: context,
+ freshness,
+ };
+}
+
+export function normalizeM0ResearchContext(value, fieldName) {
+ const context = assertExactFields(value, [
+ "state", "primary_horizon", "suitable_horizons", "source_confidence", "source_style", "theme_ids",
+ ], fieldName);
+ const primaryHorizon = cleanChoice(context.primary_horizon, M0_RESEARCH_HORIZONS, `${fieldName}.primary_horizon`);
+ if (!Array.isArray(context.suitable_horizons) || !context.suitable_horizons.length || context.suitable_horizons.length > 4) {
+ throw new Error(`${fieldName}.suitable_horizons is invalid`);
+ }
+ const suitableHorizons = context.suitable_horizons.map((horizon, index) => cleanChoice(
+ horizon, M0_RESEARCH_HORIZONS, `${fieldName}.suitable_horizons[${index}]`,
+ ));
+ if (!suitableHorizons.includes(primaryHorizon)) throw new Error(`${fieldName}.primary_horizon must be suitable`);
+ assertM0ResearchUnique(suitableHorizons, `${fieldName}.suitable_horizons`);
+ if (!Array.isArray(context.theme_ids) || context.theme_ids.length > 24) throw new Error(`${fieldName}.theme_ids is invalid`);
+ const themeIds = context.theme_ids.map((themeId, index) => normalizeM0ResearchIdentifier(themeId, `${fieldName}.theme_ids[${index}]`));
+ assertM0ResearchUnique(themeIds, `${fieldName}.theme_ids`);
+ return {
+ state: cleanChoice(context.state, M0_RESEARCH_STATES, `${fieldName}.state`),
+ primary_horizon: primaryHorizon,
+ suitable_horizons: suitableHorizons,
+ source_confidence: cleanChoice(context.source_confidence, M0_RESEARCH_CONFIDENCE, `${fieldName}.source_confidence`),
+ source_style: cleanChoice(context.source_style, M0_RESEARCH_STYLES, `${fieldName}.source_style`),
+ theme_ids: themeIds,
+ };
+}
+
+export function normalizeM0ResearchFreshness(value, fieldName, generatedMillis, expiresMillis, ledgerComputedMillis) {
+ const freshness = assertExactFields(value, ["status", "age_seconds"], fieldName);
+ const status = cleanChoice(freshness.status, ["fresh", "stale", "unknown"], `${fieldName}.status`);
+ const expectedAge = generatedMillis > ledgerComputedMillis
+ ? null
+ : Math.max(0, Math.floor((ledgerComputedMillis - generatedMillis) / 1000));
+ const age = freshness.age_seconds === null ? null : normalizeM0ResearchCount(freshness.age_seconds, `${fieldName}.age_seconds`, 315360000);
+ if (status === "unknown") {
+ if (age !== null || generatedMillis <= ledgerComputedMillis) throw new Error(`${fieldName} unknown state is invalid`);
+ return { status, age_seconds: null };
+ }
+ if (age !== expectedAge || generatedMillis > ledgerComputedMillis) throw new Error(`${fieldName}.age_seconds is invalid`);
+ if (status === "fresh" && ledgerComputedMillis >= expiresMillis) throw new Error(`${fieldName} cannot be fresh after expiry`);
+ return { status, age_seconds: age };
+}
+
+export function calculateM0ResearchHorizonViews(observations) {
+ const freshHorizons = [...new Set(observations
+ .filter((observation) => observation.freshness.status === "fresh")
+ .map((observation) => observation.research_context.primary_horizon))].sort();
+ const staleHorizons = [...new Set(observations
+ .filter((observation) => observation.freshness.status === "stale")
+ .map((observation) => observation.research_context.primary_horizon))].sort();
+ return {
+ horizon_conflict: { status: freshHorizons.length > 1 ? "conflict" : "none", primary_horizons: freshHorizons },
+ historical_stale_horizon_drift: {
+ status: freshHorizons.length
+ ? (staleHorizons.length && JSON.stringify(staleHorizons) !== JSON.stringify(freshHorizons) ? "drift" : "none")
+ : (staleHorizons.length ? "unavailable" : "none"),
+ primary_horizons: staleHorizons,
+ },
+ };
+}
+
+export function projectM0ResearchDashboardForRead(ledger, sourceLedgerSha256, now = new Date()) {
+ // The stored envelope remains the immutable, digest-bound publication
+ // record. This is deliberately a different dashboard schema: changing
+ // freshness at read time must never pretend to be a re-validatable ledger.
+ const nowMillis = now instanceof Date ? now.getTime() : Date.parse(now);
+ if (!Number.isFinite(nowMillis)) return emptyM0ResearchDashboardPayload("m0_research_ledger_unavailable");
+ const subjects = ledger.subjects.map((entry) => {
+ const observations = entry.observations.map((observation) => ({
+ ...observation,
+ freshness: projectM0ResearchObservationFreshness(observation, nowMillis),
+ }));
+ const horizonViews = calculateM0ResearchHorizonViews(observations);
+ return {
+ subject: { ...entry.subject },
+ observations,
+ horizon_conflict: horizonViews.horizon_conflict,
+ historical_stale_horizon_drift: horizonViews.historical_stale_horizon_drift,
+ };
+ });
+ const summary = summarizeM0ResearchSubjects(subjects);
+ const dataStatus = summary.fresh_observation_count > 0
+ ? "ready"
+ : (summary.observation_count > 0 ? "stale" : "unavailable");
+ return {
+ schema_version: M0_RESEARCH_DASHBOARD_SCHEMA_VERSION,
+ source_ledger_sha256: sourceLedgerSha256,
+ source_generated_at: ledger.generated_at,
+ source_computed_at: ledger.computed_at,
+ viewed_at: utcTimestampSeconds(new Date(nowMillis)),
+ data_status: dataStatus,
+ summary,
+ subjects,
+ policy: { ...ledger.policy },
+ errors: [...ledger.errors],
+ };
+}
+
+export function projectM0ResearchObservationFreshness(observation, nowMillis) {
+ const generatedMillis = Date.parse(observation.generated_at);
+ const expiresMillis = Date.parse(observation.expires_at);
+ if (!Number.isFinite(generatedMillis) || !Number.isFinite(expiresMillis) || nowMillis < generatedMillis) {
+ return { status: "unknown", age_seconds: null };
+ }
+ const ageSeconds = Math.max(0, Math.floor((nowMillis - generatedMillis) / 1000));
+ // A stale source is never promoted by this projection. A former fresh
+ // observation is demoted as soon as its own expiry is reached.
+ const status = observation.freshness.status === "fresh" && nowMillis < expiresMillis
+ ? "fresh"
+ : "stale";
+ return { status, age_seconds: ageSeconds };
+}
+
+export function normalizeM0ResearchHorizonView(value, fieldName, allowedStatuses, expected) {
+ const view = assertExactFields(value, ["status", "primary_horizons"], fieldName);
+ const status = cleanChoice(view.status, allowedStatuses, `${fieldName}.status`);
+ if (!Array.isArray(view.primary_horizons) || view.primary_horizons.length > 4) {
+ throw new Error(`${fieldName}.primary_horizons is invalid`);
+ }
+ const horizons = view.primary_horizons.map((horizon, index) => cleanChoice(
+ horizon, M0_RESEARCH_HORIZONS, `${fieldName}.primary_horizons[${index}]`,
+ ));
+ assertM0ResearchSortedUnique(horizons, (horizon) => horizon, `${fieldName}.primary_horizons`);
+ if (status !== expected.status || JSON.stringify(horizons) !== JSON.stringify(expected.primary_horizons)) {
+ throw new Error(`${fieldName} does not match observations`);
+ }
+ return { status, primary_horizons: horizons };
+}
+
+export function summarizeM0ResearchSubjects(subjects) {
+ const observations = subjects.flatMap((subject) => subject.observations);
+ return {
+ subject_count: subjects.length,
+ observation_count: observations.length,
+ fresh_observation_count: observations.filter((observation) => observation.freshness.status === "fresh").length,
+ stale_observation_count: observations.filter((observation) => observation.freshness.status === "stale").length,
+ unknown_observation_count: observations.filter((observation) => observation.freshness.status === "unknown").length,
+ horizon_conflict_count: subjects.filter((subject) => subject.horizon_conflict.status === "conflict").length,
+ historical_stale_horizon_drift_count: subjects.filter((subject) => subject.historical_stale_horizon_drift.status === "drift").length,
+ };
+}
+
+export function normalizeM0ResearchErrorCodes(value, fieldName) {
+ if (!Array.isArray(value) || value.length > 20) throw new Error(`${fieldName} is invalid`);
+ const errors = value.map((error, index) => {
+ if (typeof error !== "string" || !/^[a-z][a-z0-9_.-]{0,63}$/.test(error)) {
+ throw new Error(`${fieldName}[${index}] is invalid`);
+ }
+ return error;
+ });
+ assertM0ResearchSortedUnique(errors, (error) => error, fieldName);
+ return errors;
+}
+
+export function normalizeM0ResearchRepository(value, fieldName, allowedRepository) {
+ const repository = normalizeResearchTaskRepository(value, fieldName);
+ if (repository !== allowedRepository) throw new Error(`${fieldName} is not an approved M0 repository`);
+ return repository;
+}
+
+export function normalizeM0ResearchRevision(value, fieldName) {
+ return normalizeResearchTaskRevision(value, fieldName);
+}
+
+export function normalizeM0ResearchProducer(value, fieldName) {
+ const producer = assertExactFields(value, ["repository", "revision"], fieldName);
+ return {
+ repository: normalizeM0ResearchRepository(
+ producer.repository, `${fieldName}.repository`, M0_RESEARCH_ALLOWED_PRODUCER_REPOSITORY,
+ ),
+ revision: normalizeM0ResearchRevision(producer.revision, `${fieldName}.revision`),
+ };
+}
+
+export function normalizeM0ResearchSourceArtifact(value, fieldName) {
+ const artifact = assertExactFields(value, ["repository", "revision", "run_id", "artifact_id", "sha256"], fieldName);
+ return {
+ repository: normalizeM0ResearchRepository(
+ artifact.repository, `${fieldName}.repository`, M0_RESEARCH_ALLOWED_SOURCE_REPOSITORY,
+ ),
+ revision: normalizeM0ResearchRevision(artifact.revision, `${fieldName}.revision`),
+ run_id: normalizeM0ResearchIdentifier(artifact.run_id, `${fieldName}.run_id`),
+ artifact_id: normalizeM0ResearchArtifactId(artifact.artifact_id, `${fieldName}.artifact_id`),
+ sha256: normalizeResearchTaskDigest(artifact.sha256, `${fieldName}.sha256`),
+ };
+}
+
+export function normalizeM0ResearchArtifactId(value, fieldName) {
+ // Keep this exactly aligned with #309's generic identifier schema. Artifact
+ // IDs are provenance labels, not strategy slugs, so uppercase and `:/` are
+ // valid when they satisfy the closed source-artifact contract.
+ return normalizeM0ResearchIdentifier(value, fieldName);
+}
+
+export function normalizeM0ResearchIdentifier(value, fieldName) {
+ if (typeof value !== "string" || !/^[A-Za-z0-9._:/-]{1,128}$/.test(value)) {
+ throw new Error(`${fieldName} is invalid`);
+ }
+ return value;
+}
+
+export function normalizeM0ResearchTimestamp(value, fieldName) {
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/.test(value) || Number.isNaN(Date.parse(value))) {
+ throw new Error(`${fieldName} must be a UTC timestamp`);
+ }
+ if (new Date(value).toISOString().slice(0, 10) !== value.slice(0, 10)) {
+ throw new Error(`${fieldName} must be a real UTC timestamp`);
+ }
+ return value;
+}
+
+export function normalizeM0ResearchDate(value, fieldName) {
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value) || Number.isNaN(Date.parse(`${value}T00:00:00Z`))) {
+ throw new Error(`${fieldName} must be an ISO date`);
+ }
+ if (new Date(`${value}T00:00:00Z`).toISOString().slice(0, 10) !== value) {
+ throw new Error(`${fieldName} must be a real ISO date`);
+ }
+ return value;
+}
+
+export function normalizeM0ResearchCount(value, fieldName, maximum = 50000) {
+ if (!Number.isInteger(value) || value < 0 || value > maximum) throw new Error(`${fieldName} is invalid`);
+ return value;
+}
+
+export function normalizeM0ResearchText(value, fieldName, maximum) {
+ if (typeof value !== "string" || !value || value.length > maximum || /[<>\\\u0000-\u001f]/.test(value)) {
+ throw new Error(`${fieldName} is invalid`);
+ }
+ return value;
+}
+
+export function assertM0ResearchUnique(values, fieldName) {
+ if (new Set(values).size !== values.length) throw new Error(`${fieldName} contains duplicates`);
+}
+
+export function assertM0ResearchSortedUnique(values, key, fieldName) {
+ let previous = null;
+ for (const value of values) {
+ const current = key(value);
+ if (previous !== null && current <= previous) throw new Error(`${fieldName} must be sorted and unique`);
+ previous = current;
+ }
+}
+
+export function canonicalM0ResearchLedgerJson(value) {
+ if (value === null) return "null";
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
+ if (typeof value === "number") {
+ if (!Number.isFinite(value)) throw new Error("M0 research ledger must use finite JSON values");
+ return JSON.stringify(value);
+ }
+ if (Array.isArray(value)) return `[${value.map(canonicalM0ResearchLedgerJson).join(",")}]`;
+ if (!value || typeof value !== "object") throw new Error("M0 research ledger must use JSON values");
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalM0ResearchLedgerJson(value[key])}`).join(",")}}`;
+}
+
+export async function calculateM0ResearchLedgerSha256(ledger) {
+ const raw = new TextEncoder().encode(canonicalM0ResearchLedgerJson(ledger));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export function emptyM0ResearchDashboardPayload(errorCode, now = new Date()) {
+ return {
+ schema_version: M0_RESEARCH_DASHBOARD_SCHEMA_VERSION,
+ source_ledger_sha256: null,
+ source_generated_at: null,
+ source_computed_at: null,
+ viewed_at: utcTimestampSeconds(now),
+ data_status: "unavailable",
+ summary: {
+ subject_count: 0,
+ observation_count: 0,
+ fresh_observation_count: 0,
+ stale_observation_count: 0,
+ unknown_observation_count: 0,
+ horizon_conflict_count: 0,
+ historical_stale_horizon_drift_count: 0,
+ },
+ subjects: [],
+ policy: {
+ authority: "research_only",
+ no_order: true,
+ permitted_next_step: "research_validation_only",
+ notice: "M0 研究台账不可用;不会推断策略、平台、运行状态或订单。",
+ },
+ errors: [errorCode],
+ };
+}
+
+export async function normalizeAdaptiveSelectionSourceSnapshot(payload, fieldName = "adaptive selection source snapshot") {
+ const source = assertExactFields(payload, [
+ "schema_version", "source_id", "generated_at", "computed_at", "data_status", "decision", "errors",
+ ], fieldName);
+ if (source.schema_version !== ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ const generatedAt = normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true);
+ const computedAt = normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true);
+ const decision = source.decision === null
+ ? null
+ : await normalizeAdaptiveSelectionDecision(source.decision, `${fieldName}.decision`);
+ if (dataStatus === "unavailable" && decision !== null) {
+ throw new Error(`${fieldName}.decision must be null when unavailable`);
+ }
+ if (dataStatus !== "unavailable" && (!decision || !generatedAt || !computedAt)) {
+ throw new Error(`${fieldName} requires decision and timestamps when available`);
+ }
+ return {
+ schema_version: ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION,
+ source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
+ generated_at: generatedAt,
+ computed_at: computedAt,
+ data_status: dataStatus,
+ decision,
+ errors: normalizeStrategyHealthErrors(source.errors),
+ };
+}
+
+export async function normalizeAdaptiveSelectionDecision(payload, fieldName) {
+ const value = assertExactFields(payload, [
+ "schema", "decision_id", "created_at", "authority", "no_order", "market_context", "policy_id",
+ "recommended_strategy_profile", "recommended_platform_id", "candidates", "input_digest", "decision_digest",
+ ], fieldName);
+ if (value.schema !== ADAPTIVE_SELECTION_DECISION_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema is unsupported`);
+ }
+ if (value.authority !== ADAPTIVE_SELECTION_AUTHORITY || value.no_order !== true) {
+ throw new Error(`${fieldName} must remain shadow-only and no-order`);
+ }
+ if (!Array.isArray(value.candidates) || value.candidates.length > 1000) {
+ throw new Error(`${fieldName}.candidates must be a bounded array`);
+ }
+ const candidates = value.candidates.map((item, index) =>
+ normalizeAdaptiveSelectionCandidate(item, `${fieldName}.candidates[${index}]`),
+ );
+ const candidateIds = new Set();
+ for (const candidate of candidates) {
+ if (candidateIds.has(candidate.strategy_profile)) {
+ throw new Error(`${fieldName}.candidates contains duplicate strategy_profile`);
+ }
+ candidateIds.add(candidate.strategy_profile);
+ }
+ const recommendedStrategy = normalizeControlPlaneIdentifier(
+ value.recommended_strategy_profile, `${fieldName}.recommended_strategy_profile`, true,
+ );
+ const recommendedPlatform = normalizeControlPlaneIdentifier(
+ value.recommended_platform_id, `${fieldName}.recommended_platform_id`, true,
+ );
+ const recommendedCandidate = candidates.find((item) => item.strategy_profile === recommendedStrategy && item.accepted);
+ if ((recommendedStrategy === null) !== (recommendedPlatform === null)) {
+ throw new Error(`${fieldName}.recommended strategy and platform must be provided together`);
+ }
+ if (recommendedStrategy && (!recommendedCandidate || recommendedCandidate.selected_platform_id !== recommendedPlatform)) {
+ throw new Error(`${fieldName}.recommended candidate is not accepted`);
+ }
+ const normalized = {
+ schema: ADAPTIVE_SELECTION_DECISION_SCHEMA_VERSION,
+ decision_id: normalizeControlPlaneIdentifier(value.decision_id, `${fieldName}.decision_id`, false),
+ created_at: normalizeStrategyHealthTimestamp(value.created_at, `${fieldName}.created_at`),
+ authority: ADAPTIVE_SELECTION_AUTHORITY,
+ no_order: true,
+ market_context: normalizeAdaptiveSelectionMarketContext(value.market_context, `${fieldName}.market_context`),
+ policy_id: normalizeControlPlaneIdentifier(value.policy_id, `${fieldName}.policy_id`, false),
+ recommended_strategy_profile: recommendedStrategy,
+ recommended_platform_id: recommendedPlatform,
+ candidates,
+ input_digest: normalizeAdaptiveSelectionDigest(value.input_digest, `${fieldName}.input_digest`),
+ decision_digest: normalizeAdaptiveSelectionDigest(value.decision_digest, `${fieldName}.decision_digest`),
+ };
+ // `input_digest` cannot be reconstructed from the display projection alone:
+ // QPK calculates it from the private, immutable selection input. The QPK
+ // decision digest binds that exact input digest to every decision field that
+ // is displayed here, so a changed input digest cannot be silently accepted.
+ if (normalized.decision_digest !== await calculateAdaptiveSelectionDecisionDigest(normalized)) {
+ throw new Error(`${fieldName}.decision_digest mismatch`);
+ }
+ return normalized;
+}
+
+export function normalizeAdaptiveSelectionMarketContext(value, fieldName) {
+ const item = assertExactFields(value, [
+ "schema", "as_of", "domain", "data_version", "data_freshness_days", "regime", "regime_confidence", "factors",
+ ], fieldName);
+ if (item.schema !== "qsl.market_context_snapshot.v1") {
+ throw new Error(`${fieldName}.schema is unsupported`);
+ }
+ const asOf = String(item.as_of || "");
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(asOf) || Number.isNaN(Date.parse(`${asOf}T00:00:00Z`))) {
+ throw new Error(`${fieldName}.as_of must be an ISO date`);
+ }
+ if (!Number.isInteger(item.data_freshness_days) || item.data_freshness_days < 0 || item.data_freshness_days > 366) {
+ throw new Error(`${fieldName}.data_freshness_days is invalid`);
+ }
+ const confidence = Number(item.regime_confidence);
+ if (!Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
+ throw new Error(`${fieldName}.regime_confidence is invalid`);
+ }
+ if (!item.factors || Array.isArray(item.factors) || typeof item.factors !== "object" || Object.keys(item.factors).length > 100) {
+ throw new Error(`${fieldName}.factors is invalid`);
+ }
+ const factors = {};
+ for (const [key, raw] of Object.entries(item.factors)) {
+ if (!/^[a-z][a-z0-9_.-]{0,63}$/.test(key)) throw new Error(`${fieldName}.factors key is invalid`);
+ const numeric = Number(raw);
+ if (!Number.isFinite(numeric) || Math.abs(numeric) > 1_000_000) {
+ throw new Error(`${fieldName}.factors.${key} is invalid`);
+ }
+ factors[key] = numeric;
+ }
+ return {
+ schema: "qsl.market_context_snapshot.v1",
+ as_of: asOf,
+ domain: cleanChoice(item.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.domain`),
+ data_version: normalizeControlPlaneIdentifier(item.data_version, `${fieldName}.data_version`, false),
+ data_freshness_days: item.data_freshness_days,
+ regime: normalizeControlPlaneIdentifier(item.regime, `${fieldName}.regime`, false),
+ regime_confidence: confidence,
+ factors,
+ };
+}
+
+export function normalizeAdaptiveSelectionCandidate(value, fieldName) {
+ const item = assertExactFields(value, [
+ "strategy_profile", "release_digest", "selected_platform_id", "score", "risk_multiplier", "accepted", "reasons", "proposed_weight",
+ ], fieldName);
+ const score = item.score === null ? null : Number(item.score);
+ const riskMultiplier = Number(item.risk_multiplier);
+ if (score !== null && (!Number.isFinite(score) || Math.abs(score) > 1_000_000)) {
+ throw new Error(`${fieldName}.score is invalid`);
+ }
+ if (!Number.isFinite(riskMultiplier) || riskMultiplier < 0 || riskMultiplier > 1) {
+ throw new Error(`${fieldName}.risk_multiplier is invalid`);
+ }
+ if (typeof item.accepted !== "boolean") throw new Error(`${fieldName}.accepted must be boolean`);
+ if (item.proposed_weight !== 0) throw new Error(`${fieldName}.proposed_weight must remain zero`);
+ if (!Array.isArray(item.reasons) || item.reasons.length > 32) throw new Error(`${fieldName}.reasons is invalid`);
+ const reasons = item.reasons.map((reason) => {
+ const code = String(reason || "");
+ if (!/^[a-z][a-z0-9_.:-]{0,127}$/.test(code)) throw new Error(`${fieldName}.reason is invalid`);
+ return code;
+ });
+ return {
+ strategy_profile: normalizeControlPlaneIdentifier(item.strategy_profile, `${fieldName}.strategy_profile`, false),
+ release_digest: normalizeAdaptiveSelectionReleaseDigest(item.release_digest, `${fieldName}.release_digest`),
+ selected_platform_id: normalizeControlPlaneIdentifier(item.selected_platform_id, `${fieldName}.selected_platform_id`, true),
+ score,
+ risk_multiplier: riskMultiplier,
+ accepted: item.accepted,
+ reasons,
+ proposed_weight: 0,
+ };
+}
+
+export function normalizeAdaptiveSelectionReleaseDigest(value, fieldName) {
+ const text = String(value || "").trim();
+ if (!/^[A-Za-z0-9._:=+-]{1,160}$/.test(text) || /(token|secret|password|cookie|private|api[_-]?key)/i.test(text)) {
+ throw new Error(`${fieldName} is invalid`);
+ }
+ return text;
+}
+
+export function normalizeAdaptiveSelectionDigest(value, fieldName) {
+ const text = String(value || "");
+ if (!/^[a-f0-9]{64}$/.test(text)) throw new Error(`${fieldName} is invalid`);
+ return text;
+}
+
+export function isAdaptiveSelectionFloatPath(path) {
+ if (path[0] === "market_context") {
+ return path[1] === "regime_confidence" || path[1] === "factors";
+ }
+ return path[0] === "candidates"
+ && ["score", "risk_multiplier", "proposed_weight"].includes(path[2]);
+}
+
+export function canonicalAdaptiveSelectionNumber(value, forceFloat) {
+ if (!Number.isFinite(value)) throw new Error("adaptive selection decision must use finite JSON values");
+ if (Object.is(value, -0)) return forceFloat ? "-0.0" : "0";
+ let text = String(value);
+ const exponent = text.match(/^(.*)e([+-]?)(\d+)$/i);
+ if (exponent) {
+ const [, mantissa, sign, rawExponent] = exponent;
+ // Python's json.dumps (used by QPK canonical_sha256) pads one-digit
+ // negative exponents, while V8's Number#toString does not.
+ text = `${mantissa}e${sign || "+"}${sign === "-" ? rawExponent.padStart(2, "0") : rawExponent}`;
+ }
+ if (forceFloat && !/[.eE]/.test(text)) return `${text}.0`;
+ return text;
+}
+
+export function canonicalAdaptiveSelectionDecisionJson(value, path = []) {
+ if (value === null) return "null";
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
+ if (typeof value === "number") return canonicalAdaptiveSelectionNumber(value, isAdaptiveSelectionFloatPath(path));
+ if (Array.isArray(value)) {
+ return `[${value.map((item) => canonicalAdaptiveSelectionDecisionJson(item, [...path, "*"])).join(",")}]`;
+ }
+ if (!value || typeof value !== "object") throw new Error("adaptive selection decision must use JSON values");
+ return `{${Object.keys(value).sort().map((key) => (
+ `${JSON.stringify(key)}:${canonicalAdaptiveSelectionDecisionJson(value[key], [...path, key])}`
+ )).join(",")}}`;
+}
+
+export async function calculateAdaptiveSelectionDecisionDigest(payload) {
+ const material = { ...payload };
+ delete material.decision_digest;
+ const raw = new TextEncoder().encode(canonicalAdaptiveSelectionDecisionJson(material));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export function normalizeAdaptiveSelectionSummary(selections) {
+ const entries = Array.isArray(selections) ? selections : [];
+ const decisions = entries.map((item) => item.decision).filter(Boolean);
+ const candidates = decisions.flatMap((item) => item.candidates);
+ return {
+ source_count: entries.length,
+ decision_count: decisions.length,
+ candidate_count: candidates.length,
+ recommended_count: decisions.filter((item) => item.recommended_strategy_profile).length,
+ rejected_candidate_count: candidates.filter((item) => !item.accepted).length,
+ };
+}
+
+export function emptyAdaptiveSelectionSourceSnapshot(errorCode) {
+ return {
+ schema_version: ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION,
+ source_id: "unavailable",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ decision: null,
+ errors: [errorCode],
+ };
+}
+
+export function emptyAdaptiveSelectionPayload(errorCode) {
+ return {
+ schema_version: ADAPTIVE_SELECTION_DASHBOARD_SCHEMA_VERSION,
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { source_count: 0, decision_count: 0, candidate_count: 0, recommended_count: 0, rejected_candidate_count: 0 },
+ selections: [],
+ policy: {
+ authority: ADAPTIVE_SELECTION_AUTHORITY,
+ no_order: true,
+ execution_authority_granted: false,
+ notice: "M1 Shadow 建议尚不可用;控制台不会推断策略、平台或订单。",
+ },
+ errors: [errorCode],
+ };
+}
+
+export function adaptiveSelectionStaleTtlSeconds(env) {
+ const configured = Number(env.ADAPTIVE_SELECTION_STALE_TTL_SECONDS);
+ if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
+ return ADAPTIVE_SELECTION_DEFAULT_STALE_TTL_SECONDS;
+ }
+ return Math.floor(configured);
+}
+
+export function normalizeControlPlaneCandidates(value, fieldName) {
+ if (!Array.isArray(value) || value.length > 1000) {
+ throw new Error(`${fieldName}.candidates must be an array with at most 1000 items`);
+ }
+ const seen = new Set();
+ return value.map((item, index) => {
+ const prefix = `${fieldName}.candidates[${index}]`;
+ if (!item || Array.isArray(item) || typeof item !== "object") throw new Error(`${prefix} must be an object`);
+ const candidateId = normalizeControlPlaneIdentifier(item.candidate_id, `${prefix}.candidate_id`, false);
+ if (seen.has(candidateId)) throw new Error(`${fieldName}.candidates contains duplicate candidate_id`);
+ seen.add(candidateId);
+ const lifecycle = normalizeControlPlaneLifecycle(item.lifecycle, prefix);
+ const recommendation = normalizeControlPlaneRecommendation(item.recommendation, prefix);
+ const isOwnerDecision = lifecycle.stage === "P6";
+ if (isOwnerDecision && (lifecycle.status !== "owner_decision_required" || recommendation.code !== "owner_live_decision")) {
+ throw new Error(`${prefix} P6 must be an owner_live_decision`);
+ }
+ if (!isOwnerDecision && (lifecycle.status === "owner_decision_required" || recommendation.code === "owner_live_decision")) {
+ throw new Error(`${prefix} only P6 can require an owner_live_decision`);
+ }
+ const forwardObservation = item.forward_observation === undefined
+ ? undefined
+ : normalizeForwardObservation(item.forward_observation, lifecycle, prefix);
+ return {
+ candidate_id: candidateId,
+ candidate_kind: cleanChoice(item.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${prefix}.candidate_kind`),
+ domain: cleanChoice(item.domain, STRATEGY_HEALTH_DOMAINS, `${prefix}.domain`),
+ lifecycle,
+ evidence: normalizeControlPlaneEvidence(item.evidence, prefix),
+ recommendation,
+ freshness: normalizeStrategyHealthFreshness(item.freshness, `${prefix}.freshness`),
+ ...(forwardObservation === undefined ? {} : { forward_observation: forwardObservation }),
+ };
+ });
+}
+
+export function normalizeForwardObservation(value, lifecycle, prefix) {
+ if (!FORWARD_OBSERVATION_RESEARCH_STAGES.has(lifecycle.stage)) {
+ throw new Error(`${prefix}.forward_observation is only allowed for research stages`);
+ }
+ const observation = assertExactFields(value, [
+ "state", "observations_completed", "required_trading_sessions", "last_observed_session", "observed_at", "no_order", "live_authority_granted",
+ ], `${prefix}.forward_observation`);
+ const completed = observation.observations_completed;
+ const required = observation.required_trading_sessions;
+ if (!Number.isSafeInteger(completed) || !Number.isSafeInteger(required) || completed < 0 || required < 1 || completed > required || required > 10000) {
+ throw new Error(`${prefix}.forward_observation observation counts are invalid`);
+ }
+ if (observation.no_order !== true) throw new Error(`${prefix}.forward_observation.no_order must be true`);
+ if (observation.live_authority_granted !== false) throw new Error(`${prefix}.forward_observation.live_authority_granted must be false`);
+ return {
+ state: cleanChoice(observation.state, FORWARD_OBSERVATION_STATES, `${prefix}.forward_observation.state`),
+ observations_completed: completed,
+ required_trading_sessions: required,
+ last_observed_session: normalizeForwardObservationDate(observation.last_observed_session, `${prefix}.forward_observation.last_observed_session`),
+ observed_at: normalizeStrategyHealthTimestamp(observation.observed_at, `${prefix}.forward_observation.observed_at`),
+ no_order: true,
+ live_authority_granted: false,
+ };
+}
+
+export function normalizeForwardObservationDate(value, fieldName) {
+ const text = normalizeStrategyHealthText(value, fieldName, 10);
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(text) || Number.isNaN(Date.parse(`${text}T00:00:00.000Z`)) || new Date(`${text}T00:00:00.000Z`).toISOString().slice(0, 10) !== text) {
+ throw new Error(`${fieldName} must be an ISO date`);
+ }
+ return text;
+}
+
+export function normalizeControlPlaneIdentifier(value, fieldName, nullable = true) {
+ if ((value === null || value === undefined || value === "") && nullable) return null;
+ const text = String(value || "").trim();
+ if (!/^[A-Za-z0-9._=-]{1,128}$/.test(text)) throw new Error(`${fieldName} is invalid`);
+ if (/(token|secret|password|cookie|private|api[_-]?key)/i.test(text)) throw new Error(`${fieldName} is sensitive`);
+ return text;
+}
+
+export function normalizeControlPlaneLifecycle(value, prefix) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ stage: cleanChoice(source.stage, CONTROL_PLANE_STAGES, `${prefix}.lifecycle.stage`),
+ status: cleanChoice(source.status, CONTROL_PLANE_LIFECYCLE_STATUSES, `${prefix}.lifecycle.status`),
+ };
+}
+
+export function normalizeControlPlaneEvidence(value, prefix) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ p1_input_digest: normalizeControlPlaneIdentifier(source.p1_input_digest, `${prefix}.evidence.p1_input_digest`),
+ p2_config_digest: normalizeControlPlaneIdentifier(source.p2_config_digest, `${prefix}.evidence.p2_config_digest`),
+ p3_evidence_id: normalizeControlPlaneIdentifier(source.p3_evidence_id, `${prefix}.evidence.p3_evidence_id`),
+ source_revision: normalizeControlPlaneIdentifier(source.source_revision, `${prefix}.evidence.source_revision`),
+ };
+}
+
+export function normalizeControlPlaneRecommendation(value, prefix) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ return {
+ code: cleanChoice(source.code || "none", CONTROL_PLANE_RECOMMENDATIONS, `${prefix}.recommendation.code`),
+ reason: sanitizeStrategyHealthText(source.reason, `${prefix}.recommendation.reason`, 240, false, "没有可用的机器建议。"),
+ };
+}
+
+export function normalizeControlPlaneSummary(candidates) {
+ return {
+ candidate_count: candidates.length,
+ deferred: candidates.filter((item) => item.lifecycle.status === "deferred").length,
+ parked: candidates.filter((item) => item.lifecycle.status === "parked").length,
+ owner_decision_required: candidates.filter((item) => item.lifecycle.status === "owner_decision_required").length,
+ };
+}
+
+export function normalizeControlPlaneAttention({ dataStatus, candidates, errors }) {
+ const normalizedCandidates = Array.isArray(candidates) ? candidates : [];
+ const normalizedErrors = uniqueStrings(Array.isArray(errors) ? errors : []);
+ const reasonCodes = new Set(normalizedErrors);
+ if (dataStatus !== "ready") reasonCodes.add("control_plane_source_unavailable");
+ if (!normalizedCandidates.length && dataStatus === "ready") reasonCodes.add("control_plane_candidate_missing");
+ if (normalizedCandidates.some((item) => item.lifecycle?.status === "deferred")) {
+ reasonCodes.add("control_plane_candidate_deferred");
+ }
+ if (normalizedCandidates.some((item) => item.lifecycle?.status === "parked")) {
+ reasonCodes.add("control_plane_candidate_parked");
+ }
+ const status = dataStatus !== "ready"
+ ? "unavailable"
+ : (reasonCodes.size ? "attention_required" : "research_only");
+ return {
+ status: cleanChoice(status, CONTROL_PLANE_ATTENTION_STATUSES, "control plane attention status"),
+ reason_codes: [...reasonCodes].sort(),
+ };
+}
+
+export function normalizeControlPlanePolicy(value, fieldName) {
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
+ if (source.p6_owner_decision_required !== true) {
+ throw new Error(`${fieldName}.policy.p6_owner_decision_required must be true`);
+ }
+ return {
+ p4_p5_automation: cleanChoice(
+ source.p4_p5_automation || "not_configured",
+ CONTROL_PLANE_AUTOMATION_STATES,
+ `${fieldName}.policy.p4_p5_automation`,
+ ),
+ p6_owner_decision_required: true,
+ notice: sanitizeStrategyHealthText(source.notice, `${fieldName}.policy.notice`, 240, false, "live 仍需所有者明确决定。"),
+ };
+}
+
+export function normalizeBinancePrivateScopeReport(payload, { requireIngestFreshness = false } = {}) {
+ const report = assertExactFields(payload, [
+ "platform",
+ "observed_at",
+ "source_run_id",
+ "source_sha",
+ "account_scope_sha256",
+ "assets",
+ "historical_difference_unresolved",
+ "no_order",
+ "execution_authority_granted",
+ ], "Binance private scope report");
+ if (report.platform !== "binance") throw new Error("Binance private scope report.platform must be binance");
+ const observedAt = report.observed_at;
+ if (typeof observedAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(observedAt)) {
+ throw new Error("Binance private scope report.observed_at must be an ISO timestamp with timezone");
+ }
+ const observedAtMs = Date.parse(observedAt);
+ if (!Number.isFinite(observedAtMs)) {
+ throw new Error("Binance private scope report.observed_at must be valid");
+ }
+ if (requireIngestFreshness) {
+ const ageMs = Date.now() - observedAtMs;
+ if (ageMs > BINANCE_PRIVATE_SCOPE_INGEST_MAX_AGE_MS || ageMs < -BINANCE_PRIVATE_SCOPE_FUTURE_SKEW_MS) {
+ throw new Error("Binance private scope report.observed_at is outside the ingestion window");
+ }
+ }
+ const sourceRunId = report.source_run_id;
+ if (typeof sourceRunId !== "string" || !/^[1-9]\d{0,19}$/.test(sourceRunId)) {
+ throw new Error("Binance private scope report.source_run_id must be a decimal string");
+ }
+ const sourceSha = report.source_sha;
+ if (typeof sourceSha !== "string" || !/^[0-9a-fA-F]{40}$/.test(sourceSha)) {
+ throw new Error("Binance private scope report.source_sha must be a 40 character hex string");
+ }
+ const accountScopeSha256 = report.account_scope_sha256;
+ if (typeof accountScopeSha256 !== "string" || !/^[0-9a-fA-F]{64}$/.test(accountScopeSha256)) {
+ throw new Error("Binance private scope report.account_scope_sha256 must be a 64 character hex string");
+ }
+ if (!Array.isArray(report.assets) || report.assets.length > BINANCE_PRIVATE_SCOPE_MAX_ASSETS) {
+ throw new Error(`Binance private scope report.assets must contain at most ${BINANCE_PRIVATE_SCOPE_MAX_ASSETS} items`);
+ }
+ const seenAssets = new Set();
+ const assets = report.assets.map((value, index) => {
+ const item = assertExactFields(value, ["asset", "free", "locked"], `Binance private scope report.assets[${index}]`);
+ const asset = item.asset;
+ if (typeof asset !== "string" || !/^[\p{L}\p{N}]{1,20}$/u.test(asset)) {
+ throw new Error(`Binance private scope report.assets[${index}].asset is invalid`);
+ }
+ if (seenAssets.has(asset)) throw new Error("Binance private scope report.assets contains duplicate assets");
+ seenAssets.add(asset);
+ const free = normalizeBinancePrivateScopeDecimal(item.free, `Binance private scope report.assets[${index}].free`);
+ const locked = normalizeBinancePrivateScopeDecimal(item.locked, `Binance private scope report.assets[${index}].locked`);
+ if (binancePrivateScopeDecimalIsZero(free) && binancePrivateScopeDecimalIsZero(locked)) {
+ throw new Error(`Binance private scope report.assets[${index}] must not be an all-zero row`);
+ }
+ return { asset, free, locked };
+ });
+ if (report.historical_difference_unresolved !== true) {
+ throw new Error("Binance private scope report.historical_difference_unresolved must be true");
+ }
+ if (report.no_order !== true) throw new Error("Binance private scope report.no_order must be true");
+ if (report.execution_authority_granted !== false) {
+ throw new Error("Binance private scope report.execution_authority_granted must be false");
+ }
+ return {
+ platform: "binance",
+ observed_at: observedAt,
+ source_run_id: sourceRunId,
+ source_sha: sourceSha.toLowerCase(),
+ account_scope_sha256: accountScopeSha256.toLowerCase(),
+ assets,
+ historical_difference_unresolved: true,
+ no_order: true,
+ execution_authority_granted: false,
+ };
+}
+
+export function normalizeBinancePrivateScopeDecimal(value, fieldName) {
+ if (typeof value !== "string" || !/^\d+(?:\.\d+)?$/.test(value)) {
+ throw new Error(`${fieldName} must be a non-negative finite decimal string`);
+ }
+ return value;
+}
+
+export function binancePrivateScopeDecimalIsZero(value) {
+ return /^0+(?:\.0+)?$/.test(value);
+}
+
+export function normalizeReconciliationRecoverySourceSnapshot(payload, fieldName = "reconciliation recovery source snapshot") {
+ const source = assertExactFields(payload, [
+ "schema_version", "source_id", "generated_at", "computed_at", "data_status", "recoveries", "errors",
+ ], fieldName);
+ if (source.schema_version !== RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ if (!Array.isArray(source.recoveries) || source.recoveries.length > RECONCILIATION_RECOVERY_MAX_REQUESTS) {
+ throw new Error(`${fieldName}.recoveries must be an array with at most ${RECONCILIATION_RECOVERY_MAX_REQUESTS} items`);
+ }
+ const recoveries = [];
+ const seen = new Set();
+ for (const [index, value] of source.recoveries.entries()) {
+ const recovery = normalizeReconciliationRecoveryRequest(value, `${fieldName}.recoveries[${index}]`);
+ if (seen.has(recovery.recovery_id)) {
+ throw new Error(`${fieldName}.recoveries contains duplicate recovery_id`);
+ }
+ seen.add(recovery.recovery_id);
+ recoveries.push(recovery);
+ }
+ if (dataStatus === "unavailable" && recoveries.length) {
+ throw new Error(`${fieldName}.recoveries must be empty when unavailable`);
+ }
+ return {
+ schema_version: RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION,
+ source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
+ generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
+ data_status: dataStatus,
+ recoveries,
+ errors: normalizeStrategyHealthErrors(source.errors),
+ };
+}
+
+export function normalizeReconciliationRecoveryRequest(value, fieldName) {
+ if (value?.mode === "initial_enrollment") {
+ const item = assertExactFields(value, ["mode", "recovery_id", "target_id", "candidate", "facts"], fieldName);
+ return { mode: "initial_enrollment", recovery_id: normalizeControlPlaneIdentifier(item.recovery_id, `${fieldName}.recovery_id`, false),
+ target_id: normalizeControlPlaneIdentifier(item.target_id, `${fieldName}.target_id`, false), candidate: item.candidate, facts: item.facts };
+ }
+ const item = assertExactFields(value, [
+ "recovery_id", "platform", "strategy_profile", "environment", "reconciliation_state", "readiness",
+ "candidate_sha256", "evidence_sample_count", "first_observed_at", "last_observed_at", "dual_review", "blocker_codes",
+ ], fieldName);
+ const dualReview = assertExactFields(item.dual_review, [
+ "outcome", "reviewer_count", "evidence_binding_sha256",
+ ], `${fieldName}.dual_review`);
+ const evidenceSampleCount = Number(item.evidence_sample_count);
+ const reviewerCount = Number(dualReview.reviewer_count);
+ if (!Number.isInteger(evidenceSampleCount) || evidenceSampleCount < 0 || evidenceSampleCount > 100) {
+ throw new Error(`${fieldName}.evidence_sample_count must be a bounded integer`);
+ }
+ if (!Number.isInteger(reviewerCount) || reviewerCount < 0 || reviewerCount > 10) {
+ throw new Error(`${fieldName}.dual_review.reviewer_count must be a bounded integer`);
+ }
+ const firstObservedAt = normalizeResearchTaskTimestamp(item.first_observed_at, `${fieldName}.first_observed_at`);
+ const lastObservedAt = normalizeResearchTaskTimestamp(item.last_observed_at, `${fieldName}.last_observed_at`);
+ const observationWindowMs = Date.parse(lastObservedAt) - Date.parse(firstObservedAt);
+ if (observationWindowMs < 0) {
+ throw new Error(`${fieldName}.first_observed_at must not be after last_observed_at`);
+ }
+ if (!Array.isArray(item.blocker_codes) || item.blocker_codes.length > 20) {
+ throw new Error(`${fieldName}.blocker_codes must be an array with at most 20 items`);
+ }
+ const blockerCodes = normalizeStrategyHealthErrors(item.blocker_codes);
+ if (blockerCodes.length !== item.blocker_codes.length) {
+ throw new Error(`${fieldName}.blocker_codes must be unique stable codes`);
+ }
+ const recovery = {
+ recovery_id: normalizeControlPlaneIdentifier(item.recovery_id, `${fieldName}.recovery_id`, false),
+ platform: cleanChoice(item.platform, RECONCILIATION_RECOVERY_PLATFORMS, `${fieldName}.platform`),
+ strategy_profile: normalizeResearchTaskIdentity(item.strategy_profile, `${fieldName}.strategy_profile`),
+ environment: cleanChoice(item.environment, RECONCILIATION_RECOVERY_ENVIRONMENTS, `${fieldName}.environment`),
+ reconciliation_state: cleanChoice(
+ item.reconciliation_state,
+ RECONCILIATION_RECOVERY_STATES,
+ `${fieldName}.reconciliation_state`,
+ ),
+ readiness: cleanChoice(item.readiness, RECONCILIATION_RECOVERY_READINESS, `${fieldName}.readiness`),
+ candidate_sha256: normalizeResearchTaskDigest(item.candidate_sha256, `${fieldName}.candidate_sha256`),
+ evidence_sample_count: evidenceSampleCount,
+ first_observed_at: firstObservedAt,
+ last_observed_at: lastObservedAt,
+ dual_review: {
+ outcome: cleanChoice(
+ dualReview.outcome,
+ RECONCILIATION_RECOVERY_DUAL_REVIEW_OUTCOMES,
+ `${fieldName}.dual_review.outcome`,
+ ),
+ reviewer_count: reviewerCount,
+ evidence_binding_sha256: normalizeResearchTaskDigest(
+ dualReview.evidence_binding_sha256,
+ `${fieldName}.dual_review.evidence_binding_sha256`,
+ ),
+ },
+ blocker_codes: blockerCodes,
+ };
+ if (recovery.readiness === "awaiting_human_confirmation") {
+ if (
+ recovery.evidence_sample_count < 1 ||
+ observationWindowMs > RECONCILIATION_RECOVERY_MAX_SAMPLE_WINDOW_MS ||
+ recovery.dual_review.evidence_binding_sha256 !== recovery.candidate_sha256 ||
+ recovery.blocker_codes.length
+ ) {
+ throw new Error(`${fieldName}.readiness requires at least one observation within a 15-minute window, bound candidate, and no blockers`);
+ }
+ }
+ return recovery;
+}
+
+export function normalizeExecutionEvidenceSourceSnapshot(payload, fieldName = "execution evidence source snapshot") {
+ const source = assertExactFields(payload, [
+ "schema_version", "source_id", "generated_at", "computed_at", "data_status", "deployments", "errors",
+ ], fieldName);
+ if (source.schema_version !== EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ if (!Array.isArray(source.deployments) || source.deployments.length > 1000) {
+ throw new Error(`${fieldName}.deployments must be an array with at most 1000 items`);
+ }
+ const deployments = [];
+ const seen = new Set();
+ for (const [index, item] of source.deployments.entries()) {
+ const deployment = normalizeExecutionEvidenceDeployment(item, `${fieldName}.deployments[${index}]`);
+ if (seen.has(deployment.deployment_id)) {
+ throw new Error(`${fieldName}.deployments contains duplicate deployment_id`);
+ }
+ seen.add(deployment.deployment_id);
+ deployments.push(deployment);
+ }
+ if (dataStatus === "unavailable" && deployments.length) {
+ throw new Error(`${fieldName}.deployments must be empty when unavailable`);
+ }
+ return {
+ schema_version: EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION,
+ source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
+ generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
+ data_status: dataStatus,
+ deployments,
+ errors: normalizeStrategyHealthErrors(source.errors),
+ };
+}
+
+export function normalizeExecutionEvidenceDeployment(value, fieldName) {
+ const item = assertRequiredAndOptionalFields(value, [
+ "deployment_id", "strategy", "target", "capabilities", "evidence", "recommendation",
+ ], ["execution_receipt"], fieldName);
+ const strategy = assertExactFields(item.strategy, [
+ "candidate_id", "candidate_kind", "domain", "strategy_revision",
+ ], `${fieldName}.strategy`);
+ const target = assertExactFields(item.target, ["platform", "environment"], `${fieldName}.target`);
+ const capabilities = assertExactFields(item.capabilities, ["shadow", "paper"], `${fieldName}.capabilities`);
+ const evidence = assertExactFields(item.evidence, [
+ "strategy", "target_data", "target_execution",
+ ], `${fieldName}.evidence`);
+ const recommendation = assertExactFields(item.recommendation, ["code", "reason_code"], `${fieldName}.recommendation`);
+ const executionReceipt = item.execution_receipt === undefined
+ ? null
+ : normalizeExecutionEvidenceReceipt(item.execution_receipt, `${fieldName}.execution_receipt`);
+ const normalized = {
+ deployment_id: normalizeControlPlaneIdentifier(item.deployment_id, `${fieldName}.deployment_id`, false),
+ strategy: {
+ candidate_id: normalizeControlPlaneIdentifier(strategy.candidate_id, `${fieldName}.strategy.candidate_id`, false),
+ candidate_kind: cleanChoice(strategy.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${fieldName}.strategy.candidate_kind`),
+ domain: cleanChoice(strategy.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.strategy.domain`),
+ strategy_revision: normalizeResearchTaskRevision(strategy.strategy_revision, `${fieldName}.strategy.strategy_revision`),
+ },
+ target: {
+ platform: cleanChoice(target.platform, EXECUTION_EVIDENCE_PLATFORMS, `${fieldName}.target.platform`),
+ environment: cleanChoice(target.environment, EXECUTION_EVIDENCE_ENVIRONMENTS, `${fieldName}.target.environment`),
+ },
+ capabilities: {
+ shadow: cleanChoice(capabilities.shadow, EXECUTION_EVIDENCE_CAPABILITIES, `${fieldName}.capabilities.shadow`),
+ paper: cleanChoice(capabilities.paper, EXECUTION_EVIDENCE_CAPABILITIES, `${fieldName}.capabilities.paper`),
+ },
+ evidence: {
+ strategy: cleanChoice(evidence.strategy, EXECUTION_EVIDENCE_STATUSES, `${fieldName}.evidence.strategy`),
+ target_data: cleanChoice(evidence.target_data, EXECUTION_EVIDENCE_STATUSES, `${fieldName}.evidence.target_data`),
+ target_execution: cleanChoice(evidence.target_execution, EXECUTION_EVIDENCE_STATUSES, `${fieldName}.evidence.target_execution`),
+ },
+ recommendation: {
+ code: cleanChoice(recommendation.code, EXECUTION_EVIDENCE_RECOMMENDATIONS, `${fieldName}.recommendation.code`),
+ reason_code: cleanChoice(recommendation.reason_code, EXECUTION_EVIDENCE_REASON_CODES, `${fieldName}.recommendation.reason_code`),
+ },
+ };
+ if (normalized.recommendation.code === "continue_autonomous_shadow" && normalized.capabilities.shadow !== "available") {
+ throw new Error(`${fieldName}.recommendation requires an available shadow capability`);
+ }
+ if (normalized.recommendation.code === "run_autonomous_paper" && normalized.capabilities.paper !== "available") {
+ throw new Error(`${fieldName}.recommendation requires an available paper capability`);
+ }
+ if (normalized.recommendation.code === "owner_limited_live_canary_decision") {
+ const statuses = Object.values(normalized.evidence);
+ if (!statuses.every((status) => status === "verified")) {
+ throw new Error(`${fieldName}.recommendation requires matching verified strategy, data, and execution evidence`);
+ }
+ }
+ if (executionReceipt !== null) {
+ const expectedExecutionStatus = ["failed", "reconciliation_required"].includes(executionReceipt.outcome)
+ ? "unavailable"
+ : (["no_signal", "no_rebalance"].includes(executionReceipt.outcome) ? "not_applicable" : "verified");
+ if (normalized.evidence.target_execution !== expectedExecutionStatus) {
+ throw new Error(`${fieldName}.execution_receipt does not match target_execution evidence`);
+ }
+ normalized.execution_receipt = executionReceipt;
+ }
+ return normalized;
+}
+
+export function normalizeExecutionEvidenceReceipt(value, fieldName) {
+ const receipt = assertExactFields(value, ["outcome", "broker_confirmation", "observed_at"], fieldName);
+ const outcome = cleanChoice(receipt.outcome, EXECUTION_RECEIPT_OUTCOMES, `${fieldName}.outcome`);
+ const confirmation = cleanChoice(
+ receipt.broker_confirmation,
+ EXECUTION_RECEIPT_CONFIRMATIONS,
+ `${fieldName}.broker_confirmation`,
+ );
+ const allowedConfirmations = {
+ not_due: ["not_applicable"],
+ no_action: ["not_applicable"],
+ no_signal: ["not_applicable"],
+ no_rebalance: ["not_applicable"],
+ risk_blocked: ["not_applicable"],
+ submitted: ["not_observed"],
+ broker_acknowledged: ["acknowledged"],
+ partially_filled: ["partially_filled"],
+ filled: ["filled"],
+ reconciliation_required: ["reconciliation_required"],
+ failed: ["not_applicable", "not_observed", "reconciliation_required"],
+ };
+ if (!allowedConfirmations[outcome].includes(confirmation)) {
+ throw new Error(`${fieldName}.broker_confirmation does not match outcome`);
+ }
+ return {
+ outcome,
+ broker_confirmation: confirmation,
+ observed_at: normalizeResearchTaskTimestamp(receipt.observed_at, `${fieldName}.observed_at`),
+ };
+}
+
+export function normalizeRuntimeTargetLifecycleSourceSnapshot(payload, fieldName = "runtime target lifecycle source snapshot") {
+ const source = assertExactFields(payload, [
+ "schema_version", "source_id", "generated_at", "computed_at", "data_status", "targets", "errors",
+ ], fieldName);
+ if (source.schema_version !== RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
+ if (!Array.isArray(source.targets) || source.targets.length > 1000) {
+ throw new Error(`${fieldName}.targets must be an array with at most 1000 items`);
+ }
+ const targets = [];
+ const seen = new Set();
+ for (const [index, item] of source.targets.entries()) {
+ const target = normalizeRuntimeTargetLifecycleTarget(item, `${fieldName}.targets[${index}]`);
+ if (seen.has(target.target_id)) throw new Error(`${fieldName}.targets contains duplicate target_id`);
+ seen.add(target.target_id);
+ targets.push(target);
+ }
+ if (dataStatus === "unavailable" && targets.length) {
+ throw new Error(`${fieldName}.targets must be empty when unavailable`);
+ }
+ return {
+ schema_version: RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION,
+ source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
+ generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
+ computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
+ data_status: dataStatus,
+ targets,
+ errors: normalizeStrategyHealthErrors(source.errors),
+ };
+}
+
+export function normalizeRuntimeTargetLifecycleTarget(value, fieldName) {
+ const item = assertRequiredAndOptionalFields(value, ["target_id", "target", "monitoring", "disposition", "no_order"], ["deployment"], fieldName);
+ const target = assertExactFields(item.target, ["platform", "configured_state", "execution_mode"], `${fieldName}.target`);
+ const monitoring = assertExactFields(item.monitoring, ["runtime_guard", "execution_heartbeat"], `${fieldName}.monitoring`);
+ const disposition = assertExactFields(item.disposition, ["code", "reason_code"], `${fieldName}.disposition`);
+ if (item.no_order !== true) throw new Error(`${fieldName}.no_order must be true`);
+ const normalized = {
+ target_id: normalizeControlPlaneIdentifier(item.target_id, `${fieldName}.target_id`, false),
+ target: {
+ platform: cleanChoice(target.platform, EXECUTION_EVIDENCE_PLATFORMS, `${fieldName}.target.platform`),
+ configured_state: cleanChoice(target.configured_state, RUNTIME_TARGET_LIFECYCLE_CONFIGURED_STATES, `${fieldName}.target.configured_state`),
+ execution_mode: cleanChoice(target.execution_mode, RUNTIME_TARGET_LIFECYCLE_EXECUTION_MODES, `${fieldName}.target.execution_mode`),
+ },
+ monitoring: {
+ runtime_guard: cleanChoice(monitoring.runtime_guard, RUNTIME_TARGET_LIFECYCLE_CHECK_STATUSES, `${fieldName}.monitoring.runtime_guard`),
+ execution_heartbeat: cleanChoice(monitoring.execution_heartbeat, RUNTIME_TARGET_LIFECYCLE_CHECK_STATUSES, `${fieldName}.monitoring.execution_heartbeat`),
+ },
+ disposition: {
+ code: cleanChoice(disposition.code, RUNTIME_TARGET_LIFECYCLE_DISPOSITIONS, `${fieldName}.disposition.code`),
+ reason_code: cleanChoice(disposition.reason_code, RUNTIME_TARGET_LIFECYCLE_REASON_CODES, `${fieldName}.disposition.reason_code`),
+ },
+ no_order: true,
+ };
+ if (item.deployment !== undefined) {
+ const observed = assertRequiredAndOptionalFields(item.deployment, ["runtime_enabled", "scheduler_state", "strategy_profile", "execution_mode"], ["observed_at"], `${fieldName}.deployment`);
+ if (observed.runtime_enabled !== null && typeof observed.runtime_enabled !== "boolean") throw new Error("deployment switch must be boolean or null");
+ normalized.deployment = {
+ ...(observed.observed_at === undefined ? {} : {observed_at: normalizeM0ResearchTimestamp(observed.observed_at, "deployment.observed_at")}),
+ runtime_enabled: observed.runtime_enabled,
+ scheduler_state: cleanChoice(observed.scheduler_state, ["enabled", "paused", "mixed", "missing", "unknown", "not_applicable"], "deployment.scheduler_state"),
+ strategy_profile: observed.strategy_profile === null ? null : cleanSlug(observed.strategy_profile, "deployment.strategy_profile"),
+ execution_mode: observed.execution_mode === null ? null : cleanChoice(observed.execution_mode, RUNTIME_TARGET_LIFECYCLE_EXECUTION_MODES, "deployment.execution_mode"),
+ };
+ }
+ const guardUnavailable = normalized.monitoring.runtime_guard === "unavailable";
+ const heartbeatUnavailable = normalized.monitoring.execution_heartbeat === "unavailable";
+ const hasAttention = normalized.monitoring.runtime_guard === "attention" || normalized.monitoring.execution_heartbeat === "attention";
+ if (normalized.target.configured_state === "disabled") {
+ if (normalized.monitoring.execution_heartbeat !== "not_applicable") {
+ throw new Error(`${fieldName}.disabled target must not claim an execution heartbeat`);
+ }
+ if (!hasAttention && !guardUnavailable && normalized.disposition.code !== "continue_disabled_validation") {
+ throw new Error(`${fieldName}.disabled target requires continue_disabled_validation`);
+ }
+ } else if (!hasAttention && !guardUnavailable && !heartbeatUnavailable && normalized.disposition.code !== "continue_enabled_monitoring") {
+ throw new Error(`${fieldName}.enabled healthy target requires continue_enabled_monitoring`);
+ }
+ if (hasAttention || guardUnavailable || heartbeatUnavailable) {
+ if (normalized.disposition.code !== "parked") throw new Error(`${fieldName}.unhealthy monitoring requires parked`);
+ }
+ return normalized;
+}
+
+export function normalizeExecutionEvidenceSummary(deployments) {
+ return {
+ deployment_count: deployments.length,
+ autonomous_shadow: deployments.filter((item) => item.recommendation.code === "continue_autonomous_shadow").length,
+ autonomous_paper: deployments.filter((item) => item.recommendation.code === "run_autonomous_paper").length,
+ owner_canary_decision: deployments.filter((item) => item.recommendation.code === "owner_limited_live_canary_decision").length,
+ parked: deployments.filter((item) => item.recommendation.code === "parked").length,
+ };
+}
+
+export function emptyExecutionEvidenceSourceSnapshot(errorCode) {
+ return {
+ schema_version: EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION,
+ source_id: "unavailable",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ deployments: [],
+ errors: [errorCode],
+ };
+}
+
+export function emptyRuntimeTargetLifecycleSourceSnapshot(errorCode) {
+ return {
+ schema_version: RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION,
+ source_id: "unavailable",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ targets: [],
+ errors: [errorCode],
+ };
+}
+
+export function emptyRuntimeTargetLifecyclePayload(errorCode) {
+ return {
+ schema_version: RUNTIME_TARGET_LIFECYCLE_DASHBOARD_SCHEMA_VERSION,
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { target_count: 0, enabled: 0, disabled: 0, attention: 0 },
+ targets: [],
+ policy: {
+ lifecycle_status_read_only: true,
+ execution_observation_read_only: true,
+ no_order: true,
+ order_or_fill_evidence: "not_collected",
+ notice: "运行目标生命周期快照尚不可用;页面不会推断目标已启用或存在订单/成交。",
+ },
+ errors: [errorCode],
+ };
+}
+
+export function emptyExecutionEvidencePayload(errorCode) {
+ return {
+ schema_version: EXECUTION_EVIDENCE_DASHBOARD_SCHEMA_VERSION,
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { deployment_count: 0, autonomous_shadow: 0, autonomous_paper: 0, owner_canary_decision: 0, parked: 0 },
+ deployments: [],
+ policy: {
+ execution_evidence_read_only: true,
+ p6_owner_decision_required: true,
+ limited_live_canary_active: false,
+ notice: "执行证据尚不可用;控制台不会推断 paper 或 live 状态。",
+ },
+ errors: [errorCode],
+ };
+}
+
+export function emptyReconciliationRecoverySourceSnapshot(errorCode) {
+ return {
+ schema_version: RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION,
+ source_id: "unavailable",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ recoveries: [],
+ errors: [errorCode],
+ };
+}
+
+export function emptyReconciliationRecoveryPayload(errorCode) {
+ return {
+ schema_version: RECONCILIATION_RECOVERY_DASHBOARD_SCHEMA_VERSION,
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { recovery_count: 0, awaiting_human_confirmation: 0, blocked: 0, confirmed: 0 },
+ recoveries: [],
+ current_reconciliation_observation: currentReconciliationObservationPresentation(),
+ policy: {
+ human_confirmation_required: true,
+ current_evidence_required: true,
+ no_order: true,
+ execution_authority_granted: false,
+ notice: "恢复核验尚不可用;控制台不会推断已恢复或已启用。",
+ },
+ errors: [errorCode],
+ };
+}
+
+export function reconciliationRecoveryStaleTtlSeconds(env) {
+ const configured = Number(env.RECONCILIATION_RECOVERY_STALE_TTL_SECONDS);
+ if (!Number.isFinite(configured) || configured < 300 || configured > 3600) {
+ return RECONCILIATION_RECOVERY_DEFAULT_STALE_TTL_SECONDS;
+ }
+ return Math.floor(configured);
+}
+
+export function executionEvidenceStaleTtlSeconds(env) {
+ const configured = Number(env.EXECUTION_EVIDENCE_STALE_TTL_SECONDS);
+ if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
+ return EXECUTION_EVIDENCE_DEFAULT_STALE_TTL_SECONDS;
+ }
+ return Math.floor(configured);
+}
+
+export function emptyControlPlanePayload(errorCode) {
+ return {
+ schema_version: "qsl_control_plane_dashboard.v1",
+ generated_at: null,
+ computed_at: null,
+ data_status: "unavailable",
+ summary: { candidate_count: 0, deferred: 0, parked: 0, owner_decision_required: 0 },
+ attention: { status: "unavailable", reason_codes: ["control_plane_source_unavailable", errorCode] },
+ candidates: [],
+ policy: { p4_p5_automation: "not_configured", p6_owner_decision_required: true, notice: "live 仍需所有者明确决定。" },
+ errors: [errorCode],
+ };
+}
+
+export function controlPlaneStaleTtlSeconds(env) {
+ const configured = Number(env.CONTROL_PLANE_STALE_TTL_SECONDS);
+ if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
+ return CONTROL_PLANE_DEFAULT_STALE_TTL_SECONDS;
+ }
+ return Math.floor(configured);
+}
+
+export async function syncStrategyProfilesConfig(env, session) {
+ const profiles = normalizeStrategyProfilesPayload(DEFAULT_STRATEGY_PROFILES, "DEFAULT_STRATEGY_PROFILES");
+ if (!hasConfigStore(env)) return { synced: false, reason: "kv_not_bound", count: profiles.length };
+ let changed = true;
+ try {
+ const current = await readConfigJson(env, STRATEGY_PROFILES_KEY);
+ if (current) {
+ const normalizedCurrent = normalizeStrategyProfilesPayload(current, STRATEGY_PROFILES_KEY);
+ changed = JSON.stringify(normalizedCurrent) !== JSON.stringify(profiles);
+ }
+ } catch {
+ changed = true;
+ }
+ let auditLogged = false;
+ if (changed) {
+ await writeConfigJson(env, STRATEGY_PROFILES_KEY, profiles);
+ try {
+ await appendAuditLog(env, {
+ ts: new Date().toISOString(),
+ login: session?.login || "",
+ action: "sync_strategy_profiles",
+ count: profiles.length,
+ });
+ auditLogged = true;
+ } catch {
+ auditLogged = false;
+ }
+ }
+ return { synced: true, changed, count: profiles.length, audit_logged: auditLogged };
+}
+
+export function updateAccountOptionsDefaultStrategy(accountOptions, inputs) {
+ const options = normalizeAccountOptionsPayload(accountOptions || {}, ACCOUNT_OPTIONS_KEY);
+ const platformOptions = options[inputs.platform] || [];
+ const rawPlatformOptions = Array.isArray(accountOptions?.[inputs.platform]) ? accountOptions[inputs.platform] : [];
+ let matched = false;
+ let changed = false;
+ const updatedPlatformOptions = platformOptions.map((option, index) => {
+ if (!accountOptionMatchesInputs(option, inputs)) return option;
+ matched = true;
+ const rawOption = rawPlatformOptions[index] && typeof rawPlatformOptions[index] === "object"
+ ? rawPlatformOptions[index]
+ : {};
+ const nextOption = { ...option };
+ let optionChanged = false;
+ if ("ibit_zscore_exit_mode" in rawOption) optionChanged = true;
+ if (inputs.plugin_mode === "none") {
+ const currentPluginMode = nextOption.plugin_mode || "none";
+ if (currentPluginMode !== inputs.plugin_mode) {
+ nextOption.plugin_mode = inputs.plugin_mode;
+ optionChanged = true;
+ }
+ }
+ if (inputs.option_overlay_mode === "enabled" || inputs.option_overlay_mode === "disabled") {
+ if (nextOption.option_overlay_mode !== inputs.option_overlay_mode) {
+ nextOption.option_overlay_mode = inputs.option_overlay_mode;
+ optionChanged = true;
+ }
+ }
+ const cashOnlyExecutionMode = cashOnlyExecutionModeFromInputs(inputs);
+ if (cashOnlyExecutionMode === "enabled" || cashOnlyExecutionMode === "disabled") {
+ if (nextOption.cash_only_execution_mode !== cashOnlyExecutionMode) {
+ nextOption.cash_only_execution_mode = cashOnlyExecutionMode;
+ optionChanged = true;
+ }
+ }
+ const dcaControls = dcaControlsFromInputs(inputs);
+ if (isDcaProfile(inputs.strategy_profile)) {
+ if (dcaControls.dca_mode && nextOption.dca_mode !== dcaControls.dca_mode) {
+ nextOption.dca_mode = dcaControls.dca_mode;
+ optionChanged = true;
+ }
+ if (
+ dcaControls.dca_base_investment_usd &&
+ nextOption.dca_base_investment_usd !== dcaControls.dca_base_investment_usd
+ ) {
+ nextOption.dca_base_investment_usd = dcaControls.dca_base_investment_usd;
+ optionChanged = true;
+ }
+ } else {
+ for (const field of ["dca_mode", "dca_base_investment_usd"]) {
+ if (field in nextOption) {
+ delete nextOption[field];
+ optionChanged = true;
+ }
+ }
+ }
+ if ("ibit_zscore_exit_mode" in nextOption) {
+ delete nextOption.ibit_zscore_exit_mode;
+ optionChanged = true;
+ }
+ changed = changed || optionChanged;
+ if (!optionChanged) return option;
+ return nextOption;
+ });
+ if (!matched) throw new Error("switch inputs do not match configured account options");
+ return {
+ options: { ...options, [inputs.platform]: updatedPlatformOptions },
+ changed,
+ };
+}
+
+export function normalizeSwitchInputs(raw) {
+ const platform = cleanChoice(raw.platform, SUPPORTED_PLATFORMS, "platform");
+ const targetName = cleanSlug(raw.target_name, "target_name");
+ const strategyProfile = cleanSlug(raw.strategy_profile, "strategy_profile").toLowerCase();
+ assertDcaPlatform(platform, strategyProfile);
+ const executionMode = cleanExecutionMode(raw.execution_mode || "live");
+ if (!supportedExecutionModesForPlatform(platform).includes(executionMode)) {
+ throw new Error(`${platform} does not support ${executionMode} control execution`);
+ }
+ const liveContinuity = normalizeLiveContinuityInputs(raw, executionMode);
+ // "current" is used only by internal deployment reconciliation to retain
+ // a service's existing plugin mount. It is deliberately not exposed as a
+ // console editing mode, where operators can still select only "none".
+ const requestedPluginMode = cleanChoice(raw.plugin_mode || "none", ["auto", "none", "current"], "plugin_mode");
+ const pluginMode = requestedPluginMode === "auto" ? "none" : requestedPluginMode;
+ if (String(raw.custom_plugin_mounts_json || "").trim()) {
+ throw new Error("legacy custom plugin mounts are retired pending a P1/P2/P3-bound signal.v2 adapter");
+ }
+ const optionOverlayMode = cleanChoice(raw.option_overlay_mode || "current", OPTION_OVERLAY_MODES, "option_overlay_mode");
+ if (optionOverlayMode === "enabled") {
+ throw new Error("option overlay is retired; migrate existing option settings and obligations explicitly");
+ }
+ const cashOnlyExecutionMode = cleanChoice(
+ raw.cash_only_execution_mode || "enabled",
+ CASH_ONLY_EXECUTION_MODES,
+ "cash_only_execution_mode",
+ );
+ const variableScope = cleanChoice(
+ raw.variable_scope || "default",
+ ["default", "repository", "environment"],
+ "variable_scope",
+ );
+ const apply = cleanBoolean(raw.apply);
+ const triggerPlatformSync = cleanBoolean(raw.trigger_platform_sync) && apply;
+ const extraVariablesJson = cleanOptionalJsonObject(raw.extra_variables_json || "", "extra_variables_json");
+ const extraVariables = extraVariablesJson ? JSON.parse(extraVariablesJson) : {};
+ const directDcaVariables = [DCA_MODE_VARIABLE, DCA_BASE_INVESTMENT_VARIABLE].filter((name) =>
+ extraVariables[name] !== undefined && String(extraVariables[name] || "").trim() !== "",
+ );
+ if (directDcaVariables.length) {
+ throw new Error("use dca_mode and dca_base_investment_usd control fields instead of DCA_MODE variables");
+ }
+ const directIbitZscoreVariables = [
+ IBIT_ZSCORE_EXIT_ENABLED_VARIABLE,
+ IBIT_ZSCORE_EXIT_MODE_VARIABLE,
+ IBIT_ZSCORE_EXIT_PARKING_SYMBOL_VARIABLE,
+ "IBIT_ZSCORE_EXIT_RISK_REDUCED_EXPOSURE",
+ "IBIT_ZSCORE_EXIT_RISK_OFF_EXPOSURE",
+ "IBIT_ZSCORE_EXIT_ALLOW_OUTSIDE_EXECUTION_WINDOW",
+ ].filter((name) => extraVariables[name] !== undefined && String(extraVariables[name] || "").trim() !== "");
+ if (directIbitZscoreVariables.length) {
+ throw new Error(
+ "IBIT_ZSCORE_EXIT variables are derived from ibit_smart_dca smart DCA mode; do not set them directly",
+ );
+ }
+ rejectResearchOnlyExtraVariables(extraVariables);
+ const directCashOnlyVariables = [
+ LEGACY_CASH_ONLY_EXECUTION_VARIABLE,
+ ...Object.values(PLATFORM_CASH_ONLY_EXECUTION_VARIABLES),
+ ].filter((name) => extraVariables[name] !== undefined && String(extraVariables[name] || "").trim() !== "");
+ if (directCashOnlyVariables.length) {
+ throw new Error("use cash_only_execution_mode instead of CASH_ONLY_EXECUTION variables");
+ }
+ const dcaExtraControls = dcaPayloadFromObject(extraVariables);
+ stripLegacyIbitZscoreExitControls(extraVariables);
+
+ const inputs = {
+ platform,
+ target_name: targetName,
+ strategy_profile: strategyProfile,
+ execution_mode: executionMode,
+ live_continuity_state: liveContinuity.state,
+ variable_scope: variableScope,
+ plugin_mode: pluginMode,
+ option_overlay_mode: optionOverlayMode,
+ service_targets_mode: "auto",
+ apply: apply ? "true" : "false",
+ trigger_platform_sync: triggerPlatformSync ? "true" : "false",
+ confirm_apply: apply ? (triggerPlatformSync ? "APPLY_AND_SYNC" : "APPLY") : "",
+ platform_sync_workflow: "sync-cloud-run-env.yml",
+ };
+
+ if (liveContinuity.state !== "NONE") {
+ inputs.live_continuity_baseline_id = liveContinuity.baseline_id;
+ inputs.live_continuity_captured_at = liveContinuity.captured_at;
+ }
+
+ addOptional(inputs, "github_environment", raw.github_environment, cleanSlug);
+ addOptional(inputs, "deployment_selector", raw.deployment_selector, cleanSlug);
+ addOptional(inputs, "account_selector", raw.account_selector, cleanCsv);
+ addOptional(inputs, "account_scope", raw.account_scope, cleanSlug);
+ addOptional(inputs, "service_name", raw.service_name, cleanSlug);
+ addOptional(inputs, "reserved_cash_ratio", raw.reserved_cash_ratio, cleanRatio);
+ addOptional(inputs, "min_reserved_cash_usd", raw.min_reserved_cash_usd, cleanNonNegativeNumber);
+ addOptional(inputs, "income_layer_start_usd", raw.income_layer_start_usd, cleanNonNegativeNumber);
+ addOptional(inputs, "income_layer_max_ratio", raw.income_layer_max_ratio, cleanRatio);
+ const rawHasDcaMode = raw.dca_mode !== undefined && raw.dca_mode !== null && String(raw.dca_mode).trim() !== "";
+ const rawHasDcaBase = raw.dca_base_investment_usd !== undefined &&
+ raw.dca_base_investment_usd !== null &&
+ String(raw.dca_base_investment_usd).trim() !== "";
+ const dcaModeValue = rawHasDcaMode ? raw.dca_mode : dcaExtraControls.dca_mode;
+ const dcaBaseInvestmentValue = rawHasDcaBase
+ ? raw.dca_base_investment_usd
+ : dcaExtraControls.dca_base_investment_usd;
+ const hasDcaMode = Boolean(String(dcaModeValue || "").trim());
+ const hasDcaBase = Boolean(String(dcaBaseInvestmentValue || "").trim());
+ if (!isDcaProfile(strategyProfile) && (hasDcaMode || hasDcaBase)) {
+ throw new Error("DCA settings are only supported for DCA strategy profiles");
+ }
+ if (isDcaProfile(strategyProfile)) {
+ if (hasDcaMode) extraVariables.dca_mode = cleanDcaMode(dcaModeValue);
+ if (hasDcaBase) extraVariables.dca_base_investment_usd = cleanPositiveNumber(
+ dcaBaseInvestmentValue,
+ "dca_base_investment_usd",
+ );
+ }
+ const cashOnlyMode = cleanChoice(
+ raw.cash_only_execution_mode || extraVariables.cash_only_execution_mode || "enabled",
+ CASH_ONLY_EXECUTION_MODES,
+ "cash_only_execution_mode",
+ );
+ if (cashOnlyMode !== "current") {
+ extraVariables.cash_only_execution_mode = cashOnlyMode;
+ }
+ if (Object.keys(extraVariables).length) inputs.extra_variables_json = JSON.stringify(extraVariables);
+ return inputs;
+}
+
+export function normalizeLiveContinuityInputs(raw, executionMode) {
+ const state = String(raw.live_continuity_state || "NONE").trim().toUpperCase();
+ if (!LIVE_CONTINUITY_STATES.includes(state)) {
+ throw new Error(`live_continuity_state must be one of ${LIVE_CONTINUITY_STATES.join(", ")}`);
+ }
+ const rawBaselineId = String(raw.live_continuity_baseline_id || "").trim();
+ const rawCapturedAt = String(raw.live_continuity_captured_at || "").trim();
+ if (state === "NONE") {
+ if (rawBaselineId || rawCapturedAt) {
+ throw new Error("live continuity baseline fields require a non-NONE live_continuity_state");
+ }
+ return { state };
+ }
+ if (executionMode !== "live") {
+ throw new Error("live continuity is only valid for live execution_mode");
+ }
+ return {
+ state,
+ baseline_id: cleanSlug(rawBaselineId, "live_continuity_baseline_id"),
+ captured_at: normalizeM0ResearchDate(rawCapturedAt, "live_continuity_captured_at"),
+ };
+}
+
+export function assertSwitchIntent(inputs) {
+ if (
+ inputs.apply !== "true" ||
+ inputs.trigger_platform_sync !== "true" ||
+ inputs.confirm_apply !== "APPLY_AND_SYNC"
+ ) {
+ throw new Error("switch endpoint requires apply=true and APPLY_AND_SYNC");
+ }
+}
+
+export function assertConfiguredAccount(inputs, accountOptions) {
+ if (!accountOptions) throw new Error("account options are not configured");
+ const matched = configuredAccountForInputs(inputs, accountOptions);
+ if (!matched) throw new Error("switch inputs do not match configured account options");
+ return matched;
+}
+
+export function configuredAccountForInputs(inputs, accountOptions) {
+ if (!accountOptions) return null;
+ const options = accountOptions[inputs.platform] || [];
+ return options.find((option) => accountOptionMatchesInputs(option, inputs)) || null;
+}
+
+export function registerLegacyContinuityAccount(env, accountOptions, inputs, strategy) {
+ if (!hasConfigStore(env)) {
+ throw new Error("switch inputs do not match configured account options");
+ }
+ if (!isEligibleLegacyContinuityInput(inputs, strategy)) {
+ throw new Error("switch inputs do not match configured account options");
+ }
+ const platformOptions = accountOptions[inputs.platform] || [];
+ if (platformOptions.some((option) => option.target_name === inputs.target_name)) {
+ throw new Error("legacy continuity account target conflicts with configured account options");
+ }
+ if (platformOptions.some((option) => option.service_name
+ && option.service_name === inputs.service_name
+ && accountOptionMatchesInputs(option, { ...inputs, target_name: option.target_name }))) {
+ throw new HttpError("deployment already has a configured account; use its existing target", 400);
+ }
+ if (platformOptions.length >= 20) {
+ throw new Error(`account options for ${inputs.platform} have reached the maximum`);
+ }
+
+ const account = cleanAccountOption(
+ {
+ key: inputs.target_name,
+ label: `Legacy continuity ${inputs.target_name}`,
+ target_name: inputs.target_name,
+ account_selector: inputs.account_selector,
+ deployment_selector: inputs.deployment_selector,
+ account_scope: inputs.account_scope,
+ service_name: inputs.service_name,
+ github_environment: inputs.github_environment,
+ variable_scope: resolvedVariableScope(inputs.variable_scope, inputs),
+ supported_domains: [strategy.domain],
+ },
+ inputs.platform,
+ platformOptions.length,
+ );
+ const options = normalizeAccountOptionsPayload(
+ { ...accountOptions, [inputs.platform]: [...platformOptions, account] },
+ ACCOUNT_OPTIONS_KEY,
+ );
+ return { options, account: options[inputs.platform].at(-1), registered: true };
+}
+
+export function assertStrategyAllowedForAccount(inputs, accountOption, strategyProfiles) {
+ const strategy = strategyProfiles.find((item) => sameStrategyProfile(item.profile, inputs.strategy_profile));
+ if (!strategy) {
+ throw new Error(`strategy ${inputs.strategy_profile} is not configured`);
+ }
+ const supportedDomains = supportedDomainsForAccount(inputs.platform, accountOption);
+ if (!supportedDomains.includes(strategy.domain)) {
+ throw new Error(
+ `strategy domain ${strategy.domain} is not supported by ${inputs.platform}/${accountOption.key}`,
+ );
+ }
+ const executionMode = cleanExecutionMode(inputs.execution_mode);
+ if (!supportedExecutionModesForPlatform(inputs.platform).includes(executionMode)) {
+ throw new Error(`${inputs.platform} does not support ${executionMode} control execution`);
+ }
+ const allowedModes = strategy.allowed_execution_modes || [];
+ if (isFrozenStrategyProfile(strategy) && !(
+ ["RECONCILE_ONLY", "RISK_REDUCTION_ONLY"].includes(inputs.live_continuity_state)
+ && isEligibleLegacyContinuityInput(inputs, strategy)
+ )) {
+ throw new HttpError(`strategy ${inputs.strategy_profile} is frozen for new selection`, 409);
+ }
+ if (executionMode === "live") {
+ if (isEligibleLegacyContinuityInput(inputs, strategy)) {
+ assertDcaPlatform(inputs.platform, inputs.strategy_profile);
+ return;
+ }
+ assertLiveSwitchAllowed(strategy, inputs.strategy_profile);
+ const lifecycleStage = cleanLifecycleStage(strategy.lifecycle_stage || "research_active");
+ if (!["live_enabled", "runtime_enabled"].includes(lifecycleStage)) {
+ throw new Error(`strategy ${inputs.strategy_profile} is not live-enabled`);
+ }
+ if (!allowedModes.includes(executionMode)) {
+ throw new Error(`strategy ${inputs.strategy_profile} is not live-enabled`);
+ }
+ if (strategy.blocked_live_reason) {
+ throw new Error(`strategy ${inputs.strategy_profile} is blocked for live: ${strategy.blocked_live_reason}`);
+ }
+ } else if (allowedModes.length && !allowedModes.includes(executionMode)) {
+ throw new Error(`strategy ${inputs.strategy_profile} does not allow ${executionMode} execution`);
+ }
+ if (inputs.option_overlay_mode === "enabled" && strategy.option_overlay_enabled !== true) {
+ throw new Error(`strategy ${inputs.strategy_profile} does not define an option overlay`);
+ }
+ assertDcaPlatform(inputs.platform, inputs.strategy_profile);
+}
+
+export function isEligibleLegacyContinuityInput(inputs, strategy) {
+ if (
+ inputs.execution_mode !== "live" ||
+ !inputs.live_continuity_state ||
+ inputs.live_continuity_state === "NONE" ||
+ !inputs.live_continuity_baseline_id ||
+ !inputs.live_continuity_captured_at ||
+ inputs.plugin_mode !== "current" ||
+ inputs.option_overlay_mode !== "current" ||
+ inputs.reserved_cash_ratio ||
+ inputs.min_reserved_cash_usd ||
+ inputs.income_layer_start_usd ||
+ inputs.income_layer_max_ratio
+ ) {
+ return false;
+ }
+ const extraVariables = inputs.extra_variables_json ? JSON.parse(inputs.extra_variables_json) : {};
+ const extraVariableNames = Object.keys(extraVariables);
+ if (
+ extraVariableNames.length > 1 ||
+ (extraVariableNames.length === 1 && (
+ extraVariableNames[0] !== "RUNTIME_TARGET_ENABLED" ||
+ extraVariables.RUNTIME_TARGET_ENABLED !== "true"
+ ))
+ ) {
+ return false;
+ }
+ const policy = strategy?.live_continuity;
+ return policy?.eligible === true && Array.isArray(policy.allowed_platforms) && policy.allowed_platforms.includes(inputs.platform);
+}
+
+export function resolvedVariableScope(value, inputs) {
+ const text = String(value || "").trim();
+ if (!text || text === "default") return defaultInputValue("variable_scope", inputs);
+ return text;
+}
+
+export function accountOptionMatchesInputs(option, inputs) {
+ if (option.target_name !== inputs.target_name) return false;
+ const fields = [
+ "account_selector",
+ "deployment_selector",
+ "account_scope",
+ "service_name",
+ "github_environment",
+ "variable_scope",
+ ];
+ for (const field of fields) {
+ if (field === "variable_scope") {
+ if (resolvedVariableScope(option[field], inputs) !== resolvedVariableScope(inputs[field], inputs)) {
+ return false;
+ }
+ continue;
+ }
+ const expected = option[field] || "";
+ const actual = inputs[field] || "";
+ if (expected && actual !== expected) return false;
+ if (!expected && actual && !["default", "auto", defaultInputValue(field, inputs)].includes(actual)) return false;
+ }
+ return true;
+}
+
+export function defaultInputValue(field, inputs) {
+ const platform = inputs.platform;
+ const targetName = inputs.target_name;
+ if (field === "variable_scope") return DEFAULT_VARIABLE_SCOPE[platform] || "repository";
+ if (field === "plugin_mode") return "none";
+ if (field === "deployment_selector") {
+ if (platform === "firstrade") return "firstrade";
+ if (platform === "qmt") return "qmt";
+ return ["sg", "hk", "paper"].includes(targetName.toLowerCase()) ? targetName.toUpperCase() : targetName;
+ }
+ if (field === "account_scope") {
+ if (platform === "firstrade") return "US";
+ if (platform === "qmt") return "CN";
+ return inputs.deployment_selector || defaultInputValue("deployment_selector", inputs);
+ }
+ if (field === "account_selector") {
+ if (platform === "firstrade") return "firstrade";
+ if (platform === "qmt") return "qmt";
+ return inputs.account_scope || defaultInputValue("account_scope", inputs);
+ }
+ if (field === "github_environment") {
+ const variableScope = inputs.variable_scope === "default"
+ ? defaultInputValue("variable_scope", inputs)
+ : inputs.variable_scope;
+ if (variableScope !== "environment") return "";
+ return platform === "longbridge" ? `longbridge-${targetName.toLowerCase()}` : targetName;
+ }
+ if (field === "service_name") {
+ if (platform === "schwab") return "charles-schwab-quant-service";
+ if (platform === "firstrade") return "firstrade-quant-service";
+ if (platform === "qmt") return "qmt-quant-service";
+ if (platform === "longbridge") return `longbridge-quant-${targetName.toLowerCase()}-service`;
+ if (platform === "ibkr") return `interactive-brokers-${targetName.toLowerCase()}-service`;
+ }
+ return "";
+}
+
+export function parseAccountOptions(raw, fieldName = "account options") {
+ const text = String(raw || "").trim();
+ if (!text) return null;
+ let payload;
+ try {
+ payload = JSON.parse(text);
+ } catch (error) {
+ throw new Error(`${fieldName} must be valid JSON`);
+ }
+ return normalizeAccountOptionsPayload(payload, fieldName);
+}
+
+export function normalizeAccountOptionsInput(value, fieldName) {
+ if (typeof value === "string") return parseAccountOptions(value, fieldName) || {};
+ return normalizeAccountOptionsPayload(value, fieldName);
+}
+
+export function parseStrategyProfiles(raw, fieldName = "strategy profiles") {
+ const text = String(raw || "").trim();
+ if (!text) return null;
+ let payload;
+ try {
+ payload = JSON.parse(text);
+ } catch (error) {
+ throw new Error(`${fieldName} must be valid JSON`);
+ }
+ return normalizeStrategyProfilesPayload(payload, fieldName);
+}
+
+export function isFrozenStrategyProfile(strategy) {
+ const profile = canonicalStrategyProfile(strategy?.profile);
+ // Normalize only the policy lookup; retain the original profile in payloads.
+ return strategy?.frozen === true || DEFAULT_STRATEGY_PROFILES.some((item) => item.profile === profile && item.frozen === true);
+}
+
+export function normalizeStrategyProfilesPayload(payload, fieldName = "strategy profiles") {
+ if (!Array.isArray(payload) || payload.length > 100) {
+ throw new Error(`${fieldName} must be an array with at most 100 items`);
+ }
+
+ const result = [];
+ const seen = new Set();
+ for (const [index, item] of payload.entries()) {
+ if (!item || Array.isArray(item) || typeof item !== "object") {
+ throw new Error(`${fieldName}[${index}] must be an object`);
+ }
+ const profile = cleanCurrentStrategy(item.profile || item.strategy_profile);
+ if (!profile) throw new Error(`${fieldName}[${index}].profile is invalid`);
+ if (seen.has(profile)) continue;
+ seen.add(profile);
+ const entry = {
+ profile,
+ label: cleanLabel(item.label || item.display_name || profile, `${fieldName}[${index}].label`),
+ runtime_enabled: cleanProfileBoolean(item.runtime_enabled ?? false),
+ };
+ addConfigOptional(
+ entry,
+ "label_en",
+ item.label_en || item.display_name_en || item.label,
+ cleanLabel,
+ );
+ addConfigOptional(
+ entry,
+ "label_zh",
+ item.label_zh || item.display_name_zh,
+ cleanLabel,
+ );
+ const rawDomain = typeof item.domain === "string" ? item.domain.trim() : "";
+ entry.domain = cleanStrategyDomain(rawDomain || "us_equity", `${fieldName}[${index}].domain`);
+ Object.defineProperty(entry, "domain_explicit", { value: rawDomain !== "", enumerable: false });
+ if (isFrozenStrategyProfile(item)) entry.frozen = true;
+ const sourceLifecycleStage = item.lifecycle_stage || item.lifecycleStage;
+ const canSwitchLive = cleanOptionalBoolean(item.can_switch_live);
+ if (canSwitchLive !== null) entry.can_switch_live = canSwitchLive;
+ const allowedExecutionModes = cleanAllowedExecutionModes(item.allowed_execution_modes);
+ if (allowedExecutionModes.length) entry.allowed_execution_modes = allowedExecutionModes;
+ if (sourceLifecycleStage) {
+ entry.lifecycle_stage = canonicalLifecycleStage(sourceLifecycleStage, {
+ runtimeEnabled: entry.runtime_enabled === true,
+ canSwitchLive: canSwitchLive === true,
+ allowedExecutionModes,
+ });
+ }
+ addConfigOptional(entry, "blocked_live_reason", item.blocked_live_reason, cleanLabel);
+ if (item.live_continuity !== undefined && item.live_continuity !== null) {
+ entry.live_continuity = normalizeLiveContinuityPolicy(
+ item.live_continuity,
+ `${fieldName}[${index}].live_continuity`,
+ );
+ }
+ if (item.research_candidate_identity !== undefined && item.research_candidate_identity !== null) {
+ entry.research_candidate_identity = normalizeResearchCandidateIdentity(
+ item.research_candidate_identity,
+ `${fieldName}[${index}].research_candidate_identity`,
+ profile,
+ );
+ }
+ addConfigOptional(entry, "latest_evidence_status", item.latest_evidence_status, cleanLifecycleStage);
+ addConfigOptional(entry, "plugin_gate_status", item.plugin_gate_status, cleanLifecycleStage);
+ // DCA detection: accept from item payload OR hardcoded DCA_PROFILE_CONFIG
+ const dcaEnabled = item.dca_enabled === true || Boolean(DCA_PROFILE_CONFIG[profile]);
+ if (dcaEnabled) {
+ const dcaDefaults = DCA_PROFILE_CONFIG[profile] || null;
+ entry.dca_enabled = true;
+ entry.dca_default_mode = cleanDcaMode(item.dca_default_mode || item.default_dca_mode || dcaDefaults?.default_mode || "fixed");
+ entry.dca_default_base_investment_usd = cleanPositiveNumber(
+ item.dca_default_base_investment_usd ||
+ item.default_dca_base_investment_usd ||
+ dcaDefaults?.default_base_investment_usd ||
+ "1000",
+ `${fieldName}[${index}].dca_default_base_investment_usd`,
+ );
+ }
+ // Pass through combo_enabled and combo_mode from item payload
+ if (item.combo_enabled === true) {
+ entry.combo_enabled = true;
+ entry.combo_mode = String(item.combo_mode || "dynamic").trim() || "dynamic";
+ }
+ const incomeLayerConfig = incomeLayerConfigFromProfileItem(item, `${fieldName}[${index}]`);
+ if (incomeLayerConfig) Object.assign(entry, incomeLayerConfig);
+ const optionOverlayConfig = optionOverlayConfigFromProfileItem(item, `${fieldName}[${index}]`);
+ if (optionOverlayConfig) Object.assign(entry, optionOverlayConfig);
+ result.push(entry);
+ }
+ return result;
+}
+
+export function normalizeResearchCandidateIdentity(value, fieldName, profile) {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ assertExactFields(value, ["candidate_id", "config_sha256"], fieldName);
+ const candidateId = cleanCurrentStrategy(value.candidate_id);
+ if (!candidateId || candidateId !== profile) {
+ throw new Error(`${fieldName}.candidate_id must match profile`);
+ }
+ const configSha256 = String(value.config_sha256 || "").trim().toLowerCase();
+ if (!/^[0-9a-f]{64}$/.test(configSha256)) {
+ throw new Error(`${fieldName}.config_sha256 must be a 64-character sha256`);
+ }
+ return { candidate_id: candidateId, config_sha256: configSha256 };
+}
+
+export function normalizeLiveContinuityPolicy(value, fieldName) {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ const unsupported = Object.keys(value).filter((key) => !["eligible", "allowed_platforms"].includes(key));
+ if (unsupported.length) {
+ throw new Error(`${fieldName} contains unsupported fields: ${unsupported.sort().join(", ")}`);
+ }
+ if (typeof value.eligible !== "boolean") {
+ throw new Error(`${fieldName}.eligible must be boolean`);
+ }
+ if (!Array.isArray(value.allowed_platforms)) {
+ throw new Error(`${fieldName}.allowed_platforms must be an array`);
+ }
+ const allowedPlatforms = value.allowed_platforms.map((platform) =>
+ cleanChoice(platform, SUPPORTED_PLATFORMS, `${fieldName}.allowed_platforms`),
+ );
+ if (new Set(allowedPlatforms).size !== allowedPlatforms.length) {
+ throw new Error(`${fieldName}.allowed_platforms must not contain duplicates`);
+ }
+ if (value.eligible && !allowedPlatforms.length) {
+ throw new Error(`${fieldName}.eligible requires allowed_platforms`);
+ }
+ return { eligible: value.eligible, allowed_platforms: allowedPlatforms };
+}
+
+export function rejectResearchOnlyExtraVariables(extraVariables) {
+ const blocked = [
+ ...LEGACY_INCOME_LAYER_CONTROL_FIELDS,
+ ...LEGACY_INCOME_LAYER_VARIABLES,
+ ...OPTION_OVERLAY_CONTROL_FIELDS,
+ ...OPTION_OVERLAY_VARIABLES,
+ ].filter((name) => extraVariables[name] !== undefined);
+ if (blocked.length) {
+ throw new Error(
+ `direct option overlay settings and legacy income controls are research-only: ${blocked.join(", ")}`,
+ );
+ }
+}
+
+export function incomeLayerConfigFromProfileItem(item, fieldName) {
+ const hasIncomeLayerConfig = [
+ "income_layer_enabled",
+ "income_layer_start_usd",
+ "income_layer_max_ratio",
+ "income_layer_allocations",
+ ].some((field) => item[field] !== undefined && item[field] !== null && String(item[field]).trim() !== "");
+ if (!hasIncomeLayerConfig) return null;
+ const enabled = item.income_layer_enabled === undefined || item.income_layer_enabled === null
+ ? true
+ : cleanProfileBoolean(item.income_layer_enabled);
+ if (!enabled) return { income_layer_enabled: false };
+ return {
+ income_layer_enabled: true,
+ income_layer_start_usd: cleanNonNegativeNumber(
+ item.income_layer_start_usd,
+ `${fieldName}.income_layer_start_usd`,
+ ),
+ income_layer_max_ratio: cleanRatio(item.income_layer_max_ratio, `${fieldName}.income_layer_max_ratio`),
+ income_layer_allocations: cleanIncomeLayerAllocations(
+ item.income_layer_allocations,
+ `${fieldName}.income_layer_allocations`,
+ ),
+ };
+}
+
+export function optionOverlayConfigFromProfileItem(item, fieldName) {
+ const hasOptionOverlayConfig = OPTION_OVERLAY_PROFILE_FIELDS.some((field) =>
+ item[field] !== undefined && item[field] !== null && String(item[field]).trim() !== "",
+ );
+ if (!hasOptionOverlayConfig) return null;
+ const enabled = item.option_overlay_enabled === undefined || item.option_overlay_enabled === null
+ ? true
+ : cleanProfileBoolean(item.option_overlay_enabled);
+ const result = { option_overlay_enabled: enabled };
+ addConfigOptional(result, "option_overlay_live_gate", item.option_overlay_live_gate || (enabled ? "promotion_required" : "disabled"), (value, field) =>
+ cleanChoice(value, ["promotion_required", "live_allowed", "disabled"], field),
+ );
+ addConfigOptional(result, "option_overlay_live_status", item.option_overlay_live_status || (enabled ? "research_only" : "disabled"), (value, field) =>
+ cleanChoice(value, ["research_only", "live_allowed", "disabled"], field),
+ );
+ if (!enabled) return result;
+
+ addOptionalOptionFamilyConfig(result, item, "growth", fieldName);
+ addOptionalOptionFamilyConfig(result, item, "income", fieldName);
+ return result;
+}
+
+export function addOptionalOptionFamilyConfig(target, item, family, fieldName) {
+ const prefix = `option_${family}_overlay`;
+ const enabledField = `${prefix}_enabled`;
+ if (item[enabledField] === undefined || item[enabledField] === null || String(item[enabledField]).trim() === "") {
+ return;
+ }
+ const enabled = cleanProfileBoolean(item[enabledField]);
+ target[enabledField] = enabled;
+ if (!enabled) return;
+
+ target[`${prefix}_recipe`] = cleanSlug(item[`${prefix}_recipe`], `${fieldName}.${prefix}_recipe`);
+ target[`${prefix}_start_usd`] = cleanNonNegativeNumber(
+ item[`${prefix}_start_usd`],
+ `${fieldName}.${prefix}_start_usd`,
+ );
+ if (family === "growth") {
+ target.option_growth_overlay_nav_budget_ratio = cleanRatio(
+ item.option_growth_overlay_nav_budget_ratio,
+ `${fieldName}.option_growth_overlay_nav_budget_ratio`,
+ );
+ } else {
+ target.option_income_overlay_nav_risk_ratio = cleanRatio(
+ item.option_income_overlay_nav_risk_ratio,
+ `${fieldName}.option_income_overlay_nav_risk_ratio`,
+ );
+ }
+}
+
+export function cleanIncomeLayerAllocations(value, fieldName) {
+ if (!value || Array.isArray(value) || typeof value !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ const result = {};
+ let total = 0;
+ for (const [rawSymbol, rawWeight] of Object.entries(value)) {
+ const symbol = String(rawSymbol || "").trim().toUpperCase();
+ if (!/^[A-Z0-9.-]{1,12}$/.test(symbol)) throw new Error(`${fieldName} contains an invalid symbol`);
+ const weight = Number(cleanPositiveNumber(rawWeight, `${fieldName}.${symbol}`));
+ total += weight;
+ result[symbol] = weight;
+ }
+ if (!Object.keys(result).length || total <= 0) throw new Error(`${fieldName} must contain positive allocations`);
+ return result;
+}
+
+export function cleanProfileBoolean(value) {
+ if (value === true || value === "true" || value === "1" || value === 1) return true;
+ if (value === false || value === "false" || value === "0" || value === 0) return false;
+ throw new Error("runtime_enabled must be boolean");
+}
+
+export function normalizeAccountOptionsPayload(payload, fieldName = "account options") {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+
+ // Structural gate from account_options_schema.js; cleanAccountOption keeps
+ // console-specific enrichment (domain inference, mode defaults, length caps).
+ validateAccountOptionsSchemaOrThrow(payload, fieldName);
+
+ const result = {};
+ for (const platform of SUPPORTED_PLATFORMS) {
+ const items = payload[platform];
+ if (items === undefined) continue;
+ if (!Array.isArray(items) || items.length > 20) {
+ throw new Error(`${fieldName}.${platform} must be an array with at most 20 items`);
+ }
+ result[platform] = items.map((item, index) => cleanAccountOption(item, platform, index));
+ }
+ return result;
+}
+
+export function cleanAccountOption(item, platform, index) {
+ if (!item || Array.isArray(item) || typeof item !== "object") {
+ throw new Error(`account option ${platform}[${index}] must be an object`);
+ }
+ const key = cleanSlug(item.key || item.target_name || `${platform}-${index}`, "account key");
+ const label = cleanLabel(item.label || item.target_name || key, "account label");
+ const option = {
+ key,
+ label,
+ target_name: cleanSlug(item.target_name || key, "target_name"),
+ };
+ addConfigOptional(option, "account_selector", item.account_selector, cleanCsv);
+ addConfigOptional(option, "deployment_selector", item.deployment_selector, cleanSlug);
+ addConfigOptional(option, "account_scope", item.account_scope, cleanSlug);
+ addConfigOptional(option, "service_name", item.service_name, cleanSlug);
+ addConfigOptional(option, "runtime_status_target_id", item.runtime_status_target_id, cleanSlug);
+ addConfigOptional(option, "broker_environment", item.broker_environment, normalizeBrokerEnvironment);
+ addConfigOptional(option, "default_execution_mode", item.default_execution_mode, cleanExecutionMode);
+ addConfigOptional(option, "default_strategy_profile", item.default_strategy_profile, cleanSlug);
+ addConfigOptional(
+ option,
+ "cash_currency",
+ item.cash_currency || item.market_currency || item.trading_currency,
+ cleanCashCurrency,
+ );
+ addConfigOptional(option, "github_environment", item.github_environment, cleanSlug);
+ addConfigOptional(option, "variable_scope", item.variable_scope, (value, field) =>
+ cleanChoice(value || "default", ["default", "repository", "environment"], field),
+ );
+ addConfigOptional(option, "plugin_mode", item.plugin_mode, (value, field) =>
+ cleanChoice(value || "auto", ["auto", "none"], field),
+ );
+ addConfigOptional(option, "option_overlay_mode", item.option_overlay_mode, (value, field) =>
+ cleanChoice(value || "enabled", OPTION_OVERLAY_MODES, field),
+ );
+ addConfigOptional(option, "cash_only_execution_mode", item.cash_only_execution_mode, (value, field) =>
+ cleanChoice(value || "enabled", CASH_ONLY_EXECUTION_MODES, field),
+ );
+ addConfigOptional(option, "dca_mode", item.dca_mode, cleanDcaMode);
+ addConfigOptional(option, "dca_base_investment_usd", item.dca_base_investment_usd, cleanPositiveNumber);
+ option.supported_domains = shouldInferSupportedDomains(item.supported_domains)
+ ? inferAccountSupportedDomains(platform, option)
+ : normalizeSupportedDomains(item.supported_domains, `account option ${platform}[${index}].supported_domains`);
+ return option;
+}
+
+export function shouldInferSupportedDomains(value) {
+ if (value === undefined || value === null) return true;
+ if (Array.isArray(value)) return value.length === 0;
+ return String(value).trim() === "";
+}
+
+export function supportedDomainsForAccount(platform, option) {
+ const platformDomains = inferAccountSupportedDomains(platform, option || {});
+ if (Array.isArray(option?.supported_domains) && option.supported_domains.length) {
+ return normalizeSupportedDomains(option.supported_domains, "supported_domains")
+ .filter((domain) => platformDomains.includes(domain));
+ }
+ return platformDomains;
+}
+
+export function inferAccountSupportedDomains(platform, option) {
+ void option;
+ const domains = PLATFORM_CONFIG[platform]?.supported_domains;
+ return Array.isArray(domains) ? [...domains] : [];
+}
+
+export function platformRepositories(env) {
+ return resolvePlatformRepositories(env);
+}
+
+export function normalizeSupportedDomains(value, fieldName) {
+ const items = Array.isArray(value)
+ ? value
+ : String(value || "").split(/[\s,;]+/);
+ if (!items.length || items.length > SUPPORTED_STRATEGY_DOMAINS.length) {
+ throw new Error(`${fieldName} must list one or more strategy domains`);
+ }
+ const result = [];
+ for (const item of items) {
+ const domain = cleanStrategyDomain(item, fieldName);
+ if (!result.includes(domain)) result.push(domain);
+ }
+ if (!result.length) throw new Error(`${fieldName} must list one or more strategy domains`);
+ return result;
+}
+
+export function cleanStrategyDomain(value, fieldName) {
+ return cleanChoice(value, SUPPORTED_STRATEGY_DOMAINS, fieldName);
+}
+
+export function cleanCashCurrency(value, fieldName) {
+ return cleanChoice(String(value || "").trim().toUpperCase(), ["USD", "HKD", "CNY"], fieldName);
+}
+
+export function addConfigOptional(target, key, value, cleaner) {
+ if (value === undefined || value === null || String(value).trim() === "") return;
+ target[key] = cleaner(value, key);
+}
+
+export function addOptional(target, key, value, cleaner) {
+ if (value === undefined || value === null || String(value).trim() === "") return;
+ target[key] = cleaner(value, key);
+}
+
+export function cleanChoice(value, allowed, field) {
+ const text = String(value || "").trim();
+ if (!allowed.includes(text)) throw new Error(`${field} is invalid`);
+ return text;
+}
+
+export function isDcaProfile(profile) {
+ return Boolean(DCA_PROFILE_CONFIG[canonicalStrategyProfile(profile)]);
+}
+
+export function assertDcaPlatform(platform, strategyProfile) {
+ if (isDcaProfile(strategyProfile) && !DCA_SUPPORTED_PLATFORMS.has(platform)) {
+ throw new Error(
+ `DCA strategy profiles are not supported on ${platform}; got strategy_profile=${strategyProfile}`,
+ );
+ }
+}
+
+export function cleanDcaMode(value, field = "dca_mode") {
+ const mode = String(value || "").trim().toLowerCase();
+ const aliases = {
+ ordinary: "fixed",
+ ordinary_dca: "fixed",
+ fixed_dca: "fixed",
+ smart_dca: "smart",
+ };
+ const normalized = aliases[mode] || mode;
+ return cleanChoice(normalized, ["fixed", "smart"], field);
+}
+
+export function cleanBoolean(value) {
+ if (value === true || value === "true") return true;
+ if (value === false || value === "false" || value === "" || value === undefined || value === null) return false;
+ throw new Error("boolean input is invalid");
+}
+
+export function cleanRatio(value, field) {
+ const text = cleanNumberText(value, field);
+ const numeric = Number(text);
+ if (numeric < 0 || numeric > 1) throw new Error(`${field} must be between 0 and 1`);
+ return text;
+}
+
+export function cleanNonNegativeNumber(value, field) {
+ const text = cleanNumberText(value, field);
+ if (Number(text) < 0) throw new Error(`${field} must be non-negative`);
+ return text;
+}
+
+export function cleanPositiveNumber(value, field) {
+ const text = cleanNumberText(value, field);
+ if (Number(text) <= 0) throw new Error(`${field} must be greater than 0`);
+ return text;
+}
+
+export function cleanNumberText(value, field) {
+ const text = String(value || "").trim();
+ if (!text || text.length > 32 || !/^(?:\d+|\d*\.\d+)$/.test(text)) {
+ throw new Error(`${field} must be a finite decimal number`);
+ }
+ const numeric = Number(text);
+ if (!Number.isFinite(numeric)) throw new Error(`${field} must be finite`);
+ return text;
+}
+
+export function cleanSlug(value, field) {
+ const text = String(value || "").trim();
+ if (!text || text.length > 120 || !/^[A-Za-z0-9._=-]+$/.test(text)) {
+ throw new Error(`${field} must use letters, numbers, dot, underscore, dash, or equals`);
+ }
+ return text;
+}
+
+export function cleanRepositoryName(value, field) {
+ const text = String(value || "").trim();
+ if (!text || text.length > 160 || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(text)) {
+ throw new Error(`${field} must be owner/repo`);
+ }
+ return text;
+}
+
+export function cleanLabel(value, field) {
+ const text = String(value || "").trim();
+ if (!text || text.length > 80 || /[<>{}]/.test(text)) {
+ throw new Error(`${field} is invalid`);
+ }
+ return text;
+}
+
+export function cleanLifecycleStage(value, field = "lifecycle_stage") {
+ const text = String(value || "").trim().toLowerCase();
+ if (!text || text.length > 80 || !/^[a-z0-9._-]+$/.test(text)) {
+ throw new Error(`${field} is invalid`);
+ }
+ return text;
+}
+
+export function canonicalLifecycleStage(value, deployment = {}) {
+ const stage = cleanLifecycleStage(value);
+ // Keep runtime_enabled as a first-class catalog stage so bundled SSOT and
+ // /api/strategy-profiles readback stay bit-identical for deploy verification.
+ if (["research_active", "shadow_active", "paper_active", "live_candidate", "live_enabled", "runtime_enabled"].includes(stage)) {
+ return stage;
+ }
+ if (["research", "research_backtest_only", "ai_monitored_candidate"].includes(stage)) return "research_active";
+ if (stage === "shadow_candidate") return "shadow_active";
+ void deployment;
+ throw new Error(`lifecycle_stage ${stage} is unsupported`);
+}
+
+export function cleanAllowedExecutionModes(value) {
+ const items = Array.isArray(value)
+ ? value
+ : String(value || "").split(/[,\s/|]+/);
+ const modes = [];
+ for (const item of items) {
+ const mode = String(item || "").trim().toLowerCase();
+ if (!mode) continue;
+ if (!["live", "paper", "dry_run"].includes(mode)) {
+ throw new Error(`allowed_execution_modes contains unsupported mode ${mode}`);
+ }
+ if (!modes.includes(mode)) modes.push(mode);
+ }
+ return modes;
+}
+
+export function cleanExecutionMode(value) {
+ const mode = cleanChoice(value || "live", ["live", "paper", "dry_run"], "execution_mode");
+ return mode === "paper" ? "dry_run" : mode;
+}
+
+export function supportedExecutionModesForPlatform(platform) {
+ const modes = PLATFORM_CONFIG[platform]?.supported_execution_modes;
+ if (!Array.isArray(modes)) return [];
+ return modes.filter((mode) => mode === "live" || mode === "dry_run");
+}
+
+export function requireSameOrigin(request, options = {}) {
+ const origin = request.headers.get("Origin");
+ if (!origin) {
+ if (options.requireOrigin) throw new HttpError("Origin header is required", 403);
+ return;
+ }
+ if (origin !== new URL(request.url).origin) throw new HttpError("cross-origin request rejected", 403);
+}
+
+export const deskAuth = createDeskAuth({ readSession, requireSameOrigin });
+
+export async function fetchGithubVariables(token, repository, scope, githubEnvironment, { reportReadErrors = false, onReadFailure = () => {} } = {}) {
+ const apiUrl = githubVariablesUrl(repository, scope, githubEnvironment);
+ const values = new Map();
+ // Evidence-aware readers opt in. Other callers retain their existing fallback.
+ const failed = (reason = "read_failed") => { onReadFailure(reason); return reportReadErrors ? null : new Map(); };
+ if (!apiUrl) return failed();
+ try {
+ // Follow the variable-list pages, never arbitrary URLs returned by an upstream.
+ for (let page = 1; ; page += 1) {
+ const response = await fetchWithTimeout(`${apiUrl}?per_page=100&page=${page}`, {
+ headers: githubHeaders(token),
+ });
+ if (!response.ok) return failed([401, 403].includes(response.status) ? "permission_denied" : "read_failed");
+ const payload = await response.json();
+ if (!Array.isArray(payload?.variables)) return failed();
+ for (const item of payload.variables) {
+ if (typeof item.name === "string" && typeof item.value === "string") values.set(item.name, item.value);
+ }
+ if (!response.headers.get("Link")?.includes('rel="next"')) return values;
+ }
+ } catch {
+ return failed();
+ }
+}
+
+
+export function githubVariablesUrl(repository, scope, githubEnvironment) {
+ const [owner, repo] = String(repository || "").split("/");
+ if (!owner || !repo) return "";
+ const base = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
+ if (scope === "environment") {
+ if (!githubEnvironment) return "";
+ return `${base}/environments/${encodeURIComponent(githubEnvironment)}/variables`;
+ }
+ return `${base}/actions/variables`;
+}
+
+export function resolveVariableScope(platform, option) {
+ const configured = String(option?.variable_scope || "").trim();
+ if (configured && configured !== "default") return configured;
+ return DEFAULT_VARIABLE_SCOPE[platform] || "repository";
+}
+
+export function resolveGithubEnvironment(platform, option, variableScope) {
+ if (variableScope !== "environment") return "";
+ const configured = String(option?.github_environment || "").trim();
+ if (configured) return configured;
+ const targetName = String(option?.target_name || option?.key || "").trim();
+ if (!targetName) return "";
+ if (platform === "longbridge") return `longbridge-${targetName.toLowerCase()}`;
+ return targetName;
+}
+
+export function runtimeTargetFromServiceTargets(rawValue, platform, option) {
+ const payload = parseJsonValue(rawValue);
+ const targets = Array.isArray(payload)
+ ? payload
+ : (Array.isArray(payload?.targets) ? payload.targets : []);
+ const matches = [];
+ for (const entry of targets) {
+ if (!entry || Array.isArray(entry) || typeof entry !== "object") continue;
+ const runtimeTarget = entry.runtime_target && typeof entry.runtime_target === "object"
+ ? entry.runtime_target
+ : {};
+ if (!runtimeTargetMatchesAccount(runtimeTarget, platform, option, entry)) continue;
+ // Match deployment identity before reading overrides. The deploy planner
+ // supports nested env values and gives explicit top-level values precedence.
+ const nestedEnv = entry.env && typeof entry.env === "object" && !Array.isArray(entry.env)
+ ? entry.env : {};
+ const settings = { ...nestedEnv, ...entry };
+ matches.push({
+ ...runtimeTarget,
+ strategy_profile: runtimeTarget.strategy_profile || entry.strategy_profile,
+ ...reservedCashPayloadFromObject(platform, settings),
+ ...incomeLayerPayloadFromObject(settings),
+ ...optionOverlayPayloadFromObject(settings),
+ ...runtimeTargetEnabledPayloadFromObject(settings),
+ ...dcaPayloadFromObject(settings),
+ ...cashOnlyPayloadFromObject(platform, settings),
+ });
+ }
+ return matches.length === 1 ? matches[0] : null;
+}
+
+export async function readCashOnlyVariables({ platform, repository, variableScope, githubEnvironment, readVariable }) {
+ const platformVariable = PLATFORM_CASH_ONLY_EXECUTION_VARIABLES[platform];
+ const [platformValue, legacyValue] = await Promise.all([
+ readVariable(repository, variableScope, githubEnvironment, platformVariable),
+ readVariable(repository, variableScope, githubEnvironment, LEGACY_CASH_ONLY_EXECUTION_VARIABLE),
+ ]);
+ return cashOnlyPayloadFromValues(platformValue ?? legacyValue);
+}
+
+export function cashOnlyPayloadFromObject(platform, payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
+ return cashOnlyPayloadFromValues(
+ payload[PLATFORM_CASH_ONLY_EXECUTION_VARIABLES[platform]] ??
+ payload[LEGACY_CASH_ONLY_EXECUTION_VARIABLE] ??
+ payload.cash_only_execution,
+ );
+}
+
+export function cashOnlyPayloadFromValues(value) {
+ const enabled = cleanOptionalBoolean(value);
+ if (enabled === null) return {};
+ return { cash_only_execution: enabled };
+}
+
+export async function readReservedCashVariables({ platform, repository, variableScope, githubEnvironment, readVariable }) {
+ const [floorValue, ratioValue] = await Promise.all([
+ readVariable(repository, variableScope, githubEnvironment, PLATFORM_MIN_RESERVED_CASH_VARIABLES[platform]),
+ readVariable(repository, variableScope, githubEnvironment, PLATFORM_RESERVED_CASH_RATIO_VARIABLES[platform]),
+ ]);
+ return reservedCashPayloadFromValues(floorValue, ratioValue);
+}
+
+export async function readIncomeLayerVariables({ repository, variableScope, githubEnvironment, readVariable }) {
+ const [enabledValue, startUsdValue, maxRatioValue] = await Promise.all([
+ readVariable(repository, variableScope, githubEnvironment, INCOME_LAYER_ENABLED_VARIABLE),
+ readVariable(repository, variableScope, githubEnvironment, INCOME_LAYER_START_USD_VARIABLE),
+ readVariable(repository, variableScope, githubEnvironment, INCOME_LAYER_MAX_RATIO_VARIABLE),
+ ]);
+ return incomeLayerPayloadFromValues(enabledValue, startUsdValue, maxRatioValue);
+}
+
+export async function readOptionOverlayVariables({ repository, variableScope, githubEnvironment, readVariable }) {
+ const enabledValue = await readVariable(repository, variableScope, githubEnvironment, OPTION_OVERLAY_ENABLED_VARIABLE);
+ return optionOverlayPayloadFromValue(enabledValue);
+}
+
+export async function readRuntimeTargetEnabledVariable({ repository, variableScope, githubEnvironment, readVariable }) {
+ const value = await readVariable(repository, variableScope, githubEnvironment, RUNTIME_TARGET_ENABLED_VARIABLE);
+ return runtimeTargetEnabledPayloadFromValue(value);
+}
+
+export async function readDcaVariables({ repository, variableScope, githubEnvironment, readVariable }) {
+ const [modeValue, baseInvestmentValue] = await Promise.all([
+ readVariable(repository, variableScope, githubEnvironment, DCA_MODE_VARIABLE),
+ readVariable(repository, variableScope, githubEnvironment, DCA_BASE_INVESTMENT_VARIABLE),
+ ]);
+ return dcaPayloadFromValues(modeValue, baseInvestmentValue);
+}
+
+export function reservedCashPayloadFromObject(platform, payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
+ return reservedCashPayloadFromValues(
+ payload[PLATFORM_MIN_RESERVED_CASH_VARIABLES[platform]] ??
+ payload.min_reserved_cash_usd ??
+ payload.reserved_cash_floor_usd,
+ payload[PLATFORM_RESERVED_CASH_RATIO_VARIABLES[platform]] ??
+ payload.reserved_cash_ratio,
+ );
+}
+
+export function reservedCashPayloadFromValues(floorValue, ratioValue) {
+ const result = {};
+ const floor = cleanCurrentNonNegativeNumber(floorValue);
+ const ratio = cleanCurrentRatio(ratioValue);
+ if (floor) result.min_reserved_cash_usd = floor;
+ if (ratio) result.reserved_cash_ratio = ratio;
+ return result;
+}
+
+export function incomeLayerPayloadFromObject(payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
+ return incomeLayerPayloadFromValues(
+ payload[INCOME_LAYER_ENABLED_VARIABLE] ?? payload.income_layer_enabled,
+ payload[INCOME_LAYER_START_USD_VARIABLE] ?? payload.income_layer_start_usd,
+ payload[INCOME_LAYER_MAX_RATIO_VARIABLE] ?? payload.income_layer_max_ratio,
+ );
+}
+
+export function incomeLayerPayloadFromValues(enabledValue, startUsdValue, maxRatioValue) {
+ const result = {};
+ const enabled = cleanOptionalBoolean(enabledValue);
+ const startUsd = cleanCurrentNonNegativeNumber(startUsdValue);
+ const maxRatio = cleanCurrentRatio(maxRatioValue);
+ if (enabled !== null) result.income_layer_enabled = enabled;
+ if (startUsd) result.income_layer_start_usd = startUsd;
+ if (maxRatio) result.income_layer_max_ratio = maxRatio;
+ return result;
+}
+
+export function optionOverlayPayloadFromObject(payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
+ return optionOverlayPayloadFromValue(
+ payload[OPTION_OVERLAY_ENABLED_VARIABLE] ?? payload.option_overlay_enabled,
+ );
+}
+
+export function optionOverlayPayloadFromValue(value) {
+ const enabled = cleanOptionalBoolean(value);
+ return enabled === null ? {} : { option_overlay_enabled: enabled };
+}
+
+export function runtimeTargetEnabledPayloadFromObject(payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
+ return runtimeTargetEnabledPayloadFromValue(
+ payload[RUNTIME_TARGET_ENABLED_VARIABLE] ?? payload.runtime_target_enabled,
+ );
+}
+
+export function runtimeTargetEnabledPayloadFromValue(value) {
+ const enabled = cleanOptionalBoolean(value);
+ return enabled === null ? {} : { runtime_target_enabled: enabled };
+}
+
+export function dcaPayloadFromObject(payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
+ return dcaPayloadFromValues(
+ payload[DCA_MODE_VARIABLE] ?? payload.dca_mode,
+ payload[DCA_BASE_INVESTMENT_VARIABLE] ??
+ payload.dca_base_investment_usd ??
+ payload.base_investment_usd,
+ );
+}
+
+export function stripLegacyIbitZscoreExitControls(payload) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") return;
+ for (const field of [
+ "ibit_zscore_exit_mode",
+ "ibit_zscore_exit_enabled",
+ "ibit_zscore_exit_parking_symbol",
+ "ibit_zscore_exit_risk_reduced_exposure",
+ "ibit_zscore_exit_risk_off_exposure",
+ "ibit_zscore_exit_allow_outside_execution_window",
+ ]) {
+ delete payload[field];
+ }
+}
+
+export function dcaPayloadFromValues(modeValue, baseInvestmentValue) {
+ const result = {};
+ const mode = cleanCurrentDcaMode(modeValue);
+ const baseInvestmentUsd = cleanCurrentPositiveNumber(baseInvestmentValue);
+ if (mode) result.dca_mode = mode;
+ if (baseInvestmentUsd) result.dca_base_investment_usd = baseInvestmentUsd;
+ return result;
+}
+
+export function dcaControlsFromInputs(inputs) {
+ const payload = inputs?.extra_variables_json ? JSON.parse(inputs.extra_variables_json) : {};
+ return {
+ ...dcaPayloadFromObject(payload),
+ ...dcaPayloadFromObject(inputs),
+ };
+}
+
+export function cashOnlyExecutionModeFromInputs(inputs) {
+ const direct = String(inputs?.cash_only_execution_mode || "").trim().toLowerCase();
+ if (direct === "enabled" || direct === "disabled") return direct;
+ try {
+ const payload = inputs?.extra_variables_json ? JSON.parse(inputs.extra_variables_json) : {};
+ const mode = String(payload.cash_only_execution_mode || "").trim().toLowerCase();
+ return mode === "enabled" || mode === "disabled" ? mode : "";
+ } catch {
+ return "";
+ }
+}
+
+export function dcaPayloadForProfile(profile, payload) {
+ return isDcaProfile(profile) ? payload : {};
+}
+
+export function runtimeModePayload(runtimeTarget) {
+ const executionMode = normalizeRuntimeExecutionMode(runtimeTarget?.execution_mode, runtimeTarget?.dry_run_only);
+ const payload = {};
+ if (executionMode) payload.execution_mode = executionMode;
+ const dryRunOnly = cleanOptionalBoolean(runtimeTarget?.dry_run_only);
+ if (dryRunOnly !== null) payload.dry_run_only = dryRunOnly;
+ return payload;
+}
+
+export function normalizeRuntimeExecutionMode(value, dryRunOnly) {
+ const mode = String(value || "").trim().toLowerCase();
+ if (mode === "live" || mode === "dry_run") return mode;
+ if (mode === "paper" && cleanOptionalBoolean(dryRunOnly) !== true) return mode;
+ const dryRun = cleanOptionalBoolean(dryRunOnly);
+ if (dryRun === true) return "dry_run";
+ if (dryRun === false) return "live";
+ return "";
+}
+
+export function cleanOptionalBoolean(value) {
+ if (value === true || value === 1) return true;
+ if (value === false || value === 0) return false;
+ if (typeof value === "string") {
+ const text = value.trim().toLowerCase();
+ if (text === "true" || text === "1") return true;
+ if (text === "false" || text === "0") return false;
+ }
+ return null;
+}
+
+export function cleanCurrentNonNegativeNumber(value) {
+ const text = String(value ?? "").trim();
+ if (!text || text.length > 32 || !/^(?:\d+|\d*\.\d+)$/.test(text)) return "";
+ const numeric = Number(text);
+ if (!Number.isFinite(numeric) || numeric < 0) return "";
+ return text;
+}
+
+export function cleanCurrentRatio(value) {
+ const text = cleanCurrentNonNegativeNumber(value);
+ if (!text) return "";
+ const numeric = Number(text);
+ if (numeric < 0 || numeric > 1) return "";
+ return text;
+}
+
+export function cleanCurrentPositiveNumber(value) {
+ const text = cleanCurrentNonNegativeNumber(value);
+ if (!text || Number(text) <= 0) return "";
+ return text;
+}
+
+export function cleanCurrentDcaMode(value) {
+ try {
+ return cleanDcaMode(value || "");
+ } catch {
+ return "";
+ }
+}
+
+export function runtimeTargetMatchesAccount(runtimeTarget, platform, option, entry = {}) {
+ const runtimePlatform = String(runtimeTarget?.platform_id || "").trim().toLowerCase();
+ if (runtimePlatform && runtimePlatform !== platform) return false;
+
+ const serviceName = String(option?.service_name || defaultCurrentServiceName(platform, option?.target_name || option?.key) || "");
+ const serviceCandidates = [
+ runtimeTarget?.service_name,
+ entry?.service,
+ entry?.service_name,
+ ].filter((value) => normalizeMatchValue(value));
+ if (serviceName && serviceCandidates.length) {
+ return hasCandidate(serviceName, serviceCandidates);
+ }
+
+ if (hasCandidate(option?.account_scope, [
+ runtimeTarget?.account_scope,
+ entry?.ACCOUNT_GROUP,
+ entry?.account_scope,
+ ])) return true;
+
+ if (hasCandidate(option?.deployment_selector, [
+ runtimeTarget?.deployment_selector,
+ entry?.deployment_selector,
+ ])) return true;
+
+ const optionSelectors = splitSelectorValues(option?.account_selector);
+ const runtimeSelectors = splitSelectorValues(runtimeTarget?.account_selector || entry?.account_selector);
+ if (optionSelectors.some((value) => runtimeSelectors.includes(value))) return true;
+
+ const targetName = String(option?.target_name || option?.key || "").trim();
+ return Boolean(targetName && hasCandidate(targetName, [
+ runtimeTarget?.target_name,
+ runtimeTarget?.deployment_selector,
+ runtimeTarget?.account_scope,
+ entry?.target_name,
+ ]));
+}
+
+export function defaultCurrentServiceName(platform, targetName) {
+ const normalized = String(targetName || "").trim().toLowerCase();
+ if (!normalized) return "";
+ if (platform === "longbridge") return `longbridge-quant-${normalized}-service`;
+ if (platform === "ibkr") return `interactive-brokers-${normalized}-service`;
+ if (platform === "schwab") return "charles-schwab-quant-service";
+ if (platform === "firstrade") return "firstrade-quant-service";
+ if (platform === "qmt") return "qmt-quant-service";
+ return "";
+}
+
+export function hasCandidate(expected, candidates) {
+ const normalizedExpected = normalizeMatchValue(expected);
+ if (!normalizedExpected) return false;
+ return candidates.some((candidate) => normalizeMatchValue(candidate) === normalizedExpected);
+}
+
+export function splitSelectorValues(value) {
+ if (Array.isArray(value)) return value.map(normalizeMatchValue).filter(Boolean);
+ return String(value || "")
+ .split(/[,\s]+/)
+ .map(normalizeMatchValue)
+ .filter(Boolean);
+}
+
+export function normalizeMatchValue(value) {
+ return String(value || "").trim().toLowerCase();
+}
+
+export function parseJsonObject(value) {
+ const text = String(value || "").trim();
+ if (!text) return null;
+ for (const candidate of [text, text.replaceAll("\\n", "\n")]) {
+ try {
+ const payload = JSON.parse(candidate);
+ return payload && !Array.isArray(payload) && typeof payload === "object" ? payload : null;
+ } catch {
+ // Try the next representation.
+ }
+ }
+ return null;
+}
+
+export function parseJsonValue(value) {
+ const text = String(value || "").trim();
+ if (!text) return null;
+ for (const candidate of [text, text.replaceAll("\\n", "\n")]) {
+ try {
+ return JSON.parse(candidate);
+ } catch {
+ // Try the next representation.
+ }
+ }
+ return null;
+}
+
+export function cleanCurrentStrategy(value) {
+ const text = String(value || "").trim().toLowerCase();
+ if (!text || text.length > 120 || !/^[a-z0-9._=-]+$/.test(text)) return "";
+ return text;
+}
+
+export function cleanCsv(value, field) {
+ const text = String(value || "").trim();
+ if (text.length > 300 || !/^[A-Za-z0-9._=,\-\s]+$/.test(text)) {
+ throw new Error(`${field} is invalid`);
+ }
+ return text;
+}
+
+export function cleanJson(value, field) {
+ const text = String(value || "").trim();
+ if (!text) return "";
+ if (text.length > 8000) throw new Error(`${field} is too long`);
+ JSON.parse(text);
+ return text;
+}
+
+export function cleanOptionalJsonObject(value, field) {
+ const text = cleanJson(value, field);
+ if (!text) return "";
+ const payload = JSON.parse(text);
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${field} must be a JSON object`);
+ }
+ for (const name of Object.keys(payload)) {
+ if (looksLikeSecretName(name)) {
+ throw new Error(`${field}.${name} looks like a secret and must not be stored here`);
+ }
+ }
+ return text;
+}
+
+export function looksLikeSecretName(name) {
+ const upperName = String(name || "").toUpperCase();
+ if (/_SECRET_(ID|NAME|REF|RESOURCE|RESOURCE_NAME|VERSION)$/.test(upperName)) return false;
+ return /PASSWORD|PRIVATE_KEY|TOKEN|API_KEY|ACCESS_KEY|CLIENT_SECRET|SECRET/.test(upperName);
+}
+
+export function githubHeaders(token) {
+ return {
+ Authorization: `Bearer ${token}`,
+ Accept: "application/vnd.github+json",
+ "Content-Type": "application/json",
+ "User-Agent": "QuantRuntimeSettings-StrategySwitchConsole",
+ "X-GitHub-Api-Version": "2022-11-28",
+ };
+}
+
+export async function fetchGithubOrgLogins(token, timeoutMs = GITHUB_API_TIMEOUT_MS) {
+ const orgs = [];
+ for (let page = 1; page <= 5; page += 1) {
+ const response = await fetchWithTimeout(`https://api.github.com/user/orgs?per_page=100&page=${page}`, {
+ headers: githubHeaders(token),
+ }, timeoutMs);
+ if (!response.ok) return orgs;
+ const payload = await response.json();
+ if (!Array.isArray(payload) || !payload.length) break;
+ for (const org of payload) {
+ const login = cleanGithubOrg(org?.login || "", "github org");
+ if (login) orgs.push(login);
+ }
+ if (payload.length < 100) break;
+ }
+ return uniqueStrings(orgs);
+}
+
+export function requireEnv(env, name) {
+ if (!env[name]) throw new Error(`${name} is not configured`);
+}
+
+export async function loadAuthConfig(env) {
+ const bootstrapAdmins = parseLoginList(env.STRATEGY_SWITCH_ADMIN_LOGINS || "", "STRATEGY_SWITCH_ADMIN_LOGINS");
+ const bootstrapAdminOrgs = parseOrgList(env.STRATEGY_SWITCH_ADMIN_ORGS || "", "STRATEGY_SWITCH_ADMIN_ORGS");
+ const envAllowed = parseLoginList(
+ env.ALLOWED_GITHUB_LOGINS || env.ALLOWED_GITHUB_LOGIN || "",
+ "ALLOWED_GITHUB_LOGINS",
+ );
+ const envAllowedOrgs = parseOrgList(
+ env.ALLOWED_GITHUB_ORGS || env.ALLOWED_GITHUB_ORG || "",
+ "ALLOWED_GITHUB_ORGS",
+ );
+ let storedAllowed = [];
+ let storedAllowedOrgs = [];
+ let storedAdmins = [];
+ let storedAdminOrgs = [];
+ let source = "secret";
+ if (hasConfigStore(env)) {
+ const stored = await readConfigJson(env, AUTH_CONFIG_KEY);
+ if (stored) {
+ const normalized = normalizeAuthConfigPayload(stored, AUTH_CONFIG_KEY);
+ storedAllowed = normalized.allowed_logins;
+ storedAllowedOrgs = normalized.allowed_orgs;
+ storedAdmins = normalized.admin_logins;
+ storedAdminOrgs = normalized.admin_orgs;
+ source = "kv";
+ }
+ }
+ const adminLogins = uniqueStrings([...bootstrapAdmins, ...storedAdmins]);
+ const adminOrgs = uniqueStrings([...bootstrapAdminOrgs, ...storedAdminOrgs]);
+ const allowedLogins = uniqueStrings([...envAllowed, ...storedAllowed, ...adminLogins]);
+ const allowedOrgs = uniqueStrings([...envAllowedOrgs, ...storedAllowedOrgs]);
+ return {
+ allowed_logins: allowedLogins,
+ allowed_orgs: allowedOrgs,
+ admin_logins: adminLogins,
+ admin_orgs: adminOrgs,
+ bootstrap_admin_logins: bootstrapAdmins,
+ bootstrap_admin_orgs: bootstrapAdminOrgs,
+ env_allowed_logins: envAllowed,
+ env_allowed_orgs: envAllowedOrgs,
+ source,
+ kv_available: hasConfigStore(env),
+ };
+}
+
+export function normalizeAuthConfigPayload(payload, fieldName) {
+ if (!payload || Array.isArray(payload) || typeof payload !== "object") {
+ throw new Error(`${fieldName} must be an object`);
+ }
+ return {
+ allowed_logins: normalizeLoginList(payload.allowed_logins || [], `${fieldName}.allowed_logins`),
+ allowed_orgs: normalizeOrgList(payload.allowed_orgs || [], `${fieldName}.allowed_orgs`),
+ admin_logins: normalizeLoginList(payload.admin_logins || [], `${fieldName}.admin_logins`),
+ admin_orgs: normalizeOrgList(payload.admin_orgs || [], `${fieldName}.admin_orgs`),
+ };
+}
+
+export function parseLoginList(value, fieldName) {
+ return normalizeLoginList(value, fieldName);
+}
+
+export function normalizeLoginList(value, fieldName) {
+ const items = Array.isArray(value) ? value : String(value || "").split(/[\s,]+/);
+ if (items.length > 80) throw new Error(`${fieldName} supports at most 80 logins`);
+ return uniqueStrings(items.map((item) => cleanGithubLogin(item, fieldName)).filter(Boolean));
+}
+
+export function parseOrgList(value, fieldName) {
+ return normalizeOrgList(value, fieldName);
+}
+
+export function normalizeOrgList(value, fieldName) {
+ const items = Array.isArray(value) ? value : String(value || "").split(/[\s,]+/);
+ if (items.length > 80) throw new Error(`${fieldName} supports at most 80 orgs`);
+ return uniqueStrings(items.map((item) => cleanGithubOrg(item, fieldName)).filter(Boolean));
+}
+
+export function cleanGithubLogin(value, fieldName) {
+ const login = String(value || "").trim().toLowerCase();
+ if (!login) return "";
+ if (
+ login.length > 39 ||
+ !/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(login) ||
+ login.includes("--")
+ ) {
+ throw new Error(`${fieldName} contains an invalid GitHub login`);
+ }
+ return login;
+}
+
+export function cleanGithubOrg(value, fieldName) {
+ return cleanGithubLogin(value, fieldName);
+}
+
+export function isAdminLogin(login, orgLogins, authConfig) {
+ return authConfig.admin_logins.includes(String(login || "").toLowerCase());
+}
+
+export function isAdminPrincipal(login, orgLogins, authConfig) {
+ return isAdminLogin(login, orgLogins, authConfig) || hasOrgMatch(orgLogins, authConfig.admin_orgs);
+}
+
+export function isAllowedPrincipal(login, orgLogins, authConfig) {
+ const normalizedLogin = String(login || "").toLowerCase();
+ return (
+ authConfig.allowed_logins.includes(normalizedLogin) ||
+ hasOrgMatch(orgLogins, authConfig.allowed_orgs) ||
+ isAdminPrincipal(normalizedLogin, orgLogins, authConfig)
+ );
+}
+
+export function authorizedOrgLogins(orgLogins, authConfig) {
+ const authorized = new Set([...authConfig.allowed_orgs, ...authConfig.admin_orgs]);
+ return uniqueStrings(orgLogins).filter((org) => authorized.has(org));
+}
+
+export function hasOrgMatch(orgLogins, configuredOrgs) {
+ const orgs = new Set(uniqueStrings(orgLogins));
+ return configuredOrgs.some((org) => orgs.has(String(org || "").toLowerCase()));
+}
+
+export async function loadAccountOptionsConfig(env) {
+ if (hasRuntimeInstanceStore(env)) {
+ const state = await runtimeInstanceCommand(env);
+ if (state.initialized) return { options: state.account_options, source: "durable_object", revision: state.revision };
+ // Existing execution can read the frozen legacy configuration during import;
+ // every instance writer rejects this uninitialized state.
+ }
+ return loadLegacyAccountOptionsConfig(env);
+}
+
+export async function loadLegacyAccountOptionsConfig(env) {
+ if (hasConfigStore(env)) {
+ const stored = await readConfigJson(env, ACCOUNT_OPTIONS_KEY);
+ if (stored) {
+ return {
+ options: normalizeAccountOptionsPayload(stored, ACCOUNT_OPTIONS_KEY),
+ source: "kv",
+ };
+ }
+ }
+ return {
+ options: parseAccountOptions(env.STRATEGY_SWITCH_ACCOUNT_OPTIONS_JSON || "", "STRATEGY_SWITCH_ACCOUNT_OPTIONS_JSON"),
+ source: env.STRATEGY_SWITCH_ACCOUNT_OPTIONS_JSON ? "secret" : "none",
+ };
+}
+
+export async function loadStrategyProfilesConfig(env) {
+ if (hasConfigStore(env)) {
+ const stored = await readConfigJson(env, STRATEGY_PROFILES_KEY);
+ if (stored) return normalizeStrategyProfilesPayload(stored, STRATEGY_PROFILES_KEY);
+ }
+ const configured = parseStrategyProfiles(
+ env.STRATEGY_SWITCH_STRATEGY_PROFILES_JSON || "",
+ "STRATEGY_SWITCH_STRATEGY_PROFILES_JSON",
+ );
+ if (configured) return configured;
+ return normalizeStrategyProfilesPayload(DEFAULT_STRATEGY_PROFILES, "DEFAULT_STRATEGY_PROFILES");
+}
+
+export function riskProfileScopeId(platform, targetName) {
+ return `${platform}--${targetName}`;
+}
+
+export function riskProfileBindingTargets(accountOptions) {
+ const targets = [];
+ for (const platform of SUPPORTED_PLATFORMS) {
+ const options = Array.isArray(accountOptions?.[platform]) ? accountOptions[platform] : [];
+ for (const option of options) {
+ targets.push({
+ scope_id: riskProfileScopeId(platform, option.target_name),
+ platform,
+ target_name: option.target_name,
+ });
+ }
+ }
+ return targets.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
+}
+
+export function utcTimestampSeconds(now = new Date()) {
+ return now.toISOString().replace(/\.\d{3}Z$/, "Z");
+}
+
+export async function calculateRiskProfileSelectionSha256(payload) {
+ const material = { ...payload };
+ delete material.selection_sha256;
+ const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export async function normalizeRiskProfileSelection(payload, fieldName) {
+ const value = assertExactFields(payload, ["schema", "profile_id", "risk_preference", "selection_sha256"], fieldName);
+ const riskPreference = cleanChoice(value.risk_preference, RISK_PROFILE_PREFERENCES, `${fieldName}.risk_preference`);
+ const normalized = {
+ schema: RISK_PROFILE_SELECTION_SCHEMA_VERSION,
+ profile_id: RISK_PROFILE_IDS[riskPreference],
+ risk_preference: riskPreference,
+ selection_sha256: normalizeResearchTaskDigest(value.selection_sha256, `${fieldName}.selection_sha256`),
+ };
+ if (value.schema !== RISK_PROFILE_SELECTION_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema is unsupported`);
+ }
+ if (value.profile_id !== normalized.profile_id) {
+ throw new Error(`${fieldName}.profile_id does not match risk_preference`);
+ }
+ if (normalized.selection_sha256 !== await calculateRiskProfileSelectionSha256(normalized)) {
+ throw new Error(`${fieldName}.selection_sha256 mismatch`);
+ }
+ return normalized;
+}
+
+export async function calculateRiskProfileBindingSha256(payload) {
+ const material = { ...payload };
+ delete material.binding_sha256;
+ const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
+ const digest = await crypto.subtle.digest("SHA-256", raw);
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
+}
+
+export async function normalizeRiskProfileBinding(payload, fieldName) {
+ const value = assertExactFields(payload, [
+ "schema_version", "scope_id", "platform", "target_name", "profile_selection", "updated_at", "updated_by",
+ "no_order", "execution_authority_granted", "binding_sha256",
+ ], fieldName);
+ const platform = cleanChoice(value.platform, SUPPORTED_PLATFORMS, `${fieldName}.platform`);
+ const targetName = cleanSlug(value.target_name, `${fieldName}.target_name`);
+ const normalized = {
+ schema_version: RISK_PROFILE_BINDING_SCHEMA_VERSION,
+ scope_id: riskProfileScopeId(platform, targetName),
+ platform,
+ target_name: targetName,
+ profile_selection: await normalizeRiskProfileSelection(value.profile_selection, `${fieldName}.profile_selection`),
+ updated_at: normalizeResearchTaskTimestamp(value.updated_at, `${fieldName}.updated_at`),
+ updated_by: cleanGithubLogin(value.updated_by, `${fieldName}.updated_by`),
+ no_order: value.no_order,
+ execution_authority_granted: value.execution_authority_granted,
+ binding_sha256: normalizeResearchTaskDigest(value.binding_sha256, `${fieldName}.binding_sha256`),
+ };
+ if (value.schema_version !== RISK_PROFILE_BINDING_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ if (value.scope_id !== normalized.scope_id) {
+ throw new Error(`${fieldName}.scope_id does not match platform and target_name`);
+ }
+ if (normalized.no_order !== true || normalized.execution_authority_granted !== false) {
+ throw new Error(`${fieldName} must remain no-order and non-executable`);
+ }
+ if (normalized.binding_sha256 !== await calculateRiskProfileBindingSha256(normalized)) {
+ throw new Error(`${fieldName}.binding_sha256 mismatch`);
+ }
+ return normalized;
+}
+
+export async function normalizeRiskProfileBindingRegistry(payload, fieldName = RISK_PROFILE_BINDINGS_KEY) {
+ const value = assertExactFields(payload, ["schema_version", "bindings"], fieldName);
+ if (value.schema_version !== RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION) {
+ throw new Error(`${fieldName}.schema_version is unsupported`);
+ }
+ if (!Array.isArray(value.bindings) || value.bindings.length > SUPPORTED_PLATFORMS.length * 20) {
+ throw new Error(`${fieldName}.bindings must be a bounded array`);
+ }
+ const bindings = [];
+ const scopes = new Set();
+ for (const [index, item] of value.bindings.entries()) {
+ const binding = await normalizeRiskProfileBinding(item, `${fieldName}.bindings[${index}]`);
+ if (scopes.has(binding.scope_id)) throw new Error(`${fieldName}.bindings contains duplicate scope_id`);
+ scopes.add(binding.scope_id);
+ bindings.push(binding);
+ }
+ return bindings.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
+}
+
+export async function buildRiskProfileBindings(payload, accountOptions, updatedBy) {
+ const value = assertExactFields(payload, ["bindings"], "risk profile bindings request");
+ if (!Array.isArray(value.bindings) || value.bindings.length > SUPPORTED_PLATFORMS.length * 20) {
+ throw new Error("risk profile bindings request.bindings must be a bounded array");
+ }
+ const bindings = [];
+ const scopes = new Set();
+ const updatedAt = utcTimestampSeconds();
+ for (const [index, item] of value.bindings.entries()) {
+ const itemValue = assertExactFields(item, ["platform", "target_name", "risk_preference"], `risk profile bindings request.bindings[${index}]`);
+ const platform = cleanChoice(itemValue.platform, SUPPORTED_PLATFORMS, `risk profile bindings request.bindings[${index}].platform`);
+ const targetName = cleanSlug(itemValue.target_name, `risk profile bindings request.bindings[${index}].target_name`);
+ if (!riskProfileBindingTargets(accountOptions).some((target) => target.platform === platform && target.target_name === targetName)) {
+ throw new Error(`risk profile binding target is not configured: ${platform}/${targetName}`);
+ }
+ const scopeId = riskProfileScopeId(platform, targetName);
+ if (scopes.has(scopeId)) throw new Error("risk profile bindings request contains duplicate target");
+ scopes.add(scopeId);
+ const riskPreference = cleanChoice(
+ itemValue.risk_preference,
+ RISK_PROFILE_PREFERENCES,
+ `risk profile bindings request.bindings[${index}].risk_preference`,
+ );
+ const profileSelection = {
+ schema: RISK_PROFILE_SELECTION_SCHEMA_VERSION,
+ profile_id: RISK_PROFILE_IDS[riskPreference],
+ risk_preference: riskPreference,
+ selection_sha256: "",
+ };
+ profileSelection.selection_sha256 = await calculateRiskProfileSelectionSha256(profileSelection);
+ const binding = {
+ schema_version: RISK_PROFILE_BINDING_SCHEMA_VERSION,
+ scope_id: scopeId,
+ platform,
+ target_name: targetName,
+ profile_selection: profileSelection,
+ updated_at: updatedAt,
+ updated_by: cleanGithubLogin(updatedBy, "risk profile binding.updated_by"),
+ no_order: true,
+ execution_authority_granted: false,
+ binding_sha256: "",
+ };
+ binding.binding_sha256 = await calculateRiskProfileBindingSha256(binding);
+ bindings.push(await normalizeRiskProfileBinding(binding, `risk profile bindings request.bindings[${index}]`));
+ }
+ return bindings.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
+}
+
+export function accountSettingsIdentity(instance) {
+ const config = instance?.config || {};
+ const broker = config.broker_environment;
+ return {
+ platform: instance.platform,
+ key: instance.key,
+ target_name: typeof config.target_name === "string" ? config.target_name : "",
+ broker_environment: broker === "live" || broker === "paper" ? broker : null,
+ account_selector: typeof config.account_selector === "string" ? config.account_selector : "",
+ deployment_selector: typeof config.deployment_selector === "string" ? config.deployment_selector : "",
+ account_scope: typeof config.account_scope === "string" ? config.account_scope : "",
+ service_name: typeof config.service_name === "string" ? config.service_name : "",
+ };
+}
+
+export function accountSettingsIdentityIsComplete(identity) {
+ if (!identity || Array.isArray(identity) || typeof identity !== "object"
+ || !SUPPORTED_PLATFORMS.includes(identity.platform)
+ || (identity.broker_environment !== "paper" && identity.broker_environment !== "live")) return false;
+ return ["key", "target_name", "account_selector", "deployment_selector", "account_scope", "service_name"]
+ .every((field) => typeof identity[field] === "string" && identity[field].trim() !== "");
+}
+
+export function runtimeControlIdentityIsComplete(identity) {
+ return Boolean(identity && SUPPORTED_PLATFORMS.includes(identity.platform)
+ && [null, "live", "paper"].includes(identity.broker_environment)
+ && ["key", "target_name", "account_selector", "deployment_selector", "account_scope", "service_name"]
+ .every((field) => typeof identity[field] === "string" && identity[field].trim() !== ""));
+}
+
+export function accountSettingsProfileName(value) {
+ if (typeof value !== "string" || value.length > 128 || value !== value.trim()
+ || !/^[a-z0-9][a-z0-9._-]*$/.test(value)) return "";
+ return value;
+}
+
+export function accountSettingPositiveAmount(value) {
+ if (typeof value !== "string" || value.length > 32 || !/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value)) return false;
+ const numeric = Number(value);
+ return Number.isFinite(numeric) && numeric > 0;
+}
+
+export function accountSettingRatio(value) {
+ if (typeof value !== "string" || value.length > 32 || !/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value)) return null;
+ const [whole, frac = ""] = value.split(".");
+ if (whole === "0") return value;
+ if (whole === "1" && (frac === "" || /^0+$/.test(frac))) return value;
+ return null;
+}
+
+export function applyAccountSettingOverrides(current, patch) {
+ if (!patch || Array.isArray(patch) || typeof patch !== "object") throw new HttpError("invalid_account_setting_overrides", 400);
+ const next = current && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
+ for (const key of Object.keys(patch)) {
+ if (!ACCOUNT_SETTING_OVERRIDE_FIELDS.includes(key)) throw new HttpError("invalid_account_setting_overrides", 400);
+ const value = patch[key];
+ if (value === null) {
+ delete next[key];
+ continue;
+ }
+ if (typeof value === "number") throw new HttpError("invalid_account_setting_overrides", 400);
+ if (key === "income_layer_enabled" || key === "option_overlay_enabled") {
+ if (typeof value !== "boolean") throw new HttpError("invalid_account_setting_overrides", 400);
+ next[key] = value;
+ } else if (key === "reserved_cash_floor") {
+ if (typeof value !== "string" || value.length > 32 || !/^\d+(?:\.\d+)?$/.test(value) || !Number.isFinite(Number(value))) {
+ throw new HttpError("invalid_account_setting_overrides", 400);
+ }
+ next[key] = value;
+ } else if (key === "reserved_cash_ratio") {
+ const ratio = accountSettingRatio(value);
+ if (ratio === null) throw new HttpError("invalid_account_setting_overrides", 400);
+ next[key] = ratio;
+ } else if (key === "dca_mode") {
+ if (value !== "fixed" && value !== "smart") throw new HttpError("invalid_account_setting_overrides", 400);
+ next[key] = value;
+ } else if (key === "dca_base_investment_usd") {
+ if (!accountSettingPositiveAmount(value)) throw new HttpError("invalid_account_setting_overrides", 400);
+ next[key] = value;
+ } else if (typeof value !== "string" || value.trim() === "" || value !== value.trim()) {
+ throw new HttpError("invalid_account_setting_overrides", 400);
+ } else {
+ next[key] = value;
+ }
+ }
+ return next;
+}
+
+export async function readRiskProfileLegacy(env) {
+ if (!hasConfigStore(env)) return { state: "absent" };
+ try {
+ const stored = await readConfigJson(env, RISK_PROFILE_BINDINGS_KEY);
+ if (!stored) return { state: "absent" };
+ return { state: "valid", bindings: await normalizeRiskProfileBindingRegistry(stored) };
+ } catch {
+ return { state: "blocked" };
+ }
+}
+
+export async function loadRiskProfileBindings(env) {
+ if (!hasRuntimeInstanceStore(env)) {
+ return { bindings: [], revision: null, account_options: null, error: "runtime_instances_not_bound", status: 503 };
+ }
+ const legacy = await readRiskProfileLegacy(env);
+ try {
+ const state = await runtimeInstanceCommand(env, { action: "risk_profile_read", actor: "risk-profile-read", legacy });
+ return { bindings: state.bindings, revision: state.revision, account_options: state.account_options, error: null, status: 200 };
+ } catch (error) {
+ const status = error instanceof HttpError ? error.status : 503;
+ return {
+ bindings: [],
+ revision: null,
+ account_options: null,
+ error: error instanceof HttpError ? error.message : "runtime_instances_unavailable",
+ status,
+ };
+ }
+}
+
+// Desk reads deliberately bypass the current-strategies memory/KV cache. Raw
+// variable maps stay local; only explicit resolver fields enter the projection.
+export async function deskTargetReadback(env, target, actor, suppliedObserved = undefined) {
+ let observed = suppliedObserved;
+ if (observed === undefined) {
+ try {
+ observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor,
+ platform: target.platform, key: target.key, legacy: await readRiskProfileLegacy(env) });
+ } catch { observed = null; }
+ }
+ if (observed && observed.config?.target_name !== target.config.target_name) throw new DeskError("not_found", 404);
+ const config = observed?.config || target.config;
+ const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
+ const repository = platformRepositories(env)?.[target.platform];
+ let platform = {}, platformReason = "source_unavailable";
+ if (token && repository && config) {
+ const cache = new Map();
+ let failed = false;
+ const readVariable = async (repo, scope, environment, name) => {
+ const key = JSON.stringify([repo, scope, environment]);
+ if (!cache.has(key)) cache.set(key, fetchGithubVariables(token, repo, scope, environment, { reportReadErrors: true }));
+ const variables = await cache.get(key);
+ if (variables === null) failed = true;
+ return variables?.get(name) || "";
+ };
+ try {
+ const options = observed?.account_options?.[target.platform] || [];
+ const current = await resolveCurrentStrategyForAccount({ platform: target.platform, option: config,
+ optionsCount: options.length || target.optionsCount || 1, repository, readVariable });
+ if (failed) throw new Error("read_failed");
+ const scope = resolveVariableScope(target.platform, config);
+ const environment = resolveGithubEnvironment(target.platform, config, scope);
+ // Identity must come from a uniquely matched runtime record, never config.
+ const service = current?.source === "CLOUD_RUN_SERVICE_TARGETS_JSON"
+ ? runtimeTargetFromServiceTargets(await readVariable(repository, "repository", "", "CLOUD_RUN_SERVICE_TARGETS_JSON"), target.platform, config) : null;
+ const runtime = current?.source === "RUNTIME_TARGET_JSON"
+ ? parseJsonObject(await readVariable(repository, scope, environment, "RUNTIME_TARGET_JSON")) : null;
+ if (failed) throw new Error("read_failed");
+ const identity = current?.source === "CLOUD_RUN_SERVICE_TARGETS_JSON" ? service
+ : runtime && runtimeTargetMatchesAccount(runtime, target.platform, config) ? runtime : null;
+ platform = { strategy_profile: current?.strategy_profile, enabled: current?.runtime_target_enabled,
+ income_layer_enabled: current?.income_layer_enabled, option_overlay_enabled: current?.option_overlay_enabled,
+ reserved_cash_floor: current?.min_reserved_cash_usd, reserved_cash_ratio: current?.reserved_cash_ratio,
+ dca_mode: current?.dca_mode, dca_base_investment_usd: current?.dca_base_investment_usd,
+ broker_environment: identity?.broker_environment, account_selector: identity?.account_selector,
+ cash_currency: identity?.cash_currency, runtime_status_target_id: identity?.runtime_status_target_id };
+ platformReason = "never_read";
+ } catch { platform = {}; platformReason = "read_failed"; }
+ }
+ return buildReadback({ target, observed, platform, platformReason, now: Date.now(), cleanRatio: cleanCurrentRatio, splitSelectorValues });
+}
+
+export async function effectiveAccountSettings(env, observed) {
+ const broker = observed.identity?.broker_environment === "live" || observed.identity?.broker_environment === "paper"
+ ? { status: "known", value: observed.identity.broker_environment }
+ : { status: "unknown" };
+ // Keep the legacy value shape: non-DCA settings remain absent for old clients.
+ const effective = {
+ strategy_profile: { status: "unknown" },
+ broker_environment: broker,
+ income_layer_enabled: { status: "unknown" },
+ option_overlay_enabled: { status: "unknown" },
+ reserved_cash_floor: { status: "unknown" },
+ reserved_cash_ratio: { status: "unknown" },
+ };
+ const fields = ["strategy_profile", "dca_mode", "dca_base_investment_usd", "income_layer_enabled",
+ "option_overlay_enabled", "reserved_cash_floor", "reserved_cash_ratio"];
+ // This names the resolver path, not a particular variable, deployment or broker readback.
+ const finish = (reason = "runtime_setting_unresolved", dcaReason = reason) => ({
+ effective,
+ effectiveRead: Object.fromEntries(fields.map(field => [field, {
+ status: effective[field]?.status === "known" ? "known" : "unknown",
+ source: "github_runtime_configuration",
+ source_as_of: null,
+ reason: effective[field]?.status === "known" ? null : field.startsWith("dca_") ? dcaReason : reason,
+ }])),
+ });
+ const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
+ const repository = platformRepositories(env)?.[observed.platform];
+ if (!token) return finish("reader_not_configured");
+ if (!repository) return finish("repository_not_configured");
+ if (!observed.config) return finish("account_config_unavailable");
+ const options = Array.isArray(observed.account_options?.[observed.platform]) ? observed.account_options[observed.platform] : [];
+ const variableCache = new Map();
+ let readFailed = false;
+ const readVariable = async (repo, scope, githubEnvironment, name) => {
+ const cacheKey = [repo, scope, githubEnvironment || ""].join("|");
+ if (!variableCache.has(cacheKey)) variableCache.set(cacheKey, fetchGithubVariables(token, repo, scope, githubEnvironment, { reportReadErrors: true }));
+ const values = await variableCache.get(cacheKey);
+ if (values === null) readFailed = true;
+ return values?.get(name) || "";
+ };
+ let current = null;
+ try {
+ current = await resolveCurrentStrategyForAccount({
+ platform: observed.platform,
+ option: observed.config,
+ optionsCount: options.length || 1,
+ repository,
+ readVariable,
+ });
+ } catch {
+ return finish("runtime_configuration_read_failed");
+ }
+ // A failed later page must discard earlier values, never certify missing settings.
+ if (readFailed) return finish("runtime_configuration_read_failed");
+ if (!current || typeof current !== "object") current = {};
+ if (typeof current.strategy_profile === "string" && current.strategy_profile) {
+ effective.strategy_profile = { status: "known", value: current.strategy_profile };
+ }
+ if (typeof current.income_layer_enabled === "boolean") effective.income_layer_enabled = { status: "known", value: current.income_layer_enabled };
+ if (typeof current.option_overlay_enabled === "boolean") effective.option_overlay_enabled = { status: "known", value: current.option_overlay_enabled };
+ if (typeof current.min_reserved_cash_usd === "string" && current.min_reserved_cash_usd) {
+ effective.reserved_cash_floor = { status: "known", value: current.min_reserved_cash_usd };
+ }
+ if (typeof current.reserved_cash_ratio === "string") {
+ const ratio = cleanCurrentRatio(current.reserved_cash_ratio);
+ if (ratio) effective.reserved_cash_ratio = { status: "known", value: ratio };
+ }
+ const profile = effective.strategy_profile.status === "known" ? effective.strategy_profile.value : "";
+ if (isDcaProfile(profile) && DCA_SUPPORTED_PLATFORMS.has(observed.platform)) {
+ const mode = current.dca_mode === "fixed" || current.dca_mode === "smart" ? current.dca_mode : "";
+ const amount = typeof current.dca_base_investment_usd === "string" ? current.dca_base_investment_usd : "";
+ effective.dca_mode = mode ? { status: "known", value: mode } : { status: "unknown" };
+ effective.dca_base_investment_usd = amount ? { status: "known", value: amount } : { status: "unknown" };
+ return finish();
+ }
+ return finish("runtime_setting_unresolved", !DCA_SUPPORTED_PLATFORMS.has(observed.platform) || profile
+ ? "dca_not_applicable" : "strategy_profile_unresolved");
+}
+
+export async function accountSettingsProfileRuntimeReadback(env, observed, resolved = null) {
+ const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
+ const repository = resolved?.repository ?? platformRepositories(env)?.[observed.platform];
+ if (!token || !repository || !observed.config) return null;
+ const options = Array.isArray(observed.account_options?.[observed.platform])
+ ? observed.account_options[observed.platform] : [];
+ const variableCache = new Map();
+ const readVariable = async (repo, scope, githubEnvironment, name) => {
+ const cacheKey = [repo, scope, githubEnvironment || ""].join("|");
+ if (!variableCache.has(cacheKey)) {
+ variableCache.set(cacheKey, fetchGithubVariables(token, repo, scope, githubEnvironment));
+ }
+ return (await variableCache.get(cacheKey)).get(name) || "";
+ };
+ try {
+ const current = await resolveCurrentStrategyForAccount({
+ platform: observed.platform,
+ option: observed.config,
+ optionsCount: options.length || 1,
+ repository,
+ readVariable,
+ });
+ if (!current) return null;
+ const variableScope = resolved?.variableScope ?? resolveVariableScope(observed.platform, observed.config);
+ const githubEnvironment = resolved?.githubEnvironment ?? resolveGithubEnvironment(observed.platform, observed.config, variableScope);
+ const variables = await variableCache.get([repository, variableScope, githubEnvironment || ""].join("|"));
+ return {
+ strategy_profile: current.strategy_profile || null,
+ runtime_target_enabled: variables?.get(RUNTIME_TARGET_ENABLED_VARIABLE) || null,
+ };
+ } catch {
+ return null;
+ }
+}
+
+export function hasConfigStore(env) {
+ return Boolean(configStore(env));
+}
+
+export function configStore(env) {
+ const store = env.STRATEGY_SWITCH_CONFIG;
+ if (!store || typeof store.get !== "function" || typeof store.put !== "function") return null;
+ return store;
+}
+
+export async function readConfigJson(env, key) {
+ const store = configStore(env);
+ if (!store) return null;
+ const text = await store.get(key);
+ if (!text) return null;
+ try {
+ return JSON.parse(text);
+ } catch (error) {
+ throw new Error(`STRATEGY_SWITCH_CONFIG.${key} must be valid JSON`);
+ }
+}
+
+export async function writeConfigJson(env, key, value) {
+ const store = configStore(env);
+ if (!store) throw new Error("STRATEGY_SWITCH_CONFIG KV binding is required");
+ const text = JSON.stringify(value, null, 2);
+ if (indexedKey(key)) await directoryCommand(env, { action: "put", key, value: text });
+ else await store.put(key, text);
+}
+
+export async function loadAuditLog(env) {
+ if (!hasConfigStore(env)) return [];
+ const payload = await readConfigJson(env, AUDIT_LOG_KEY);
+ if (!Array.isArray(payload)) return [];
+ return payload
+ .filter((entry) => entry && !Array.isArray(entry) && typeof entry === "object")
+ .slice(0, AUDIT_LOG_LIMIT);
+}
+
+export async function appendAuditLog(env, entry) {
+ if (!hasConfigStore(env)) return;
+ let current = [];
+ try {
+ current = await loadAuditLog(env);
+ } catch (error) {
+ current = [];
+ }
+ await writeConfigJson(env, AUDIT_LOG_KEY, [entry, ...current].slice(0, AUDIT_LOG_LIMIT));
+}
+
+export function accountCounts(accountOptions) {
+ const counts = {};
+ for (const platform of SUPPORTED_PLATFORMS) {
+ counts[platform] = Array.isArray(accountOptions[platform]) ? accountOptions[platform].length : 0;
+ }
+ return counts;
+}
+
+export function uniqueStrings(items) {
+ const result = [];
+ const seen = new Set();
+ for (const item of items) {
+ const text = String(item || "").trim().toLowerCase();
+ if (!text || seen.has(text)) continue;
+ seen.add(text);
+ result.push(text);
+ }
+ return result;
+}
+
+export function randomToken() {
+ const bytes = new Uint8Array(24);
+ crypto.getRandomValues(bytes);
+ return base64UrlEncodeBytes(bytes);
+}
+
+export function base64UrlEncodeJson(value) {
+ return base64UrlEncodeBytes(new TextEncoder().encode(JSON.stringify(value)));
+}
+
+export function base64UrlEncodeBytes(bytes) {
+ let binary = "";
+ for (const byte of bytes) binary += String.fromCharCode(byte);
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
+}
+
+export function base64UrlDecode(value) {
+ const base64 = value.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
+ const binary = atob(base64);
+ const bytes = new Uint8Array(binary.length);
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
+ return new TextDecoder().decode(bytes);
+}
+
+export function parseCookies(header) {
+ const result = {};
+ for (const part of header.split(";")) {
+ const [name, ...rest] = part.trim().split("=");
+ if (!name) continue;
+ result[name] = decodeURIComponent(rest.join("="));
+ }
+ return result;
+}
+
+export function cookie(name, value, maxAge) {
+ return `${name}=${encodeURIComponent(value)}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=${maxAge}`;
+}
+
+export function clearCookie(name) {
+ return `${name}=; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=0`;
+}
+
+export function clearOAuthCookie() {
+ return { "Set-Cookie": clearCookie(OAUTH_STATE_COOKIE) };
+}
+
+
+export function requireMarketBenchmarkSyncToken(request, env) {
+ const expected = String(env.MARKET_BENCHMARK_SYNC_TOKEN || env.STRATEGY_SWITCH_SYNC_TOKEN || env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
+ if (!expected) throw new HttpError("market_benchmark_sync_token_missing", 503);
+ const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (!token || token !== expected) throw new HttpError("unauthorized", 401);
+ // Fail closed if the bearer equals another dedicated sync token family when those are set differently.
+ const forbidden = [
+ env.ACCOUNT_FACTS_SYNC_TOKEN,
+ env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.EXECUTION_EVIDENCE_SYNC_TOKEN,
+ ].filter((value) => typeof value === "string" && value && value !== expected);
+ if (forbidden.includes(token)) throw new HttpError("unauthorized", 401);
+}
+
+export async function marketBenchmarkResponse(request, env) {
+ if (request.method !== "GET" && request.method !== "HEAD") {
+ return json({ ok: false, error: "method_not_allowed" }, 405);
+ }
+ if (!hasRuntimeInstanceStore(env)) {
+ return json({ ok: false, error: "market_benchmark_store_unavailable" }, 503);
+ }
+ try {
+ const stored = await runtimeInstanceCommand(env, {
+ action: "market_benchmark_read",
+ });
+ const body = {
+ ok: true,
+ schema_version: MARKET_BENCHMARK_SCHEMA,
+ inception_date: stored.inception_date ?? null,
+ timezone: stored.timezone || "Asia/Shanghai",
+ points: Array.isArray(stored.points) ? stored.points : [],
+ };
+ const headers = responseHeaders({ "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
+ return new Response(request.method === "HEAD" ? null : JSON.stringify(body), { status: 200, headers });
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 500);
+ return json({ ok: false, error: "market_benchmark_unavailable" }, 503);
+ }
+}
+
+
+export function requireMarketBenchmarkRevisionToken(request, env) {
+ // Dedicated secret only — never fall back to sync/dispatch tokens.
+ const expected = String(env.MARKET_BENCHMARK_REVISION_TOKEN || "");
+ if (!expected) throw new HttpError("market_benchmark_revision_token_missing", 503);
+ const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
+ if (!token || token !== expected) throw new HttpError("unauthorized", 401);
+ const forbidden = [
+ env.MARKET_BENCHMARK_SYNC_TOKEN,
+ env.STRATEGY_SWITCH_SYNC_TOKEN,
+ env.RUNTIME_SETTINGS_DISPATCH_TOKEN,
+ env.ACCOUNT_FACTS_SYNC_TOKEN,
+ env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
+ env.EXECUTION_EVIDENCE_SYNC_TOKEN,
+ ].filter((value) => typeof value === "string" && value && value !== expected);
+ if (forbidden.includes(token)) throw new HttpError("unauthorized", 401);
+}
+
+export async function reviseMarketBenchmarkResponse(request, env) {
+ try {
+ requireMarketBenchmarkRevisionToken(request, env);
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 401);
+ return json({ ok: false, error: "unauthorized" }, 401);
+ }
+ if (!hasRuntimeInstanceStore(env)) {
+ return json({ ok: false, error: "market_benchmark_store_unavailable" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, 64 * 1024);
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 400);
+ return json({ ok: false, error: "invalid_market_benchmark_revision_payload" }, 400);
+ }
+ try {
+ const stored = await runtimeInstanceCommand(env, {
+ action: "market_benchmark_read",
+ });
+ const appliedAt = typeof raw.applied_at === "string" && !Number.isNaN(Date.parse(raw.applied_at))
+ ? raw.applied_at
+ : new Date().toISOString();
+ const digestHex = async (value) => sha256Hex(String(value));
+ // planRevisionApply expects sync digest; pre-hash with Web Crypto then use a map.
+ const strings = new Set();
+ const proposal = raw.proposal;
+ if (proposal && Array.isArray(proposal.entries)) {
+ strings.add(JSON.stringify(proposal.entries));
+ for (const entry of proposal.entries) {
+ if (entry && typeof entry.series_id_sha256 === "string") strings.add(entry.series_id_sha256);
+ }
+ }
+ for (const point of (raw.replacements || [])) {
+ if (point?.seriesId) strings.add(point.seriesId);
+ if (point?.close) strings.add(point.close);
+ }
+ for (const point of (Array.isArray(stored.points) ? stored.points : [])) {
+ if (point?.close) strings.add(point.close);
+ if (point?.seriesId) strings.add(point.seriesId);
+ }
+ const cache = new Map();
+ for (const value of strings) cache.set(value, await digestHex(value));
+ // Also hash every seriesId/close used by planRevisionApply via digest()
+ const digest = (value) => {
+ const text = String(value);
+ if (cache.has(text)) return cache.get(text);
+ throw new HttpError("benchmark_revision_digest_cache_miss", 500);
+ };
+ // Ensure proposal.entries JSON and all replacement/stored closes/seriesIds are cached —
+ // re-walk after building any missing by computing individually.
+ async function ensure(value) {
+ const text = String(value);
+ if (!cache.has(text)) cache.set(text, await digestHex(text));
+ return cache.get(text);
+ }
+ await ensure(JSON.stringify(proposal?.entries || []));
+ for (const point of (raw.replacements || [])) {
+ await ensure(point.seriesId);
+ await ensure(point.close);
+ }
+ for (const point of (Array.isArray(stored.points) ? stored.points : [])) {
+ await ensure(point.seriesId);
+ await ensure(point.close);
+ }
+ const plan = planRevisionApply({
+ proposal: raw.proposal,
+ approvedProposalSha256: raw.approved_proposal_sha256,
+ replacements: raw.replacements || [],
+ storedPoints: Array.isArray(stored.points) ? stored.points : [],
+ digest: (value) => cache.get(String(value)) || (() => { throw new HttpError("benchmark_revision_digest_cache_miss", 500); })(),
+ appliedAt,
+ previouslyAppliedProposalSha256s: [],
+ });
+ const result = await runtimeInstanceCommand(env, {
+ action: "market_benchmark_revise",
+ plan: {
+ proposal_sha256: plan.proposal_sha256,
+ overwrites: plan.overwrites,
+ deletes: plan.deletes,
+ updates: plan.updates,
+ ledger_entries: plan.ledger_entries,
+ },
+ applied_at: appliedAt,
+ });
+ return json({
+ ok: true,
+ applied: true,
+ proposal_sha256: result.proposal_sha256 || plan.proposal_sha256,
+ overwrites: result.overwrites || plan.overwrites,
+ deletes: 0,
+ ledger_entries: result.ledger_entries || plan.ledger_entries.length,
+ log: revisionApplyLogSummary(plan),
+ });
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 500);
+ if (error instanceof MarketBenchmarkRevisionError) return json({ ok: false, error: error.code }, error.status || 400);
+ if (error instanceof MarketBenchmarkError) return json({ ok: false, error: error.code }, error.status || 400);
+ return json({ ok: false, error: "market_benchmark_revision_failed" }, 502);
+ }
+}
+
+export async function syncMarketBenchmarkResponse(request, env) {
+ try {
+ requireMarketBenchmarkSyncToken(request, env);
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 401);
+ return json({ ok: false, error: "unauthorized" }, 401);
+ }
+ if (!hasRuntimeInstanceStore(env)) {
+ return json({ ok: false, error: "market_benchmark_store_unavailable" }, 503);
+ }
+ let raw;
+ try {
+ raw = await readBoundedJson(request, 64 * 1024);
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 400);
+ return json({ ok: false, error: "invalid_market_benchmark_payload" }, 400);
+ }
+ try {
+ const result = await runtimeInstanceCommand(env, {
+ action: "market_benchmark_put",
+ payload: raw,
+ });
+ return json({
+ ok: true,
+ stored: true,
+ schema_version: MARKET_BENCHMARK_SCHEMA,
+ inception_date: result.inception_date ?? null,
+ written: result.written || 0,
+ unchanged: result.unchanged || 0,
+ points: result.points || 0,
+ });
+ } catch (error) {
+ if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 500);
+ if (error instanceof MarketBenchmarkError) return json({ ok: false, error: error.code }, error.status || 400);
+ return json({ ok: false, error: "market_benchmark_sync_failed" }, 502);
+ }
+}
+
+export async function overviewFxResponse(request, fetchImpl = fetch) {
+ return overviewFxResponseImpl(request, {
+ fetchImpl,
+ fetchWithTimeout,
+ json,
+ responseHeaders,
+ });
+}
+
+export function json(payload, status = 200, headers = {}) {
+ return new Response(JSON.stringify(payload, null, 2), {
+ status,
+ headers: responseHeaders({
+ "Content-Type": "application/json; charset=utf-8",
+ "Cache-Control": "no-store",
+ }, headers),
+ });
+}
+
+export function html(body, status = 200, headers = {}) {
+ return new Response(body, {
+ status,
+ headers: responseHeaders({
+ "Content-Type": "text/html; charset=utf-8",
+ "Cache-Control": "no-store",
+ }, headers),
+ });
+}
+
+export function redirect(location, headers = {}) {
+ return new Response(null, {
+ status: 302,
+ headers: responseHeaders({ Location: location }, headers),
+ });
+}
+
+export function responseHeaders(base = {}, extra = {}) {
+ const headers = new Headers(SECURITY_HEADERS);
+ appendHeaderEntries(headers, base);
+ appendHeaderEntries(headers, extra);
+ return headers;
+}
+
+export function appendHeaderEntries(headers, values) {
+ for (const [name, value] of Object.entries(values)) {
+ if (Array.isArray(value)) {
+ for (const item of value) headers.append(name, item);
+ } else {
+ headers.set(name, value);
+ }
+ }
+}
+
+export function renderMessage(title, message) {
+ return `${escapeHtml(title)}
+
+${escapeHtml(title)}
${escapeHtml(message)}
返回控制台
`;
+}
+
+export function escapeHtml(value) {
+ return String(value)
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """);
+}
diff --git a/web/strategy-switch-console/worker.js b/web/strategy-switch-console/worker.js
index 407d74ac..deb8b7a6 100644
--- a/web/strategy-switch-console/worker.js
+++ b/web/strategy-switch-console/worker.js
@@ -162,636 +162,216 @@ import {
researchPromotionApplicationResponse as researchPromotionApplicationResponseImpl,
researchPromotionApplicationInternalResponse as researchPromotionApplicationInternalResponseImpl,
} from "./application/research_promotion/applications.js";
-
-const CYCLE_HEALTH_HISTORY_PAGE_SIZE = 50;
-const CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION = "qsl_runtime_cycle_health_state_summary.v1";
-const DEFAULT_REPOSITORY = "QuantStrategyLab/QuantRuntimeSettings";
-const DEFAULT_WORKFLOW = "manual-strategy-switch.yml";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_PATH = "/api/internal/account-settings/profile-application/claim";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_AUDIENCE = "qrs-profile-application";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REPOSITORY = "QuantStrategyLab/QuantRuntimeSettings";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REF = "refs/heads/main";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_WORKFLOW_REF = "QuantStrategyLab/QuantRuntimeSettings/.github/workflows/apply-approved-hk-profile.yml@refs/heads/main";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_JWKS_URL = "https://token.actions.githubusercontent.com/.well-known/jwks";
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_TOKEN_BYTES = 8192;
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_JWKS_BYTES = 32 * 1024;
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_TIMEOUT_MS = 5000;
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_TIMEOUT_MS = 1000;
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_MAX_BODY_BYTES = 1024;
-const SESSION_COOKIE = "qsl_switch_session";
-const OAUTH_STATE_COOKIE = "qsl_switch_oauth_state";
-const SESSION_TTL_SECONDS = 8 * 60 * 60;
-const AUTH_CONFIG_KEY = "auth_config";
-const ACCOUNT_OPTIONS_KEY = "account_options";
-const STRATEGY_PROFILES_KEY = "strategy_profiles";
-// Risk preferences are a separate, low-frequency owner-intent record. They
-// must never be merged into a strategy switch input, runtime target, or any
-// execution credential/policy path.
-const RISK_PROFILE_BINDINGS_KEY = "risk_profile_bindings";
-const RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION = "qsl.risk_profile_binding_registry.v1";
-const RISK_PROFILE_BINDING_SCHEMA_VERSION = "qsl.risk_profile_binding.v1";
-const RISK_PROFILE_SELECTION_SCHEMA_VERSION = "qsl.risk_profile_selection.v1";
-const RISK_PROFILE_IDS = {
- CAPITAL_PRESERVATION: "capital_preservation_v1",
- BALANCED_COMPOUNDING: "balanced_compounding_v1",
- GROWTH_COMPOUNDING: "growth_compounding_v1",
-};
-const RISK_PROFILE_PREFERENCES = Object.keys(RISK_PROFILE_IDS);
-const DECISION_ACTION_SCHEMA_VERSION = "qsl.decision_action_result.v1";
-const OPERATION_SCHEMA_VERSION = "qsl.operation.v1";
-const AUDIT_EVENTS_SCHEMA_VERSION = "qsl.audit_events.v1";
-const DECISION_ACTION_MAX_BODY_BYTES = 8 * 1024;
-const AUDIT_EVENTS_MAX_ROWS = 101;
-const AUDIT_LOG_KEY = "audit_log";
-const AUDIT_LOG_LIMIT = 50;
-const CURRENT_STRATEGIES_TIMEOUT_MS = 25000;
-const CURRENT_STRATEGIES_CACHE_KEY = "current_strategies_cache";
-// The keep-alive bump stays below the KV fresh window so one missed cron tick
-// (the schedule is */5) still leaves the entry inside it; a cold isolate then
-// never has to fan out to GitHub just because the stamp aged out.
-const CURRENT_STRATEGIES_MEMO_TTL_MS = 60_000; // 60 sec — a warm isolate re-checks GitHub after this
-const CURRENT_STRATEGIES_KV_FRESH_MS = 1_800_000; // 30 min — a cold isolate serves the KV entry without any GitHub fan-out
-const CURRENT_STRATEGIES_STALE_TTL_MS = 3_600_000; // 60 min — return stale plus background refresh before blocking on GitHub
-const CURRENT_STRATEGIES_KV_BUMP_MS = 900_000; // 15 min — ceiling for ts-only rewrites when the content did not change
-const GITHUB_API_TIMEOUT_MS = 8000;
-const GITHUB_LOGIN_REQUEST_TIMEOUT_MS = 20000;
-const UX1_CALCULATOR_DEADLINE_MS = 30000;
-const UX1_CALCULATOR_MAX_BYTES = 65536;
-const UX1_RESEARCH_REPOSITORY = "QuantStrategyLab/UsEquityStrategies";
-const UX1_RESEARCH_WORKFLOW_FILE = "ux1-research-preview.yml";
-const UX1_RESEARCH_WORKFLOW_PATH = ".github/workflows/ux1-research-preview.yml";
-const UX1_JOB_BODY_MAX_BYTES = 80 * 1024;
-const UX1_GITHUB_DEADLINE_MS = 8000;
-const UX1_GITHUB_MAX_BYTES = 65536;
-const UX1_JOB_UNKNOWN_AFTER_MS = 30 * 60 * 1000;
-const UX1_PUBLIC_JOB_REASONS = new Set([
- "dispatch_rejected",
- "dispatch_unconfirmed",
- "input_unavailable",
- "calculator_failed",
- "check_required",
- "config_changed",
-]);
-const STRATEGY_HEALTH_SNAPSHOT_KEY = "strategy_health_snapshot";
-const STRATEGY_HEALTH_MAX_BODY_BYTES = 256 * 1024;
-const STRATEGY_HEALTH_DEFAULT_STALE_TTL_SECONDS = 2 * 60 * 60;
-const STRATEGY_HEALTH_STATUSES = ["healthy", "watch", "review", "critical"];
-// Derived from the generated platform config so a domain is declared once.
-const SUPPORTED_STRATEGY_DOMAINS = Object.freeze([
- ...new Set(Object.values(PLATFORM_CONFIG).flatMap((platform) => platform.supported_domains || [])),
-]);
-const STRATEGY_HEALTH_DOMAINS = SUPPORTED_STRATEGY_DOMAINS;
-const STRATEGY_HEALTH_DATA_STATUSES = ["ready", "unavailable", "stale"];
-const CONTROL_PLANE_SNAPSHOT_KEY = "control_plane_snapshot";
-const CONTROL_PLANE_SOURCE_PREFIX = "control_plane_source:";
-const CONTROL_PLANE_SOURCE_SCHEMA_VERSION = "qsl_control_plane_source_snapshot.v1";
-const CONTROL_PLANE_SOURCE_RETIREMENTS_KEY = "control_plane_source_retirements";
-const CONTROL_PLANE_ATTENTION_STATUSES = ["research_only", "attention_required", "unavailable"];
-const CONTROL_PLANE_MAX_SOURCES = 100;
-const CONTROL_PLANE_MAX_BODY_BYTES = 256 * 1024;
-// The current source is a once-per-trading-day P1/P3 lane, rather than a live
-// execution heartbeat. Freshness therefore preserves the normal TTL, but also
-// waits for the next scheduled research window across the weekend before it
-// calls an otherwise usable Friday/Saturday snapshot stale.
-const CONTROL_PLANE_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
-const CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_DAYS = new Set([2, 3, 4, 5, 6]);
-const CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_HOUR = 3;
-const CONTROL_PLANE_RESEARCH_DELIVERY_GRACE_MS = 4 * 60 * 60 * 1000;
-const CONTROL_PLANE_CANDIDATE_KINDS = ["individual", "portfolio", "plugin"];
-const CONTROL_PLANE_STAGES = ["P1", "P2", "P3", "P4", "P5", "P6"];
-const CONTROL_PLANE_LIFECYCLE_STATUSES = [
- "research", "evidence_pending", "verified", "deferred", "parked", "paper", "shadow", "owner_decision_required",
-];
-const CONTROL_PLANE_RECOMMENDATIONS = [
- "none", "keep_research", "defer", "park", "auto_paper_evaluation", "auto_shadow_evaluation", "owner_live_decision",
-];
-const CONTROL_PLANE_AUTOMATION_STATES = ["not_configured", "configured", "active"];
-const FORWARD_OBSERVATION_STATES = [
- "PARKED", "FORWARD_ACTIVE", "PAUSED", "FORWARD_COMPLETE_HUMAN_REVIEW", "MANUAL_HOLD", "IDENTITY_MISMATCH", "RISK_BLOCKED", "REVOKED", "SUPERSEDED",
-];
-const FORWARD_OBSERVATION_RESEARCH_STAGES = new Set(["P1", "P2", "P3", "P4"]);
-// M1 adaptive selections are a separate read-only projection. They are not
-// lifecycle evidence, an account instruction, or an execution permission.
-const ADAPTIVE_SELECTION_SOURCE_PREFIX = "adaptive_selection_source:";
-const ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION = "qsl.adaptive_selection_source_snapshot.v1";
-const ADAPTIVE_SELECTION_DASHBOARD_SCHEMA_VERSION = "qsl.adaptive_selection_dashboard.v1";
-const ADAPTIVE_SELECTION_DECISION_SCHEMA_VERSION = "qsl.selection_decision.v1";
-const ADAPTIVE_SELECTION_MAX_SOURCES = 100;
-const ADAPTIVE_SELECTION_MAX_BODY_BYTES = 256 * 1024;
-const ADAPTIVE_SELECTION_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
-const ADAPTIVE_SELECTION_AUTHORITY = "shadow_only";
-// M0 research arrives through a separate, signed-at-transport-boundary
-// snapshot. It is deliberately neither an M1 selection input nor a research
-// task: this Worker only retains a closed, no-order ledger for authenticated
-// readers. No strategy/platform/runtime/broker helper may consume it here.
-const M0_RESEARCH_TRANSPORT_SCHEMA_VERSION = "qsl_m0_research_publisher_envelope.v1";
-const M0_RESEARCH_LEDGER_SCHEMA_VERSION = "qsl_m0_research_ledger.v1";
-const M0_RESEARCH_DASHBOARD_SCHEMA_VERSION = "qsl_m0_research_dashboard.v1";
-const M0_RESEARCH_STORAGE_SCHEMA_VERSION = "qsl_m0_research_ledger_storage.v1";
-const M0_RESEARCH_CURRENT_KEY = "m0_research_ledger_current";
-const M0_RESEARCH_ARCHIVE_PREFIX = "m0_research_ledger_archive:";
-const M0_RESEARCH_MAX_BODY_BYTES = 256 * 1024;
-const M0_RESEARCH_RETENTION_SECONDS = 14 * 24 * 60 * 60;
-const M0_RESEARCH_ALLOWED_SOURCE_REPOSITORY = "QuantStrategyLab/QuantAdvisorResearch";
-const M0_RESEARCH_ALLOWED_PRODUCER_REPOSITORY = "QuantStrategyLab/QuantRuntimeSettings";
-const M0_RESEARCH_SUBJECT_KINDS = ["asset_idea", "theme_context", "strategy_hypothesis", "risk_context"];
-const M0_RESEARCH_HORIZONS = ["short", "medium", "long", "not_applicable"];
-const M0_RESEARCH_STATES = ["candidate", "source_verification_required", "deferred", "context_only"];
-const M0_RESEARCH_CONFIDENCE = ["high", "medium", "low", "mixed", "no_event", "unknown"];
-const M0_RESEARCH_STYLES = ["event_driven", "long_horizon_growth", "value_quality", "macro_context", "mixed_research"];
-const M0_RESEARCH_SUMMARY_FIELDS = [
- "subject_count",
- "observation_count",
- "fresh_observation_count",
- "stale_observation_count",
- "unknown_observation_count",
- "horizon_conflict_count",
- "historical_stale_horizon_drift_count",
-];
-// A console decision is intentionally an auditable owner intent, not an
-// execution permit. It remains separate from workflow dispatch credentials,
-// broker credentials, and any future deterministic execution gateway.
-const OWNER_DECISION_INTENT_PREFIX = "owner_decision_intent:";
-const OWNER_DECISION_CURRENT_PREFIX = "owner_decision_current:";
-const OWNER_DECISION_INTENT_SCHEMA_VERSION = "qsl_owner_decision_intent.v1";
-const OWNER_DECISION_QUEUE_SCHEMA_VERSION = "qsl_owner_decision_queue.v1";
-const OWNER_DECISION_CHOICES = ["approve_limited_live_canary", "keep_parked", "retire_candidate"];
-const OWNER_DECISION_MAX_CANDIDATES = 100;
-// Reconciliation recovery has a different authority boundary from P6
-// strategy promotion. It can only describe an already-authorised legacy
-// target that is currently RECONCILE_ONLY; it can never create a new strategy
-// release, order, broker credential, or runtime mutation from this Worker.
-const RECONCILIATION_RECOVERY_SOURCE_PREFIX = "reconciliation_recovery_source:";
-const RECONCILIATION_RECOVERY_CONFIRMATION_PREFIX = "reconciliation_recovery_confirmation:";
-const RECONCILIATION_RECOVERY_CURRENT_PREFIX = "reconciliation_recovery_current:";
-const RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION = "qsl_reconciliation_recovery_source_snapshot.v1";
-const RECONCILIATION_RECOVERY_DASHBOARD_SCHEMA_VERSION = "qsl_reconciliation_recovery_dashboard.v1";
-const RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION = "qsl_reconciliation_recovery_confirmation.v1";
-const RECONCILIATION_RECOVERY_CONTROLLER_READ_SCHEMA_VERSION = "qsl_reconciliation_recovery_controller_read.v1";
-const RECONCILIATION_RECOVERY_MAX_SOURCES = 100;
-const RECONCILIATION_RECOVERY_MAX_BODY_BYTES = 128 * 1024;
-const RECONCILIATION_RECOVERY_DEFAULT_STALE_TTL_SECONDS = 30 * 60;
-const RECONCILIATION_RECOVERY_MAX_SAMPLE_WINDOW_MS = 15 * 60 * 1000;
-const RECONCILIATION_RECOVERY_PLATFORMS = OBSERVABILITY_PLATFORM_IDS;
-const RECONCILIATION_RECOVERY_ENVIRONMENTS = ["live"];
-const RECONCILIATION_RECOVERY_STATES = ["RECONCILE_ONLY"];
-const RECONCILIATION_RECOVERY_READINESS = ["blocked", "awaiting_human_confirmation"];
-const RECONCILIATION_RECOVERY_DUAL_REVIEW_OUTCOMES = ["approved", "rejected", "unavailable"];
-const RECONCILIATION_RECOVERY_MAX_REQUESTS = 100;
-// Private Binance holdings use one isolated KV record. They are never folded
-// into public health, recovery, control-plane, or admin aggregates.
-const BINANCE_PRIVATE_SCOPE_KEY = "private_binance_scope_report";
-const BINANCE_PRIVATE_SCOPE_MAX_BODY_BYTES = 256 * 1024;
-const BINANCE_PRIVATE_SCOPE_MAX_ASSETS = 5000;
-const BINANCE_PRIVATE_SCOPE_WRITE_TTL_SECONDS = 24 * 60 * 60;
-const BINANCE_PRIVATE_SCOPE_INGEST_MAX_AGE_MS = 10 * 60 * 1000;
-const BINANCE_PRIVATE_SCOPE_FUTURE_SKEW_MS = 60 * 1000;
-const BINANCE_PRIVATE_SCOPE_READ_MAX_AGE_MS = 24 * 60 * 60 * 1000;
-// Execution evidence is deliberately a separate, read-only projection. A
-// candidate's research lifecycle is portable; a broker/data/execution result
-// is only meaningful for the exact target platform and lane that produced it.
-// Keeping this contract separate prevents a P1/P3 source from accidentally
-// turning into an execution or P6 authority source.
-const EXECUTION_EVIDENCE_SOURCE_PREFIX = "execution_evidence_source:";
-const RUNTIME_DAILY_KEY_PREFIX = "runtime_daily:";
-const RUNTIME_DAILY_MAX_BODY_BYTES = 64 * 1024;
-const RUNTIME_DAILY_MAX_RUNS = 20;
-const RUNTIME_DAILY_MAX_LIST = 20;
-// History coverage lists the already-stored business dates for one target. It
-// never reads record bodies and stays bounded so a large backlog cannot stall
-// the read model; hitting the page cap only marks the listing as truncated.
-const RUNTIME_DAILY_HISTORY_PAGE = 100;
-const RUNTIME_DAILY_HISTORY_MAX_PAGES = 10;
-const RUNTIME_DAILY_STALE_MS = 36 * 60 * 60 * 1000;
-const RUNTIME_DAILY_FUTURE_SKEW_MS = 5 * 60 * 1000;
-const RUNTIME_DAILY_STATUSES = [
- "no_submission", "no_signal", "no_rebalance", "submitted", "broker_acknowledged", "partially_filled", "filled",
- "reconciliation_required", "unknown", "failed", "blocked", "dry_run", "shadow", "validation",
- "not_due", "market_closed", "outside_window", "within_grace", "missing_report", "read_incomplete", "insufficient", "conflict",
-];
-const RUNTIME_DAILY_SCHEDULE_ONLY = ["not_due", "market_closed", "outside_window", "within_grace"];
-const RUNTIME_DAILY_ANOMALY_STATUSES = [
- "reconciliation_required", "unknown", "failed", "blocked", "conflict", "missing_report", "read_incomplete", "insufficient",
- "dry_run", "shadow", "validation",
-];
-const RUNTIME_DAILY_ACTIVITIES = [
- "no_submission", "no_signal", "no_rebalance", "submitted", "broker_acknowledged", "partially_filled", "filled",
- "reconciliation_required", "unknown", "failed", "blocked", "previewed", "insufficient",
-];
-const RUNTIME_DAILY_LANES = ["paper", "live", "dry_run", "shadow", "validation", "insufficient"];
-const RUNTIME_DAILY_SCHEDULE_STATES = ["unevaluable", "not_due", "market_closed", "within_grace", "due", "outside_window"];
-const RUNTIME_DAILY_KINDS = ["run", "schedule", "incomplete"];
-const EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION = "qsl_execution_evidence_source_snapshot.v1";
-const EXECUTION_EVIDENCE_DASHBOARD_SCHEMA_VERSION = "qsl_execution_evidence_dashboard.v1";
-const EXECUTION_EVIDENCE_MAX_SOURCES = 100;
-const EXECUTION_EVIDENCE_MAX_BODY_BYTES = 256 * 1024;
-const EXECUTION_EVIDENCE_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
-const EXECUTION_EVIDENCE_PLATFORMS = OBSERVABILITY_PLATFORM_IDS;
-const EXECUTION_EVIDENCE_ENVIRONMENTS = ["shadow", "paper", "live"];
-const EXECUTION_EVIDENCE_CAPABILITIES = ["available", "unavailable", "unknown"];
-const EXECUTION_EVIDENCE_STATUSES = ["verified", "pending", "unavailable", "not_applicable"];
-const EXECUTION_RECEIPT_OUTCOMES = [
- "not_due", "no_action", "no_signal", "no_rebalance", "risk_blocked", "submitted", "broker_acknowledged", "partially_filled", "filled", "reconciliation_required", "failed",
-];
-const EXECUTION_RECEIPT_CONFIRMATIONS = [
- "not_applicable", "not_observed", "acknowledged", "partially_filled", "filled", "reconciliation_required",
-];
-const EXECUTION_EVIDENCE_RECOMMENDATIONS = [
- "continue_autonomous_shadow", "run_autonomous_paper", "owner_limited_live_canary_decision", "parked",
-];
-const EXECUTION_EVIDENCE_REASON_CODES = [
- "none", "target_execution_evidence_missing", "paper_not_supported", "paper_execution_evidence_needed",
- "policy_not_active", "source_stale", "manual_live_decision_required", "target_execution_receipt_observed",
- "target_execution_reconciliation_required", "target_execution_receipt_failed",
-];
-// Runtime target lifecycle is intentionally separate from execution evidence:
-// it records whether a target is enabled and whether its no-order monitors are
-// healthy. A disabled target is not a missing broker or a paper/live result.
-const RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX = "runtime_target_lifecycle_source:";
-const RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION = "qsl_runtime_target_lifecycle_source_snapshot.v1";
-const RUNTIME_TARGET_LIFECYCLE_DASHBOARD_SCHEMA_VERSION = "qsl_runtime_target_lifecycle_dashboard.v1";
-const RUNTIME_TARGET_LIFECYCLE_MAX_SOURCES = 100;
-const RUNTIME_TARGET_LIFECYCLE_MAX_BODY_BYTES = 256 * 1024;
-const RUNTIME_TARGET_LIFECYCLE_CONFIGURED_STATES = ["enabled", "disabled"];
-const RUNTIME_TARGET_LIFECYCLE_EXECUTION_MODES = ["dry_run", "paper", "live"];
-const RUNTIME_TARGET_LIFECYCLE_CHECK_STATUSES = ["pass", "attention", "not_due", "not_applicable", "unavailable"];
-const RUNTIME_TARGET_LIFECYCLE_DISPOSITIONS = ["continue_enabled_monitoring", "continue_disabled_validation", "parked"];
-const RUNTIME_TARGET_LIFECYCLE_EXECUTION_OBSERVATIONS = ["not_due", "monitoring_only", "not_applicable", "attention", "unavailable"];
-const RUNTIME_TARGET_LIFECYCLE_REASON_CODES = [
- "none", "target_intentionally_disabled", "runtime_guard_attention", "execution_heartbeat_attention", "monitoring_unavailable",
-];
-const ACCOUNT_DIAGNOSIS_REQUEST_PATH = "/api/account-diagnosis";
-const ACCOUNT_DIAGNOSIS_INTERNAL_PREFIX = "/api/internal/account-diagnosis/";
-const ACCOUNT_DIAGNOSIS_TARGET_ID = "binance.crypto_live_pool_rotation";
-const ACCOUNT_DIAGNOSIS_TARGETS = Object.freeze({
- [ACCOUNT_DIAGNOSIS_TARGET_ID]: Object.freeze({
- platform: "binance",
- recheckRepository: "QuantStrategyLab/BinancePlatform",
- recheckWorkflow: "runtime-target-lifecycle.yml",
- }),
- "longbridge.paper": Object.freeze({
- platform: "longbridge",
- recheckRepository: "QuantStrategyLab/LongBridgePlatform",
- recheckWorkflow: "runtime-target-lifecycle.yml",
- }),
- "longbridge.hk": Object.freeze({
- platform: "longbridge",
- recheckRepository: "QuantStrategyLab/LongBridgePlatform",
- recheckWorkflow: "runtime-target-lifecycle.yml",
- }),
- "longbridge.sg": Object.freeze({
- platform: "longbridge",
- recheckRepository: "QuantStrategyLab/LongBridgePlatform",
- recheckWorkflow: "runtime-target-lifecycle.yml",
- }),
- "schwab.primary": Object.freeze({
- platform: "schwab",
- recheckRepository: "QuantStrategyLab/CharlesSchwabPlatform",
- recheckWorkflow: "runtime-target-lifecycle.yml",
- }),
- "firstrade.primary": Object.freeze({
- platform: "firstrade",
- recheckRepository: "QuantStrategyLab/FirstradePlatform",
- recheckWorkflow: "runtime-target-lifecycle.yml",
- }),
-});
-const ACCOUNT_DIAGNOSIS_TRIGGERS = ["incident", "manual_check"];
-const ACCOUNT_DIAGNOSIS_STATUSES = ["queued", "running", "succeeded", "failed", "unknown"];
-const ACCOUNT_DIAGNOSIS_REASON_CODES = ["diagnosis_ready", "capacity_unavailable", "codex_unavailable", "invalid_response"];
-const ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES = 16 * 1024;
-const ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS = 600;
-const ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS = 24 * 60 * 60 * 1000;
-const ACCOUNT_DIAGNOSIS_AUTO_ENABLED_ENV = "ACCOUNT_DIAGNOSIS_AUTO_ENABLED";
-const ACCOUNT_DIAGNOSIS_DO_ACTIONS = new Set([
- "diagnosis_create", "diagnosis_latest", "diagnosis_read", "diagnosis_mark_dispatch", "diagnosis_claim", "diagnosis_result", "diagnosis_mark_recheck", "diagnosis_native_intent", "diagnosis_native_save", "diagnosis_native_cancel",
-]);
-/** Stable 409/qualification reason codes for /api/account-diagnosis (P0-08). */
-const ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT = Object.freeze({
- account_diagnosis_config_unavailable: "账户选项配置不可用,无法绑定诊断身份。",
- account_diagnosis_account_not_found: "未找到匹配的账户选项。",
- account_diagnosis_account_not_unique: "账户选项不唯一,无法安全绑定诊断身份。",
- account_diagnosis_target_not_admitted: "该 target 未纳入账户诊断准入清单。",
- account_diagnosis_identity_conflict: "target 与账户身份冲突或不唯一。",
- account_diagnosis_lifecycle_store_unavailable: "生命周期配置存储不可用。",
- account_diagnosis_lifecycle_match_missing: "缺少匹配的生命周期观测来源。",
- account_diagnosis_lifecycle_match_ambiguous: "生命周期观测来源不唯一。",
- account_diagnosis_source_unavailable: "生命周期来源不可用(非 ready/stale)。",
- account_diagnosis_observation_missing: "缺少观测时间,无法确认诊断资格。",
- account_diagnosis_incident_requires_attention: "incident 触发需要已确认的监测关注项。",
- account_diagnosis_native_binding_conflict: "诊断原生任务身份或材料绑定冲突。",
- account_diagnosis_workflow_binding_conflict: "诊断工作流运行绑定冲突。",
- account_diagnosis_schema_incompatible: "诊断上下文 schema 不兼容。",
-});
-function accountDiagnosisConflict(reasonCode, status = 409) {
- const reason = ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT[reasonCode] || "";
- return new HttpError(reasonCode, status, { reason_code: reasonCode, reason });
-}
-function accountDiagnosisErrorPayload(error) {
- const reason_code = String(error?.reason_code || error?.message || "account_diagnosis_unavailable");
- const payload = { ok: false, error: reason_code, reason_code };
- const reason = String(error?.reason || ACCOUNT_DIAGNOSIS_CONFLICT_REASON_TEXT[reason_code] || "").trim();
- if (reason) payload.reason = reason;
- return payload;
-}
-const HUMAN_DECISION_DO_ACTIONS = new Set([
- "owner_sync_materials", "recovery_sync_materials", "promotion_sync_materials",
- "owner_decide", "recovery_decide", "promotion_decide",
- "owner_read", "recovery_read", "promotion_read",
-]);
-const ACCOUNT_SETTINGS_DO_ACTIONS = new Set([
- "risk_profile_read", "risk_profile_replace", "risk_profile_set",
- "account_settings_read", "account_settings_save", "account_declarations_read",
- "account_settings_profile_application_lookup", "account_settings_profile_application_approve",
- "account_settings_profile_application_claim",
-]);
-const ACCOUNT_FACTS_DO_ACTIONS = new Set([
- "account_external_flow_put",
- "account_executions_put", "account_executions_read",
- "account_period_return_put", "account_period_return_read", "account_daily_native_return_research_read",
- "account_facts_put", "account_facts_read", "account_facts_list", "account_facts_history_read", "account_facts_history_put",
- "binance_wallet_history_put", "binance_wallet_history_read",
- "binance_detail_put", "binance_detail_read",
-]);
-const MARKET_BENCHMARK_DO_ACTIONS = new Set([
- "market_benchmark_put", "market_benchmark_read", "market_benchmark_revise",
-]);
-const HK_STOP_DO_ACTIONS = new Set(["hk_stop_claim", "hk_stop_record", "hk_stop_read", "hk_stop_accept_result"]);
-const RUNTIME_CONTROL_DO_ACTIONS = new Set(["runtime_control_claim", "runtime_control_record", "runtime_control_read", "runtime_control_resolve", "runtime_control_capture", "runtime_control_begin_check", "runtime_control_record_check"]);
-const HK_STOP_TARGET_ID = "longbridge/hk";
-const HK_STOP_REQUEST_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
-const ACCOUNT_SETTING_OVERRIDE_FIELDS = ["strategy_profile", "income_layer_enabled", "option_overlay_enabled", "reserved_cash_floor", "reserved_cash_ratio", "dca_mode", "dca_base_investment_usd"];
-const ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
-// Research tasks are a separate, immutable and no-order index. They do not
-// share storage or a sync credential with candidate lifecycle snapshots.
-const RESEARCH_TASK_SOURCE_PREFIX = "research_task_source:";
-const RESEARCH_TASK_SOURCE_SCHEMA_VERSION = "qsl_research_task_source_snapshot.v1";
-const RESEARCH_TASK_SCHEMA_VERSION = "qsl.research_task.v1";
-const RESEARCH_TASK_DASHBOARD_SCHEMA_VERSION = "qsl_research_task_dashboard.v1";
-const RESEARCH_TASK_MAX_SOURCES = 100;
-const RESEARCH_TASK_MAX_BODY_BYTES = 256 * 1024;
-const RESEARCH_TASK_DEFAULT_STALE_TTL_SECONDS = 36 * 60 * 60;
-const RESEARCH_TASK_TYPES = [
- "strategy_diagnosis", "hypothesis_evaluation", "parameter_challenge", "strategy_candidate", "portfolio_candidate", "plugin_candidate",
-];
-const RESEARCH_TASK_OBJECTIVES = ["diagnose_degradation", "test_hypothesis", "challenge_parameters", "evaluate_candidate"];
-
-// Research promotion tickets mirror QPK research_promotion_cycle.to_dict().
-// Console may record human intent only; live_authority_granted stays false.
-const RESEARCH_PROMOTION_TICKET_PREFIX = "research_promotion_ticket:";
-const RESEARCH_PROMOTION_TICKET_SCHEMA = "qsl.research_promotion_ticket.v1";
-const RESEARCH_PROMOTION_QUEUE_SCHEMA = "qsl.research_promotion_ticket_queue.v1";
-const RESEARCH_PROMOTION_MAX_TICKETS = 100;
-const RESEARCH_PROMOTION_MAX_BODY_BYTES = 64 * 1024;
-const RESEARCH_PROMOTION_STATES = [
- "parked",
- "bounded_reopt",
- "shadow_recorded",
- "awaiting_human",
- "human_accepted",
- "human_rejected",
-];
-const RESEARCH_PROMOTION_RISK_PROFILES = [
- "CAPITAL_PRESERVATION",
- "BALANCED_COMPOUNDING",
- "GROWTH_COMPOUNDING",
-];
-const RESEARCH_PROMOTION_EXECUTION_MODES = ["live", "paper"];
-const DEFAULT_RESEARCH_PROMOTION_RISK_PROFILE = "CAPITAL_PRESERVATION";
-const V7_PAPER_PREVIEW_PROFILE = "soxl_soxx_core_only_p2_v7_longterm_compounding_cash_reserve";
-const V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY = "QuantStrategyLab/LongBridgePlatform";
-const V7_PAPER_APPLICATION_WORKFLOW = "apply-paper-candidate.yml";
-const V7_PAPER_APPLICATION_UES_REVISION = "b83ef4b3ae67c47d132ddd660ba3ccc60d474c85";
-// Reviewed LongBridge application merge SHA for the paused validation slice.
-// This remains a server constant and is never caller input or an enablement.
-const V7_PAPER_APPLICATION_SOURCE_COMMIT = "dcdcb579001e0be5579810121fc7894206e06445";
-const V7_PAPER_APPLICATION_TICKET_RE = /^rpt_[0-9a-f]{64}$/;
-const V7_PAPER_APPLICATION_ACCOUNT_KEY = "paper";
-const V7_PAPER_APPLICATION_ACCOUNT_SCOPE = "PAPER";
-const V7_PAPER_APPLICATION_SERVICE = "longbridge-quant-paper-service";
-const V7_PAPER_APPLICATION_MAX_BODY_BYTES = 16 * 1024;
-const V7_PAPER_APPLICATION_STATUSES = ["approved", "claimed", "applied_paused", "rejected", "uncertain"];
-const V7_PAPER_APPLICATION_DISPATCH_STATES = ["pending", "sent", "unknown"];
-const V7_PAPER_APPLICATION_REASON_CODES = ["", "readback_mismatch", "workflow_rejected", "workflow_uncertain", "dispatch_unverified", "account_changed", "qualification_failed"];
-const V7_PAPER_APPLICATION_DO_ACTIONS = new Set([
- "application_create", "application_latest", "application_read", "application_mark_dispatch", "application_claim", "application_result",
-]);
-// The workflow has an explicit fail-closed guard until immutable activation
-// and durable single-use consumption are connected. Keep the console from
-// dispatching a workflow that cannot apply the requested target.
-const SWITCH_ACTIVATION_CONNECTED = false;
-
-
-const RISK_ENVELOPE_PREFERENCE_META = {
- CAPITAL_PRESERVATION: {
- short_zh: "保全",
- short_en: "Preserve",
- composer_mdd_multiple: 1.0,
- promotion_size_scale: 0.5,
- },
- BALANCED_COMPOUNDING: {
- short_zh: "均衡",
- short_en: "Balance",
- composer_mdd_multiple: 1.25,
- promotion_size_scale: 0.75,
- },
- GROWTH_COMPOUNDING: {
- short_zh: "增长",
- short_en: "Growth",
- composer_mdd_multiple: 1.5,
- promotion_size_scale: 1.0,
- },
-};
-
-/** Read-only console view: preference / capital band / status lamp. No KV writes. */
-function buildRiskEnvelopeView({ riskPreference = null, equityUsd = null, status = null } = {}) {
- const preferenceRaw = String(riskPreference || "").trim().toUpperCase();
- const preference = RESEARCH_PROMOTION_RISK_PROFILES.includes(preferenceRaw) ? preferenceRaw : null;
- const meta = preference ? RISK_ENVELOPE_PREFERENCE_META[preference] : null;
- const hasEquity = equityUsd != null && Number.isFinite(Number(equityUsd));
- // Equity injection is not wired yet — band/status/capital_scale stay unknown.
- const source = hasEquity ? "reconciled_equity" : "design_preview";
- const statusId = hasEquity && status ? String(status) : "unknown";
- const statusLabels = {
- normal: { zh: "正常", en: "Normal" },
- stepped_down: { zh: "已降档", en: "Stepped down" },
- new_risk_blocked: { zh: "禁止新增风险", en: "New risk blocked" },
- unknown: { zh: "待对账权益注入", en: "Awaiting reconciled equity" },
- };
- const statusLabel = statusLabels[statusId] || statusLabels.unknown;
- return {
- schema: "qsl.risk_envelope_view.v1",
- source,
- preference: preference
- ? {
- id: preference,
- label_zh: meta.short_zh,
- label_en: meta.short_en,
- }
- : {
- id: "unknown",
- label_zh: "未设定",
- label_en: "Unset",
- },
- capital_band: {
- id: "unknown",
- label_zh: "待对账权益注入",
- label_en: "Awaiting reconciled equity",
- },
- status: {
- id: statusId,
- label_zh: statusLabel.zh,
- label_en: statusLabel.en,
- },
- scales: {
- composer_mdd_multiple: meta ? meta.composer_mdd_multiple : null,
- promotion_size_scale: meta ? meta.promotion_size_scale : null,
- capital_scale: null,
- vol_scale: null,
- dd_scale: null,
- },
- detail: {
- dual_scale_note_zh:
- "双口径:Composer 相对无杠杆基准 MDD 天花板为 1.00 / 1.25 / 1.50;晋级仓位缩放为 0.50 / 0.75 / 1.00(仅新晋级/材料变更)。资金信封 combined_scale = capital_scale × vol_scale × dd_scale(各因子 ≤1),由系统按权益/波动/回撤计算,禁止自动升档。",
- dual_scale_note_en:
- "Dual scale: Composer unlevered-benchmark MDD caps are 1.00 / 1.25 / 1.50; promotion size scales are 0.50 / 0.75 / 1.00 (new promotion / material change only). Envelope combined_scale = capital_scale × vol_scale × dd_scale (each ≤1), system-computed from equity/vol/drawdown; auto step-up is forbidden.",
- },
- live_authority_granted: false,
- };
-}
-
-function attachRiskEnvelopeView(ticket) {
- if (!ticket || typeof ticket !== "object") return ticket;
- return {
- ...ticket,
- risk_envelope_view: buildRiskEnvelopeView({
- riskPreference: ticket.suggested_risk_profile,
- equityUsd: null,
- }),
- };
-}
-
-
-
-const SUPPORTED_PLATFORMS = Object.keys(PLATFORM_CONFIG);
-
-function validateAccountOptionsSchemaOrThrow(payload, fieldName = "account_options") {
- return normalizeAccountOptionsSchemaPayload(payload, fieldName);
-}
-
-
-const LIVE_CONTINUITY_STATES = [
- "NONE",
- "ACTIVE_LKG",
- "ACTIVE_REDUCED",
- "RECONCILE_ONLY",
- "RISK_REDUCTION_ONLY",
- "PAUSED",
- "ROLLBACK_LKG",
-];
-const LEGACY_CASH_ONLY_EXECUTION_VARIABLE = "CASH_ONLY_EXECUTION";
-const CASH_ONLY_EXECUTION_MODES = ["current", "enabled", "disabled"];
-const INCOME_LAYER_ENABLED_VARIABLE = "INCOME_LAYER_ENABLED";
-const INCOME_LAYER_START_USD_VARIABLE = "INCOME_LAYER_START_USD";
-const INCOME_LAYER_MAX_RATIO_VARIABLE = "INCOME_LAYER_MAX_RATIO";
-const OPTION_OVERLAY_ENABLED_VARIABLE = "OPTION_OVERLAY_ENABLED";
-const RUNTIME_TARGET_ENABLED_VARIABLE = "RUNTIME_TARGET_ENABLED";
-const DCA_MODE_VARIABLE = "DCA_MODE";
-const DCA_BASE_INVESTMENT_VARIABLE = "DCA_BASE_INVESTMENT_USD";
-const IBIT_ZSCORE_EXIT_MODE_VARIABLE = "IBIT_ZSCORE_EXIT_MODE";
-const IBIT_ZSCORE_EXIT_ENABLED_VARIABLE = "IBIT_ZSCORE_EXIT_ENABLED";
-const IBIT_ZSCORE_EXIT_PARKING_SYMBOL_VARIABLE = "IBIT_ZSCORE_EXIT_PARKING_SYMBOL";
-const LEGACY_INCOME_LAYER_CONTROL_FIELDS = [
- "income_threshold_usd",
- "qqqi_income_ratio",
- "income_layer_qqqi_weight",
- "income_layer_spyi_weight",
-];
-const LEGACY_INCOME_LAYER_VARIABLES = [
- "INCOME_THRESHOLD_USD",
- "QQQI_INCOME_RATIO",
- "INCOME_LAYER_QQQI_WEIGHT",
- "INCOME_LAYER_SPYI_WEIGHT",
-];
-const OPTION_OVERLAY_CONTROL_FIELDS = [
- "option_overlay_enabled",
- "option_growth_overlay_enabled",
- "option_growth_overlay_recipe",
- "option_growth_overlay_start_usd",
- "option_growth_overlay_nav_budget_ratio",
- "option_income_overlay_enabled",
- "option_income_overlay_recipe",
- "option_income_overlay_start_usd",
- "option_income_overlay_nav_risk_ratio",
-];
-const OPTION_OVERLAY_VARIABLES = OPTION_OVERLAY_CONTROL_FIELDS.map((field) => field.toUpperCase());
-const OPTION_OVERLAY_PROFILE_FIELDS = [
- ...OPTION_OVERLAY_CONTROL_FIELDS,
- "option_overlay_live_gate",
- "option_overlay_live_status",
-];
-const OPTION_OVERLAY_MODES = ["current", "enabled", "disabled"];
-const DCA_PROFILE_CONFIG = Object.fromEntries(
- Object.entries(DCA_PROFILE_DEFAULTS).map(([profile, defaults]) => [
- profile,
- {
- default_mode: defaults.defaultMode || "fixed",
- default_base_investment_usd: defaults.defaultBaseInvestmentUsd || "1000",
- },
- ]),
-);
-const SECURITY_HEADERS = {
- "Content-Security-Policy": [
- "default-src 'self'",
- "base-uri 'none'",
- "object-src 'none'",
- "frame-ancestors 'none'",
- "frame-src https://fred.stlouisfed.org/graph/graph-landing.php",
- "form-action 'self'",
- "img-src 'self' data:",
- "connect-src 'self'",
- "script-src 'self'",
- "style-src 'self'",
- ].join("; "),
- "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=()",
- "Referrer-Policy": "no-referrer",
- "X-Content-Type-Options": "nosniff",
- "X-Frame-Options": "DENY",
-};
-
-// This is deliberately a same-origin, public configuration bootstrap. It
-// contains only the config projections already shown by the public console;
-// private account routing still arrives after an authenticated /api/config
-// request. Keeping it external preserves the strict CSP without unsafe-inline.
-const BOOTSTRAP_CONFIG_JS = [
- "// Generated from non-secret console configuration. Do not edit by hand.",
- `window.__PLATFORM_META__ = ${JSON.stringify(PLATFORM_META)};`,
- `window.__PLATFORM_REPOSITORIES__ = ${JSON.stringify(PLATFORM_REPOSITORIES)};`,
- `window.__PLATFORM_CONFIG__ = ${JSON.stringify(PLATFORM_CONFIG)};`,
- `window.__DEFAULT_ACCOUNT_OPTIONS__ = ${JSON.stringify(DEFAULT_ACCOUNT_OPTIONS)};`,
- `window.__DOMAIN_LABELS__ = ${JSON.stringify(DOMAIN_LABELS)};`,
- `window.__DEFAULT_STRATEGY_PROFILES__ = ${JSON.stringify(DEFAULT_STRATEGY_PROFILES)};`,
- `window.__DCA_PROFILE_DEFAULTS__ = ${JSON.stringify(DCA_PROFILE_DEFAULTS)};`,
- `window.__INCOME_LAYER_DEFAULTS__ = ${JSON.stringify(FALLBACK_INCOME_LAYER_DEFAULTS)};`,
- `window.__OPTION_OVERLAY_DEFAULTS__ = ${JSON.stringify(FALLBACK_OPTION_OVERLAY_DEFAULTS)};`,
- `window.__PLATFORM_MIN_RESERVED_CASH_VARIABLES__ = ${JSON.stringify(PLATFORM_MIN_RESERVED_CASH_VARIABLES)};`,
- `window.__PLATFORM_RESERVED_CASH_RATIO_VARIABLES__ = ${JSON.stringify(PLATFORM_RESERVED_CASH_RATIO_VARIABLES)};`,
-].join("\n");
-
-// A secondary external script keeps a failed or stale main bundle from
-// trapping a visitor behind the loading screen forever. It does not fetch,
-// mutate configuration, or grant access: it only reveals the static login
-// surface after the main boot flow has had time to finish its own timeout.
-const BOOT_RECOVERY_JS = [
- "(() => {",
- " const delayMs = 20_000;",
- " window.setTimeout(() => {",
- " if (!document.body?.classList.contains('app-loading')) return;",
- " document.body.classList.remove('app-loading');",
- " const login = document.getElementById('login-link');",
- " if (login) login.hidden = false;",
- " }, delayMs);",
- "})();",
-].join("\n");
+import { HttpError } from "./application/http_error.js";
+import { buildRiskEnvelopeView, attachRiskEnvelopeView } from "./application/risk_envelope.js";
+import {
+ ACCOUNT_DIAGNOSIS_REQUEST_PATH,
+ ACCOUNT_DIAGNOSIS_INTERNAL_PREFIX,
+} from "./application/account_diagnosis/constants.js";
+import {
+ UX1_CALCULATOR_DEADLINE_MS,
+ UX1_CALCULATOR_MAX_BYTES,
+ UX1_JOB_UNKNOWN_AFTER_MS,
+} from "./application/ux1/constants.js";
+import {
+ runtimeInstanceCommand,
+} from "./application/runtime_instances/command.js";
+import { readSession, makeSession } from "./application/auth/session.js";
+import { startLogin, finishLogin } from "./application/auth/login.js";
+import {
+ ux1DraftGet,
+ ux1DraftPost,
+ ux1PreviewPost,
+ ux1IntentPost,
+ ux1JobClaimPost,
+ ux1JobResultPost,
+ presentUx1Preview,
+ projectUx1Job,
+ ux1RunMatches,
+ ux1RuntimeEpoch,
+ readUx1CalculatorExchange,
+} from "./application/ux1/research.js";
+
+import * as api from './application/worker/runtime_support.js';
+import { RuntimeInstances } from "./application/runtime_instances/durable_object.js";
+export { RuntimeInstances };
+
+const {
+ ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_PATH,
+ CURRENT_STRATEGIES_KV_BUMP_MS,
+ CURRENT_STRATEGIES_KV_FRESH_MS,
+ CURRENT_STRATEGIES_TIMEOUT_MS,
+ DEFAULT_REPOSITORY,
+ acceptHkStopResult,
+ accountDiagnosisInternalResponse,
+ accountDiagnosisResponse,
+ accountDraftStrategyChoices,
+ accountFactsErrorResponse,
+ accountFactsHistoryResponse,
+ accountFactsResponse,
+ accountOptionMatchesInputs,
+ accountSettingsAuditChanges,
+ accountSettingsResponse,
+ adaptiveSelectionResponse,
+ adminConfigResponse,
+ aggregateRuntimeTargetLifecycleSources,
+ approveAccountSettingsProfileApplication,
+ assertAccountDraftPatch,
+ assertConfiguredAccount,
+ assertStrategyAllowedForAccount,
+ attachPromotionQueueReadMetadata,
+ attachResearchPromotionApplicationPreparation,
+ auditEventAction,
+ auditEventsResponse,
+ binanceAccountFactsReadinessResponse,
+ binanceAccountFactsResponse,
+ binanceDetailArchiveResponse,
+ binanceDigestSnapshotResponse,
+ binancePrivateScopeResponse,
+ binanceWalletHistoryResponse,
+ BOOTSTRAP_CONFIG_JS,
+ BOOT_RECOVERY_JS,
+ buildRiskProfileBindings,
+ calculateAdaptiveSelectionDecisionDigest,
+ calculateM0ResearchLedgerSha256,
+ calculateReconciliationRecoveryConfirmationSha256,
+ calculateResearchTaskSha256,
+ calculateRiskProfileBindingSha256,
+ calculateRiskProfileSelectionSha256,
+ canonicalResearchTaskJson,
+ claimAccountSettingsProfileApplicationFromGitHub,
+ configPayload,
+ consoleRunControls,
+ controlPlaneResearchSnapshotFreshness,
+ controlPlaneResponse,
+ credentialMaintenanceResponse,
+ dcaDraftSupported,
+ decisionActionResponse,
+ decisionReviewResponse,
+ deskAuth,
+ deskTargetReadback,
+ dispatchAccountDiagnosis,
+ dispatchBinanceResume,
+ dispatchRuntimeStop,
+ dispatchSwitch,
+ effectiveAccountSettings,
+ emptyAdaptiveSelectionPayload,
+ emptyControlPlanePayload,
+ emptyExecutionEvidencePayload,
+ emptyM0ResearchDashboardPayload,
+ emptyReconciliationRecoveryPayload,
+ emptyResearchTaskPayload,
+ emptyStrategyHealthPayload,
+ executionEvidenceResponse,
+ fetchResearchPromotionTicketResponse,
+ fetchWithTimeout,
+ hasConfigStore,
+ html,
+ humanDecisionReceipt,
+ inferAccountSupportedDomains,
+ isConfigJsonParseError,
+ isDegradedCurrentStrategies,
+ json,
+ loadAccountOptionsConfig,
+ loadAuditLog,
+ loadCurrentStrategies,
+ loadCurrentStrategiesSafely,
+ loadPlatformMeta,
+ loadStrategyProfilesConfig,
+ logout,
+ m0ResearchLedgerResponse,
+ marketBenchmarkResponse,
+ normalizeAccountOptionsPayload,
+ normalizeAdaptiveSelectionSourceSnapshot,
+ normalizeControlPlaneSnapshot,
+ normalizeControlPlaneSourceSnapshot,
+ normalizeExecutionEvidenceSourceSnapshot,
+ normalizeM0ResearchLedgerTransport,
+ normalizeReconciliationRecoveryConfirmation,
+ normalizeReconciliationRecoverySourceSnapshot,
+ normalizeResearchPromotionTicket,
+ normalizeResearchTask,
+ normalizeResearchTaskSourceSnapshot,
+ normalizeRiskProfileBindingRegistry,
+ normalizeRuntimeTargetLifecycleTarget,
+ normalizeStrategyHealthSnapshot,
+ normalizeStrategyProfilesPayload,
+ normalizeSwitchInputs,
+ operationResponse,
+ overviewFxResponse,
+ ownerDecisionQueueResponse,
+ platformRepositories,
+ projectM0ResearchDashboardForRead,
+ projectRuntimeAccountState,
+ readBoundAccountExecutions,
+ readCurrentStrategies,
+ readCurrentStrategiesCacheEntry,
+ readRuntimeStop,
+ reconciliationRecoveryControllerReadResponse,
+ reconciliationRecoveryResponse,
+ recordOwnerDecisionResponse,
+ recordReconciliationRecoveryConfirmationResponse,
+ recordResearchPromotionDecisionResponse,
+ requireSameOrigin,
+ researchPromotionApplicationInternalResponse,
+ researchPromotionApplicationResponse,
+ researchPromotionMaterialKey,
+ researchPromotionReviewBinding,
+ researchPromotionReviewMaterial,
+ researchPromotionTicketsResponse,
+ researchTaskResponse,
+ resolvedVariableScope,
+ responseHeaders,
+ reviseMarketBenchmarkResponse,
+ riskProfileBindingTargets,
+ riskProfileBindingsResponse,
+ runtimeCatalogResponse,
+ runtimeCycleHealthAdmissionResponse,
+ runtimeCycleHealthSourceResponse,
+ runtimeDailyPublicBindings,
+ runtimeDailyReadModelEnabled,
+ runtimeDailyRegisteredBindings,
+ runtimeDailyResponse,
+ runtimeInstancesResponse,
+ runtimeReadbackResponse,
+ runtimeTargetLifecycleResponse,
+ saveAccountSettings,
+ saveAdminConfig,
+ saveCombinedAccountDraft,
+ saveRiskProfileBindings,
+ sessionPayload,
+ sha256Hex,
+ splitSelectorValues,
+ strategyHealthResponse,
+ strategyProfilesPayload,
+ supportedDomainsForAccount,
+ syncAccountDefaultResponse,
+ syncAccountExecutionsResponse,
+ syncAccountExternalFlowResponse,
+ syncAccountFactsResponse,
+ syncAccountPeriodReturnResponse,
+ syncAdaptiveSelectionSourceResponse,
+ syncBinanceAccountFactsResponse,
+ syncBinancePrivateScopeResponse,
+ syncControlPlaneResponse,
+ syncControlPlaneSourceResponse,
+ syncDefaultStrategyForAccount,
+ syncExecutionEvidenceSourceResponse,
+ syncM0ResearchLedgerResponse,
+ syncMarketBenchmarkResponse,
+ syncReconciliationRecoverySourceResponse,
+ syncResearchPromotionTicketResponse,
+ syncResearchTaskSourceResponse,
+ syncRuntimeDailyResponse,
+ syncRuntimeTargetLifecycleSourceResponse,
+ syncStrategyHealthResponse,
+ syncStrategyProfilesConfig,
+ syncStrategyProfilesResponse,
+ updateAccountOptionsDefaultStrategy,
+ validateResearchPromotionSelectedAccount,
+ withTimeout,
+ writeCurrentStrategiesCache,
+} = api;
export default {
async fetch(request, env, ctx) {
@@ -1164,17548 +744,6 @@ export default {
},
};
-class HttpError extends Error {
- constructor(message, status, details = null) {
- super(message);
- this.status = status;
- this.reason_code = (details && details.reason_code) || message;
- this.reason = (details && details.reason) || "";
- }
-}
-
-// One fixed object owns instance state and its revision. KV remains the ACL and
-// observation store; it is never a CAS substitute or a writable replica here.
-function hasRuntimeInstanceStore(env) {
- return env.STRATEGY_SWITCH_RUNTIME_INSTANCES !== undefined && env.STRATEGY_SWITCH_RUNTIME_INSTANCES !== null;
-}
-
-async function runtimeInstanceCommand(env, command) {
- const namespace = env.STRATEGY_SWITCH_RUNTIME_INSTANCES;
- if (!namespace?.idFromName || !namespace?.get) throw new HttpError("runtime_instances_not_bound", 503);
- try {
- const stub = namespace.get(namespace.idFromName("runtime-instances"));
- const response = await stub.fetch("https://runtime-instances/", command ? {
- method: "POST", body: JSON.stringify(command),
- } : {});
- const result = await response.json();
- if (!response.ok) throw new HttpError(result.error || "runtime_instances_unavailable", response.status);
- return result;
- } catch (error) {
- if (error instanceof HttpError) throw error;
- throw new HttpError("runtime_instances_unavailable", 503);
- }
-}
-
-async function credentialMaintenanceResponse(request, env, url) {
- const machine = url.pathname.startsWith("/api/internal/");
- const suffix = url.pathname.split("/").at(-1);
- let action = "credential_maintenance_read";
- if (machine) {
- const expected = typeof env.STRATEGY_SWITCH_SYNC_TOKEN === "string" ? env.STRATEGY_SWITCH_SYNC_TOKEN : "";
- // No dispatch fallback, and no alias for broker, control or session authority.
- const aliases = Object.entries(env).filter(([name, value]) => name !== "STRATEGY_SWITCH_SYNC_TOKEN" &&
- (name.endsWith("_TOKEN") || name === "SESSION_SECRET") && typeof value === "string" && value && value === expected);
- if (!expected || aliases.length) throw new HttpError("credential_maintenance_auth_unavailable", 503);
- const supplied = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (supplied !== expected) throw new HttpError("credential_maintenance_auth_invalid", 401);
- if (suffix === "claim" || suffix === "ack") {
- if (request.method !== "POST") throw new HttpError("method_not_allowed", 405);
- action = `credential_maintenance_${suffix}`;
- } else if (request.method !== "GET") throw new HttpError("method_not_allowed", 405);
- } else {
- const session = await requireUx1Session(request, env);
- if (request.method === "POST") {
- if (!session.admin) throw new HttpError("admin required", 403);
- requireSameOrigin(request, { requireOrigin: true });
- action = "credential_maintenance_save";
- } else if (request.method !== "GET") throw new HttpError("method_not_allowed", 405);
- }
- let body;
- if (request.method === "POST") {
- const text = await request.text();
- if (text.length > 1024) throw new HttpError("invalid_credential_maintenance_request", 400);
- try { body = JSON.parse(text); } catch { throw new HttpError("invalid_credential_maintenance_request", 400); }
- }
- const result = await runtimeInstanceCommand(env, { action, body });
- return json(!machine && request.method === "GET" ? { ...result, ...decisionFields(result, "credential_maintenance") } : result);
-}
-
-let ux1ModuleEpoch = "";
-
-function ux1RuntimeEpoch(env) {
- const configured = env?.UX1_RUNTIME_EPOCH;
- if (typeof configured === "string" && /^[a-f0-9]{32}$/.test(configured)) return configured;
- if (!ux1ModuleEpoch) {
- const bytes = new Uint8Array(16);
- crypto.getRandomValues(bytes);
- ux1ModuleEpoch = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
- }
- return ux1ModuleEpoch;
-}
-
-function ux1PreviewMatchesEpoch(preview, env) {
- return Boolean(preview && preview.runtime_epoch === ux1RuntimeEpoch(env));
-}
-
-function ux1ExpectedEvidenceMatches(preview, env) {
- if (!preview.evidence) return !["computed", "no_advantage", "no_action"].includes(preview.status);
- if (!env.UX1_EXPECTED_EVIDENCE_HASHES) return true;
- let expected;
- try { expected = JSON.parse(env.UX1_EXPECTED_EVIDENCE_HASHES); } catch { return false; }
- return expected && typeof expected === "object" && !Array.isArray(expected)
- && Object.keys(expected).length === UX1_EVIDENCE_HASH_KEYS.length
- && UX1_EVIDENCE_HASH_KEYS.every((key) => /^[a-f0-9]{64}$/.test(expected[key]) && preview.evidence[key] === expected[key]);
-}
-
-function ux1PreviewBindingStale(preview, env) {
- if (!preview) return false;
- if (!ux1PreviewMatchesEpoch(preview, env)) return true;
- if (!preview.evidence || !env?.UX1_EXPECTED_EVIDENCE_HASHES) return false;
- return !ux1ExpectedEvidenceMatches(preview, env);
-}
-
-function presentUx1Preview(preview, env) {
- if (!preview) return null;
- if (!ux1PreviewBindingStale(preview, env)) return preview;
- return {
- ...preview,
- status: "stale",
- stale: true,
- actionable: false,
- recompute_required: true,
- };
-}
-
-function ux1Flags() {
- return {
- schema_version: UX1_DRAFT_SCHEMA,
- study: UX1_STUDY,
- account_connection: "native_not_observed",
- native_observed: false,
- credential_access_unavailable: true,
- research_only: true,
- no_order: true,
- execution_authority_granted: false,
- workflow_dispatched: false,
- runtime_mutated: false,
- d1_native: "NATIVE_PENDING_EXTERNAL",
- d1_status: "PARTIAL",
- };
-}
-
-function ux1StatePayload(env, { revision, fingerprint, draft, preview, intent, job = null, duplicate = false, unchanged = false }) {
- const publicJob = projectUx1Job(job, Date.now(), revision, env);
- const waiting = Boolean(publicJob && ["queued", "running", "unknown"].includes(publicJob.status));
- let shown = waiting ? null : presentUx1Preview(preview, env);
- if (shown && ux1TerminalJobConfigStale(job, env)) {
- shown = { ...shown, status: "stale", stale: true, actionable: false, recompute_required: true };
- }
- return {
- ok: true,
- ...ux1Flags(),
- research_workflow_dispatched: job?.dispatch_state === "dispatched",
- revision,
- fingerprint,
- custom_draft: ux1CustomDraft(draft),
- draft,
- preview: shown,
- preview_stale: Boolean(shown?.stale),
- intent: waiting ? null : intent,
- job: publicJob,
- duplicate,
- unchanged,
- };
-}
-
-async function requireUx1Session(request, env) {
- const session = await readSession(request, env);
- if (!session) throw new HttpError("login required", 401);
- if (!session.allowed) throw new HttpError("allowlist required", 403);
- return session;
-}
-
-async function readUx1Body(request) {
- const text = await request.text();
- if (text.length > 16384) throw new Ux1InputError("ux1_body_too_large");
- try {
- return JSON.parse(text);
- } catch {
- throw new Ux1InputError("ux1_invalid_json");
- }
-}
-
-function parseUx1Slot(result) {
- if (!result?.found) return null;
- return {
- revision: result.revision,
- fingerprint: result.fingerprint,
- draft: JSON.parse(result.draft_json),
- preview: result.preview_json ? JSON.parse(result.preview_json) : null,
- intent: result.intent_json ? JSON.parse(result.intent_json) : null,
- job: result.job_json ? JSON.parse(result.job_json) : null,
- };
-}
-
-async function ux1ReadSlot(env, login) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("ux1_research_store_not_bound", 503);
- return parseUx1Slot(await runtimeInstanceCommand(env, { action: "ux1_read", login }));
-}
-
-async function ux1DraftGet(request, env) {
- const session = await requireUx1Session(request, env);
- const slot = await ux1ReadSlot(env, session.login);
- if (!slot) {
- const draft = defaultUx1Draft();
- return json(ux1StatePayload(env, { revision: 0, fingerprint: await ux1Fingerprint(draft), draft, preview: null, intent: null }));
- }
- return json(ux1StatePayload(env, slot));
-}
-
-async function ux1DraftPost(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await requireUx1Session(request, env);
- const parsed = assertUx1DraftPost(await readUx1Body(request));
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("ux1_research_store_not_bound", 503);
- const saved = await runtimeInstanceCommand(env, {
- action: "ux1_save",
- login: session.login,
- expected_revision: parsed.expected_revision,
- draft_json: canonicalJson(parsed.draft),
- fingerprint: await ux1Fingerprint(parsed.draft),
- });
- return json(ux1StatePayload(env, { ...parseUx1Slot({ ...saved, found: true }), unchanged: Boolean(saved.unchanged) }));
-}
-
-function ux1AbortError() {
- return new DOMException("The operation was aborted", "AbortError");
-}
-
-function abandonUx1Reader(reader) {
- if (!reader) return;
- try {
- const canceling = reader.cancel();
- if (canceling && typeof canceling.catch === "function") canceling.catch(() => {});
- } catch {
- /* cancel failed before returning a promise */
- }
-}
-
-function abandonUx1Response(response) {
- if (!response?.body) return;
- try {
- abandonUx1Reader(response.body.getReader());
- } catch {
- /* body already locked or disturbed */
- }
-}
-
-async function readLimitedUtf8Body(response, maxBytes, controller, abortPromise) {
- if (!response?.body) return "";
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
- let received = 0;
- let text = "";
- const stopReader = () => {
- if (!controller.signal.aborted) controller.abort();
- abandonUx1Reader(reader);
- };
- const onAbort = () => { abandonUx1Reader(reader); };
- controller.signal.addEventListener("abort", onAbort);
- try {
- while (true) {
- if (controller.signal.aborted) throw ux1AbortError();
- const readPromise = reader.read();
- readPromise.catch(() => {});
- const next = await Promise.race([readPromise, abortPromise]);
- if (next.done) break;
- const bytes = next.value?.byteLength ?? 0;
- received += bytes;
- if (received > maxBytes) {
- stopReader();
- throw new Error("ux1_calculator_body_limit");
- }
- text += decoder.decode(next.value, { stream: true });
- }
- text += decoder.decode();
- return text;
- } catch (error) {
- stopReader();
- throw error;
- } finally {
- controller.signal.removeEventListener("abort", onAbort);
- }
-}
-
-async function readUx1CalculatorExchange(binding, body, limits) {
- const deadlineMs = Number.isFinite(limits?.deadlineMs) ? limits.deadlineMs : UX1_CALCULATOR_DEADLINE_MS;
- const maxBytes = Number.isFinite(limits?.maxBytes) ? limits.maxBytes : UX1_CALCULATOR_MAX_BYTES;
- const controller = new AbortController();
- let rejectAbort = () => {};
- const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
- abortPromise.catch(() => {});
- const onAbort = () => rejectAbort(ux1AbortError());
- controller.signal.addEventListener("abort", onAbort);
- const timer = setTimeout(() => controller.abort(), deadlineMs);
- const pending = Promise.resolve().then(() => binding.fetch("https://ux1-research-calculator/preview", {
- method: "POST",
- headers: { "content-type": "application/json" },
- body,
- signal: controller.signal,
- }));
- let accepted = false;
- pending.then((response) => {
- if (accepted || !controller.signal.aborted) return;
- abandonUx1Response(response);
- }, () => {});
- try {
- const response = await Promise.race([pending, abortPromise]);
- accepted = true;
- const text = await readLimitedUtf8Body(response, maxBytes, controller, abortPromise);
- return { status: response.status, ok: response.ok, text };
- } finally {
- clearTimeout(timer);
- controller.signal.removeEventListener("abort", onAbort);
- }
-}
-
-async function ux1ClearStoredPreview(env, login, slot) {
- await runtimeInstanceCommand(env, {
- action: "ux1_clear_preview", login,
- expected_revision: slot.revision,
- fingerprint: slot.fingerprint,
- });
-}
-
-async function ux1PreviewPost(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await requireUx1Session(request, env);
- const parsed = assertUx1PreviewPost(await readUx1Body(request));
- const slot = await ux1ReadSlot(env, session.login);
- if (!slot || slot.revision !== parsed.expected_revision) throw new HttpError("ux1_preview_conflict", 409);
- const draft = normalizeUx1Draft(slot.draft);
- const fingerprint = await ux1Fingerprint(draft);
- if (fingerprint !== slot.fingerprint) throw new HttpError("ux1_preview_conflict", 409);
- if (ux1StoredJobBlocks(slot.job)) return json(ux1StatePayload(env, slot));
- const previewMode = ux1PreviewMode(env);
- if (previewMode === "rejected") throw new HttpError("ux1_preview_mode_rejected", 400);
- const gate = classifyUx1Draft(draft);
- let preview;
- if (gate.kind === "missing_input" || gate.kind === "unsupported_scope") {
- preview = localUx1Preview({ draft, fingerprint, status: gate.kind, reasons: gate.reasons });
- } else if (previewMode === "github_actions") {
- return await ux1DispatchPreview(env, session, slot, draft, fingerprint);
- } else {
- const binding = env.UX1_RESEARCH_CALCULATOR;
- if (!binding || typeof binding.fetch !== "function") {
- await ux1ClearStoredPreview(env, session.login, slot);
- return json({
- ok: false,
- error: "calculator_not_connected",
- status: "calculator_not_connected",
- recompute_required: true,
- ...ux1Flags(),
- revision: slot.revision,
- fingerprint,
- custom_draft: ux1CustomDraft(draft),
- draft,
- preview: null,
- decision_preview: null,
- historical_execution_check: null,
- }, 503);
- }
- const calculatorRequest = buildUx1PreviewRequest(draft);
- let exchange;
- try {
- exchange = await readUx1CalculatorExchange(binding, canonicalJson(calculatorRequest));
- } catch {
- await ux1ClearStoredPreview(env, session.login, slot);
- throw new HttpError("calculator_failed", 502);
- }
- const calculatorText = exchange.text;
- if (exchange.status === 429) {
- let busy = false;
- try { busy = JSON.parse(calculatorText).error === "calculator_busy"; } catch { busy = false; }
- if (busy) throw new HttpError("calculator_busy", 429);
- }
- if (!exchange.ok) {
- await ux1ClearStoredPreview(env, session.login, slot);
- throw new HttpError("calculator_failed", 502);
- }
- let raw;
- try {
- raw = JSON.parse(calculatorText);
- } catch {
- await ux1ClearStoredPreview(env, session.login, slot);
- throw new HttpError("calculator_failed", 502);
- }
- try {
- preview = projectUx1CalculatorResult(raw, calculatorRequest, draft, fingerprint);
- if (!ux1ExpectedEvidenceMatches(preview, env)) throw new Ux1InputError("calculator_result_rejected", 502);
- } catch (error) {
- await ux1ClearStoredPreview(env, session.login, slot);
- if (error instanceof Ux1InputError) throw new HttpError(error.message, error.status || 502);
- throw new HttpError("calculator_result_rejected", 502);
- }
- }
- preview = { ...preview, runtime_epoch: ux1RuntimeEpoch(env) };
- const stored = await runtimeInstanceCommand(env, {
- action: "ux1_store_preview",
- login: session.login,
- expected_revision: slot.revision,
- fingerprint,
- preview_json: canonicalJson(preview),
- });
- return json(ux1StatePayload(env, parseUx1Slot({ ...stored, found: true })));
-}
-
-async function ux1IntentPost(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await requireUx1Session(request, env);
- const parsed = assertUx1IntentPost(await readUx1Body(request));
- const slot = await ux1ReadSlot(env, session.login);
- if (!slot || slot.revision !== parsed.expected_revision || slot.fingerprint !== parsed.fingerprint) {
- throw new HttpError("ux1_intent_conflict", 409);
- }
- if (ux1StoredJobBlocks(slot.job)) throw new HttpError("ux1_job_active", 409);
- if (ux1PreviewBindingStale(slot.preview, env) || ux1TerminalJobConfigStale(slot.job, env)) throw new HttpError("ux1_preview_stale", 409);
- if (!ux1IntentAllowed(slot.preview) || slot.preview.fingerprint !== parsed.fingerprint) {
- throw new HttpError("ux1_intent_conflict", 409);
- }
- const intent = ux1IntentRecord({
- login: session.login,
- revision: slot.revision,
- fingerprint: slot.fingerprint,
- receiptId: await ux1ReceiptId(session.login, slot.revision, slot.fingerprint),
- });
- const stored = await runtimeInstanceCommand(env, {
- action: "ux1_save_intent",
- login: session.login,
- expected_revision: slot.revision,
- fingerprint: slot.fingerprint,
- intent_json: canonicalJson(intent),
- });
- return json(ux1StatePayload(env, { ...parseUx1Slot({ ...stored, found: true }), duplicate: Boolean(stored.duplicate) }));
-}
-
-function ux1PreviewMode(env) {
- const mode = String(env?.UX1_PREVIEW_MODE ?? "").trim();
- if (!mode) return "local";
- if (mode === "github_actions") return "github_actions";
- return "rejected";
-}
-
-function ux1EvidenceRecord(value) {
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
- if (Object.keys(value).length !== UX1_EVIDENCE_HASH_KEYS.length) return null;
- const evidence = {};
- for (const key of UX1_EVIDENCE_HASH_KEYS) {
- if (typeof value[key] !== "string" || !/^[a-f0-9]{64}$/.test(value[key])) return null;
- evidence[key] = value[key];
- }
- return evidence;
-}
-
-function ux1AsyncConfig(env) {
- const ues = String(env?.UX1_UES_REVISION || "");
- const epoch = String(env?.UX1_RUNTIME_EPOCH || "");
- const token = String(env?.UX1_RESEARCH_JOB_TOKEN || "");
- if (!/^[a-f0-9]{40}$/.test(ues) || !/^[a-f0-9]{32}$/.test(epoch) || token.length < 16 || token.length > 256) return null;
- return ux1EvidenceRecord(ux1ParseJsonObject(env?.UX1_EXPECTED_EVIDENCE_HASHES))
- ? { ues, epoch, evidence: ux1EvidenceRecord(ux1ParseJsonObject(env.UX1_EXPECTED_EVIDENCE_HASHES)) }
- : null;
-}
-
-function ux1ParseJsonObject(text) {
- if (typeof text !== "string" || !text) return null;
- try {
- const parsed = JSON.parse(text);
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
- } catch {
- return null;
- }
-}
-
-function ux1StoredJobBlocks(job) {
- return Boolean(job && (job.status === "queued" || job.status === "running" || job.status === "unknown"));
-}
-
-function ux1PublicJobReason(reason) {
- return UX1_PUBLIC_JOB_REASONS.has(reason) ? reason : null;
-}
-
-function ux1JobConfigStale(job, env) {
- const config = ux1AsyncConfig(env);
- if (!config || !job) return false;
- if (job.runtime_epoch !== config.epoch || job.ues_revision !== config.ues) return true;
- return UX1_EVIDENCE_HASH_KEYS.some((key) => job.evidence?.[key] !== config.evidence[key]);
-}
-
-function ux1TerminalJobConfigStale(job, env) {
- return Boolean(job && !ux1StoredJobBlocks(job) && ux1JobConfigStale(job, env));
-}
-
-function ux1JobBindingMatchesConfig(job, env) {
- return Boolean(job && ux1AsyncConfig(env) && !ux1JobConfigStale(job, env));
-}
-
-function projectUx1Job(job, now, slotRevision, env) {
- if (!job || typeof job !== "object") return null;
- const created = Date.parse(job.created_at);
- const age = Number.isFinite(created) ? now - created : 0;
- let status = job.status;
- let reason = job.reason || null;
- if (ux1StoredJobBlocks(job) && age >= UX1_JOB_UNKNOWN_AFTER_MS) {
- status = "unknown";
- reason = "check_required";
- } else if (!ux1StoredJobBlocks(job) && (job.revision !== slotRevision || ux1JobConfigStale(job, env))) {
- status = "superseded";
- reason = "config_changed";
- }
- return {
- request_id: job.request_id,
- status,
- dispatch_state: job.dispatch_state,
- created_at: job.created_at,
- updated_at: job.updated_at,
- reason: ux1PublicJobReason(reason),
- };
-}
-
-function ux1BearerMatches(header, secret) {
- const match = /^Bearer ([!-~]{16,256})$/.exec(String(header || ""));
- if (!match || typeof secret !== "string" || secret.length < 16 || secret.length > 256) return false;
- const left = new TextEncoder().encode(match[1]);
- const right = new TextEncoder().encode(secret);
- let diff = left.length ^ right.length;
- const length = Math.max(left.length, right.length);
- for (let index = 0; index < length; index += 1) diff |= (left[index] || 0) ^ (right[index] || 0);
- return diff === 0;
-}
-
-function ux1ExactKeys(value, keys) {
- return Boolean(value && typeof value === "object" && !Array.isArray(value)
- && Object.keys(value).length === keys.length
- && keys.every((key) => Object.hasOwn(value, key)));
-}
-
-function ux1RequestIdOk(value) {
- return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
-}
-
-function ux1PositiveInt(value) {
- return typeof value === "string" && /^[1-9][0-9]{0,18}$/.test(value);
-}
-
-async function ux1Digest(value) {
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalJson(value)));
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function readUx1LimitedJson(request, maxBytes) {
- const controller = new AbortController();
- let rejectAbort = () => {};
- const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
- abortPromise.catch(() => {});
- const onAbort = () => rejectAbort(ux1AbortError());
- controller.signal.addEventListener("abort", onAbort);
- const timer = setTimeout(() => controller.abort(), UX1_GITHUB_DEADLINE_MS);
- try {
- const text = await readLimitedUtf8Body(request, maxBytes, controller, abortPromise);
- try {
- return JSON.parse(text);
- } catch {
- throw new HttpError("ux1_invalid_body", 400);
- }
- } catch (error) {
- if (error instanceof HttpError) throw error;
- if (String(error?.message || "") === "ux1_calculator_body_limit") throw new HttpError("ux1_body_too_large", 400);
- throw new HttpError("ux1_invalid_body", 400);
- } finally {
- clearTimeout(timer);
- controller.signal.removeEventListener("abort", onAbort);
- }
-}
-
-async function ux1GithubExchange(url, init) {
- const controller = new AbortController();
- let rejectAbort = () => {};
- const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
- abortPromise.catch(() => {});
- const onAbort = () => rejectAbort(ux1AbortError());
- controller.signal.addEventListener("abort", onAbort);
- const timer = setTimeout(() => controller.abort(), UX1_GITHUB_DEADLINE_MS);
- const pending = Promise.resolve().then(() => fetch(url, { ...init, redirect: "manual", signal: controller.signal }));
- let accepted = false;
- pending.then((response) => {
- if (accepted || !controller.signal.aborted) return;
- abandonUx1Response(response);
- }, () => {});
- try {
- const response = await Promise.race([pending, abortPromise]);
- accepted = true;
- const text = await readLimitedUtf8Body(response, UX1_GITHUB_MAX_BYTES, controller, abortPromise);
- return { status: response.status, ok: response.ok, text };
- } finally {
- clearTimeout(timer);
- controller.signal.removeEventListener("abort", onAbort);
- }
-}
-
-async function ux1DispatchResearchJob(env, requestId) {
- if (!env.RUNTIME_SETTINGS_DISPATCH_TOKEN) return "unknown";
- try {
- const exchange = await ux1GithubExchange(
- `https://api.github.com/repos/${UX1_RESEARCH_REPOSITORY}/actions/workflows/${UX1_RESEARCH_WORKFLOW_FILE}/dispatches`,
- {
- method: "POST",
- headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
- body: JSON.stringify({ ref: "main", inputs: { ux1_request_id: requestId } }),
- },
- );
- if (exchange.status >= 200 && exchange.status < 300) return "dispatched";
- if (exchange.status >= 400 && exchange.status < 500) return "rejected";
- return "unknown";
- } catch {
- return "unknown";
- }
-}
-
-async function ux1DispatchPreview(env, session, slot, draft, fingerprint) {
- const config = ux1AsyncConfig(env);
- if (!config || !env.RUNTIME_SETTINGS_DISPATCH_TOKEN) {
- await ux1ClearStoredPreview(env, session.login, slot);
- return json({
- ok: false,
- error: "ux1_async_not_connected",
- status: "ux1_async_not_connected",
- recompute_required: true,
- ...ux1Flags(),
- research_workflow_dispatched: false,
- revision: slot.revision,
- fingerprint,
- custom_draft: ux1CustomDraft(draft),
- draft,
- preview: null,
- job: projectUx1Job(slot.job, Date.now(), slot.revision, env),
- decision_preview: null,
- historical_execution_check: null,
- }, 503);
- }
- const begun = await runtimeInstanceCommand(env, {
- action: "ux1_begin_job",
- login: session.login,
- revision: slot.revision,
- fingerprint,
- epoch: config.epoch,
- ues: config.ues,
- evidence: config.evidence,
- request: buildUx1PreviewRequest(draft),
- });
- const job = JSON.parse(begun.job_json);
- if (begun.created) {
- const outcome = await ux1DispatchResearchJob(env, job.request_id);
- await runtimeInstanceCommand(env, {
- action: "ux1_record_dispatch",
- login: session.login,
- request_id: job.request_id,
- outcome,
- });
- }
- return json(ux1StatePayload(env, await ux1ReadSlot(env, session.login)));
-}
-
-function ux1RunMatches(run, job, runId, runAttempt) {
- if (!run || typeof run !== "object" || Array.isArray(run) || !job) return false;
- const repository = run.repository;
- const headRepository = run.head_repository;
- if (!repository || typeof repository !== "object" || !headRepository || typeof headRepository !== "object") return false;
- return String(run.id) === runId
- && run.event === "workflow_dispatch"
- && run.path === UX1_RESEARCH_WORKFLOW_PATH
- && run.head_sha === job.ues_revision
- && run.display_title === `UX1 preview ${job.request_id}`
- && String(run.run_attempt) === runAttempt
- && run.head_branch === "main"
- && repository.full_name === UX1_RESEARCH_REPOSITORY
- && headRepository.full_name === UX1_RESEARCH_REPOSITORY
- && repository.fork !== true
- && headRepository.fork !== true;
-}
-
-async function ux1FetchRun(env, runId) {
- let exchange;
- try {
- exchange = await ux1GithubExchange(
- `https://api.github.com/repos/${UX1_RESEARCH_REPOSITORY}/actions/runs/${runId}`,
- { method: "GET", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN) },
- );
- } catch {
- throw new HttpError("ux1_run_unverified", 502);
- }
- if (!exchange.ok) throw new HttpError("ux1_run_unverified", 502);
- try {
- return JSON.parse(exchange.text);
- } catch {
- throw new HttpError("ux1_run_unverified", 502);
- }
-}
-
-function ux1ClaimDenied(requestId, runId, runAttempt) {
- return json({ ok: true, claimed: false, request_id: requestId, run_id: runId, run_attempt: runAttempt });
-}
-
-async function ux1JobClaimPost(request, env) {
- if (!ux1BearerMatches(request.headers.get("Authorization"), env.UX1_RESEARCH_JOB_TOKEN)) {
- throw new HttpError("ux1_job_unauthorized", 401);
- }
- const body = await readUx1LimitedJson(request, UX1_JOB_BODY_MAX_BYTES);
- if (!ux1ExactKeys(body, ["request_id", "run_id", "run_attempt"]) || !ux1RequestIdOk(body.request_id) || !ux1PositiveInt(body.run_id) || !ux1PositiveInt(body.run_attempt)) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- const looked = await runtimeInstanceCommand(env, { action: "ux1_lookup_job", request_id: body.request_id });
- if (!looked.found) throw new HttpError("ux1_job_not_found", 404);
- const job = JSON.parse(looked.job_json);
- if (job.claimed_run_id || (job.status !== "queued" && job.status !== "unknown")) {
- return ux1ClaimDenied(body.request_id, body.run_id, body.run_attempt);
- }
- const draft = {
- objective: job.request?.objective,
- research_case_id: job.request?.research_case_id,
- advanced_settings: job.request?.advanced_settings,
- };
- try {
- if (!job.request || canonicalJson(buildUx1PreviewRequest(draft)) !== canonicalJson(job.request) || await ux1Fingerprint(draft) !== job.fingerprint) {
- throw new HttpError("ux1_run_unverified", 502);
- }
- } catch (error) {
- if (error instanceof HttpError) throw error;
- throw new HttpError("ux1_run_unverified", 502);
- }
- const run = await ux1FetchRun(env, body.run_id);
- if (!ux1RunMatches(run, job, body.run_id, body.run_attempt)) throw new HttpError("ux1_run_unverified", 502);
- const claimed = await runtimeInstanceCommand(env, {
- action: "ux1_claim_job",
- request_id: body.request_id,
- run_id: body.run_id,
- run_attempt: body.run_attempt,
- });
- if (!claimed.claimed) return ux1ClaimDenied(body.request_id, body.run_id, body.run_attempt);
- return json({
- ok: true,
- claimed: true,
- request_id: body.request_id,
- run_id: body.run_id,
- run_attempt: body.run_attempt,
- request: claimed.request,
- });
-}
-
-async function ux1JobResultPost(request, env) {
- if (!ux1BearerMatches(request.headers.get("Authorization"), env.UX1_RESEARCH_JOB_TOKEN)) {
- throw new HttpError("ux1_job_unauthorized", 401);
- }
- const body = await readUx1LimitedJson(request, UX1_JOB_BODY_MAX_BYTES);
- if (!ux1ExactKeys(body, ["request_id", "run_id", "run_attempt", "result", "error_code"]) || !ux1RequestIdOk(body.request_id) || !ux1PositiveInt(body.run_id) || !ux1PositiveInt(body.run_attempt)) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- if (!(body.error_code === null || body.error_code === "input_unavailable" || body.error_code === "calculator_failed")) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- if (body.error_code === null ? body.result === null : body.result !== null) throw new HttpError("ux1_invalid_body", 400);
- const looked = await runtimeInstanceCommand(env, { action: "ux1_lookup_job", request_id: body.request_id });
- if (!looked.found) throw new HttpError("ux1_job_not_found", 404);
- const job = JSON.parse(looked.job_json);
- if (job.claimed_run_id !== body.run_id || job.claimed_run_attempt !== body.run_attempt) {
- throw new HttpError("ux1_result_conflict", 409);
- }
- let previewJson = null;
- if (!body.error_code) {
- const draft = {
- objective: job.request?.objective,
- research_case_id: job.request?.research_case_id,
- advanced_settings: job.request?.advanced_settings,
- };
- try {
- if (canonicalJson(buildUx1PreviewRequest(draft)) !== canonicalJson(job.request)) throw new Ux1InputError("calculator_result_rejected", 502);
- const preview = projectUx1CalculatorResult(body.result, job.request, draft, job.fingerprint);
- const evidence = { evidence: Object.fromEntries(UX1_EVIDENCE_HASH_KEYS.map((key) => [key, preview.evidence?.[key]])) };
- if (!preview.evidence || !ux1ExpectedEvidenceMatches(evidence, { UX1_EXPECTED_EVIDENCE_HASHES: JSON.stringify(job.evidence) })) {
- throw new Ux1InputError("calculator_result_rejected", 502);
- }
- if (ux1JobBindingMatchesConfig(job, env)) previewJson = canonicalJson({ ...preview, runtime_epoch: job.runtime_epoch });
- } catch (error) {
- if (error instanceof Ux1InputError && error.message === "calculator_failed") throw new HttpError("calculator_failed", 502);
- throw new HttpError("calculator_result_rejected", 502);
- }
- }
- const finished = await runtimeInstanceCommand(env, {
- action: "ux1_finish_job",
- request_id: body.request_id,
- run_id: body.run_id,
- run_attempt: body.run_attempt,
- error_code: body.error_code,
- preview_json: previewJson,
- terminal_digest: await ux1Digest({ error_code: body.error_code, result: body.result }),
- });
- return json({ ok: true, accepted: true, duplicate: Boolean(finished.duplicate) });
-}
-
-function ux1SelectSlot(sql, login) {
- return sql.exec(
- "SELECT revision, draft_json, fingerprint, preview_json, intent_json, job_json FROM ux1_research_slot WHERE login = ?",
- login,
- ).toArray()[0] || null;
-}
-
-function ux1SlotPayload(row, extra = {}) {
- return {
- ok: true,
- found: Boolean(row),
- revision: row ? Number(row.revision) : 0,
- draft_json: row?.draft_json || null,
- fingerprint: row?.fingerprint || null,
- preview_json: row?.preview_json || null,
- intent_json: row?.intent_json || null,
- job_json: row?.job_json || null,
- ...extra,
- };
-}
-
-function ux1ParseStoredJob(text) {
- if (!text) return null;
- try {
- const job = JSON.parse(text);
- return job && typeof job === "object" && !Array.isArray(job) ? job : null;
- } catch {
- return null;
- }
-}
-
-function ux1SelectJob(sql, requestId) {
- return sql.exec(
- `SELECT login, revision, draft_json, fingerprint, preview_json, intent_json, job_json
- FROM ux1_research_slot WHERE json_extract(job_json, '$.request_id') = ?`,
- requestId,
- ).toArray()[0] || null;
-}
-
-function ux1WriteJob(sql, login, job) {
- const text = JSON.stringify(job);
- if (text.length > 65536) throw new HttpError("ux1_invalid_body", 400);
- sql.exec("UPDATE ux1_research_slot SET job_json = ? WHERE login = ?", text, login);
- return text;
-}
-
-function ux1SameSucceededBinding(job, command, row) {
- const evidence = ux1EvidenceRecord(command.evidence);
- if (!job || job.status !== "succeeded" || !evidence || !row) return false;
- return job.revision === Number(row.revision)
- && job.fingerprint === row.fingerprint
- && job.revision === command.revision
- && job.fingerprint === command.fingerprint
- && job.runtime_epoch === command.epoch
- && job.ues_revision === command.ues
- && UX1_EVIDENCE_HASH_KEYS.every((key) => job.evidence?.[key] === evidence[key]);
-}
-
-function ux1MutateJob(sql, command) {
- if (command.action === "ux1_lookup_job") {
- if (!ux1RequestIdOk(command.request_id)) throw new HttpError("ux1_invalid_body", 400);
- const row = ux1SelectJob(sql, command.request_id);
- return row ? ux1SlotPayload(row) : { ok: true, found: false };
- }
- if (command.action === "ux1_claim_job" || command.action === "ux1_finish_job") {
- if (!ux1RequestIdOk(command.request_id) || !ux1PositiveInt(command.run_id) || !ux1PositiveInt(command.run_attempt)) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- const row = ux1SelectJob(sql, command.request_id);
- if (!row) throw new HttpError("ux1_job_not_found", 404);
- const job = ux1ParseStoredJob(row.job_json);
- if (!job) throw new HttpError("ux1_job_not_found", 404);
- const now = new Date().toISOString();
- if (command.action === "ux1_claim_job") {
- if (job.claimed_run_id || (job.status !== "queued" && job.status !== "unknown")) {
- return { ok: true, claimed: false };
- }
- job.status = "running";
- job.claimed_run_id = command.run_id;
- job.claimed_run_attempt = command.run_attempt;
- job.updated_at = now;
- ux1WriteJob(sql, row.login, job);
- return { ok: true, claimed: true, request: job.request };
- }
- if (job.claimed_run_id !== command.run_id || job.claimed_run_attempt !== command.run_attempt) {
- throw new HttpError("ux1_result_conflict", 409);
- }
- if (job.terminal_digest) {
- if (job.terminal_digest === command.terminal_digest) return { ok: true, duplicate: true };
- throw new HttpError("ux1_result_conflict", 409);
- }
- if (job.status !== "running") throw new HttpError("ux1_result_conflict", 409);
- if (typeof command.terminal_digest !== "string" || !/^[a-f0-9]{64}$/.test(command.terminal_digest)) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- job.status = command.error_code ? "failed" : "succeeded";
- job.reason = command.error_code || null;
- job.terminal_digest = command.terminal_digest;
- job.updated_at = now;
- ux1WriteJob(sql, row.login, job);
- const sameSlot = Number(row.revision) === job.revision && row.fingerprint === job.fingerprint;
- if (command.error_code && sameSlot) {
- sql.exec(
- "UPDATE ux1_research_slot SET preview_json = NULL, intent_json = NULL WHERE login = ? AND revision = ? AND fingerprint = ?",
- row.login, Number(row.revision), row.fingerprint,
- );
- } else if (!command.error_code && sameSlot && typeof command.preview_json === "string" && command.preview_json.length <= 65536) {
- sql.exec(
- "UPDATE ux1_research_slot SET preview_json = ? WHERE login = ? AND revision = ? AND fingerprint = ?",
- command.preview_json, row.login, Number(row.revision), row.fingerprint,
- );
- }
- return { ok: true, duplicate: false };
- }
- const login = String(command?.login || "");
- if (!/^[a-z0-9-]{1,39}$/.test(login)) throw new HttpError("ux1_login_invalid", 400);
- const row = ux1SelectSlot(sql, login);
- if (!row) throw new HttpError("ux1_preview_conflict", 409);
- const job = ux1ParseStoredJob(row.job_json);
- if (command.action === "ux1_begin_job") {
- if (ux1StoredJobBlocks(job)) return { ...ux1SlotPayload(row), created: false };
- if (ux1SameSucceededBinding(job, command, row)) return { ...ux1SlotPayload(row), created: false };
- const evidence = ux1EvidenceRecord(command.evidence);
- if (!evidence || command.revision !== Number(row.revision) || command.fingerprint !== row.fingerprint) {
- throw new HttpError("ux1_preview_conflict", 409);
- }
- if (!/^[a-f0-9]{32}$/.test(String(command.epoch || "")) || !/^[a-f0-9]{40}$/.test(String(command.ues || ""))) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- if (!command.request || command.request.schema !== "qsl.ux1.preview_request.v1" || JSON.stringify(command.request).length > 16384) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- const now = new Date().toISOString();
- const next = {
- request_id: crypto.randomUUID(),
- status: "queued",
- dispatch_state: "pending",
- revision: Number(row.revision),
- fingerprint: row.fingerprint,
- runtime_epoch: command.epoch,
- ues_revision: command.ues,
- evidence,
- request: command.request,
- created_at: now,
- updated_at: now,
- claimed_run_id: null,
- claimed_run_attempt: null,
- reason: null,
- terminal_digest: null,
- };
- const jobJson = ux1WriteJob(sql, login, next);
- sql.exec("UPDATE ux1_research_slot SET preview_json = NULL, intent_json = NULL WHERE login = ?", login);
- return { ...ux1SlotPayload(row), preview_json: null, intent_json: null, job_json: jobJson, created: true };
- }
- if (command.action === "ux1_record_dispatch") {
- if (!job || job.request_id !== command.request_id || job.dispatch_state !== "pending") {
- return { ...ux1SlotPayload(row), recorded: false };
- }
- if (command.outcome === "dispatched") job.dispatch_state = "dispatched";
- else if (command.outcome === "rejected") {
- job.dispatch_state = "rejected";
- if (job.status === "queued") job.status = "failed";
- job.reason = "dispatch_rejected";
- } else {
- job.dispatch_state = "unknown";
- if (job.status === "queued") job.status = "unknown";
- job.reason = "dispatch_unconfirmed";
- }
- job.updated_at = new Date().toISOString();
- const jobJson = ux1WriteJob(sql, login, job);
- return { ...ux1SlotPayload(row), job_json: jobJson, recorded: true };
- }
- throw new HttpError("unsupported_ux1_action", 400);
-}
-
-function runtimeInstanceAccountOptions(instances) {
- const options = {};
- for (const instance of instances) {
- if (instance.kind !== "existing") continue;
- (options[instance.platform] ||= []).push(instance.config);
- }
- return options;
-}
-
-function runtimeInstanceConflict(instances, platform, config, exceptKey = null) {
- const selectors = (value) => String(value || "").split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
- for (const item of instances) {
- if (item.platform !== platform || item.key === exceptKey) continue;
- const other = item.config;
- if (item.key === config.key || other.target_name === config.target_name ||
- (other.service_name && other.service_name === config.service_name) ||
- selectors(other.account_selector).some((value) => selectors(config.account_selector).includes(value))) {
- throw new HttpError("runtime_instance_identity_conflict", 409);
- }
- }
-}
-
-function runtimeInstanceFields(raw, allowed) {
- if (!raw || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).some((key) => !allowed.includes(key))) {
- throw new HttpError("invalid_runtime_instance_fields", 400);
- }
-}
-
-function accountDiagnosisTaskFromRow(row) {
- if (!row) return null;
- return {
- request_id: row.request_id,
- platform: row.platform,
- key: row.account_key,
- target_id: row.target_id,
- trigger: row.trigger,
- observed_at: row.observed_at,
- checks: JSON.parse(row.checks_json),
- state_fingerprint: row.state_fingerprint,
- status: row.status,
- native: row.native_json ? JSON.parse(row.native_json) : null,
- backend_kind: row.native_json ? "native" : "legacy",
- workflow_run_id: row.workflow_run_id || null,
- workflow_run_attempt: row.workflow_run_attempt || null,
- job_id: row.job_id || null,
- summary: row.summary || "",
- reason_code: row.reason_code || "",
- dispatch_state: row.dispatch_state,
- recheck_dispatch_state: row.recheck_dispatch_state,
- auto_source: row.auto_source || "manual",
- created_at: row.created_at,
- updated_at: row.updated_at,
- };
-}
-
-function researchPromotionApplicationFromRow(row) {
- if (!row) return null;
- return {
- application_id: row.application_id,
- ticket_id: row.ticket_id,
- status: row.status,
- dispatch_state: row.dispatch_state,
- claim_token: row.claim_token,
- platform_id: row.platform_id,
- account_key: row.account_key,
- account_scope: row.account_scope,
- account_selector: row.account_selector,
- service_name: row.service_name,
- broker_environment: row.broker_environment,
- expected_revision: Number(row.expected_revision),
- expected_strategy_profile: row.expected_strategy_profile,
- strategy_profile: row.strategy_profile,
- candidate_id: row.candidate_id,
- config_sha256: row.config_sha256,
- source_commit: row.source_commit,
- approved_ues_revision: row.approved_ues_revision,
- desired_state: row.desired_state,
- workflow_run_id: row.workflow_run_id || null,
- workflow_run_attempt: row.workflow_run_attempt || null,
- reason_code: row.reason_code || "",
- readback: row.readback_json ? JSON.parse(row.readback_json) : null,
- created_at: row.created_at,
- updated_at: row.updated_at,
- };
-}
-
-async function runtimeInstancesResponse(request, env) {
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- if (request.method === "GET") return json(await runtimeInstanceCommand(env));
- if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
- requireSameOrigin(request, { requireOrigin: true });
- let raw;
- try {
- const text = await request.text();
- if (text.length > 16384) throw new Error();
- raw = JSON.parse(text);
- } catch {
- throw new HttpError("invalid_runtime_instance_request", 400);
- }
- runtimeInstanceFields(raw, ["action", "expected_revision", "platform", "key", "config", "broker_environment", "confirm"]);
- const command = { action: raw.action, expected_revision: raw.expected_revision, actor: session.login };
- if (raw.action === "initialize") {
- if (raw.confirm !== "IMPORT_EXISTING_CONFIG") throw new HttpError("runtime_instance_import_confirmation_required", 400);
- // Explicit, one-time import only. A deployment must freeze legacy writers
- // and review this input before enabling the binding and importing it.
- command.account_options = (await loadLegacyAccountOptionsConfig(env)).options || {};
- } else if (raw.action === "create" || raw.action === "edit") {
- try {
- if (!SUPPORTED_PLATFORMS.includes(raw.platform) || PLATFORM_CONFIG[raw.platform].dry_run_only) throw new Error();
- runtimeInstanceFields(raw.config, ["key", "label", "target_name", "account_selector", "deployment_selector", "account_scope", "service_name", "github_environment", "variable_scope", "cash_currency", "supported_domains", "broker_environment", "default_strategy_profile", "default_execution_mode"]);
- const option = cleanAccountOption(raw.config, raw.platform, 0);
- if (!option.account_selector || !option.deployment_selector || !option.service_name) throw new Error();
- option.default_execution_mode = raw.config.default_execution_mode || "dry_run";
- option.default_strategy_profile = cleanSlug(raw.config.default_strategy_profile, "default_strategy_profile");
- assertStrategyAllowedForAccount({ platform: raw.platform, strategy_profile: option.default_strategy_profile, execution_mode: option.default_execution_mode }, option, await loadStrategyProfilesConfig(env));
- command.platform = raw.platform;
- command.config = option;
- if (raw.action === "edit") command.key = cleanSlug(raw.key, "key");
- } catch {
- throw new HttpError("invalid_runtime_instance_config", 400);
- }
- } else if (raw.action === "set_broker_environment") {
- try {
- if (!SUPPORTED_PLATFORMS.includes(raw.platform) || PLATFORM_CONFIG[raw.platform].dry_run_only) throw new Error();
- command.platform = cleanChoice(raw.platform, SUPPORTED_PLATFORMS, "platform");
- command.key = cleanSlug(raw.key, "key");
- command.broker_environment = normalizeBrokerEnvironment(raw.broker_environment);
- if (!supportedBrokerEnvironmentsForPlatform(command.platform).includes(command.broker_environment)) throw new Error();
- } catch {
- throw new HttpError("invalid_broker_environment", 400);
- }
- } else if (raw.action === "request_retirement") {
- command.platform = raw.platform;
- command.key = raw.key;
- } else {
- throw new HttpError("unsupported_runtime_instance_action", 400);
- }
- return json(await runtimeInstanceCommand(env, command));
-}
-
-import { dateOnlyExternalFlow, externalFlowEnabled, initializeExternalFlow, normalizeExternalFlow, putExternalFlow, readExternalFlow, readExternalFlowCoverage } from "./application/account_facts/external_flow.js";
-import { initializeExecutions, normalizeExecutions, putExecutions, readExecutions } from "./application/account_facts/executions.js";
-
-export class RuntimeInstances {
- constructor(ctx, env) {
- this.directory = new KvDirectory(ctx.storage, env?.STRATEGY_SWITCH_CONFIG, env);
- this.storage = ctx.storage;
- this.sql = ctx.storage.sql;
- initializeExecutions(this.sql);
- this.externalFlowEnabled = externalFlowEnabled(env);
- initializeExternalFlow(this.sql);
- initializeCredentialMaintenance(this.sql);
- initializeSecretRotation(this.sql);
- this.rotationEnv = env;
- this.deskReadbacks = new DeskReadbackStore(ctx.storage, async (id, actor) => {
- const state = this.read();
- const target = readbackTargets({ options: runtimeInstanceAccountOptions(state.instances), revision: state.revision }).find(target => target.id === id);
- if (!target) throw new DeskError("not_found", 404);
- let observed = null;
- try { observed = this.readAccountSettings({ platform: target.platform, key: target.key, legacy: await readRiskProfileLegacy(env) }); } catch { /* Degrade saved independently. */ }
- return deskTargetReadback(env, target, actor, observed);
- });
- // Native intervals remain in the existing private account read-model store.
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_period_return (
- account_key TEXT PRIMARY KEY, payload_json TEXT NOT NULL
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_daily_native_return (
- account_key TEXT NOT NULL, source_binding_id TEXT NOT NULL, currency TEXT NOT NULL,
- observation_date TEXT NOT NULL, payload_json TEXT NOT NULL,
- PRIMARY KEY(account_key, source_binding_id, currency, observation_date)
- )`);
- // Dormant: only an independent protected provisioning step may seed admission.
- // There is deliberately no ingress/admin command that writes an admission.
- this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_source (
- source_id TEXT PRIMARY KEY, target_id TEXT NOT NULL UNIQUE, binding_fingerprint TEXT NOT NULL,
- configuration_sha256 TEXT NOT NULL, authority_revision INTEGER NOT NULL,
- required_from TEXT NOT NULL, observed_at TEXT, observation_json TEXT,
- observation_sha256 TEXT, received_at TEXT, checkpoint_revision INTEGER
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_checkpoint (
- target_id TEXT NOT NULL, binding_fingerprint TEXT NOT NULL, source_id TEXT NOT NULL,
- revision INTEGER NOT NULL, payload_json TEXT NOT NULL,
- PRIMARY KEY (target_id, binding_fingerprint)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_incident (
- target_id TEXT NOT NULL, binding_fingerprint TEXT NOT NULL, source_id TEXT NOT NULL,
- cycle_id TEXT NOT NULL, cycle_json TEXT NOT NULL, category TEXT NOT NULL,
- active_category TEXT, latest_fault_at TEXT NOT NULL, attempt_count INTEGER NOT NULL,
- resolution_history_json TEXT NOT NULL,
- PRIMARY KEY (target_id, binding_fingerprint, source_id, cycle_id)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS runtime_cycle_health_attempt (
- history_id INTEGER PRIMARY KEY AUTOINCREMENT,
- target_id TEXT NOT NULL, binding_fingerprint TEXT NOT NULL, source_id TEXT NOT NULL,
- cycle_id TEXT NOT NULL, attempt_key TEXT NOT NULL, fault_at TEXT NOT NULL,
- category TEXT NOT NULL, configuration_sha256 TEXT NOT NULL, cycle_json TEXT NOT NULL,
- resolution_ref TEXT,
- UNIQUE (target_id, binding_fingerprint, source_id, attempt_key)
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS runtime_cycle_health_history_page ON runtime_cycle_health_attempt (target_id, source_id, history_id)");
- this.sql.exec("CREATE TABLE IF NOT EXISTS instance_state (id INTEGER PRIMARY KEY CHECK (id = 1), revision INTEGER NOT NULL, payload TEXT NOT NULL)");
- this.sql.exec("CREATE TABLE IF NOT EXISTS instance_history (revision INTEGER PRIMARY KEY, entry TEXT NOT NULL)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_diagnosis_tasks (
- request_id TEXT PRIMARY KEY,
- platform TEXT NOT NULL,
- account_key TEXT NOT NULL,
- target_id TEXT NOT NULL,
- trigger TEXT NOT NULL,
- observed_at TEXT NOT NULL,
- checks_json TEXT NOT NULL,
- state_fingerprint TEXT NOT NULL,
- status TEXT NOT NULL,
- workflow_run_id TEXT,
- workflow_run_attempt TEXT,
- job_id TEXT,
- summary TEXT NOT NULL,
- reason_code TEXT NOT NULL,
- dispatch_state TEXT NOT NULL,
- recheck_dispatch_state TEXT NOT NULL,
- created_at TEXT NOT NULL,
- updated_at TEXT NOT NULL
- )`);
- try { this.sql.exec("ALTER TABLE account_diagnosis_tasks ADD COLUMN auto_source TEXT NOT NULL DEFAULT 'manual'"); } catch { /* already present */ }
- try { this.sql.exec("ALTER TABLE account_diagnosis_tasks ADD COLUMN native_json TEXT"); } catch { /* already present */ }
- this.sql.exec("CREATE INDEX IF NOT EXISTS account_diagnosis_tasks_fingerprint ON account_diagnosis_tasks (target_id, state_fingerprint, updated_at)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS research_promotion_applications (
- application_id TEXT PRIMARY KEY,
- ticket_id TEXT NOT NULL,
- status TEXT NOT NULL,
- dispatch_state TEXT NOT NULL,
- claim_token TEXT NOT NULL,
- platform_id TEXT NOT NULL,
- account_key TEXT NOT NULL,
- account_scope TEXT NOT NULL,
- account_selector TEXT NOT NULL,
- service_name TEXT NOT NULL,
- broker_environment TEXT NOT NULL,
- expected_revision INTEGER NOT NULL,
- expected_strategy_profile TEXT NOT NULL,
- strategy_profile TEXT NOT NULL,
- candidate_id TEXT NOT NULL,
- config_sha256 TEXT NOT NULL,
- source_commit TEXT NOT NULL,
- approved_ues_revision TEXT NOT NULL,
- desired_state TEXT NOT NULL,
- workflow_run_id TEXT,
- workflow_run_attempt TEXT,
- reason_code TEXT NOT NULL,
- readback_json TEXT,
- created_at TEXT NOT NULL,
- updated_at TEXT NOT NULL
- )`);
- // A rejected application is a terminal record, but an explicitly
- // re-qualified user request may create a new attempt. Keep history while
- // deduplicating all still-active/uncertain attempts.
- this.sql.exec("DROP INDEX IF EXISTS research_promotion_applications_ticket_account");
- this.sql.exec("CREATE INDEX IF NOT EXISTS research_promotion_applications_ticket_account_idx ON research_promotion_applications (ticket_id, platform_id, account_key, status)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS ux1_research_slot (
- login TEXT PRIMARY KEY,
- revision INTEGER NOT NULL,
- draft_json TEXT NOT NULL,
- fingerprint TEXT NOT NULL,
- preview_json TEXT,
- intent_json TEXT,
- job_json TEXT
- )`);
- try {
- this.sql.exec("ALTER TABLE ux1_research_slot ADD COLUMN job_json TEXT");
- } catch {
- /* already migrated */
- }
- this.sql.exec(`CREATE TABLE IF NOT EXISTS human_decision_material (
- kind TEXT NOT NULL,
- subject_id TEXT NOT NULL,
- source_id TEXT NOT NULL,
- material_key TEXT NOT NULL,
- summary_json TEXT NOT NULL,
- eligible INTEGER NOT NULL,
- expires_at_ms INTEGER,
- legacy_state TEXT NOT NULL,
- legacy_block TEXT NOT NULL,
- updated_at TEXT NOT NULL,
- PRIMARY KEY (kind, subject_id)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS human_decision_record (
- request_key TEXT PRIMARY KEY,
- kind TEXT NOT NULL,
- subject_id TEXT NOT NULL,
- material_key TEXT NOT NULL,
- action TEXT NOT NULL,
- actor TEXT NOT NULL,
- decided_at TEXT NOT NULL,
- target_json TEXT NOT NULL,
- payload_json TEXT NOT NULL
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS human_decision_record_subject ON human_decision_record (kind, subject_id, material_key)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS human_decision_source_material (
- kind TEXT NOT NULL,
- subject_id TEXT NOT NULL,
- source_id TEXT NOT NULL,
- material_key TEXT NOT NULL,
- summary_json TEXT NOT NULL,
- eligible INTEGER NOT NULL,
- expires_at_ms INTEGER,
- updated_at TEXT NOT NULL,
- PRIMARY KEY (kind, subject_id, source_id)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS risk_profile_authority (
- id INTEGER PRIMARY KEY CHECK (id = 1),
- revision INTEGER NOT NULL,
- imported INTEGER NOT NULL,
- bindings_json TEXT NOT NULL
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_setting_draft (
- platform TEXT NOT NULL,
- account_key TEXT NOT NULL,
- revision INTEGER NOT NULL,
- identity_json TEXT NOT NULL,
- overrides_json TEXT NOT NULL,
- updated_at TEXT NOT NULL,
- PRIMARY KEY (platform, account_key)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_setting_declaration (
- platform TEXT NOT NULL, account_key TEXT NOT NULL, revision INTEGER NOT NULL,
- identity_json TEXT NOT NULL, declaration_json TEXT NOT NULL,
- PRIMARY KEY (platform, account_key)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_setting_profile_application (
- request_key TEXT PRIMARY KEY,
- platform TEXT NOT NULL,
- account_key TEXT NOT NULL,
- identity_json TEXT NOT NULL,
- instance_revision INTEGER NOT NULL,
- draft_revision INTEGER NOT NULL,
- old_profile TEXT NOT NULL,
- new_profile TEXT NOT NULL,
- approved_by TEXT NOT NULL,
- approved_at TEXT NOT NULL,
- status TEXT NOT NULL,
- workflow_run_id TEXT,
- workflow_run_attempt TEXT,
- claimed_at TEXT
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS account_setting_profile_application_target ON account_setting_profile_application (platform, account_key, status)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_facts_observation (
- platform TEXT NOT NULL,
- account_key TEXT NOT NULL,
- payload_json TEXT NOT NULL,
- observed_finished_at TEXT NOT NULL,
- observation_date TEXT NOT NULL,
- target_id TEXT NOT NULL,
- source_binding_id TEXT NOT NULL,
- account_scope TEXT NOT NULL,
- updated_at TEXT NOT NULL,
- PRIMARY KEY (platform, account_key)
- )`);
- this.sql.exec(`CREATE TABLE IF NOT EXISTS account_facts_daily (
- platform TEXT NOT NULL,
- account_key TEXT NOT NULL,
- observation_date TEXT NOT NULL,
- payload_json TEXT NOT NULL,
- observed_finished_at TEXT NOT NULL,
- target_id TEXT NOT NULL,
- source_binding_id TEXT NOT NULL,
- account_scope TEXT NOT NULL,
- updated_at TEXT NOT NULL,
- PRIMARY KEY (platform, account_key, observation_date)
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS account_facts_daily_account ON account_facts_daily (platform, account_key, observation_date)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS market_benchmark_daily (
- series_id TEXT NOT NULL,
- observation_date TEXT NOT NULL,
- close TEXT NOT NULL,
- source TEXT,
- updated_at TEXT NOT NULL,
- PRIMARY KEY (series_id, observation_date)
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS market_benchmark_daily_date ON market_benchmark_daily (observation_date)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS market_benchmark_revision_ledger (
- proposal_sha256 TEXT NOT NULL,
- entry_index INTEGER NOT NULL,
- series_id_sha256 TEXT NOT NULL,
- observation_date TEXT NOT NULL,
- prior_close_sha256 TEXT NOT NULL,
- new_close_sha256 TEXT NOT NULL,
- candidate_source TEXT NOT NULL,
- reason TEXT NOT NULL,
- applied_at TEXT NOT NULL,
- PRIMARY KEY (proposal_sha256, entry_index)
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS market_benchmark_revision_ledger_date ON market_benchmark_revision_ledger (observation_date)");
- this.sql.exec(`CREATE TABLE IF NOT EXISTS hk_stop_request (
- request_id TEXT PRIMARY KEY,
- target_id TEXT NOT NULL,
- identity_json TEXT NOT NULL,
- source_revision INTEGER NOT NULL,
- action TEXT NOT NULL,
- requested_at TEXT NOT NULL,
- phase TEXT NOT NULL,
- dispatch_result TEXT,
- workflow_run_id TEXT,
- workflow_run_attempt TEXT,
- updated_at TEXT NOT NULL
- )`);
- this.sql.exec("CREATE INDEX IF NOT EXISTS hk_stop_request_target ON hk_stop_request (target_id, requested_at)");
- for (const column of ["source_identity_sha256", "runtime_identity_sha256", "result_json", "stopped_at"]) {
- try { this.sql.exec(`ALTER TABLE hk_stop_request ADD COLUMN ${column} TEXT`); } catch { /* already present */ }
- }
- }
-
- emptyCycleHealthState(targetId, bindingId) {
- return {
- schema_version: CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION,
- target_id: targetId, source_binding_id: bindingId,
- incident_count: 0, fault_attempt_count: 0, unresolved_count: 0,
- highest_severity: null, active_category: null, latest_fault_at: null,
- resolution_history_count: 0, history_complete: false,
- execution_authority_granted: false,
- };
- }
-
- cycleHealthHistoryCursor(sourceId, targetId, bindingFingerprint, throughId, afterId) {
- return [sourceId, targetId, bindingFingerprint, throughId, afterId].join(":");
- }
-
- cycleHealthHistoryPage(sourceId, targetId, bindingFingerprint, cursor = null) {
- let throughId, afterId;
- if (cursor) {
- const parts = cursor.split(":");
- if (parts.length !== 5 || parts[0] !== sourceId || parts[1] !== targetId || parts[2] !== bindingFingerprint) {
- throw new HttpError("cycle_health_history_cursor_mismatch", 400);
- }
- throughId = Number(parts[3]); afterId = Number(parts[4]);
- if (!Number.isSafeInteger(throughId) || throughId < 0 || !Number.isSafeInteger(afterId) || afterId < 0 || afterId > throughId) {
- throw new HttpError("cycle_health_history_cursor_invalid", 400);
- }
- } else {
- throughId = Number(this.sql.exec("SELECT COALESCE(MAX(history_id), 0) AS highwater FROM runtime_cycle_health_attempt WHERE target_id = ? AND source_id = ?", targetId, sourceId).toArray()[0]?.highwater || 0);
- afterId = 0;
- }
- const rows = this.sql.exec(`SELECT a.history_id, a.binding_fingerprint, a.cycle_id, a.attempt_key, a.fault_at,
- a.category, a.configuration_sha256, a.cycle_json, a.resolution_ref, i.resolution_history_json
- FROM runtime_cycle_health_attempt a JOIN runtime_cycle_health_incident i
- ON i.target_id = a.target_id AND i.binding_fingerprint = a.binding_fingerprint
- AND i.source_id = a.source_id AND i.cycle_id = a.cycle_id
- WHERE a.target_id = ? AND a.source_id = ? AND a.history_id > ? AND a.history_id <= ?
- ORDER BY a.history_id ASC LIMIT ?`, targetId, sourceId, afterId, throughId, CYCLE_HEALTH_HISTORY_PAGE_SIZE + 1).toArray();
- const hasMore = rows.length > CYCLE_HEALTH_HISTORY_PAGE_SIZE;
- const selected = rows.slice(0, CYCLE_HEALTH_HISTORY_PAGE_SIZE);
- const items = selected.map(row => {
- let cycle, resolutionHistory;
- try { cycle = JSON.parse(row.cycle_json); resolutionHistory = JSON.parse(row.resolution_history_json); }
- catch { throw new HttpError("cycle_health_history_stored_invalid", 409); }
- return {
- history_id: row.history_id, binding_fingerprint: row.binding_fingerprint,
- continuity: row.binding_fingerprint === bindingFingerprint ? "same_binding" : "unconfirmed",
- cycle_id: row.cycle_id, attempt_key: row.attempt_key, fault_at: row.fault_at,
- category: row.category, configuration_sha256: row.configuration_sha256,
- cycle, resolution_ref: row.resolution_ref, resolution_history: resolutionHistory,
- };
- });
- const nextCursor = hasMore && selected.length
- ? this.cycleHealthHistoryCursor(sourceId, targetId, bindingFingerprint, throughId, selected.at(-1).history_id)
- : null;
- return {
- items, snapshot_through_id: throughId, complete: !hasMore,
- next_cursor: nextCursor,
- };
- }
-
- cycleHealthRecordAttempt({ targetId, bindingFingerprint, sourceId, configurationSha, cycle, resolutionRef = null, resolutionHistory = null, state }) {
- const category = cycleHealthFaultCategory(cycle);
- const attemptKey = cycleHealthAttemptKey(cycle);
- const cycleJson = canonicalCycleJson(cycle);
- const oldAttempt = this.sql.exec(`SELECT cycle_json FROM runtime_cycle_health_attempt
- WHERE target_id = ? AND binding_fingerprint = ? AND source_id = ? AND attempt_key = ?`,
- targetId, bindingFingerprint, sourceId, attemptKey).toArray()[0];
- if (oldAttempt) {
- if (oldAttempt.cycle_json !== cycleJson) throw new HttpError("cycle_health_fault_receipt_conflict", 409);
- return { state, inserted: false };
- }
- if (!category) return { state, inserted: false };
- const faultAt = cycleHealthFaultTime(cycle);
- const prior = this.sql.exec(`SELECT * FROM runtime_cycle_health_incident
- WHERE target_id = ? AND binding_fingerprint = ? AND source_id = ? AND cycle_id = ?`,
- targetId, bindingFingerprint, sourceId, cycle.cycle_id).toArray()[0] || null;
- let incidentCycle = cycle, incidentCategory = category, latestFaultAt = faultAt;
- let activeCategory = resolutionRef === null ? category : null;
- let attemptCount = 1;
- let history = resolutionHistory || [];
- if (prior) {
- let oldCycle;
- try { oldCycle = JSON.parse(prior.cycle_json); history = JSON.parse(prior.resolution_history_json); }
- catch { throw new HttpError("cycle_health_checkpoint_invalid", 409); }
- const oldRank = prior.category === "execution_uncertainty" ? 2 : 1;
- const newRank = category === "execution_uncertainty" ? 2 : 1;
- const timeOrder = compareCycleInstants(faultAt, prior.latest_fault_at);
- if (newRank > oldRank || (newRank === oldRank && (timeOrder > 0 || (timeOrder === 0 && attemptKey > cycleHealthAttemptKey(oldCycle))))) {
- incidentCycle = cycle;
- } else {
- incidentCycle = oldCycle;
- }
- incidentCategory = newRank > oldRank ? category : prior.category;
- latestFaultAt = timeOrder > 0 ? faultAt : prior.latest_fault_at;
- attemptCount = prior.attempt_count + 1;
- if (resolutionRef === null) {
- const priorActiveRank = prior.active_category === "execution_uncertainty" ? 2 : prior.active_category === "operational" ? 1 : 0;
- activeCategory = newRank > priorActiveRank ? category : prior.active_category;
- } else activeCategory = prior.active_category;
- }
- this.sql.exec(`INSERT INTO runtime_cycle_health_attempt (
- target_id, binding_fingerprint, source_id, cycle_id, attempt_key, fault_at,
- category, configuration_sha256, cycle_json, resolution_ref
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, targetId, bindingFingerprint, sourceId,
- cycle.cycle_id, attemptKey, faultAt, category, configurationSha, cycleJson, resolutionRef);
- this.sql.exec(`INSERT INTO runtime_cycle_health_incident (
- target_id, binding_fingerprint, source_id, cycle_id, cycle_json, category,
- active_category, latest_fault_at, attempt_count, resolution_history_json
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- ON CONFLICT(target_id, binding_fingerprint, source_id, cycle_id) DO UPDATE SET
- cycle_json = excluded.cycle_json, category = excluded.category,
- active_category = excluded.active_category, latest_fault_at = excluded.latest_fault_at,
- attempt_count = excluded.attempt_count, resolution_history_json = excluded.resolution_history_json`,
- targetId, bindingFingerprint, sourceId, cycle.cycle_id, canonicalCycleJson(incidentCycle), incidentCategory,
- activeCategory, latestFaultAt, attemptCount, JSON.stringify(history));
- const next = { ...state };
- if (!prior) next.incident_count += 1;
- next.fault_attempt_count += 1;
- if (activeCategory !== null && (!prior || prior.active_category === null)) next.unresolved_count += 1;
- if (!prior && Array.isArray(history)) next.resolution_history_count += history.length;
- if (activeCategory !== null && !next.active_category) next.active_category = activeCategory;
- const stateRank = next.highest_severity === "execution_uncertainty" ? 2 : next.highest_severity === "operational" ? 1 : 0;
- const incidentRank = incidentCategory === "execution_uncertainty" ? 2 : 1;
- if (incidentRank > stateRank) next.highest_severity = incidentCategory;
- const activeRank = next.active_category === "execution_uncertainty" ? 2 : next.active_category === "operational" ? 1 : 0;
- const nextActiveRank = activeCategory === "execution_uncertainty" ? 2 : activeCategory === "operational" ? 1 : 0;
- if (nextActiveRank > activeRank) next.active_category = activeCategory;
- if (!next.latest_fault_at || compareCycleInstants(faultAt, next.latest_fault_at) > 0) next.latest_fault_at = faultAt;
- next.history_complete = false;
- return { state: next, inserted: true };
- }
-
- migrateCycleHealthCheckpoint(row) {
- let checkpoint;
- try { checkpoint = JSON.parse(row.payload_json); } catch { throw new HttpError("cycle_health_checkpoint_invalid", 409); }
- if (checkpoint?.state?.schema_version === CYCLE_HEALTH_SUMMARY_SCHEMA_VERSION) return checkpoint;
- const oldState = checkpoint?.state;
- if (!oldState || !Array.isArray(oldState.incidents)) throw new HttpError("cycle_health_checkpoint_invalid", 409);
- let state = this.emptyCycleHealthState(row.target_id, oldState.source_binding_id);
- for (const incident of oldState.incidents) {
- if (!incident || !Array.isArray(incident.fault_attempts) || !incident.fault_attempts.length) throw new HttpError("cycle_health_checkpoint_invalid", 409);
- for (const attempt of incident.fault_attempts) {
- if (!attempt?.cycle || typeof attempt.configuration_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(attempt.configuration_sha256)
- || (attempt.resolution_ref !== null && (typeof attempt.resolution_ref !== "string" || !/^[a-f0-9]{64}$/.test(attempt.resolution_ref)))) {
- throw new HttpError("cycle_health_checkpoint_invalid", 409);
- }
- state = this.cycleHealthRecordAttempt({ targetId: row.target_id, bindingFingerprint: row.binding_fingerprint,
- sourceId: row.source_id, configurationSha: attempt.configuration_sha256, cycle: attempt.cycle,
- resolutionRef: attempt.resolution_ref, resolutionHistory: incident.resolution_history || [], state }).state;
- }
- }
- checkpoint.state = state;
- checkpoint.schema_version = "qsl_runtime_cycle_health_checkpoint_state.v2";
- checkpoint.covered_through = null;
- checkpoint.coverage_complete = false;
- checkpoint.coverage_incomplete_reason = "legacy_watermark_unavailable";
- const source = this.sql.exec("SELECT binding_fingerprint, configuration_sha256, required_from, observed_at, observation_json FROM runtime_cycle_health_source WHERE source_id = ?", row.source_id).toArray()[0];
- if (row.binding_fingerprint === source?.binding_fingerprint && checkpoint.baseline_established === true
- && checkpoint.configuration_sha256 === source.configuration_sha256 && checkpoint.required_from === source.required_from
- && source.observation_json && source.observed_at) {
- try {
- const observation = JSON.parse(source.observation_json);
- const coverage = observation?.targets?.[0]?.cycle_health?.coverage;
- if (observation.computed_at === source.observed_at && compareCycleInstants(coverage?.through, observation.computed_at) <= 0
- && cycleCoverageComplete(coverage, { since: source.required_from, through: source.required_from })) {
- checkpoint.covered_through = coverage.through;
- checkpoint.coverage_complete = true;
- checkpoint.coverage_incomplete_reason = null;
- }
- } catch { /* Keep legacy coverage unproven when the stored source record is invalid. */ }
- }
- this.sql.exec("UPDATE runtime_cycle_health_checkpoint SET payload_json = ? WHERE target_id = ? AND binding_fingerprint = ? AND source_id = ? AND revision = ?",
- JSON.stringify(checkpoint), row.target_id, row.binding_fingerprint, row.source_id, row.revision);
- return checkpoint;
- }
-
- cycleHealthCommand(command) {
- const rows = [...this.sql.exec("SELECT * FROM runtime_cycle_health_source WHERE source_id = ?", command.source_id)];
- const a = rows[0];
- if (!a || a.target_id !== command.target_id || a.binding_fingerprint !== command.binding_fingerprint
- || !/^[a-f0-9]{64}$/.test(a.configuration_sha256)
- || !Number.isSafeInteger(a.authority_revision) || a.authority_revision < 1) throw new HttpError("cycle_health_source_not_admitted", 409);
- try { normalizeCycleInstant(a.required_from); } catch { throw new HttpError("cycle_health_baseline_not_admitted", 409); }
- if (command.action === "cycle_health_admission") return {
- authority_revision: a.authority_revision, configuration_sha256: a.configuration_sha256, required_from: a.required_from,
- };
- if (command.authority_revision !== a.authority_revision || command.configuration_sha256 !== a.configuration_sha256
- || command.required_from !== a.required_from) throw new HttpError("cycle_health_admission_changed", 409);
- let partitions = [...this.sql.exec("SELECT * FROM runtime_cycle_health_checkpoint WHERE target_id = ? AND source_id = ?", a.target_id, a.source_id)];
- const owner = [...this.sql.exec("SELECT source_id FROM runtime_cycle_health_checkpoint WHERE target_id = ? AND binding_fingerprint = ?", a.target_id, a.binding_fingerprint)][0];
- if (owner && owner.source_id !== a.source_id) throw new HttpError("cycle_health_source_partition_conflict", 409);
- partitions = partitions.map(row => ({ ...row, checkpoint: this.migrateCycleHealthCheckpoint(row) }));
- const row = partitions.find(p => p.binding_fingerprint === a.binding_fingerprint) || null;
- const previous = row?.checkpoint || null;
- const priorPartitions = partitions.filter(p => p.binding_fingerprint !== a.binding_fingerprint).map(p => ({
- checkpoint_revision: p.revision, checkpoint: p.checkpoint,
- }));
- if (row && a.checkpoint_revision !== row.revision) throw new HttpError("cycle_health_checkpoint_revision_conflict", 409);
- const state = previous?.state || this.emptyCycleHealthState(a.target_id, command.source_binding_id);
- const admissionTransition = previous && (previous.configuration_sha256 !== a.configuration_sha256 || previous.required_from !== a.required_from);
- const effectiveCheckpoint = admissionTransition ? {
- ...previous, baseline_established: false, covered_through: null, coverage_complete: false,
- coverage_incomplete_reason: "admission_changed",
- } : previous;
- const result = (status, checkpoint = previous, revision = row?.revision || 0) => ({
- ok: true, schema_version: "qsl_runtime_cycle_health_checkpoint.v2", status,
- source_id: a.source_id, target_id: a.target_id, authority_revision: a.authority_revision,
- configuration_sha256: a.configuration_sha256, source_binding_id: command.source_binding_id,
- checkpoint_revision: revision, observed_at: a.observed_at, observation_sha256: a.observation_sha256,
- received_at: a.received_at, required_from: a.required_from, checkpoint,
- covered_through: checkpoint?.covered_through || null,
- coverage_complete: checkpoint?.coverage_complete === true,
- coverage_incomplete_reason: checkpoint?.coverage_incomplete_reason || null,
- ...(command.action === "cycle_health_read"
- ? { history_page: this.cycleHealthHistoryPage(a.source_id, a.target_id, a.binding_fingerprint, command.history_cursor || null) }
- : {}),
- prior_partitions: priorPartitions, continuity: priorPartitions.length ? "unconfirmed" : "same_binding",
- adopted: false, no_order: true, execution_authority_granted: false,
- });
- if (command.action === "cycle_health_read") {
- const r = result(!previous ? "uninitialized" : state.unresolved_count || priorPartitions.length ? "blocked"
- : !effectiveCheckpoint.baseline_established || effectiveCheckpoint.coverage_complete !== true ? "incomplete" : "complete", effectiveCheckpoint);
- if (a.observed_at && (Date.now() - Date.parse(a.observed_at) > ACCOUNT_FACTS_STALE_MS || Date.parse(a.observed_at) - Date.now() > ACCOUNT_FACTS_FUTURE_SKEW_MS)) r.status = "stale";
- if (previous && (previous.configuration_sha256 !== a.configuration_sha256 || previous.required_from !== a.required_from)) r.status = "incomplete";
- if (priorPartitions.length || state.unresolved_count) r.status = "blocked";
- return r;
- }
- if (command.action !== "cycle_health_put") throw new HttpError("unsupported_cycle_health_action", 400);
- const packet = command.observation;
- if (packet.targets[0].cycle_health.configuration_sha256 !== a.configuration_sha256) throw new HttpError("cycle_health_configuration_not_admitted", 409);
- const order = a.observed_at ? compareCycleInstants(packet.computed_at, a.observed_at) : 1;
- if (order < 0) throw new HttpError("cycle_health_stale_observation", 409);
- if (order === 0) {
- if (command.observation_json !== a.observation_json || command.observation_sha256 !== a.observation_sha256) throw new HttpError("cycle_health_observation_conflict", 409);
- return { ...result("unchanged"), schema_version: "qsl_runtime_cycle_health_ack.v1", result: "unchanged" };
- }
- const h = packet.targets[0].cycle_health;
- const transition = previous && (previous.configuration_sha256 !== a.configuration_sha256 || previous.required_from !== a.required_from);
- const expectedCoverageFrom = !transition && previous?.covered_through ? previous.covered_through : a.required_from;
- const scanComplete = cycleCoverageComplete(h.coverage);
- const coverageContinuous = scanComplete
- && compareCycleInstants(h.coverage.from, expectedCoverageFrom) <= 0
- && compareCycleInstants(h.coverage.through, expectedCoverageFrom) >= 0;
- const coveredThrough = coverageContinuous ? h.coverage.through : transition ? null : previous?.covered_through || null;
- const incompleteReason = coverageContinuous ? null : !scanComplete ? "scan_incomplete"
- : compareCycleInstants(h.coverage.from, expectedCoverageFrom) > 0 ? "coverage_gap" : "coverage_not_advanced";
- let nextState = structuredClone(state);
- for (const cycle of h.cycles) {
- nextState = this.cycleHealthRecordAttempt({ targetId: a.target_id, bindingFingerprint: a.binding_fingerprint,
- sourceId: a.source_id, configurationSha: h.configuration_sha256, cycle, state: nextState }).state;
- }
- const baselineEstablished = coverageContinuous
- ? (!previous || transition || previous.baseline_established || !previous.covered_through)
- : Boolean(previous && !transition && previous.baseline_established);
- const checkpoint = {
- schema_version: "qsl_runtime_cycle_health_checkpoint_state.v2",
- configuration_sha256: a.configuration_sha256, required_from: a.required_from,
- baseline_established: baselineEstablished,
- covered_through: coveredThrough, coverage_complete: coverageContinuous,
- coverage_incomplete_reason: incompleteReason,
- state: nextState,
- };
- const revision = (row?.revision || 0) + 1;
- this.sql.exec("UPDATE runtime_cycle_health_source SET observed_at = ?, observation_json = ?, observation_sha256 = ?, received_at = ?, checkpoint_revision = ? WHERE source_id = ?",
- packet.computed_at, command.observation_json, command.observation_sha256, command.received_at, revision, a.source_id);
- this.sql.exec(`INSERT INTO runtime_cycle_health_checkpoint (target_id, binding_fingerprint, source_id, revision, payload_json)
- VALUES (?, ?, ?, ?, ?) ON CONFLICT(target_id, binding_fingerprint) DO UPDATE SET revision = excluded.revision, payload_json = excluded.payload_json`,
- a.target_id, a.binding_fingerprint, a.source_id, revision, JSON.stringify(checkpoint));
- a.observed_at = packet.computed_at; a.observation_sha256 = command.observation_sha256; a.received_at = command.received_at;
- return { ...result("stored", checkpoint, revision), schema_version: "qsl_runtime_cycle_health_ack.v1", result: "stored" };
- }
-
- cycleHealthProvisionCommand(command) {
- const { source_id: sourceId, target_id: targetId, binding_fingerprint: bindingFingerprint,
- configuration_sha256: configurationSha, required_from: requiredFrom,
- expected_authority_revision: expectedRevision } = command || {};
- if (targetId !== "longbridge.paper" || !/^[a-f0-9]{64}$/.test(bindingFingerprint || "")
- || !/^[a-f0-9]{64}$/.test(configurationSha || "")
- || !Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
- throw new HttpError("cycle_health_admission_request_invalid", 400);
- }
- const normalizedSourceId = normalizeControlPlaneIdentifier(sourceId, "source_id", false);
- let normalizedRequiredFrom;
- try { normalizedRequiredFrom = normalizeCycleInstant(requiredFrom); }
- catch { throw new HttpError("cycle_health_baseline_not_admitted", 400); }
- const current = [...this.sql.exec("SELECT * FROM runtime_cycle_health_source WHERE target_id = ?", targetId)][0] || null;
- const sourceOwner = [...this.sql.exec("SELECT * FROM runtime_cycle_health_source WHERE source_id = ?", normalizedSourceId)][0] || null;
- if (sourceOwner && sourceOwner.target_id !== targetId) throw new HttpError("cycle_health_source_target_conflict", 409);
- if (current && current.source_id !== normalizedSourceId) throw new HttpError("cycle_health_source_id_change_requires_support", 409);
- if (current?.binding_fingerprint !== bindingFingerprint
- && [...this.sql.exec("SELECT 1 AS found FROM runtime_cycle_health_checkpoint WHERE target_id = ? AND binding_fingerprint = ?", targetId, bindingFingerprint)][0]) {
- throw new HttpError("cycle_health_binding_partition_reuse_requires_support", 409);
- }
- const currentRevision = current?.authority_revision || 0;
- const sameAdmission = current && current.binding_fingerprint === bindingFingerprint
- && current.configuration_sha256 === configurationSha && current.required_from === normalizedRequiredFrom;
- if (sameAdmission) {
- if (expectedRevision > currentRevision || expectedRevision < currentRevision - 1) {
- throw new HttpError("cycle_health_admission_revision_conflict", 409);
- }
- return {
- ok: true, schema_version: "qsl_runtime_cycle_health_admission.v1", result: "unchanged",
- source_id: normalizedSourceId, target_id: targetId, authority_revision: currentRevision,
- configuration_sha256: configurationSha, required_from: normalizedRequiredFrom,
- status: "admission_unchanged", adopted: false, no_order: true,
- execution_authority_granted: false,
- };
- }
- if (expectedRevision !== currentRevision) throw new HttpError("cycle_health_admission_revision_conflict", 409);
- if (current && compareCycleInstants(normalizedRequiredFrom, current.required_from) > 0) {
- throw new HttpError("cycle_health_baseline_range_shrink_rejected", 409);
- }
- const nextRevision = currentRevision + 1;
- if (!Number.isSafeInteger(nextRevision)) throw new HttpError("cycle_health_admission_revision_exhausted", 409);
- if (!current) {
- this.sql.exec(`INSERT INTO runtime_cycle_health_source (
- source_id, target_id, binding_fingerprint, configuration_sha256,
- authority_revision, required_from, observed_at, observation_json,
- observation_sha256, received_at, checkpoint_revision
- ) VALUES (?, ?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL)`,
- normalizedSourceId, targetId, bindingFingerprint, configurationSha, nextRevision, normalizedRequiredFrom);
- } else {
- const bindingChanged = current.binding_fingerprint !== bindingFingerprint;
- this.sql.exec(`UPDATE runtime_cycle_health_source SET binding_fingerprint = ?, configuration_sha256 = ?,
- authority_revision = ?, required_from = ?, observed_at = ?, observation_json = ?, observation_sha256 = ?,
- received_at = ?, checkpoint_revision = ? WHERE source_id = ? AND authority_revision = ?`,
- bindingFingerprint, configurationSha, nextRevision, normalizedRequiredFrom,
- bindingChanged ? null : current.observed_at,
- bindingChanged ? null : current.observation_json,
- bindingChanged ? null : current.observation_sha256,
- bindingChanged ? null : current.received_at,
- bindingChanged ? null : current.checkpoint_revision,
- normalizedSourceId, currentRevision);
- if (this.sql.exec("SELECT changes() AS changed").toArray()[0]?.changed !== 1) {
- throw new HttpError("cycle_health_admission_revision_conflict", 409);
- }
- }
- return {
- ok: true, schema_version: "qsl_runtime_cycle_health_admission.v1", result: "stored",
- source_id: normalizedSourceId, target_id: targetId, authority_revision: nextRevision,
- configuration_sha256: configurationSha, required_from: normalizedRequiredFrom,
- status: "admission_configured", adopted: false, no_order: true,
- execution_authority_granted: false,
- };
- }
-
- accountFactsCommand(command) {
- if (!command || typeof command.action !== "string") throw new HttpError("unsupported_account_facts_action", 400);
- if (command.action === "account_daily_native_return_research_read") return this.researchNativeDailyReturns(command);
- if (["binance_detail_put", "binance_detail_read"].includes(command.action)) return binanceDetailCommand(this.sql, command);
- if (command.action === "binance_wallet_history_put" || command.action === "binance_wallet_history_read") {
- return this.binanceWalletHistoryCommand(command);
- }
- if (command.action === "account_period_return_put" || command.action === "account_period_return_read") return this.accountPeriodReturnCommand(command);
- if (["account_executions_put", "account_executions_read"].includes(command.action)) {
- const context = this.accountFactsStorageContext(command);
- if (context.platform !== "ibkr") throw new HttpError("invalid_execution_platform", 400);
- return command.action === "account_executions_read"
- ? { ok: true, executions: readExecutions(this.sql, context) }
- : { ok: true, ...putExecutions(this.sql, context, command.payload) };
- }
- if (command.action === "account_external_flow_put") {
- const context = this.accountFactsStorageContext(command);
- const flow = normalizeExternalFlow(command.externalFlow);
- if (!this.externalFlowEnabled && !dateOnlyExternalFlow(flow)) throw new HttpError("external_flow_disabled", 409);
- const source = { ibkr: "ibkr_flex", schwab: "schwab_transactions", longbridge: "longbridge_cashflow" }[context.platform];
- if (!source || flow.windows.some(w => w.source !== source)) throw new HttpError("external_flow_source_mismatch", 409);
- const stored = putExternalFlow(this.sql, context, flow);
- const readback = readExternalFlow(this.sql, context);
- const readbackVerified = flow.windows.every(w => readback?.windows.some(saved => JSON.stringify(saved) === JSON.stringify(w)));
- if (!readbackVerified) throw new HttpError("external_flow_readback_failed", 503);
- return { ok: true, ...stored, readback_verified: true };
- }
- if (command.action === "account_facts_put") return this.putAccountFactsObservation(command);
- if (command.action === "account_facts_history_put") return this.putAccountFactsHistoricalObservation(command);
- if (command.action === "account_facts_read") return this.readAccountFactsObservation(command);
- if (command.action === "account_facts_list") return this.listAccountFactsObservations(command);
- if (command.action === "account_facts_history_read") return this.readAccountFactsDailyHistory(command);
- throw new HttpError("unsupported_account_facts_action", 400);
- }
-
-
- marketBenchmarkCommand(command) {
- if (!command || typeof command.action !== "string") throw new HttpError("unsupported_market_benchmark_action", 400);
- if (command.action === "market_benchmark_read") return this.readMarketBenchmarkPoints(command);
- if (command.action === "market_benchmark_put") return this.putMarketBenchmarkPoints(command);
- if (command.action === "market_benchmark_revise") return this.reviseMarketBenchmarkPoints(command);
- throw new HttpError("unsupported_market_benchmark_action", 400);
- }
-
- readMarketBenchmarkPoints(command = {}) {
- const rows = this.sql.exec(
- `SELECT series_id, observation_date, close, source FROM market_benchmark_daily
- ORDER BY series_id ASC, observation_date ASC`,
- ).toArray();
- const points = rows.map((row) => ({
- seriesId: row.series_id,
- observationDate: row.observation_date,
- close: row.close,
- ...(row.source ? { source: row.source } : {}),
- }));
- if (command.performance === true) return { ok: true, points };
- return { ok: true, ...publicMarketBenchmarkReadModel(points) };
- }
-
- putMarketBenchmarkPoints(command) {
- let normalized;
- try {
- normalized = normalizeMarketBenchmarkSyncPayload(command.payload || command);
- } catch (error) {
- if (error instanceof MarketBenchmarkError) throw new HttpError(error.code, error.status || 400);
- throw error;
- }
- const updatedAt = new Date().toISOString();
- let written = 0;
- let unchanged = 0;
- for (const point of normalized.points) {
- const existing = this.sql.exec(
- `SELECT close, source FROM market_benchmark_daily WHERE series_id = ? AND observation_date = ?`,
- point.seriesId,
- point.observationDate,
- ).toArray()[0];
- if (existing && existing.close === point.close
- && (existing.source || null) === (point.source || null)) {
- unchanged += 1;
- continue;
- }
- if (existing && existing.close !== point.close) {
- throw new HttpError("market_benchmark_point_conflict", 409);
- }
- this.sql.exec(
- `INSERT INTO market_benchmark_daily (series_id, observation_date, close, source, updated_at)
- VALUES (?, ?, ?, ?, ?)
- ON CONFLICT(series_id, observation_date) DO UPDATE SET
- close = excluded.close,
- source = excluded.source,
- updated_at = excluded.updated_at`,
- point.seriesId,
- point.observationDate,
- point.close,
- point.source || null,
- updatedAt,
- );
- written += 1;
- }
- return {
- ok: true,
- stored: true,
- schema_version: MARKET_BENCHMARK_SCHEMA,
- inception_date: this.readMarketBenchmarkPoints().inception_date,
- written,
- unchanged,
- points: normalized.points.length,
- };
- }
-
- reviseMarketBenchmarkPoints(command) {
- const appliedAt = typeof command.applied_at === "string" && !Number.isNaN(Date.parse(command.applied_at))
- ? command.applied_at
- : new Date().toISOString();
- // Plan is validated by the HTTP layer (hashes + concrete updates); DO only applies.
- const plan = command.plan;
- if (!plan || !Array.isArray(plan.updates) || !Array.isArray(plan.ledger_entries)) {
- throw new HttpError("benchmark_revision_plan_required", 400);
- }
- if (plan.overwrites !== plan.updates.length || plan.deletes !== 0) {
- throw new HttpError("benchmark_revision_plan_invalid", 400);
- }
- const existingProposal = this.sql.exec(
- `SELECT proposal_sha256 FROM market_benchmark_revision_ledger WHERE proposal_sha256 = ? LIMIT 1`,
- plan.proposal_sha256,
- ).toArray()[0];
- if (existingProposal) throw new HttpError("benchmark_revision_already_applied", 409);
- let written = 0;
- for (const point of plan.updates) {
- const existing = this.sql.exec(
- `SELECT close, source FROM market_benchmark_daily WHERE series_id = ? AND observation_date = ?`,
- point.seriesId,
- point.observationDate,
- ).toArray()[0];
- if (!existing) throw new HttpError("benchmark_revision_target_missing", 404);
- if (existing.close === point.close) throw new HttpError("benchmark_revision_noop", 400);
- this.sql.exec(
- `UPDATE market_benchmark_daily SET close = ?, source = ?, updated_at = ? WHERE series_id = ? AND observation_date = ?`,
- point.close,
- point.source || null,
- appliedAt,
- point.seriesId,
- point.observationDate,
- );
- written += 1;
- }
- for (const entry of plan.ledger_entries) {
- this.sql.exec(
- `INSERT INTO market_benchmark_revision_ledger (
- proposal_sha256, entry_index, series_id_sha256, observation_date,
- prior_close_sha256, new_close_sha256, candidate_source, reason, applied_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
- entry.proposal_sha256,
- entry.entry_index,
- entry.series_id_sha256,
- entry.observation_date,
- entry.prior_close_sha256,
- entry.new_close_sha256,
- entry.candidate_source,
- entry.reason,
- entry.applied_at || appliedAt,
- );
- }
- return {
- ok: true,
- applied: true,
- proposal_sha256: plan.proposal_sha256,
- overwrites: written,
- deletes: 0,
- ledger_entries: plan.ledger_entries.length,
- };
- }
-
-
- binanceWalletHistoryContext(command) {
- const accountKey = command?.account_key;
- const sourceBindingId = command?.source_binding_id;
- if (typeof accountKey !== "string" || !accountKey
- || typeof sourceBindingId !== "string" || !/^[a-f0-9]{64}$/.test(sourceBindingId)
- || command.storage_account_key !== `${accountKey}:${sourceBindingId}`
- || typeof command.target_id !== "string" || !command.target_id
- || typeof command.account_scope !== "string" || !command.account_scope) {
- throw new HttpError("invalid_binance_wallet_history_account", 400);
- }
- return {
- account_key: command.storage_account_key,
- target_id: command.target_id,
- account_scope: command.account_scope,
- source_binding_id: sourceBindingId,
- binding: {
- target_id: command.target_id,
- account_scope: command.account_scope,
- source_binding: { kind: "binance_readonly_scope_revision", id: sourceBindingId },
- },
- };
- }
-
- binanceWalletHistoryCommand(command) {
- const context = this.binanceWalletHistoryContext(command);
- if (command.action === "binance_wallet_history_read") {
- const rows = this.sql.exec(
- `SELECT payload_json, target_id, source_binding_id, account_scope FROM account_facts_daily
- WHERE platform = 'binance' AND account_key = ? ORDER BY observation_date ASC`,
- context.account_key,
- ).toArray();
- const days = [];
- for (const row of rows) {
- if (row.target_id !== context.target_id || row.source_binding_id !== context.source_binding_id
- || row.account_scope !== context.account_scope) {
- throw new HttpError("binance_wallet_history_identity_mismatch", 409);
- }
- let payload;
- try { payload = JSON.parse(row.payload_json); }
- catch { throw new HttpError("binance_wallet_history_stored_invalid", 409); }
- try { days.push(normalizeBinanceWalletHistoryEntry(payload, context.binding)); }
- catch { throw new HttpError("binance_wallet_history_stored_invalid", 409); }
- }
- return { ok: true, days };
- }
-
- let history;
- try { history = normalizeBinanceWalletHistoryEntry(command.history, context.binding); }
- catch { throw new HttpError("invalid_binance_wallet_history", 400); }
- const row = this.sql.exec(
- `SELECT payload_json, target_id, source_binding_id, account_scope FROM account_facts_daily
- WHERE platform = 'binance' AND account_key = ? AND observation_date = ?`,
- context.account_key,
- history.observation_date,
- ).toArray()[0];
- let existing = null;
- if (row) {
- if (row.target_id !== context.target_id || row.source_binding_id !== context.source_binding_id
- || row.account_scope !== context.account_scope) {
- throw new HttpError("binance_wallet_history_identity_mismatch", 409);
- }
- try { existing = normalizeBinanceWalletHistoryEntry(JSON.parse(row.payload_json), context.binding); }
- catch { throw new HttpError("binance_wallet_history_stored_invalid", 409); }
- }
- if (existing) {
- const existingTime = Date.parse(existing.report_observed_finished_at);
- const incomingTime = Date.parse(history.report_observed_finished_at);
- if (incomingTime < existingTime) return { ok: true, unchanged: true };
- if (incomingTime === existingTime) {
- if (JSON.stringify(existing) !== JSON.stringify(history)) {
- throw new HttpError("binance_wallet_history_conflict", 409);
- }
- return { ok: true, unchanged: true };
- }
- }
- const updatedAt = new Date().toISOString();
- this.sql.exec(
- `INSERT INTO account_facts_daily (
- platform, account_key, observation_date, payload_json, observed_finished_at,
- target_id, source_binding_id, account_scope, updated_at
- ) VALUES ('binance', ?, ?, ?, ?, ?, ?, ?, ?)
- ON CONFLICT(platform, account_key, observation_date) DO UPDATE SET
- payload_json = excluded.payload_json,
- observed_finished_at = excluded.observed_finished_at,
- target_id = excluded.target_id,
- source_binding_id = excluded.source_binding_id,
- account_scope = excluded.account_scope,
- updated_at = excluded.updated_at`,
- context.account_key,
- history.observation_date,
- JSON.stringify(history),
- history.report_observed_finished_at,
- context.target_id,
- context.source_binding_id,
- context.account_scope,
- updatedAt,
- );
- const latestDate = this.sql.exec(
- "SELECT MAX(observation_date) AS latest_date FROM account_facts_daily WHERE platform = 'binance' AND account_key = ?",
- context.account_key,
- ).toArray()[0]?.latest_date;
- const cutoff = historyRetentionCutoff(latestDate, BINANCE_WALLET_HISTORY_MAX_DAYS);
- if (cutoff) {
- this.sql.exec("DELETE FROM account_facts_daily WHERE platform = 'binance' AND account_key = ? AND observation_date < ?",
- context.account_key, cutoff);
- }
- return { ok: true, unchanged: false };
- }
-
- accountPeriodReturnCommand(command) {
- const context = this.accountFactsStorageContext(command);
- if (context.platform !== "ibkr") throw new HttpError("invalid_account_period_return", 400);
- const binding = { ...context, source_binding: { id: context.source_binding_id } };
- const sourceIds = [context.source_binding_id, ...(context.history_source_binding_ids || [])];
- const sources = new Set(sourceIds);
- const readStored = (payloadJson) => {
- const payload = JSON.parse(payloadJson);
- if (!sources.has(payload?.source_binding_id)) throw new HttpError("account_period_return_source_unqualified", 409);
- return normalizeIbkrPeriodReturn(payload, {
- binding: { ...binding, source_binding: { id: payload.source_binding_id } }, enforceFresh: false,
- });
- };
- const existing = this.sql.exec("SELECT payload_json FROM account_period_return WHERE account_key = ?", context.account_key).toArray()[0];
- let prior = null;
- if (existing) {
- try { prior = readStored(existing.payload_json); }
- catch { /* Keep the latest interval unavailable; independently qualify daily rows below. */ }
- }
- if (command.action === "account_period_return_read") {
- const dailyByDay = new Map();
- let conflictingDailyValues = false;
- const conflictingNav = new Set();
- const navByDay = new Map();
- const addDaily = (row) => {
- const key = `${row.currency}:${row.period.to}`;
- const old = dailyByDay.get(key);
- if (old && Number(old.value) !== Number(row.value)) {
- conflictingDailyValues = true;
- return;
- }
- if (row.nav_change) {
- const nav = canonicalResearchTaskJson(row.nav_change);
- if (navByDay.has(key) && navByDay.get(key) !== nav) conflictingNav.add(key);
- else navByDay.set(key, nav);
- }
- if (!old || row.source_binding_id === context.source_binding_id
- || (old.source_binding_id !== context.source_binding_id
- && Date.parse(row.observed_at) > Date.parse(old.observed_at))) dailyByDay.set(key, row);
- };
- const rows = this.sql.exec(`SELECT payload_json FROM account_daily_native_return
- WHERE account_key = ? AND source_binding_id IN (${sourceIds.map(() => "?").join(",")})
- ORDER BY observation_date DESC LIMIT ?`, context.account_key, ...sourceIds, 366 * sourceIds.length);
- for (const stored of rows) {
- let row;
- try { row = readStored(stored.payload_json); } catch { continue; }
- addDaily(row);
- }
- if (prior && prior.period.from === prior.period.to) addDaily(prior);
- if (conflictingDailyValues) return { ok: true, return: {
- ...ACCOUNT_FACTS_RETURN_UNAVAILABLE, reason: "native_return_history_conflict",
- } };
- const daily = [...dailyByDay.values()].sort((a, b) => b.period.to.localeCompare(a.period.to)).slice(0, 366);
- const latest = prior ? publicIbkrPeriodReturn(prior) : { ...ACCOUNT_FACTS_RETURN_UNAVAILABLE };
- if (prior && prior.period.from === prior.period.to && conflictingNav.has(`${prior.currency}:${prior.period.to}`)) delete latest.nav_change;
- return { ok: true, return: { ...latest,
- daily: daily.sort((a, b) => a.period.to.localeCompare(b.period.to)).map(row => {
- const projected = publicIbkrPeriodReturn(row);
- if (conflictingNav.has(`${row.currency}:${row.period.to}`)) delete projected.nav_change;
- return projected;
- }) } };
- }
- const incoming = normalizeIbkrPeriodReturn(command.payload, { binding });
- const historical = command.historical === true;
- if (historical && (incoming.period.from !== incoming.period.to || Date.now() - Date.parse(incoming.period.to + "T00:00:00Z") > 366 * 86400000)) throw new HttpError("invalid_account_daily_return", 400);
- if (prior && !historical) {
- if (incoming.period.to < prior.period.to || Date.parse(incoming.observed_at) < Date.parse(prior.observed_at)) throw new HttpError("account_period_return_stale_write", 409);
- if (incoming.observed_at === prior.observed_at && canonicalResearchTaskJson(incoming) !== canonicalResearchTaskJson(prior)) throw new HttpError("account_period_return_conflict", 409);
- }
- if (incoming.period.from === incoming.period.to) {
- const oldDay = this.sql.exec("SELECT payload_json FROM account_daily_native_return WHERE account_key = ? AND source_binding_id = ? AND currency = ? AND observation_date = ?", context.account_key, context.source_binding_id, incoming.currency, incoming.period.to).toArray()[0];
- if (oldDay) {
- const old = normalizeIbkrPeriodReturn(JSON.parse(oldDay.payload_json), { binding, enforceFresh: false });
- if (Date.parse(incoming.observed_at) < Date.parse(old.observed_at)) throw new HttpError("account_daily_return_stale_write", 409);
- if (incoming.observed_at === old.observed_at && canonicalResearchTaskJson(incoming) !== canonicalResearchTaskJson(old)) throw new HttpError("account_daily_return_conflict", 409);
- }
- this.sql.exec("INSERT INTO account_daily_native_return (account_key, source_binding_id, currency, observation_date, payload_json) VALUES (?, ?, ?, ?, ?) ON CONFLICT(account_key, source_binding_id, currency, observation_date) DO UPDATE SET payload_json = excluded.payload_json", context.account_key, context.source_binding_id, incoming.currency, incoming.period.to, JSON.stringify(incoming));
- }
- if (historical && prior && (incoming.period.to < prior.period.to || Date.parse(incoming.observed_at) < Date.parse(prior.observed_at))) return { ok: true, unchanged: false };
- if (prior && canonicalResearchTaskJson(incoming) === canonicalResearchTaskJson(prior)) return { ok: true, unchanged: true };
- this.sql.exec("INSERT INTO account_period_return (account_key, payload_json) VALUES (?, ?) ON CONFLICT(account_key) DO UPDATE SET payload_json = excluded.payload_json", context.account_key, JSON.stringify(incoming));
- return { ok: true, unchanged: false };
- }
-
- // Internal only: a future authorized caller must supply verified account and
- // source bindings. The browser/session and publisher routes do not call this.
- researchNativeDailyReturns(command) {
- const context = this.accountFactsStorageContext(command);
- const from = runtimeDailyCalendarDate(command.from), to = runtimeDailyCalendarDate(command.to);
- const start = Date.parse(`${from}T00:00:00Z`), end = Date.parse(`${to}T00:00:00Z`);
- if (context.platform !== "ibkr" || !/^[a-f0-9]{64}$/.test(context.source_binding_id)
- || !context.account_scope || !context.account_selector || !context.target_id
- || typeof command.currency !== "string" || !/^[A-Z]{3}$/.test(command.currency)
- || !from || !to || end < start || (end - start) / 86400000 >= 366)
- throw new HttpError("invalid_native_return_research_range", 400);
- const sources = new Set([context.source_binding_id, ...(context.history_source_binding_ids || [])]);
- let stored;
- try {
- stored = this.sql.exec(`SELECT source_binding_id, currency, observation_date, payload_json
- FROM account_daily_native_return WHERE account_key = ? AND currency = ? AND observation_date >= ? AND observation_date <= ?
- ORDER BY observation_date, source_binding_id LIMIT ?`, context.account_key, command.currency, from, to, 366 * 65 + 1).toArray();
- } catch { throw new HttpError("native_return_read_failed", 503); }
- if (stored.length > 366 * 65) throw new HttpError("native_return_read_limit_exceeded", 503);
- const byDate = new Map();
- const navByDate = new Map();
- const decimal = text => {
- const [whole, fraction = ""] = text.split(".");
- return { number: BigInt(whole + fraction), scale: fraction.length };
- };
- const decimalEqual = (left, right) => {
- const a = decimal(left), b = decimal(right);
- return a.number * 10n ** BigInt(b.scale) === b.number * 10n ** BigInt(a.scale);
- };
- const navFields = ["startingValue", "endingValue", "depositsWithdrawals", "internalCashTransfers", "assetTransfers", "linkingAdjustments"];
- for (const item of stored) {
- const date = runtimeDailyCalendarDate(item.observation_date);
- if (!date) return { ok: false, error: "native_return_record_invalid", date: null };
- if (!sources.has(item.source_binding_id)) return { ok: false, error: "native_return_source_unqualified", date };
- let raw;
- try {
- raw = JSON.parse(item.payload_json);
- const validated = normalizeIbkrPeriodReturn(raw, { binding: { ...context, source_binding: { id: item.source_binding_id } }, enforceFresh: false });
- if (validated.currency !== item.currency || validated.period.from !== date || validated.period.to !== date) throw Error();
- } catch { return { ok: false, error: "native_return_record_invalid", date }; }
- const previous = byDate.get(date);
- if (previous) {
- if (!decimalEqual(previous.value, raw.value))
- return { ok: false, error: "native_return_history_conflict", date };
- }
- if (raw.nav_change) {
- const priorNav = navByDate.get(date), nav = raw.nav_change;
- if (priorNav && (!decimalEqual(priorNav.amount, nav.amount)
- || navFields.some(field => !decimalEqual(priorNav.components[field], nav.components[field]))))
- return { ok: false, error: "native_return_nav_conflict", date };
- navByDate.set(date, nav);
- }
- // SQL order is deterministic; prefer the currently configured source.
- if (!previous || raw.source_binding_id === context.source_binding_id) byDate.set(date, raw);
- }
- const rows = [...byDate.values()];
- const datesWithoutRecords = [];
- for (let day = start; day <= end; day += 86400000) {
- const date = new Date(day).toISOString().slice(0, 10);
- if (!byDate.has(date)) datesWithoutRecords.push(date);
- }
- return { ok: true, status: "ok", currency: command.currency, from, to, rows,
- source_row_count: stored.length, duplicate_row_count: stored.length - rows.length,
- returned_from: rows[0]?.period.to || null, returned_to: rows.at(-1)?.period.to || null,
- dates_without_records: datesWithoutRecords, calendar_qualification: "unknown", published_at: null, historical_pit: "unknown" };
- }
-
- accountFactsStorageContext(command) {
- if (!ACCOUNT_FACTS_SUPPORTED_PLATFORMS.includes(command?.platform)
- || typeof command.account_key !== "string" || !command.account_key
- || typeof command.account_scope !== "string"
- || typeof command.account_selector !== "string"
- || typeof command.target_id !== "string"
- || typeof command.source_binding_id !== "string") {
- throw new HttpError("invalid_account_facts_account", 400);
- }
- const historyIds = command.history_source_binding_ids;
- if (historyIds !== undefined && (!["account_facts_history_read", "account_facts_history_put", "account_period_return_read", "account_period_return_put", "account_daily_native_return_research_read", "account_executions_read", "account_executions_put"].includes(command.action)
- || !Array.isArray(historyIds) || historyIds.length < 1 || historyIds.length > 64
- || new Set(historyIds).size !== historyIds.length
- || historyIds.some(id => typeof id !== "string" || !/^[a-f0-9]{64}$/.test(id)
- || id === command.source_binding_id))) throw new HttpError("invalid_account_facts_history_sources", 400);
- const brokerAccountId = command.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? command.broker_account_id : null;
- if (command.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM && !validFirstradeAccountId(brokerAccountId)) {
- throw new HttpError("invalid_account_facts_account", 400);
- }
- const brokerAccountHash = command.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
- ? command.broker_account_hash
- : null;
- if (command.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
- && (typeof brokerAccountHash !== "string" || !brokerAccountHash || brokerAccountHash.length > 256)) {
- throw new HttpError("invalid_account_facts_account", 400);
- }
- return {
- platform: command.platform,
- ...(command.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? { broker_account_id: brokerAccountId } : {}),
- account_key: command.account_key,
- account_scope: command.account_scope,
- account_selector: command.account_selector,
- target_id: command.target_id,
- source_binding_id: command.source_binding_id,
- ...(historyIds ? { history_source_binding_ids: [...historyIds] } : {}),
- ...(command.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
- ? { broker_account_hash: brokerAccountHash }
- : {}),
- };
- }
-
- validateAccountFactsStoragePayload(payload, context, { historical = false } = {}) {
- try {
- const normalize = historical ? normalizeAccountFactsHistoricalPayload : normalizeAccountFactsHistoryPayload;
- return normalize(payload, {
- expectedPlatform: context.platform,
- expectedTargetId: context.target_id,
- expectedBindingId: context.source_binding_id,
- expectedOptionScope: context.account_scope,
- expectedAccountSelector: context.platform === IBKR_ACCOUNT_FACTS_PLATFORM
- ? context.account_selector
- : null,
- expectedBrokerAccountHash: context.platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
- ? context.broker_account_hash
- : null,
- expectedBrokerAccountId: context.platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? context.broker_account_id : null,
- enforceObservationWindow: false,
- });
- } catch (error) {
- if (error instanceof AccountFactsError) throw new HttpError(error.code, error.status || 400);
- throw error;
- }
- }
-
- validatePriorAccountFactsForAccount(row, context) {
- if (!row) return null;
- if (row.platform !== context.platform || row.account_key !== context.account_key
- || row.account_scope !== context.account_scope || row.target_id !== context.target_id) {
- throw new HttpError("account_facts_identity_mismatch", 409);
- }
- const priorBindingId = row.payload?.source_binding?.id;
- if (typeof priorBindingId !== "string") throw new HttpError("account_facts_stored_invalid", 409);
- const priorContext = { ...context, source_binding_id: priorBindingId };
- const payload = this.validateAccountFactsStoragePayload(row.payload, priorContext);
- if (row.source_binding_id !== priorBindingId
- || payload.target_id !== row.target_id
- || payload.source_binding.id !== row.source_binding_id) {
- throw new HttpError("account_facts_identity_mismatch", 409);
- }
- return { ...row, payload };
- }
-
- readAccountFactsRow(platform, accountKey, context = null) {
- const row = this.sql.exec(
- "SELECT payload_json, observed_finished_at, observation_date, target_id, source_binding_id, account_scope FROM account_facts_observation WHERE platform = ? AND account_key = ?",
- platform,
- accountKey,
- ).toArray()[0];
- if (!row) return null;
- let payload;
- try { payload = JSON.parse(row.payload_json); } catch { throw new HttpError("account_facts_stored_invalid", 409); }
- if (context) {
- if (platform !== context.platform || accountKey !== context.account_key
- || row.target_id !== context.target_id
- || row.source_binding_id !== context.source_binding_id
- || row.account_scope !== context.account_scope) {
- throw new HttpError("account_facts_identity_mismatch", 409);
- }
- payload = this.validateAccountFactsStoragePayload(payload, context);
- }
- return {
- platform,
- account_key: accountKey,
- payload,
- observed_finished_at: row.observed_finished_at,
- observation_date: row.observation_date,
- target_id: row.target_id,
- source_binding_id: row.source_binding_id,
- account_scope: row.account_scope,
- };
- }
-
- putAccountFactsObservation(command) {
- const context = this.accountFactsStorageContext(command);
- if (!command.history || typeof command.history !== "object" || Array.isArray(command.history)) {
- throw new HttpError("invalid_account_facts_history", 400);
- }
- let history;
- try {
- history = this.validateAccountFactsStoragePayload(command.history, context);
- } catch (error) {
- if (error instanceof AccountFactsError) throw new HttpError(error.code, error.status || 400);
- throw error;
- }
- const existingRow = this.validatePriorAccountFactsForAccount(
- this.readAccountFactsRow(command.platform, command.account_key),
- context,
- );
- const decision = decideAccountFactsPut(existingRow?.payload || null, history);
- if (decision.action === "reject") throw new HttpError(decision.reason, decision.status || 409);
- let flowChanged = false;
- if (command.externalFlow !== undefined) {
- if (!this.externalFlowEnabled) throw new HttpError("external_flow_disabled", 409);
- const flow = normalizeExternalFlow(command.externalFlow);
- const source = { ibkr: "ibkr_flex", schwab: "schwab_transactions", longbridge: "longbridge_cashflow" }[context.platform];
- const currencies = new Set(history.broker_reported_balances.map(b => b.currency));
- if (flow.windows.some(w => w.source !== source || !currencies.has(w.currency)
- || Date.parse(w.period_end) > Date.parse(history.observed_finished_at))) {
- throw new HttpError("external_flow_observation_mismatch", 409);
- }
- flowChanged = !putExternalFlow(this.sql, context, flow).unchanged;
- }
- if (decision.action === "keep") {
- // Latest table unchanged; still ensure the accepted day is retained.
- this.upsertAccountFactsDaily(context, history);
- return {
- ok: true,
- stored: true,
- unchanged: !flowChanged,
- platform: command.platform,
- account_key: command.account_key,
- observation_date: existingRow.observation_date,
- observed_finished_at: existingRow.observed_finished_at,
- };
- }
- const updatedAt = new Date().toISOString();
- const payloadJson = JSON.stringify(history);
- this.sql.exec(
- `INSERT INTO account_facts_observation (
- platform, account_key, payload_json, observed_finished_at, observation_date,
- target_id, source_binding_id, account_scope, updated_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
- ON CONFLICT(platform, account_key) DO UPDATE SET
- payload_json = excluded.payload_json,
- observed_finished_at = excluded.observed_finished_at,
- observation_date = excluded.observation_date,
- target_id = excluded.target_id,
- source_binding_id = excluded.source_binding_id,
- account_scope = excluded.account_scope,
- updated_at = excluded.updated_at`,
- command.platform,
- command.account_key,
- payloadJson,
- history.observed_finished_at,
- history.observation_date,
- history.target_id,
- history.source_binding.id,
- command.account_scope,
- updatedAt,
- );
- this.upsertAccountFactsDaily(context, history);
- return {
- ok: true,
- stored: true,
- unchanged: false,
- platform: command.platform,
- account_key: command.account_key,
- observation_date: history.observation_date,
- observed_finished_at: history.observed_finished_at,
- };
- }
-
- putAccountFactsHistoricalObservation(command) {
- const context = this.accountFactsStorageContext(command);
- const sourceId = command.history?.source_binding?.id;
- if (![context.source_binding_id, ...(context.history_source_binding_ids || [])].includes(sourceId)) {
- throw new HttpError("account_facts_binding_unmatched", 409);
- }
- const history = this.validateAccountFactsStoragePayload(command.history,
- { ...context, source_binding_id: sourceId }, { historical: true });
- // Deliberately bypass latest observation and external-flow writes. Reuse
- // daily storage with replacement and retention deletion disabled.
- return { ok: true, stored: true, ...this.upsertAccountFactsDaily(context, history, { appendOnly: true }) };
- }
-
- readAccountFactsDailyRow(platform, accountKey, observationDate, context = null) {
- const row = this.sql.exec(
- `SELECT payload_json, observed_finished_at, observation_date, target_id, source_binding_id, account_scope
- FROM account_facts_daily WHERE platform = ? AND account_key = ? AND observation_date = ?`,
- platform,
- accountKey,
- observationDate,
- ).toArray()[0];
- if (!row) return null;
- let payload;
- try { payload = JSON.parse(row.payload_json); } catch { throw new HttpError("account_facts_stored_invalid", 409); }
- if (context) {
- if (platform !== context.platform || accountKey !== context.account_key
- || row.target_id !== context.target_id
- || row.source_binding_id !== context.source_binding_id
- || row.account_scope !== context.account_scope) {
- throw new HttpError("account_facts_identity_mismatch", 409);
- }
- payload = this.validateAccountFactsStoragePayload(payload, context);
- }
- return {
- platform,
- account_key: accountKey,
- observation_date: row.observation_date,
- payload,
- observed_finished_at: row.observed_finished_at,
- target_id: row.target_id,
- source_binding_id: row.source_binding_id,
- account_scope: row.account_scope,
- };
- }
-
- upsertAccountFactsDaily(context, history, { appendOnly = false } = {}) {
- const { platform, account_key: accountKey, account_scope: accountScope } = context;
- const existing = this.validatePriorAccountFactsForAccount(
- this.readAccountFactsDailyRow(platform, accountKey, history.observation_date),
- context,
- );
- if (appendOnly && existing) {
- if (existing.observed_finished_at !== history.observed_finished_at
- || canonicalizeAccountFactsHistory(existing.payload) !== canonicalizeAccountFactsHistory(history)) {
- throw new HttpError("account_facts_daily_conflict", 409);
- }
- return { unchanged: true };
- }
- let decision;
- try {
- decision = decideAccountFactsDailyUpsert(existing?.payload || null, history);
- } catch (error) {
- if (error instanceof AccountFactsError) throw new HttpError(error.code, error.status || 400);
- throw error;
- }
- if (decision.action === "reject") throw new HttpError(decision.reason, decision.status || 409);
- if (decision.action === "skip" || decision.action === "keep") {
- this.pruneAccountFactsDaily(platform, accountKey, history.observation_date);
- return { unchanged: true };
- }
- const updatedAt = new Date().toISOString();
- this.sql.exec(
- `INSERT INTO account_facts_daily (
- platform, account_key, observation_date, payload_json, observed_finished_at,
- target_id, source_binding_id, account_scope, updated_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
- ${appendOnly ? "" : `ON CONFLICT(platform, account_key, observation_date) DO UPDATE SET
- payload_json = excluded.payload_json,
- observed_finished_at = excluded.observed_finished_at,
- target_id = excluded.target_id,
- source_binding_id = excluded.source_binding_id,
- account_scope = excluded.account_scope,
- updated_at = excluded.updated_at`}`,
- platform,
- accountKey,
- history.observation_date,
- JSON.stringify(history),
- history.observed_finished_at,
- history.target_id,
- history.source_binding.id,
- accountScope,
- updatedAt,
- );
- if (!appendOnly) this.pruneAccountFactsDaily(platform, accountKey, history.observation_date);
- return { unchanged: false };
- }
-
- pruneAccountFactsDaily(platform, accountKey, latestDate) {
- const cutoff = historyRetentionCutoff(latestDate, ACCOUNT_FACTS_HISTORY_MAX_DAYS);
- if (!cutoff) return;
- this.sql.exec(
- "DELETE FROM account_facts_daily WHERE platform = ? AND account_key = ? AND observation_date < ?",
- platform,
- accountKey,
- cutoff,
- );
- }
-
- readAccountFactsDailyHistory(command) {
- const context = this.accountFactsStorageContext(command);
- const { platform, account_key: accountKey } = context;
- if (command.projection === "external-flow-coverage") {
- return { ok: true, ...readExternalFlowCoverage(this.sql, context) };
- }
- if (command.projection !== undefined) {
- const dates = accountFactsIdentityDates(command.from, command.to);
- if (command.projection !== "identity" || !dates) {
- throw new HttpError("invalid_account_facts_identity_query", 400);
- }
- // Deliberately exclude payload_json: identity inspection must not read assets.
- const rows = this.sql.exec(
- `SELECT observation_date, observed_finished_at, target_id, source_binding_id, account_scope
- FROM account_facts_daily WHERE platform = ? AND account_key = ?
- AND observation_date >= ? AND observation_date <= ? ORDER BY observation_date ASC`,
- platform, accountKey, dates[0], dates.at(-1),
- ).toArray();
- const same = (value, expected) => typeof value === "string" && value.length > 0 && value.length <= 512
- ? value === expected : null;
- return { ok: true, records: dates.map(date => {
- const matches = rows.filter(row => row.observation_date === date);
- const row = matches.length === 1 ? matches[0] : null;
- const source = row?.source_binding_id;
- return {
- observation_date: date, observed_finished_at: row?.observed_finished_at ?? null,
- target_id_matches: same(row?.target_id, context.target_id),
- source_binding_id_matches: same(source, context.source_binding_id),
- account_scope_matches: same(row?.account_scope, context.account_scope),
- record_revision: null,
- row_present: matches.length > 1 ? null : Boolean(row),
- source_binding_id_trusted: typeof source === "string" && source.length > 0 && source.length <= 512
- ? [context.source_binding_id, ...(context.history_source_binding_ids || [])].includes(source) : null,
- stored_source_binding_id: typeof source === "string" && /^[a-f0-9]{64}$/.test(source) ? source : null,
- };
- }) };
- }
- const rows = this.sql.exec(
- `SELECT payload_json, observed_finished_at, observation_date, target_id, source_binding_id, account_scope
- FROM account_facts_daily WHERE platform = ? AND account_key = ? ORDER BY observation_date ASC`,
- platform,
- accountKey,
- ).toArray();
- const days = [];
- for (const row of rows) {
- // Same-account history may use an explicitly qualified prior source.
- // Current observations and ordinary sync still require the current source.
- if (row.target_id !== context.target_id
- || ![context.source_binding_id, ...(context.history_source_binding_ids || [])].includes(row.source_binding_id)
- || row.account_scope !== context.account_scope) continue;
- let payload;
- try { payload = JSON.parse(row.payload_json); } catch { throw new HttpError("account_facts_stored_invalid", 409); }
- payload = this.validateAccountFactsStoragePayload(payload, { ...context, source_binding_id: row.source_binding_id });
- days.push({
- observation_date: row.observation_date,
- payload,
- observed_finished_at: row.observed_finished_at,
- target_id: row.target_id,
- source_binding_id: row.source_binding_id,
- account_scope: row.account_scope,
- });
- }
- return { ok: true, days,
- externalFlow: readExternalFlow(this.sql, context, { dateOnly: !this.externalFlowEnabled }),
- };
- }
-
- readAccountFactsObservation(command) {
- const context = this.accountFactsStorageContext(command);
- const row = this.readAccountFactsRow(context.platform, context.account_key, context);
- return { ok: true, observation: row };
- }
-
- listAccountFactsObservations(command) {
- const wanted = Array.isArray(command.accounts) ? command.accounts : [];
- const observations = [];
- for (const item of wanted) {
- if (!item || typeof item.platform !== "string" || typeof item.account_key !== "string") continue;
- const context = this.accountFactsStorageContext(item);
- try {
- const row = this.readAccountFactsRow(context.platform, context.account_key, context);
- if (row) observations.push(row);
- } catch (error) {
- // A trusted binding rotation makes older rows ineligible for display.
- // Keep them stored for audit, but treat them as absent until refreshed.
- if (!(error instanceof HttpError) || error.message !== "account_facts_identity_mismatch") throw error;
- }
- }
- return { ok: true, observations };
- }
-
- accountSettingsCommand(command) {
- if (!command || typeof command.actor !== "string" || !command.actor) throw new HttpError("runtime_instance_actor_required", 400);
- if (command.action === "risk_profile_read") return this.readRiskProfileAuthority(command.legacy);
- if (command.action === "risk_profile_replace") return this.replaceRiskProfileAuthority(command);
- if (command.action === "risk_profile_set") return this.setRiskProfileAuthority(command);
- if (command.action === "account_declarations_read") {
- const state = this.read();
- if (!state.initialized) throw new HttpError("runtime_instances_not_initialized", 409);
- return { declarations: state.instances.filter(item => item.kind === "existing").map(item => ({
- platform: item.platform, key: item.key, binding_environment: accountSettingsIdentity(item).broker_environment,
- ...this.accountSettingDeclaration(item, accountSettingsIdentity(item)),
- })) };
- }
- if (command.action === "account_settings_read") return this.readAccountSettings(command);
- if (command.action === "account_settings_save") return this.saveAccountSettings(command);
- if (command.action === "account_settings_profile_application_lookup") return this.readAccountSettingsProfileApplication(command);
- if (command.action === "account_settings_profile_application_approve") return this.approveAccountSettingsProfileApplication(command);
- if (command.action === "account_settings_profile_application_claim") return this.claimAccountSettingsProfileApplication(command);
- throw new HttpError("unsupported_account_settings_action", 400);
- }
-
- ensureRiskProfileAuthority(legacy) {
- const row = this.sql.exec("SELECT revision, imported, bindings_json FROM risk_profile_authority WHERE id = 1").toArray()[0];
- if (row) return row;
- if (legacy?.state === "blocked") throw new HttpError("risk_profile_bindings_invalid", 409);
- const bindings = legacy?.state === "valid" && Array.isArray(legacy.bindings) ? legacy.bindings : [];
- const payload = JSON.stringify(bindings);
- this.sql.exec("INSERT INTO risk_profile_authority (id, revision, imported, bindings_json) VALUES (1, 0, 1, ?)", payload);
- return { revision: 0, imported: 1, bindings_json: payload };
- }
-
- storedRiskBindings(row) {
- let bindings;
- try { bindings = JSON.parse(row.bindings_json); } catch { throw new HttpError("risk_profile_bindings_invalid", 409); }
- if (!Array.isArray(bindings)) throw new HttpError("risk_profile_bindings_invalid", 409);
- return bindings;
- }
-
- assertStoredRiskBinding(binding, accountOptions) {
- if (!binding || Array.isArray(binding) || typeof binding !== "object") throw new HttpError("invalid_risk_profile_binding", 400);
- if (binding.no_order !== true || binding.execution_authority_granted !== false) throw new HttpError("risk_profile_execution_authority_rejected", 400);
- if (binding.scope_id !== riskProfileScopeId(binding.platform, binding.target_name)) throw new HttpError("invalid_risk_profile_binding", 400);
- if (!RISK_PROFILE_PREFERENCES.includes(binding.profile_selection?.risk_preference)) throw new HttpError("invalid_risk_profile_binding", 400);
- const policy = RISK_TIER_POLICY_BINDINGS[binding.profile_selection?.risk_preference];
- if (!policy || binding.profile_selection?.profile_id !== policy.profile_id) {
- throw new HttpError("risk_profile_policy_binding_invalid", 409);
- }
- if (!riskProfileBindingTargets(accountOptions).some((target) => target.platform === binding.platform && target.target_name === binding.target_name)) {
- throw new HttpError("risk_profile_binding_target_not_configured", 409);
- }
- }
-
- writeRiskProfileAuthority(row, bindings) {
- const current = this.storedRiskBindings(row);
- const same = canonicalResearchTaskJson(current) === canonicalResearchTaskJson(bindings);
- const revision = same ? Number(row.revision) : Number(row.revision) + 1;
- if (!same) this.sql.exec("UPDATE risk_profile_authority SET revision = ?, bindings_json = ? WHERE id = 1", revision, JSON.stringify(bindings));
- const state = this.read();
- return {
- ok: true,
- revision,
- bindings,
- account_options: runtimeInstanceAccountOptions(state.instances),
- instance_revision: state.revision,
- initialized: state.initialized,
- no_order: true,
- execution_authority_granted: false,
- };
- }
-
- readRiskProfileAuthority(legacy) {
- const row = this.ensureRiskProfileAuthority(legacy);
- const state = this.read();
- return {
- ok: true,
- revision: Number(row.revision),
- bindings: this.storedRiskBindings(row),
- account_options: runtimeInstanceAccountOptions(state.instances),
- instance_revision: state.revision,
- initialized: state.initialized,
- no_order: true,
- execution_authority_granted: false,
- };
- }
-
- requireRiskRevision(command, row) {
- if (!Number.isSafeInteger(command.expected_revision) || command.expected_revision !== Number(row.revision)) {
- throw new HttpError("risk_profile_revision_conflict", 409);
- }
- }
-
- replaceRiskProfileAuthority(command) {
- const row = this.ensureRiskProfileAuthority(command.legacy);
- this.requireRiskRevision(command, row);
- const options = runtimeInstanceAccountOptions(this.read().instances);
- if (!Array.isArray(command.bindings)) throw new HttpError("invalid_risk_profile_binding", 400);
- for (const binding of command.bindings) this.assertStoredRiskBinding(binding, options);
- const bindings = [...command.bindings].sort((left, right) => left.scope_id.localeCompare(right.scope_id));
- return this.writeRiskProfileAuthority(row, bindings);
- }
-
- setRiskProfileAuthority(command) {
- const row = this.ensureRiskProfileAuthority(command.legacy);
- this.requireRiskRevision(command, row);
- const options = runtimeInstanceAccountOptions(this.read().instances);
- if (!riskProfileBindingTargets(options).some((target) => target.platform === command.platform && target.target_name === command.target_name)) {
- throw new HttpError("risk_profile_binding_target_not_configured", 409);
- }
- const scopeId = riskProfileScopeId(command.platform, command.target_name);
- const current = this.storedRiskBindings(row).filter((binding) => binding.scope_id !== scopeId);
- if (command.risk_change === "clear") return this.writeRiskProfileAuthority(row, current);
- if (command.risk_change !== "set") throw new HttpError("invalid_risk_profile_change", 400);
- this.assertStoredRiskBinding(command.binding, options);
- if (command.binding.scope_id !== scopeId) throw new HttpError("invalid_risk_profile_binding", 400);
- current.push(command.binding);
- current.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
- return this.writeRiskProfileAuthority(row, current);
- }
-
- existingAccountInstance(platform, key) {
- const state = this.read();
- if (!state.initialized) throw new HttpError("runtime_instances_not_initialized", 409);
- const item = state.instances.find((candidate) => candidate.kind === "existing" && candidate.platform === platform && candidate.key === key);
- if (!item) throw new HttpError("account_settings_not_found", 404);
- return { state, item, identity: accountSettingsIdentity(item) };
- }
-
- accountSettingDraftView(item, identity) {
- const row = this.sql.exec(
- "SELECT revision, identity_json, overrides_json FROM account_setting_draft WHERE platform = ? AND account_key = ?",
- item.platform, item.key,
- ).toArray()[0];
- if (!row) return { status: "empty", revision: 0, identity: null, current_identity: identity, overrides: {} };
- let storedIdentity = null;
- let overrides = {};
- try {
- storedIdentity = JSON.parse(row.identity_json);
- overrides = JSON.parse(row.overrides_json);
- } catch {
- throw new HttpError("account_settings_draft_invalid", 409);
- }
- const conflict = canonicalResearchTaskJson(storedIdentity) !== canonicalResearchTaskJson(identity);
- return {
- status: conflict ? "identity_conflict" : "current",
- revision: Number(row.revision),
- identity: storedIdentity,
- current_identity: identity,
- overrides: overrides && typeof overrides === "object" && !Array.isArray(overrides) ? overrides : {},
- };
- }
-
- accountSettingDeclaration(item, identity) {
- const row = this.sql.exec("SELECT revision, identity_json, declaration_json FROM account_setting_declaration WHERE platform = ? AND account_key = ?", item.platform, item.key).toArray()[0];
- if (!row) return { status: "empty", revision: 0, environment: null, account_type: null, source: "user_declared" };
- const matches = canonicalResearchTaskJson(JSON.parse(row.identity_json)) === canonicalResearchTaskJson(identity);
- const value = JSON.parse(row.declaration_json);
- return { status: matches ? "current" : "identity_conflict", revision: Number(row.revision),
- environment: matches ? value.environment : null, account_type: matches ? value.account_type : null, source: "user_declared" };
- }
-
- saveAccountSettingDeclaration(item, identity, command) {
- if (!command.identity || canonicalResearchTaskJson(command.identity) !== canonicalResearchTaskJson(identity)) throw new HttpError("account_settings_identity_conflict", 409);
- const current = this.accountSettingDeclaration(item, identity);
- if (!Number.isSafeInteger(command.expected_declaration_revision) || command.expected_declaration_revision !== current.revision) throw new HttpError("account_settings_declaration_revision_conflict", 409);
- if (current.status === "identity_conflict") throw new HttpError("account_settings_identity_conflict", 409);
- const value = command.declaration;
- if (!value || Array.isArray(value) || typeof value !== "object" || Object.keys(value).some(k => !["environment", "account_type"].includes(k))
- || ![null, "live", "paper"].includes(value.environment) || ![null, "cash", "margin"].includes(value.account_type)) throw new HttpError("invalid_account_settings_declaration", 400);
- if (current.status === "current" && current.environment === value.environment && current.account_type === value.account_type) return;
- this.sql.exec("INSERT INTO account_setting_declaration (platform, account_key, revision, identity_json, declaration_json) VALUES (?, ?, ?, ?, ?) ON CONFLICT (platform, account_key) DO UPDATE SET revision = excluded.revision, identity_json = excluded.identity_json, declaration_json = excluded.declaration_json", item.platform, item.key, current.revision + 1, JSON.stringify(identity), JSON.stringify(value));
- }
-
- readAccountSettings(command) {
- const { state, item, identity } = this.existingAccountInstance(command.platform, command.key);
- const risk = this.readRiskProfileAuthority(command.legacy);
- const scopeId = riskProfileScopeId(item.platform, identity.target_name);
- const binding = risk.bindings.find((entry) => entry.scope_id === scopeId) || null;
- return {
- ok: true,
- found: true,
- platform: item.platform,
- key: item.key,
- instance_revision: state.revision,
- enabled: item.enabled,
- identity,
- config: item.config,
- draft: this.accountSettingDraftView(item, identity),
- declaration: this.accountSettingDeclaration(item, identity),
- risk: {
- revision: risk.revision,
- scope_id: scopeId,
- preference: binding?.profile_selection?.risk_preference || null,
- binding,
- },
- bindings: risk.bindings,
- account_options: risk.account_options,
- no_order: true,
- execution_authority_granted: false,
- };
- }
-
- saveAccountSettingDraft(item, identity, command) {
- if (!command.identity || Array.isArray(command.identity) || typeof command.identity !== "object") {
- throw new HttpError("account_settings_identity_required", 400);
- }
- if (canonicalResearchTaskJson(command.identity) !== canonicalResearchTaskJson(identity)) {
- throw new HttpError("account_settings_identity_conflict", 409);
- }
- if (!Number.isSafeInteger(command.expected_draft_revision) || command.expected_draft_revision < 0) {
- throw new HttpError("account_settings_draft_revision_conflict", 409);
- }
- const row = this.sql.exec(
- "SELECT revision, identity_json, overrides_json FROM account_setting_draft WHERE platform = ? AND account_key = ?",
- item.platform, item.key,
- ).toArray()[0];
- const now = new Date().toISOString();
- if (!row) {
- if (command.expected_draft_revision !== 0) throw new HttpError("account_settings_draft_revision_conflict", 409);
- const overrides = applyAccountSettingOverrides({}, command.overrides);
- this.sql.exec(
- "INSERT INTO account_setting_draft (platform, account_key, revision, identity_json, overrides_json, updated_at) VALUES (?, ?, 1, ?, ?, ?)",
- item.platform, item.key, JSON.stringify(identity), JSON.stringify(overrides), now,
- );
- return;
- }
- if (command.expected_draft_revision !== Number(row.revision)) throw new HttpError("account_settings_draft_revision_conflict", 409);
- const storedIdentity = JSON.parse(row.identity_json);
- const conflict = canonicalResearchTaskJson(storedIdentity) !== canonicalResearchTaskJson(identity);
- if (conflict && command.acknowledge_identity_conflict !== true) throw new HttpError("account_settings_identity_conflict", 409);
- const storedOverrides = JSON.parse(row.overrides_json);
- const base = conflict ? {} : storedOverrides;
- const overrides = applyAccountSettingOverrides(base, command.overrides);
- if (!conflict && canonicalResearchTaskJson(overrides) === canonicalResearchTaskJson(storedOverrides)) return;
- this.sql.exec(
- "UPDATE account_setting_draft SET revision = ?, identity_json = ?, overrides_json = ?, updated_at = ? WHERE platform = ? AND account_key = ?",
- Number(row.revision) + 1, JSON.stringify(identity), JSON.stringify(overrides), now, item.platform, item.key,
- );
- }
-
- saveAccountSettings(command) {
- const { item, identity } = this.existingAccountInstance(command.platform, command.key);
- const hasDraft = Object.prototype.hasOwnProperty.call(command, "overrides");
- const hasRisk = Object.prototype.hasOwnProperty.call(command, "risk_change");
- const hasDeclaration = Object.prototype.hasOwnProperty.call(command, "declaration");
- if (!hasDraft && !hasRisk && !hasDeclaration) throw new HttpError("account_settings_change_required", 400);
- if (hasDeclaration) this.saveAccountSettingDeclaration(item, identity, command);
- if (hasDraft) this.saveAccountSettingDraft(item, identity, command);
- if (hasRisk) {
- if (!command.identity || Array.isArray(command.identity) || typeof command.identity !== "object") {
- throw new HttpError("account_settings_identity_required", 400);
- }
- if (canonicalResearchTaskJson(command.identity) !== canonicalResearchTaskJson(identity)) {
- throw new HttpError("account_settings_identity_conflict", 409);
- }
- this.setRiskProfileAuthority({
- ...command,
- platform: identity.platform,
- target_name: identity.target_name,
- expected_revision: command.expected_risk_revision,
- });
- }
- return { ...this.readAccountSettings(command), adopted: false };
- }
-
- accountSettingsProfileApplicationFromRow(row) {
- if (!row) return null;
- let identity;
- try { identity = JSON.parse(row.identity_json); } catch { throw new HttpError("account_settings_profile_application_invalid", 409); }
- return {
- request_key: row.request_key,
- platform: row.platform,
- key: row.account_key,
- identity,
- instance_revision: Number(row.instance_revision),
- draft_revision: Number(row.draft_revision),
- old_profile: row.old_profile,
- new_profile: row.new_profile,
- approved_by: row.approved_by,
- approved_at: row.approved_at,
- status: row.status,
- workflow_run_id: row.workflow_run_id || null,
- workflow_run_attempt: row.workflow_run_attempt || null,
- claimed_at: row.claimed_at || null,
- runtime_applied: false,
- variables_updated: false,
- no_order: true,
- execution_authority_granted: false,
- };
- }
-
- readAccountSettingsProfileApplication(command) {
- const requestKey = String(command.request_key || "");
- if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(requestKey)) {
- throw new HttpError("account_settings_profile_application_request_invalid", 400);
- }
- const row = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
- return { ok: true, application: this.accountSettingsProfileApplicationFromRow(row) };
- }
-
- approveAccountSettingsProfileApplication(command) {
- const requestKey = String(command.request_key || "");
- if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(requestKey)) {
- throw new HttpError("account_settings_profile_application_request_invalid", 400);
- }
- if (!SUPPORTED_PLATFORMS.includes(command.platform) || typeof command.key !== "string" || !command.key) {
- throw new HttpError("account_settings_account_required", 400);
- }
- if (!Number.isSafeInteger(command.expected_instance_revision) || command.expected_instance_revision < 0
- || !Number.isSafeInteger(command.expected_draft_revision) || command.expected_draft_revision < 0) {
- throw new HttpError("account_settings_profile_application_revision_invalid", 400);
- }
- const identity = command.identity;
- if (!accountSettingsIdentityIsComplete(identity)) throw new HttpError("account_settings_identity_required", 400);
- const identityJson = canonicalResearchTaskJson(identity);
- const oldProfile = accountSettingsProfileName(command.old_profile);
- const newProfile = accountSettingsProfileName(command.new_profile);
- if (!oldProfile || !newProfile || oldProfile === newProfile) throw new HttpError("account_settings_profile_application_profile_invalid", 400);
-
- const existing = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
- if (existing) {
- const sameRequest = existing.platform === command.platform
- && existing.account_key === command.key
- && existing.identity_json === identityJson
- && Number(existing.instance_revision) === command.expected_instance_revision
- && Number(existing.draft_revision) === command.expected_draft_revision
- && existing.old_profile === oldProfile
- && existing.new_profile === newProfile
- && existing.approved_by === command.actor;
- if (!sameRequest) throw new HttpError("account_settings_profile_application_conflict", 409);
- return { ok: true, replayed: true, application: this.accountSettingsProfileApplicationFromRow(existing) };
- }
-
- if (command.current_profile !== oldProfile || command.runtime_target_enabled !== false) {
- throw new HttpError("account_settings_profile_application_runtime_conflict", 409);
- }
- const { state, item, identity: currentIdentity } = this.existingAccountInstance(command.platform, command.key);
- if (state.revision !== command.expected_instance_revision || identityJson !== canonicalResearchTaskJson(currentIdentity)) {
- throw new HttpError("account_settings_profile_application_identity_conflict", 409);
- }
- const draft = this.accountSettingDraftView(item, currentIdentity);
- if (draft.status !== "current" || draft.revision !== command.expected_draft_revision
- || canonicalResearchTaskJson(draft.identity) !== identityJson
- || Object.keys(draft.overrides).length !== 1
- || draft.overrides.strategy_profile !== newProfile) {
- throw new HttpError("account_settings_profile_application_draft_conflict", 409);
- }
- if (isDcaProfile(oldProfile) || isDcaProfile(newProfile)) {
- throw new HttpError("account_settings_profile_application_profile_only_required", 409);
- }
-
- const priorApprovals = this.sql.exec(
- "SELECT request_key, identity_json, instance_revision, draft_revision, old_profile, new_profile FROM account_setting_profile_application WHERE platform = ? AND account_key = ? AND status = 'approved'",
- command.platform, command.key,
- ).toArray();
- for (const prior of priorApprovals) {
- const stale = prior.identity_json !== identityJson
- || Number(prior.instance_revision) !== state.revision
- || Number(prior.draft_revision) !== draft.revision
- || prior.old_profile !== oldProfile
- || prior.new_profile !== newProfile;
- if (stale) {
- this.sql.exec(
- "UPDATE account_setting_profile_application SET status = 'invalidated' WHERE request_key = ? AND status = 'approved'",
- prior.request_key,
- );
- }
- }
- const active = this.sql.exec(
- "SELECT request_key FROM account_setting_profile_application WHERE platform = ? AND account_key = ? AND status IN ('approved', 'claimed') LIMIT 1",
- command.platform, command.key,
- ).toArray()[0];
- if (active) throw new HttpError("account_settings_profile_application_pending", 409);
-
- const approvedAt = new Date().toISOString();
- this.sql.exec(
- `INSERT INTO account_setting_profile_application
- (request_key, platform, account_key, identity_json, instance_revision, draft_revision,
- old_profile, new_profile, approved_by, approved_at, status, workflow_run_id,
- workflow_run_attempt, claimed_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'approved', NULL, NULL, NULL)`,
- requestKey, command.platform, command.key, identityJson, command.expected_instance_revision,
- command.expected_draft_revision, oldProfile, newProfile, command.actor, approvedAt,
- );
- const row = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
- return { ok: true, replayed: false, application: this.accountSettingsProfileApplicationFromRow(row) };
- }
-
- claimAccountSettingsProfileApplication(command) {
- const requestKey = String(command.request_key || "");
- if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(requestKey)) {
- throw new HttpError("account_settings_profile_application_request_invalid", 400);
- }
- const row = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
- if (!row) throw new HttpError("account_settings_profile_application_not_found", 404);
- const workflowRunId = String(command.workflow_run_id || "");
- const workflowRunAttempt = String(command.workflow_run_attempt || "");
- if (!/^\d{1,20}$/.test(workflowRunId) || !/^[1-9]\d{0,5}$/.test(workflowRunAttempt)) {
- throw new HttpError("account_settings_profile_application_run_invalid", 400);
- }
- const identityJson = accountSettingsIdentityIsComplete(command.identity)
- ? canonicalResearchTaskJson(command.identity)
- : "";
- const safeResult = { no_order: true, execution_authority_granted: false, runtime_applied: false, variables_updated: false };
- const boundRequest = identityJson === row.identity_json
- && Number(command.expected_instance_revision) === Number(row.instance_revision)
- && Number(command.expected_draft_revision) === Number(row.draft_revision)
- && command.old_profile === row.old_profile
- && command.new_profile === row.new_profile
- && command.current_profile === row.old_profile
- && command.runtime_target_enabled === false;
- if (!boundRequest) throw new HttpError("account_settings_profile_application_conflict", 409);
- if (row.status === "claimed") {
- if (row.workflow_run_id !== workflowRunId || row.workflow_run_attempt !== workflowRunAttempt) {
- throw new HttpError("account_settings_profile_application_already_claimed", 409);
- }
- return { ok: true, claimed: false, replayed: true, application: this.accountSettingsProfileApplicationFromRow(row), ...safeResult };
- }
- if (row.status !== "approved") throw new HttpError("account_settings_profile_application_conflict", 409);
- if (!Number.isSafeInteger(command.expected_instance_revision) || !Number.isSafeInteger(command.expected_draft_revision)) {
- throw new HttpError("account_settings_profile_application_revision_invalid", 409);
- }
- const { state, item, identity: currentIdentity } = this.existingAccountInstance(row.platform, row.account_key);
- if (state.revision !== Number(row.instance_revision)
- || canonicalResearchTaskJson(currentIdentity) !== row.identity_json) {
- throw new HttpError("account_settings_profile_application_identity_conflict", 409);
- }
- const draft = this.accountSettingDraftView(item, currentIdentity);
- if (draft.status !== "current" || draft.revision !== Number(row.draft_revision)
- || canonicalResearchTaskJson(draft.identity) !== row.identity_json
- || Object.keys(draft.overrides).length !== 1
- || draft.overrides.strategy_profile !== row.new_profile) {
- throw new HttpError("account_settings_profile_application_draft_conflict", 409);
- }
- const claimedAt = new Date().toISOString();
- this.sql.exec(
- `UPDATE account_setting_profile_application
- SET status = 'claimed', workflow_run_id = ?, workflow_run_attempt = ?, claimed_at = ?
- WHERE request_key = ? AND status = 'approved'`,
- workflowRunId, workflowRunAttempt, claimedAt, requestKey,
- );
- const claimedRow = this.sql.exec("SELECT * FROM account_setting_profile_application WHERE request_key = ?", requestKey).toArray()[0];
- return { ok: true, claimed: true, replayed: false, application: this.accountSettingsProfileApplicationFromRow(claimedRow), ...safeResult };
- }
-
- runtimeControlCommand(command) {
- const platform = command?.platform;
- const key = command?.key;
- if (!["ibkr", "schwab"].includes(platform) || typeof key !== "string" || !key) throw new HttpError("runtime_control_target_invalid", 400);
- const found = this.existingAccountInstance(platform, key);
- const identity = found.identity;
- if (!runtimeControlIdentityIsComplete(identity)) throw new HttpError("runtime_control_identity_incomplete", 409);
- const targetId = `${platform}/${identity.target_name}`;
- const latest = () => {
- const row = this.sql.exec("SELECT * FROM hk_stop_request WHERE target_id = ? ORDER BY requested_at DESC, rowid DESC LIMIT 1", targetId).toArray()[0];
- return row ? { ...this.hkStopPublic(row), result_json: row.result_json || null } : null;
- };
- if (command.action === "runtime_control_read") return { ok: true, record: latest() };
- const requestId = String(command.request_id || "");
- if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("runtime_control_request_invalid", 400);
- const stored = this.hkStopStored(requestId);
- if (command.action === "runtime_control_claim") {
- if (!["enable", "disable"].includes(command.operation) || !Number.isSafeInteger(command.source_revision)
- || found.state.revision !== command.source_revision
- || canonicalResearchTaskJson(identity) !== canonicalResearchTaskJson(command.identity)) throw new HttpError("runtime_control_identity_conflict", 409);
- if (stored) {
- if (stored.target_id !== targetId || stored.action !== command.operation || stored.identity_json !== canonicalResearchTaskJson(identity)) throw new HttpError("runtime_control_identity_conflict", 409);
- return { ok: true, state: "replay", record: stored };
- }
- const open = this.hkStopPublic(this.sql.exec(
- "SELECT * FROM hk_stop_request WHERE target_id = ? AND phase IN ('reserved', 'unknown', 'accepted', 'partial') ORDER BY requested_at ASC LIMIT 1", targetId,
- ).toArray()[0]);
- if (open) return { ok: true, state: "blocked", record: open };
- const now = new Date().toISOString();
- this.sql.exec(`INSERT INTO hk_stop_request
- (request_id, target_id, identity_json, source_revision, action, requested_at, phase, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, 'reserved', ?)`, requestId, targetId, canonicalResearchTaskJson(identity), command.source_revision, command.operation, now, now);
- return { ok: true, state: "reserved", record: this.hkStopStored(requestId) };
- }
- if (!stored || stored.target_id !== targetId || stored.identity_json !== canonicalResearchTaskJson(identity)) throw new HttpError("runtime_control_identity_conflict", 409);
- if (command.action === "runtime_control_record") {
- if (!["accepted", "unknown", "rejected"].includes(command.phase)) throw new HttpError("runtime_control_result_invalid", 400);
- if (command.run_id != null && !/^[1-9][0-9]*$/.test(String(command.run_id))) throw new HttpError("runtime_control_result_invalid", 400);
- if (stored.workflow_run_id && command.run_id && String(stored.workflow_run_id) !== String(command.run_id)) throw new HttpError("runtime_control_result_invalid", 409);
- if (stored.phase === "reserved") this.sql.exec(
- "UPDATE hk_stop_request SET phase = ?, dispatch_result = ?, workflow_run_id = ?, updated_at = ? WHERE request_id = ? AND phase = 'reserved'",
- command.phase, command.phase, command.run_id || null, new Date().toISOString(), requestId,
- );
- else if (stored.phase === "unknown" && !stored.workflow_run_id && command.run_id) this.sql.exec(
- "UPDATE hk_stop_request SET workflow_run_id = ?, updated_at = ? WHERE request_id = ? AND phase = 'unknown' AND workflow_run_id IS NULL",
- String(command.run_id), new Date().toISOString(), requestId,
- );
- return { ok: true, record: this.hkStopStored(requestId) };
- }
- if (command.action === "runtime_control_capture") {
- if (!stored.workflow_run_id || String(stored.workflow_run_id) !== String(command.run_id)
- || !/^[1-9][0-9]*$/.test(String(command.platform_run_id || ""))) throw new HttpError("runtime_control_result_invalid", 400);
- let details = {};
- try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
- if (details.platform_run_id && details.platform_run_id !== String(command.platform_run_id)) throw new HttpError("runtime_control_result_invalid", 409);
- details.platform_run_id = String(command.platform_run_id);
- if (["platform_result_unavailable", "platform_dispatch_unverified"].includes(command.reason)) details.reason = command.reason;
- this.sql.exec("UPDATE hk_stop_request SET result_json = ?, updated_at = ? WHERE request_id = ?", JSON.stringify(details), new Date().toISOString(), requestId);
- return { ok: true, record: latest() };
- }
- if (command.action === "runtime_control_begin_check") {
- let details = {};
- try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
- if (!["unknown", "accepted", "partial"].includes(stored.phase) || !details.platform_run_id) throw new HttpError("runtime_control_check_unavailable", 409);
- if (details.check_id && !details.check_complete) return { ok: true, state: "replay", record: latest() };
- if (!HK_STOP_REQUEST_ID.test(String(command.check_id || ""))) throw new HttpError("runtime_control_request_invalid", 400);
- Object.assign(details, { check_id: command.check_id, check_run_id: null, check_complete: false, check_requested_at: new Date().toISOString() });
- this.sql.exec("UPDATE hk_stop_request SET result_json = ?, updated_at = ? WHERE request_id = ?", JSON.stringify(details), new Date().toISOString(), requestId);
- return { ok: true, state: "reserved", record: latest() };
- }
- if (command.action === "runtime_control_record_check") {
- let details = {};
- try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
- if (!details.check_id || details.check_id !== command.check_id) throw new HttpError("runtime_control_result_invalid", 409);
- if (command.run_id != null && !/^[1-9][0-9]*$/.test(String(command.run_id))) throw new HttpError("runtime_control_result_invalid", 400);
- if (details.check_run_id && command.run_id && details.check_run_id !== String(command.run_id)) throw new HttpError("runtime_control_result_invalid", 409);
- if (command.run_id) details.check_run_id = String(command.run_id);
- if (command.complete === true) details.check_complete = true;
- if (command.reason === "readback_dispatch_rejected") details.reason = command.reason;
- this.sql.exec("UPDATE hk_stop_request SET result_json = ?, updated_at = ? WHERE request_id = ?", JSON.stringify(details), new Date().toISOString(), requestId);
- return { ok: true, record: latest() };
- }
- if (command.action === "runtime_control_resolve") {
- if (!["applied", "partial", "protected", "rejected"].includes(command.phase) || !command.run_id
- || String(stored.workflow_run_id) !== String(command.run_id)) throw new HttpError("runtime_control_result_invalid", 400);
- if (command.check_id) {
- let check = {};
- try { check = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
- if (check.check_id !== command.check_id || check.check_run_id !== String(command.check_run_id)) throw new HttpError("runtime_control_result_invalid", 409);
- }
- const reason = ["runtime_control_workflow_permission_denied", "runtime_control_workflow_unavailable", "runtime_control_target_unsupported", "stop_source_permission_denied", "stop_source_not_accessible", "platform_dispatch_rejected", "platform_result_unavailable", "platform_dispatch_unverified"].includes(command.reason) ? command.reason : null;
- let details = {};
- try { details = JSON.parse(latest()?.result_json || "{}"); } catch { throw new HttpError("runtime_control_result_invalid", 409); }
- if (["accepted", "unknown", "partial"].includes(stored.phase)) this.sql.exec(
- "UPDATE hk_stop_request SET phase = ?, result_json = ?, updated_at = ? WHERE request_id = ?", command.phase, JSON.stringify({ ...details, reason }), new Date().toISOString(), requestId,
- );
- return { ok: true, record: latest() };
- }
- throw new HttpError("runtime_control_action_invalid", 400);
- }
-
- hkStopCommand(command) {
- if (command?.action === "hk_stop_read") return { ok: true, record: this.hkStopOpen() || this.hkStopLatest() };
- if (command?.action === "hk_stop_claim") return this.hkStopClaim(command);
- if (command?.action === "hk_stop_record") return this.hkStopRecord(command);
- if (command?.action === "hk_stop_accept_result") return this.hkStopAcceptResult(command);
- throw new HttpError("unsupported_hk_stop_action", 400);
- }
-
- hkStopPublic(row) {
- if (!row) return null;
- return {
- target_id: row.target_id,
- request_id: row.request_id,
- identity_json: row.identity_json,
- source_revision: Number(row.source_revision),
- action: row.action,
- requested_at: row.requested_at,
- phase: row.phase,
- dispatch_result: row.dispatch_result || null,
- workflow_run_id: row.workflow_run_id || null,
- workflow_run_attempt: row.workflow_run_attempt || null,
- source_identity_sha256: row.source_identity_sha256 || null,
- runtime_identity_sha256: row.runtime_identity_sha256 || null,
- updated_at: row.updated_at,
- };
- }
-
- hkStopStored(requestId) {
- return this.hkStopPublic(this.sql.exec("SELECT * FROM hk_stop_request WHERE request_id = ?", requestId).toArray()[0]);
- }
-
- hkStopOpen() {
- return this.hkStopPublic(this.sql.exec(
- "SELECT * FROM hk_stop_request WHERE target_id = ? AND phase IN ('reserved', 'unknown', 'accepted', 'stopped') ORDER BY requested_at ASC",
- HK_STOP_TARGET_ID,
- ).toArray()[0]);
- }
-
- hkStopLatest() {
- return this.hkStopPublic(this.sql.exec(
- "SELECT * FROM hk_stop_request WHERE target_id = ? ORDER BY requested_at DESC",
- HK_STOP_TARGET_ID,
- ).toArray()[0]);
- }
-
- hkStopLiveIdentity(sourceRevision, identity) {
- let found;
- try {
- found = this.existingAccountInstance("longbridge", "hk");
- } catch {
- throw new HttpError("hk_stop_source_conflict", 409);
- }
- if (found.state.revision !== sourceRevision) throw new HttpError("hk_stop_source_conflict", 409);
- const live = hkStopSourceIdentity(found.item.config, found.item);
- if (!hkStopIdentityComplete(live) || canonicalResearchTaskJson(live) !== canonicalResearchTaskJson(identity)) {
- throw new HttpError("hk_stop_source_conflict", 409);
- }
- return live;
- }
-
- hkStopClaim(command) {
- const requestId = String(command.request_id || "").toLowerCase();
- if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("invalid_hk_stop_request_id", 400);
- if (command.action_name !== "stop") throw new HttpError("hk_stop_action_conflict", 409);
- const identity = command.identity;
- if (!identity || Array.isArray(identity) || typeof identity !== "object") throw new HttpError("hk_stop_identity_incomplete", 400);
- if (!Number.isSafeInteger(command.source_revision)) throw new HttpError("hk_stop_source_conflict", 409);
- const storedIdentity = canonicalResearchTaskJson(identity);
- const existing = this.hkStopStored(requestId);
- if (existing) {
- if (existing.action !== "stop" || existing.identity_json !== storedIdentity) {
- throw new HttpError("hk_stop_identity_conflict", 409);
- }
- return { ok: true, state: "replay", record: existing };
- }
- const open = this.hkStopOpen();
- if (open) {
- if (open.identity_json !== storedIdentity) throw new HttpError("hk_stop_identity_conflict", 409);
- return { ok: true, state: "blocked", record: open };
- }
- this.hkStopLiveIdentity(command.source_revision, identity);
- const sourceHash = hkStopDigestOrEmpty(command.source_identity_sha256);
- const runtimeHash = hkStopDigestOrEmpty(command.runtime_identity_sha256);
- if ((sourceHash === "") !== (runtimeHash === "")) throw new HttpError("hk_stop_identity_incomplete", 400);
- const now = new Date().toISOString();
- this.sql.exec(
- `INSERT INTO hk_stop_request (
- request_id, target_id, identity_json, source_revision, action, requested_at, phase, dispatch_result, workflow_run_id, workflow_run_attempt, source_identity_sha256, runtime_identity_sha256, updated_at
- ) VALUES (?, ?, ?, ?, 'stop', ?, 'reserved', NULL, NULL, NULL, ?, ?, ?)`,
- requestId, HK_STOP_TARGET_ID, storedIdentity, command.source_revision, now, sourceHash || null, runtimeHash || null, now,
- );
- return { ok: true, state: "reserved", record: this.hkStopStored(requestId) };
- }
-
- hkStopRecord(command) {
- const requestId = String(command.request_id || "").toLowerCase();
- const phase = command.phase;
- if (!HK_STOP_REQUEST_ID.test(requestId) || !["accepted", "rejected", "unknown"].includes(phase)) {
- throw new HttpError("hk_stop_result_rejected", 400);
- }
- const existing = this.hkStopStored(requestId);
- if (!existing) throw new HttpError("hk_stop_request_conflict", 409);
- if (existing.phase === "stopped" || existing.phase !== "reserved") return { ok: true, recorded: false, record: existing };
- const now = new Date().toISOString();
- this.sql.exec(
- "UPDATE hk_stop_request SET phase = ?, dispatch_result = ?, updated_at = ? WHERE request_id = ? AND phase = 'reserved'",
- phase, phase, now, requestId,
- );
- return { ok: true, recorded: true, record: this.hkStopStored(requestId) };
- }
-
- hkStopAcceptResult(command) {
- const result = command?.result;
- const now = Date.parse(command?.now);
- if (!result?.producer || !result.readback) throw new HttpError("hk_stop_result_rejected", 400);
- const requestId = String(result?.request_id || "").toLowerCase();
- if (!HK_STOP_REQUEST_ID.test(requestId) || !Number.isFinite(now)) throw new HttpError("hk_stop_result_rejected", 400);
- const row = this.sql.exec("SELECT * FROM hk_stop_request WHERE request_id = ?", requestId).toArray()[0];
- if (!row) throw new HttpError("hk_stop_request_conflict", 409);
- if (!row.source_identity_sha256 || !row.runtime_identity_sha256) {
- throw new HttpError("hk_stop_result_unlinked", 409);
- }
- const requestedAt = Date.parse(row.requested_at);
- const observedAt = Date.parse(result.observed_at);
- if (!Number.isFinite(requestedAt) || !Number.isFinite(observedAt)) throw new HttpError("hk_stop_result_rejected", 400);
- if (result.source_revision !== Number(row.source_revision)
- || result.source_identity_sha256 !== row.source_identity_sha256
- || result.runtime_identity_sha256 !== row.runtime_identity_sha256
- || result.target_id !== row.target_id) {
- throw new HttpError("hk_stop_identity_conflict", 409);
- }
- let live;
- try {
- live = this.existingAccountInstance("longbridge", "hk");
- } catch {
- throw new HttpError("hk_stop_identity_conflict", 409);
- }
- const current = hkStopSourceIdentity(live.item.config, live.item);
- if (!hkStopIdentityComplete(current) || canonicalResearchTaskJson(current) !== row.identity_json) {
- throw new HttpError("hk_stop_identity_conflict", 409);
- }
- if (observedAt < requestedAt || observedAt > now + 60000) throw new HttpError("hk_stop_result_stale", 409);
- const canonical = canonicalResearchTaskJson(result);
- const sameRun = row.workflow_run_id === result.producer.run_id && String(row.workflow_run_attempt) === String(result.producer.run_attempt);
- if (row.phase === "stopped") {
- if (row.result_json === canonical && sameRun) return { ok: true, replayed: true, record: this.hkStopStored(requestId) };
- throw new HttpError("hk_stop_result_conflict", 409);
- }
- if (!["reserved", "accepted", "unknown"].includes(row.phase)) throw new HttpError("hk_stop_result_conflict", 409);
- if (now - requestedAt > 24 * 60 * 60 * 1000) throw new HttpError("hk_stop_result_stale", 409);
- const stamp = new Date(now).toISOString();
- this.sql.exec(
- `UPDATE hk_stop_request
- SET phase = 'stopped', workflow_run_id = ?, workflow_run_attempt = ?, result_json = ?, stopped_at = ?, updated_at = ?
- WHERE request_id = ? AND phase IN ('reserved', 'accepted', 'unknown')`,
- result.producer.run_id, String(result.producer.run_attempt), canonical, stamp, stamp, requestId,
- );
- const stored = this.hkStopStored(requestId);
- if (stored?.phase !== "stopped") throw new HttpError("hk_stop_result_conflict", 409);
- return { ok: true, replayed: false, record: stored };
- }
-
- read() {
- const row = this.sql.exec("SELECT revision, payload FROM instance_state WHERE id = 1").toArray()[0];
- return row ? { revision: row.revision, instances: JSON.parse(row.payload), initialized: true } : { revision: 0, instances: [], initialized: false };
- }
-
- response(state) {
- return {
- ok: true, ...state, account_options: runtimeInstanceAccountOptions(state.instances),
- history: this.sql.exec("SELECT entry FROM instance_history ORDER BY revision DESC LIMIT 50").toArray().map((row) => JSON.parse(row.entry)),
- no_order: true, execution_authority_granted: false,
- };
- }
-
- async alarm() { await this.deskReadbacks.alarm(); }
-
- async fetch(request) {
- try {
- if (new URL(request.url).pathname === DIRECTORY_PATH) {
- if (request.method !== "POST") throw new HttpError("method_not_allowed", 405);
- const result = await this.directory.command(await request.json());
- return json(result, result.ok ? 200 : 503);
- }
- if (request.method === "GET") return json(this.response(this.read()));
- if (request.method !== "POST") throw new HttpError("method_not_allowed", 405);
- let command;
- try { command = await request.json(); } catch { throw new HttpError("invalid_runtime_instance_request", 400); }
- if (["desk_readback_start", "desk_readback_get", "desk_readback_fresh"].includes(command?.action)) {
- try { return json(await this.deskReadbacks.command(command)); }
- catch (error) { return deskErrorResponse(error); }
- }
- if (typeof command?.action === "string" && command.action.startsWith("rotation_")) {
- return json(await durableRotationCommand(this.storage, this.sql, this.rotationEnv, command));
- }
- if (["credential_maintenance_read", "credential_maintenance_save", "credential_maintenance_claim", "credential_maintenance_ack"].includes(command?.action)) {
- return json(this.storage.transactionSync(() => credentialMaintenanceCommand(this.sql, command)));
- }
- if (ACCOUNT_DIAGNOSIS_DO_ACTIONS.has(command?.action)) {
- return json(await this.accountDiagnosisCommand(command));
- }
- if (["console_decision_history", "console_settings_history", "console_account_metadata", "console_audit_events"].includes(command?.action)) {
- return json(this.consoleReadCommand(command));
- }
- if (HUMAN_DECISION_DO_ACTIONS.has(command?.action)) {
- return json(this.humanDecisionCommand(command));
- }
- if (V7_PAPER_APPLICATION_DO_ACTIONS.has(command?.action)) {
- return json(await this.applicationCommand(command));
- }
- if (typeof command?.action === "string" && command.action.startsWith("ux1_")) {
- return json(this.ux1ResearchCommand(command));
- }
- if (["cycle_health_admission", "cycle_health_put", "cycle_health_read", "cycle_health_provision"].includes(command?.action)) {
- if (command.action === "cycle_health_provision") {
- return json(this.storage.transactionSync(() => this.cycleHealthProvisionCommand(command)));
- }
- return json(this.storage.transactionSync(() => this.cycleHealthCommand(command)));
- }
- if (ACCOUNT_SETTINGS_DO_ACTIONS.has(command?.action)) {
- return json(this.storage.transactionSync(() => this.accountSettingsCommand(command)));
- }
- if (ACCOUNT_FACTS_DO_ACTIONS.has(command?.action)) {
- const result = this.storage.transactionSync(() => this.accountFactsCommand(command));
- return json(result, command.action === "account_daily_native_return_research_read" && !result.ok ? 409 : 200);
- }
- if (MARKET_BENCHMARK_DO_ACTIONS.has(command?.action)) {
- return json(this.storage.transactionSync(() => this.marketBenchmarkCommand(command)));
- }
- if (RUNTIME_CONTROL_DO_ACTIONS.has(command?.action)) {
- return json(this.storage.transactionSync(() => this.runtimeControlCommand(command)));
- }
- if (HK_STOP_DO_ACTIONS.has(command?.action)) {
- return json(this.storage.transactionSync(() => this.hkStopCommand(command)));
- }
- // No awaits or external I/O inside this SQLite transaction. Every state
- // change, version advance, and history row commits together or rolls back.
- return json(this.storage.transactionSync(() => {
- const state = this.read();
- if (!command || typeof command.actor !== "string" || !command.actor) throw new HttpError("runtime_instance_actor_required", 400);
- if (command.action !== "sync_defaults") {
- if (!Number.isSafeInteger(command.expected_revision) || command.expected_revision < 0) throw new HttpError("runtime_instance_revision_required", 400);
- if (command.expected_revision !== state.revision) throw new HttpError("runtime_instance_revision_conflict", 409);
- }
- const ts = new Date().toISOString();
- let changed = true;
- let before = null;
- let after = null;
- if (command.action === "initialize") {
- if (state.initialized) throw new HttpError("runtime_instances_already_initialized", 409);
- for (const [platform, options] of Object.entries(command.account_options)) {
- for (const config of options) {
- if (state.instances.some((item) => item.platform === platform && (item.key === config.key || item.config.target_name === config.target_name))) throw new HttpError("runtime_instance_identity_conflict", 409);
- state.instances.push({ platform, key: config.key, kind: "existing", config, enabled: null, platform_applied: null, application_status: "unknown", retirement_status: "none", created_at: ts, updated_at: ts });
- }
- }
- state.initialized = true;
- } else {
- if (!state.initialized) throw new HttpError("runtime_instances_not_initialized", 409);
- const item = state.instances.find((candidate) => candidate.platform === command.platform && candidate.key === command.key);
- if (command.action === "create") {
- if (state.instances.length >= 120) throw new HttpError("runtime_instance_limit_reached", 409);
- runtimeInstanceConflict(state.instances, command.platform, command.config);
- after = { platform: command.platform, key: command.config.key, kind: "draft", config: command.config, enabled: false, platform_applied: false, application_status: "unapplied", retirement_status: "none", created_at: ts, updated_at: ts };
- state.instances.push(after);
- } else if (command.action === "edit") {
- if (!item || item.kind !== "draft" || item.retirement_status !== "none") throw new HttpError("runtime_instance_draft_edit_required", 409);
- if (item.key !== command.config.key) throw new HttpError("runtime_instance_key_immutable", 409);
- runtimeInstanceConflict(state.instances, command.platform, command.config, item.key);
- before = structuredClone(item);
- item.config = command.config;
- item.updated_at = ts;
- after = item;
- } else if (command.action === "request_retirement") {
- if (!item) throw new HttpError("runtime_instance_not_found", 404);
- before = structuredClone(item);
- changed = item.retirement_status !== "requested";
- item.retirement_status = "requested";
- if (changed) item.updated_at = ts;
- after = item;
- } else if (command.action === "set_broker_environment") {
- if (!item || item.kind !== "existing") throw new HttpError("runtime_instance_existing_required", 409);
- if (!BROKER_ENVIRONMENTS.includes(command.broker_environment)
- || !supportedBrokerEnvironmentsForPlatform(command.platform).includes(command.broker_environment)) {
- throw new HttpError("invalid_broker_environment", 400);
- }
- before = structuredClone(item);
- changed = item.config.broker_environment !== command.broker_environment;
- if (changed) {
- item.config = { ...item.config, broker_environment: command.broker_environment };
- item.updated_at = ts;
- }
- after = item;
- } else if (command.action === "sync_defaults") {
- const current = runtimeInstanceAccountOptions(state.instances);
- const update = updateAccountOptionsDefaultStrategy(current, command.inputs);
- changed = update.changed;
- for (const instance of state.instances) {
- if (instance.kind !== "existing") continue;
- const config = update.options[instance.platform]?.find((option) => option.key === instance.key);
- if (config) {
- const defaults = {};
- for (const field of ["default_execution_mode", "default_strategy_profile"]) {
- if (instance.config[field] !== undefined) defaults[field] = instance.config[field];
- }
- instance.config = { ...config, ...defaults };
- }
- }
- } else {
- throw new HttpError("unsupported_runtime_instance_action", 400);
- }
- }
- if (changed) {
- state.revision += 1;
- this.sql.exec("INSERT INTO instance_state (id, revision, payload) VALUES (1, ?, ?) ON CONFLICT(id) DO UPDATE SET revision = excluded.revision, payload = excluded.payload", state.revision, JSON.stringify(state.instances));
- this.sql.exec("INSERT INTO instance_history (revision, entry) VALUES (?, ?)", state.revision, JSON.stringify({ revision: state.revision, ts, login: command.actor, action: command.action, before, after }));
- }
- return this.response(state);
- }));
- } catch (error) {
- return json({ ok: false, error: error instanceof HttpError || error instanceof CycleHealthError || error instanceof CredentialMaintenanceError || error instanceof RotationError ? error.message : "runtime_instance_transaction_failed" }, error instanceof HttpError || error instanceof CycleHealthError || error instanceof CredentialMaintenanceError || error instanceof RotationError ? error.status : 409);
- }
- }
-
- accountDiagnosisCommand(command) {
- return this.storage.transactionSync(() => {
- if (!command || typeof command.actor !== "string" || !command.actor) {
- throw new HttpError("runtime_instance_actor_required", 400);
- }
- if (command.action === "diagnosis_create") {
- const autoSource = command.auto_source === "source_sync" ? "source_sync" : "manual";
- // Unclosed work keeps its original obligation regardless of age or fingerprint.
- const unresolved = this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE target_id = ? AND status IN ('queued', 'running', 'unknown') ORDER BY updated_at DESC LIMIT 1", command.target_id).toArray()[0];
- if (unresolved) return { ok: true, created: false, task: accountDiagnosisTaskFromRow(unresolved) };
- const existing = autoSource === "source_sync"
- ? this.sql.exec(
- "SELECT * FROM account_diagnosis_tasks WHERE target_id = ? AND auto_source = ? AND updated_at >= ? ORDER BY updated_at DESC LIMIT 1",
- command.target_id, autoSource, new Date(Number(command.now) - ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS).toISOString(),
- ).toArray()[0]
- : this.sql.exec(
- "SELECT * FROM account_diagnosis_tasks WHERE target_id = ? AND state_fingerprint = ? ORDER BY updated_at DESC LIMIT 1",
- command.target_id, command.state_fingerprint,
- ).toArray()[0];
- const existingAge = existing ? Date.parse(existing.updated_at) : Number.NaN;
- const existingIsRecent = Number.isFinite(existingAge)
- && existingAge >= Number(command.now) - ACCOUNT_DIAGNOSIS_DEDUPE_WINDOW_MS;
- if (existing && existingIsRecent) return { ok: true, created: false, task: accountDiagnosisTaskFromRow(existing) };
- const task = {
- request_id: command.request_id,
- platform: command.platform,
- key: command.key,
- target_id: command.target_id,
- trigger: command.trigger,
- observed_at: command.observed_at,
- checks: command.checks,
- state_fingerprint: command.state_fingerprint,
- status: "queued",
- workflow_run_id: null,
- workflow_run_attempt: null,
- job_id: null,
- summary: "",
- reason_code: "",
- dispatch_state: "pending",
- recheck_dispatch_state: "not_requested",
- created_at: command.created_at,
- updated_at: command.created_at,
- };
- this.sql.exec(
- `INSERT INTO account_diagnosis_tasks
- (request_id, platform, account_key, target_id, trigger, observed_at, checks_json, state_fingerprint,
- status, workflow_run_id, workflow_run_attempt, job_id, summary, reason_code, dispatch_state,
- recheck_dispatch_state, created_at, updated_at, auto_source)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
- task.request_id, task.platform, task.key, task.target_id, task.trigger, task.observed_at,
- JSON.stringify(task.checks), task.state_fingerprint, task.status, null, null, null,
- task.summary, task.reason_code, task.dispatch_state, task.recheck_dispatch_state,
- task.created_at, task.updated_at, autoSource,
- );
- return { ok: true, created: true, task };
- }
- if (command.action === "diagnosis_latest") {
- const row = this.sql.exec(
- "SELECT * FROM account_diagnosis_tasks WHERE platform = ? AND account_key = ? ORDER BY updated_at DESC LIMIT 1",
- command.platform, command.key,
- ).toArray()[0];
- return { ok: true, task: accountDiagnosisTaskFromRow(row) };
- }
- const requestId = command.request_id;
- const row = this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0];
- if (!row) throw new HttpError("account_diagnosis_request_not_found", 404);
- if (command.action === "diagnosis_read") return { ok: true, task: accountDiagnosisTaskFromRow(row) };
- if (command.action === "diagnosis_native_intent") {
- if (row.native_json) {
- const old = JSON.parse(row.native_json);
- if (canonicalResearchTaskJson(old.binding) !== canonicalResearchTaskJson(command.native.binding)
- || old.request_sha256 !== command.native.request_sha256) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- return { ok: true, created: false, task: accountDiagnosisTaskFromRow(row) };
- }
- if (row.workflow_run_id || row.workflow_run_attempt || row.status !== "queued" || row.dispatch_state !== "pending") {
- throw new HttpError("account_diagnosis_legacy_retired", 409);
- }
- this.sql.exec("UPDATE account_diagnosis_tasks SET native_json = ?, updated_at = ? WHERE request_id = ?",
- JSON.stringify(command.native), command.updated_at, requestId);
- return { ok: true, created: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
- }
- if (command.action === "diagnosis_native_cancel") {
- if (!row.native_json) throw new HttpError("account_diagnosis_legacy_retired", 409);
- const native = JSON.parse(row.native_json);
- // The first durable terminal receipt or cancellation wins atomically.
- if (native.receipt) return { ok: true, send_cancel: false, task: accountDiagnosisTaskFromRow(row) };
- const send = Boolean(native.task_id && !native.cancel_sent);
- native.cancel_requested = true;
- native.cancel_sent = native.cancel_sent || send;
- native.phase = "hold";
- this.sql.exec("UPDATE account_diagnosis_tasks SET native_json = ?, status = 'unknown', summary = '', reason_code = '', recheck_dispatch_state = 'not_requested', updated_at = ? WHERE request_id = ?",
- JSON.stringify(native), command.updated_at, requestId);
- return { ok: true, send_cancel: send, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
- }
- if (command.action === "diagnosis_native_save") {
- if (!row.native_json) throw new HttpError("account_diagnosis_legacy_retired", 409);
- const old = JSON.parse(row.native_json), next = command.native;
- for (const field of ["version", "binding", "request", "input_sha256", "request_sha256", "operation_key", "deadline"]) {
- if (canonicalResearchTaskJson(old[field]) !== canonicalResearchTaskJson(next[field])) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- if ((old.task_id && old.task_id !== next.task_id) || (old.task_deadline !== null && old.task_deadline !== next.task_deadline)
- || (old.claim && canonicalResearchTaskJson(old.claim) !== canonicalResearchTaskJson(next.claim))
- || (old.cancel_sent && !next.cancel_sent) || (old.cancel_requested && !next.cancel_requested)
- || !ACCOUNT_DIAGNOSIS_STATUSES.includes(command.status)) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- if (old.receipt) {
- if (old.receipt !== next.receipt) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- return { ok: true, changed: false, task: accountDiagnosisTaskFromRow(row) };
- }
- if (command.status === "succeeded" && (old.cancel_requested || old.cancel_sent
- || Date.now() / 1000 >= Math.min(old.deadline, next.task_deadline ?? Infinity))) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- const recheck = command.status === "succeeded" ? "pending" : row.recheck_dispatch_state;
- this.sql.exec("UPDATE account_diagnosis_tasks SET native_json = ?, status = ?, summary = ?, reason_code = ?, dispatch_state = 'sent', recheck_dispatch_state = ?, updated_at = ? WHERE request_id = ?",
- JSON.stringify(next), command.status, command.summary, command.reason_code, recheck, command.updated_at, requestId);
- return { ok: true, changed: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
- }
- if (command.action === "diagnosis_mark_dispatch") {
- if (row.dispatch_state !== "pending") return { ok: true, changed: false, task: accountDiagnosisTaskFromRow(row) };
- if (command.dispatch_state === "unknown" && row.native_json) {
- const native = { ...JSON.parse(row.native_json), phase: "hold" };
- this.sql.exec("UPDATE account_diagnosis_tasks SET dispatch_state = 'unknown', status = 'unknown', native_json = ?, updated_at = ? WHERE request_id = ?",
- JSON.stringify(native), command.updated_at, requestId);
- } else {
- this.sql.exec("UPDATE account_diagnosis_tasks SET dispatch_state = ?, updated_at = ? WHERE request_id = ?", command.dispatch_state, command.updated_at, requestId);
- }
- return { ok: true, changed: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
- }
- if (command.action === "diagnosis_claim" || command.action === "diagnosis_result") {
- throw new HttpError("account_diagnosis_legacy_retired", 409);
- }
- if (command.action === "diagnosis_mark_recheck") {
- if (row.recheck_dispatch_state !== "pending") return { ok: true, changed: false, task: accountDiagnosisTaskFromRow(row) };
- this.sql.exec("UPDATE account_diagnosis_tasks SET recheck_dispatch_state = ?, updated_at = ? WHERE request_id = ?", command.recheck_dispatch_state, command.updated_at, requestId);
- return { ok: true, changed: true, task: accountDiagnosisTaskFromRow(this.sql.exec("SELECT * FROM account_diagnosis_tasks WHERE request_id = ?", requestId).toArray()[0]) };
- }
- throw new HttpError("unsupported_account_diagnosis_action", 400);
- });
- }
-
- consoleReadCommand(command) {
- if (!command.actor) throw new HttpError("runtime_instance_actor_required", 400);
- if (command.action === "console_audit_events") {
- const limit = command.limit;
- if (!Number.isSafeInteger(limit) || limit < 1 || limit > AUDIT_EVENTS_MAX_ROWS) throw new HttpError("invalid_pagination", 400);
- const { snapshot, before } = command;
- // Normalize time once, and use the same binary id tie-break as the HTTP merge.
- return { rows: this.sql.exec(`
- WITH events AS (
- SELECT 'decision' AS source, kind, subject_id, material_key AS revision,
- action, actor, strftime('%Y-%m-%dT%H:%M:%fZ', decided_at) AS occurred_at,
- request_key AS ref, 'decided' AS status, 'durable_human_decision:' || request_key AS event_id
- FROM human_decision_record
- UNION ALL
- SELECT 'promotion_application', 'promotion', ticket_id, '', status, '',
- strftime('%Y-%m-%dT%H:%M:%fZ', updated_at), application_id, status,
- 'research_promotion_application:' || application_id FROM research_promotion_applications
- UNION ALL
- SELECT 'account_settings_application', 'account_settings', platform || ':' || account_key, '',
- status, approved_by, strftime('%Y-%m-%dT%H:%M:%fZ', approved_at), request_key, status,
- 'account_settings_application:' || request_key FROM account_setting_profile_application
- UNION ALL
- SELECT 'credential_rotation', 'credential', 'ibkr_flex', '', action, actor,
- occurred_at, operation_id, outcome, 'credential_rotation:' || event_id
- FROM credential_rotation_audit
- ) SELECT * FROM events WHERE occurred_at <= ?
- AND (? IS NULL OR occurred_at < ? OR (occurred_at = ? AND event_id > ?))
- ORDER BY occurred_at DESC, event_id ASC LIMIT ?`, snapshot,
- before?.at ?? null, before?.at ?? null, before?.at ?? null, before?.id ?? null, limit).toArray() };
- }
- if (command.action === "console_decision_history") {
- const { limit, offset } = command;
- if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100 || !Number.isSafeInteger(offset) || offset < 0 || offset > 100000) throw new HttpError("invalid_pagination", 400);
- return { rows: this.sql.exec("SELECT request_key, kind, subject_id, material_key, action, actor, decided_at, target_json, json_extract(payload_json, '$.ticket.confirmation_execution_mode') AS confirmation_execution_mode FROM human_decision_record ORDER BY decided_at DESC, request_key DESC LIMIT ? OFFSET ?", limit + 1, offset).toArray() };
- }
- if (command.action === "console_settings_history") {
- this.existingAccountInstance(command.platform, command.key);
- return { approvals: this.sql.exec("SELECT request_key, status, identity_json, instance_revision, old_profile, new_profile, approved_at, approved_by, draft_revision FROM account_setting_profile_application WHERE platform = ? AND account_key = ? ORDER BY approved_at DESC", command.platform, command.key).toArray() };
- }
- const drafts = this.sql.exec("SELECT platform, account_key, overrides_json, updated_at FROM account_setting_draft").toArray();
- const approvals = this.sql.exec("SELECT platform, account_key, MAX(approved_at) AS approved_at FROM account_setting_profile_application GROUP BY platform, account_key").toArray();
- return { rows: this.read().instances.map(item => {
- const draft = drafts.find(row => row.platform === item.platform && row.account_key === item.key);
- const approval = approvals.find(row => row.platform === item.platform && row.account_key === item.key);
- return { platform: item.platform, account_key: item.key,
- pending_draft_count: draft ? new Set(Object.keys(JSON.parse(draft.overrides_json)).map(field => field.startsWith("dca_") ? "dca" : field.startsWith("reserved_") ? "cash" : field)).size : 0,
- last_change_at: [draft?.updated_at, approval?.approved_at, item.updated_at].filter(Boolean).sort().at(-1) || null,
- };
- }) };
- }
-
- humanDecisionCommand(command) {
- return this.storage.transactionSync(() => {
- if (!command || typeof command.actor !== "string" || !command.actor) {
- throw new HttpError("runtime_instance_actor_required", 400);
- }
- if (command.action === "owner_sync_materials") return this.syncHumanDecisionMaterials(command, "owner");
- if (command.action === "recovery_sync_materials") return this.syncHumanDecisionMaterials(command, "recovery");
- if (command.action === "promotion_sync_materials") return this.syncHumanDecisionMaterials(command, "promotion");
- if (command.action === "owner_decide") return this.writeHumanDecision(command, "owner");
- if (command.action === "recovery_decide") return this.writeHumanDecision(command, "recovery");
- if (command.action === "promotion_decide") return this.writeHumanDecision(command, "promotion");
- if (command.action === "owner_read") return this.readHumanDecision(command, "owner");
- if (command.action === "recovery_read") return this.readHumanDecision(command, "recovery");
- if (command.action === "promotion_read") return this.readHumanDecision(command, "promotion");
- throw new HttpError("unsupported_human_decision_action", 400);
- });
- }
-
- humanDecisionMaterialRow(kind, subjectId) {
- return this.sql.exec(
- "SELECT * FROM human_decision_material WHERE kind = ? AND subject_id = ?",
- kind, subjectId,
- ).toArray()[0] || null;
- }
-
- humanDecisionTerminalRow(kind, subjectId, materialKey) {
- return this.sql.exec(
- "SELECT * FROM human_decision_record WHERE kind = ? AND subject_id = ? AND material_key = ? ORDER BY decided_at ASC LIMIT 1",
- kind, subjectId, materialKey,
- ).toArray()[0] || null;
- }
-
- humanDecisionRecordPayload(row) {
- let payload = {};
- try {
- payload = JSON.parse(row.payload_json);
- } catch {
- throw new HttpError("human_decision_record_invalid", 409);
- }
- return {
- request_key: row.request_key,
- kind: row.kind,
- subject_id: row.subject_id,
- material_key: row.material_key,
- action: row.action,
- actor: row.actor,
- decided_at: row.decided_at,
- target_json: row.target_json,
- payload,
- };
- }
-
- humanDecisionSourceRow(kind, subjectId, sourceId) {
- return this.sql.exec(
- "SELECT * FROM human_decision_source_material WHERE kind = ? AND subject_id = ? AND source_id = ?",
- kind, subjectId, sourceId,
- ).toArray()[0] || null;
- }
-
- upsertHumanDecisionSource(kind, subjectId, sourceId, item, eligible, updatedAt) {
- if (this.humanDecisionSourceRow(kind, subjectId, sourceId)) {
- this.sql.exec(
- `UPDATE human_decision_source_material
- SET material_key = ?, summary_json = ?, eligible = ?, expires_at_ms = ?, updated_at = ?
- WHERE kind = ? AND subject_id = ? AND source_id = ?`,
- item.material_key, item.summary_json || "{}", eligible, item.expires_at_ms ?? null, updatedAt, kind, subjectId, sourceId,
- );
- return;
- }
- this.sql.exec(
- `INSERT INTO human_decision_source_material
- (kind, subject_id, source_id, material_key, summary_json, eligible, expires_at_ms, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
- kind, subjectId, sourceId, item.material_key, item.summary_json || "{}", eligible, item.expires_at_ms ?? null, updatedAt,
- );
- }
-
- recomputeHumanDecisionSubject(kind, subjectId, updatedAt) {
- const sources = this.sql.exec(
- "SELECT * FROM human_decision_source_material WHERE kind = ? AND subject_id = ?",
- kind, subjectId,
- ).toArray();
- let projection = this.humanDecisionMaterialRow(kind, subjectId);
- if (!projection && !sources.length) return;
- if (!projection) {
- this.insertHumanDecisionMaterial(kind, subjectId, sources[0].source_id, sources[0], 0, { state: "none", block: "" }, updatedAt);
- projection = this.humanDecisionMaterialRow(kind, subjectId);
- }
- if (projection.legacy_state === "blocked") {
- this.sql.exec(
- "UPDATE human_decision_material SET eligible = 0, updated_at = ? WHERE kind = ? AND subject_id = ?",
- updatedAt, kind, subjectId,
- );
- return;
- }
- if (sources.length !== 1) {
- const keys = new Set(sources.map((row) => row.material_key));
- const materialKey = keys.size === 1 ? sources[0].material_key : "";
- this.sql.exec(
- "UPDATE human_decision_material SET source_id = ?, material_key = ?, eligible = 0, updated_at = ? WHERE kind = ? AND subject_id = ?",
- "", materialKey, updatedAt, kind, subjectId,
- );
- return;
- }
- const only = sources[0];
- this.sql.exec(
- `UPDATE human_decision_material
- SET source_id = ?, material_key = ?, summary_json = ?, eligible = ?, expires_at_ms = ?, updated_at = ?
- WHERE kind = ? AND subject_id = ?`,
- only.source_id, only.material_key, only.summary_json, only.eligible, only.expires_at_ms, updatedAt, kind, subjectId,
- );
- }
-
- insertHumanDecisionMaterial(kind, subjectId, sourceId, item, eligible, legacyState, updatedAt) {
- this.sql.exec(
- `INSERT INTO human_decision_material
- (kind, subject_id, source_id, material_key, summary_json, eligible, expires_at_ms, legacy_state, legacy_block, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
- kind, subjectId, sourceId, item.material_key, item.summary_json || "{}", eligible,
- item.expires_at_ms ?? null, legacyState.state, legacyState.block, updatedAt,
- );
- }
-
- insertHumanDecisionRecord(record) {
- this.sql.exec(
- `INSERT INTO human_decision_record
- (request_key, kind, subject_id, material_key, action, actor, decided_at, target_json, payload_json)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
- record.request_key, record.kind, record.subject_id, record.material_key, record.action,
- record.actor, record.decided_at, record.target_json, record.payload_json,
- );
- }
-
- importHumanDecisionLegacy(kind, subjectId, item) {
- const legacy = item.legacy;
- if (!legacy) return { state: "none", block: "" };
- const record = legacy.record;
- if (legacy.blocked || !record || record.material_key !== item.material_key || !record.action || !record.actor || !record.decided_at || !record.payload || typeof record.payload !== "object") {
- return { state: "blocked", block: "unexplained_legacy" };
- }
- this.insertHumanDecisionRecord({
- request_key: `legacy:${kind}:${subjectId}:${item.material_key}`,
- kind,
- subject_id: subjectId,
- material_key: item.material_key,
- action: record.action,
- actor: record.actor,
- decided_at: record.decided_at,
- target_json: record.target_json || "{}",
- payload_json: JSON.stringify(record.payload),
- });
- return { state: "imported", block: "" };
- }
-
- syncHumanDecisionMaterials(command, kind) {
- const sourceId = String(command.source_id || "");
- const updatedAt = String(command.updated_at || "");
- const materials = Array.isArray(command.materials) ? command.materials : [];
- const seen = new Set();
- const affected = new Set();
- let terminal = false;
- let terminalState = "";
- let identityConflict = false;
- let legacyBlocked = false;
- for (const item of materials) {
- const subjectId = String(item.subject_id || "");
- if (!subjectId || seen.has(subjectId)) continue;
- seen.add(subjectId);
- const sourceRow = this.humanDecisionSourceRow(kind, subjectId, sourceId);
- const incomingTerminal = this.humanDecisionTerminalRow(kind, subjectId, item.material_key);
- if (
- kind === "promotion" && sourceRow && sourceRow.material_key !== item.material_key && !incomingTerminal
- && !this.humanDecisionTerminalRow(kind, subjectId, sourceRow.material_key)
- ) {
- identityConflict = true;
- continue;
- }
- if (kind === "promotion" && incomingTerminal) {
- terminal = true;
- terminalState = incomingTerminal.action === "accept" ? "human_accepted" : "human_rejected";
- }
- let projection = this.humanDecisionMaterialRow(kind, subjectId);
- if (!projection) {
- const legacyState = this.importHumanDecisionLegacy(kind, subjectId, item);
- this.insertHumanDecisionMaterial(kind, subjectId, sourceId, item, 0, legacyState, updatedAt);
- if (legacyState.state === "blocked") legacyBlocked = true;
- const imported = this.humanDecisionTerminalRow(kind, subjectId, item.material_key);
- if (imported && kind === "promotion") {
- terminal = true;
- terminalState = imported.action === "accept" ? "human_accepted" : "human_rejected";
- }
- projection = this.humanDecisionMaterialRow(kind, subjectId);
- } else if (projection.legacy_state === "blocked") {
- legacyBlocked = true;
- }
- const blocked = projection?.legacy_state === "blocked";
- this.upsertHumanDecisionSource(kind, subjectId, sourceId, item, blocked ? 0 : (item.eligible ? 1 : 0), updatedAt);
- affected.add(subjectId);
- }
- if (command.replace_source) {
- const rows = this.sql.exec(
- "SELECT subject_id FROM human_decision_source_material WHERE kind = ? AND source_id = ?",
- kind, sourceId,
- ).toArray();
- for (const row of rows) {
- if (seen.has(row.subject_id)) continue;
- this.sql.exec(
- "DELETE FROM human_decision_source_material WHERE kind = ? AND subject_id = ? AND source_id = ?",
- kind, row.subject_id, sourceId,
- );
- affected.add(row.subject_id);
- }
- }
- for (const subjectId of command.duplicate_subject_ids || []) {
- if (typeof subjectId !== "string" || !subjectId) continue;
- this.sql.exec(
- "UPDATE human_decision_source_material SET eligible = 0, updated_at = ? WHERE kind = ? AND subject_id = ? AND source_id = ?",
- updatedAt, kind, subjectId, sourceId,
- );
- affected.add(subjectId);
- }
- for (const subjectId of affected) this.recomputeHumanDecisionSubject(kind, subjectId, updatedAt);
- return { ok: true, terminal, terminal_state: terminalState, identity_conflict: identityConflict, legacy_blocked: legacyBlocked };
- }
-
- writeHumanDecision(command, kind) {
- if (kind === "owner" && command.action_name === "retire_candidate") {
- throw new HttpError("owner_retirement_proposal_required", 409);
- }
- const subjectId = String(command.subject_id || "");
- const materialKey = String(command.material_key || "");
- const actionName = String(command.action_name || "");
- const requestKey = String(command.request_key || "");
- const targetJson = String(command.target_json || "{}");
- if (!subjectId || !materialKey || !actionName || !requestKey) throw new HttpError("human_decision_request_invalid", 400);
- let row = this.humanDecisionMaterialRow(kind, subjectId);
- if (!row && command.legacy) {
- const legacyState = this.importHumanDecisionLegacy(kind, subjectId, { material_key: materialKey, legacy: command.legacy });
- this.insertHumanDecisionMaterial(kind, subjectId, String(command.source_id || kind), {
- material_key: materialKey,
- summary_json: command.summary_json || "{}",
- expires_at_ms: command.expires_at_ms ?? null,
- }, legacyState.state === "blocked" ? 0 : 1, legacyState, String(command.decided_at || ""));
- row = this.humanDecisionMaterialRow(kind, subjectId);
- }
- if (!row) throw new HttpError("human_decision_material_unavailable", 409);
- if (row.legacy_state === "blocked") throw new HttpError("human_decision_legacy_blocked", 409);
- if (row.material_key !== materialKey) throw new HttpError("human_decision_material_conflict", 409);
- if (Number(row.eligible) !== 1) throw new HttpError("human_decision_material_ineligible", 409);
- if (row.expires_at_ms != null && Number(command.now_ms) >= Number(row.expires_at_ms)) {
- throw new HttpError("human_decision_material_expired", 409);
- }
- if (kind === "promotion" && command.review_binding !== undefined
- && !promotionReviewBindingsMatch(command.review_binding, promotionMaterialReviewBinding(row))) {
- throw new HttpError("human_decision_review_material_conflict", 409);
- }
- const assertReview = terminal => {
- if (kind === "promotion" && command.review_binding !== undefined
- && !promotionReviewBindingsMatch(command.review_binding, this.humanDecisionRecordPayload(terminal).payload?.review_binding)) {
- throw new HttpError("human_decision_review_binding_unqualified", 409);
- }
- };
- const byRequest = this.sql.exec("SELECT * FROM human_decision_record WHERE request_key = ?", requestKey).toArray()[0];
- if (byRequest) {
- if (byRequest.kind !== kind || byRequest.subject_id !== subjectId || byRequest.material_key !== materialKey || byRequest.action !== actionName || byRequest.target_json !== targetJson) {
- throw new HttpError("human_decision_conflict", 409);
- }
- assertReview(byRequest);
- return { ok: true, replayed: true, record: this.humanDecisionRecordPayload(byRequest) };
- }
- const terminal = this.humanDecisionTerminalRow(kind, subjectId, materialKey);
- if (terminal) {
- if (terminal.action !== actionName || terminal.target_json !== targetJson) throw new HttpError("human_decision_conflict", 409);
- assertReview(terminal);
- return { ok: true, replayed: true, record: this.humanDecisionRecordPayload(terminal) };
- }
- const payload = command.payload && typeof command.payload === "object" ? structuredClone(command.payload) : {};
- if (kind === "promotion" && actionName === "accept") {
- const instances = this.read();
- if (instances.initialized) {
- const preflightRevision = Number(command.preflight_revision);
- if (!Number.isSafeInteger(preflightRevision) || preflightRevision !== instances.revision) {
- throw new HttpError("runtime_instance_revision_conflict", 409);
- }
- payload.account_revision = instances.revision;
- } else {
- payload.account_revision = null;
- }
- }
- const record = {
- request_key: requestKey,
- kind,
- subject_id: subjectId,
- material_key: materialKey,
- action: actionName,
- actor: String(command.actor || ""),
- decided_at: String(command.decided_at || ""),
- target_json: targetJson,
- payload_json: JSON.stringify(payload),
- };
- this.insertHumanDecisionRecord(record);
- return { ok: true, replayed: false, record: this.humanDecisionRecordPayload(this.humanDecisionTerminalRow(kind, subjectId, materialKey)) };
- }
-
- readHumanDecision(command, kind) {
- const subjectId = String(command.subject_id || "");
- const now = Number.isFinite(Number(command.now_ms)) ? Number(command.now_ms) : Date.now();
- const row = this.humanDecisionMaterialRow(kind, subjectId);
- const expiry = (material) => material.expires_at_ms == null ? null : new Date(Number(material.expires_at_ms)).toISOString();
- const expired = (material) => material.expires_at_ms != null && now >= Number(material.expires_at_ms);
- // Historical receipt lookup deliberately does not substitute the current material.
- // It grants no eligibility or authority to act on the current material.
- if (command.exact_material_key !== undefined) {
- const materialKey = command.exact_material_key;
- if (!/^[0-9a-f]{64}$/.test(materialKey) || !subjectId || subjectId.length > 256) {
- throw new HttpError("human_decision_lookup_invalid", 400);
- }
- const terminal = this.humanDecisionTerminalRow(kind, subjectId, materialKey);
- return {
- ok: true,
- exact_material_key: materialKey,
- decision: terminal ? this.humanDecisionRecordPayload(terminal) : null,
- current_material: row ? {
- matches: row.material_key === materialKey,
- eligible: Number(row.eligible) === 1 && !expired(row),
- expired: expired(row),
- expires_at: expiry(row),
- blocked: row.legacy_state === "blocked",
- ...(kind === "promotion" ? { review_binding: promotionMaterialReviewBinding(row) } : {}),
- } : null,
- };
- }
- if (!row) return { ok: true, migrated: false, blocked: false, eligible: false, expired: false, expires_at: null, material_key: null, decision: null };
- const terminal = this.humanDecisionTerminalRow(kind, subjectId, row.material_key);
- return {
- ok: true,
- migrated: true,
- blocked: row.legacy_state === "blocked",
- eligible: Number(row.eligible) === 1 && !expired(row),
- expired: expired(row),
- expires_at: expiry(row),
- material_key: row.material_key,
- ...(kind === "promotion" ? { review_binding: promotionMaterialReviewBinding(row) } : {}),
- decision: terminal ? this.humanDecisionRecordPayload(terminal) : null,
- };
- }
-
- applicationCommand(command) {
- return this.storage.transactionSync(() => {
- if (!command || typeof command.actor !== "string" || !command.actor) {
- throw new HttpError("runtime_instance_actor_required", 400);
- }
- if (command.action === "application_create") {
- const currentMaterial = this.humanDecisionMaterialRow("promotion", command.ticket_id);
- if (!currentMaterial || currentMaterial.legacy_state === "blocked" || Number(currentMaterial.eligible) !== 1 || currentMaterial.material_key !== command.promotion_material_key) {
- throw new HttpError("research candidate is not human_accepted", 409);
- }
- const decisionRow = this.humanDecisionTerminalRow("promotion", command.ticket_id, currentMaterial.material_key);
- if (!decisionRow || decisionRow.action !== "accept") throw new HttpError("research candidate is not human_accepted", 409);
- let decisionPayload = {};
- try { decisionPayload = JSON.parse(decisionRow.payload_json); } catch { throw new HttpError("research candidate is not human_accepted", 409); }
- const selected = decisionPayload.selected_account || {};
- if (selected.platform !== command.platform_id || selected.key !== command.account_key) {
- throw new HttpError("promotion_account_binding_conflict", 409);
- }
- const instances = this.read();
- if (!instances.initialized || instances.revision !== Number(command.expected_revision) || !Number.isSafeInteger(decisionPayload.account_revision) || decisionPayload.account_revision !== instances.revision) {
- throw new HttpError("runtime_instance_revision_conflict", 409);
- }
- const existing = this.sql.exec(
- "SELECT * FROM research_promotion_applications WHERE ticket_id = ? AND platform_id = ? AND account_key = ? AND status <> 'rejected' ORDER BY created_at DESC LIMIT 1",
- command.ticket_id, command.platform_id, command.account_key,
- ).toArray()[0];
- if (existing) return { ok: true, created: false, application: researchPromotionApplicationFromRow(existing) };
- const application = {
- application_id: command.application_id,
- ticket_id: command.ticket_id,
- status: "approved",
- dispatch_state: "pending",
- claim_token: command.claim_token,
- platform_id: command.platform_id,
- account_key: command.account_key,
- account_scope: command.account_scope,
- account_selector: command.account_selector,
- service_name: command.service_name,
- broker_environment: command.broker_environment,
- expected_revision: command.expected_revision,
- expected_strategy_profile: command.expected_strategy_profile,
- strategy_profile: command.strategy_profile,
- candidate_id: command.candidate_id,
- config_sha256: command.config_sha256,
- source_commit: command.source_commit,
- approved_ues_revision: command.approved_ues_revision,
- desired_state: "paused",
- workflow_run_id: null,
- workflow_run_attempt: null,
- reason_code: "",
- readback: null,
- created_at: command.created_at,
- updated_at: command.created_at,
- };
- this.sql.exec(
- `INSERT INTO research_promotion_applications
- (application_id, ticket_id, status, dispatch_state, claim_token, platform_id, account_key,
- account_scope, account_selector, service_name, broker_environment, expected_revision,
- expected_strategy_profile, strategy_profile, candidate_id, config_sha256, source_commit,
- approved_ues_revision, desired_state, workflow_run_id, workflow_run_attempt, reason_code,
- readback_json, created_at, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
- application.application_id, application.ticket_id, application.status, application.dispatch_state,
- application.claim_token, application.platform_id, application.account_key, application.account_scope,
- application.account_selector, application.service_name, application.broker_environment,
- application.expected_revision, application.expected_strategy_profile, application.strategy_profile,
- application.candidate_id, application.config_sha256, application.source_commit,
- application.approved_ues_revision, application.desired_state, null, null, application.reason_code,
- null, application.created_at, application.updated_at,
- );
- return { ok: true, created: true, application };
- }
- if (command.action === "application_latest") {
- const row = this.sql.exec(
- "SELECT * FROM research_promotion_applications WHERE ticket_id = ? ORDER BY created_at DESC LIMIT 1",
- command.ticket_id,
- ).toArray()[0];
- return { ok: true, application: researchPromotionApplicationFromRow(row) };
- }
- const applicationId = command.application_id;
- const row = this.sql.exec("SELECT * FROM research_promotion_applications WHERE application_id = ?", applicationId).toArray()[0];
- if (!row) throw new HttpError("research_promotion_application_not_found", 404);
- if (command.action === "application_read") return { ok: true, application: researchPromotionApplicationFromRow(row) };
- if (command.action === "application_mark_dispatch") {
- if (row.status !== "approved" || row.dispatch_state !== "pending") return { ok: true, changed: false, application: researchPromotionApplicationFromRow(row) };
- this.sql.exec("UPDATE research_promotion_applications SET dispatch_state = ?, updated_at = ? WHERE application_id = ?", command.dispatch_state, command.updated_at, applicationId);
- return { ok: true, changed: true, application: researchPromotionApplicationFromRow(this.sql.exec("SELECT * FROM research_promotion_applications WHERE application_id = ?", applicationId).toArray()[0]) };
- }
- if (command.action === "application_claim") {
- const state = this.read();
- const instance = state.instances.find((item) => item.kind === "existing"
- && item.platform === row.platform_id && item.key === row.account_key);
- const config = instance?.config || {};
- const bindingStillMatches = state.revision === Number(row.expected_revision)
- && String(config.default_strategy_profile || "") === row.expected_strategy_profile
- && String(config.broker_environment || "") === row.broker_environment
- && String(config.account_selector || "") === row.account_selector
- && String(config.service_name || "") === row.service_name;
- const claimed = row.status === "approved" && ["pending", "sent", "unknown"].includes(row.dispatch_state)
- && row.claim_token === command.claim_token && bindingStillMatches;
- if (claimed) {
- this.sql.exec(
- "UPDATE research_promotion_applications SET status = 'claimed', workflow_run_id = ?, workflow_run_attempt = ?, updated_at = ? WHERE application_id = ? AND status = 'approved'",
- command.workflow_run_id, command.workflow_run_attempt, command.updated_at, applicationId,
- );
- }
- return { ok: true, claimed, reason: claimed ? "" : (bindingStillMatches ? "already_claimed_or_invalid_token" : "account_changed") };
- }
- if (command.action === "application_result") {
- const sameRun = row.workflow_run_id === command.workflow_run_id
- && row.workflow_run_attempt === command.workflow_run_attempt
- && row.claim_token === command.claim_token;
- if (["applied_paused", "rejected", "uncertain"].includes(row.status)) {
- if (!sameRun) throw new HttpError("research_promotion_application_workflow_binding_conflict", 409);
- return { ok: true, changed: false, application: researchPromotionApplicationFromRow(row) };
- }
- if (row.status !== "claimed" || !sameRun) throw new HttpError("research_promotion_application_workflow_binding_conflict", 409);
- let effectiveStatus = command.status;
- let effectiveReasonCode = command.reason_code;
- if (command.status === "applied_paused") {
- const state = this.read();
- const instance = state.instances.find((item) => item.kind === "existing"
- && item.platform === row.platform_id && item.key === row.account_key);
- const config = instance?.config || {};
- const bindingStillMatches = state.revision === Number(row.expected_revision)
- && String(config.default_strategy_profile || "") === row.expected_strategy_profile
- && String(config.broker_environment || "") === row.broker_environment
- && String(config.account_selector || "") === row.account_selector
- && String(config.service_name || "") === row.service_name;
- if (!bindingStillMatches) {
- effectiveStatus = "uncertain";
- effectiveReasonCode = "account_changed";
- } else {
- const before = structuredClone(instance);
- instance.config = { ...instance.config, default_strategy_profile: row.strategy_profile };
- instance.enabled = false;
- instance.platform_applied = true;
- instance.application_status = "applied_paused";
- instance.updated_at = command.updated_at;
- state.revision += 1;
- this.sql.exec("INSERT INTO instance_state (id, revision, payload) VALUES (1, ?, ?) ON CONFLICT(id) DO UPDATE SET revision = excluded.revision, payload = excluded.payload", state.revision, JSON.stringify(state.instances));
- this.sql.exec("INSERT INTO instance_history (revision, entry) VALUES (?, ?)", state.revision, JSON.stringify({
- revision: state.revision,
- ts: command.updated_at,
- login: command.actor,
- action: "research_promotion_application_applied_paused",
- before,
- after: instance,
- }));
- }
- }
- this.sql.exec(
- `UPDATE research_promotion_applications
- SET status = ?, reason_code = ?, readback_json = ?, updated_at = ?
- WHERE application_id = ?`,
- effectiveStatus, effectiveReasonCode, command.readback ? JSON.stringify(command.readback) : null,
- command.updated_at, applicationId,
- );
- return { ok: true, changed: true, application: researchPromotionApplicationFromRow(this.sql.exec("SELECT * FROM research_promotion_applications WHERE application_id = ?", applicationId).toArray()[0]) };
- }
- throw new HttpError("unsupported_research_promotion_application_action", 400);
- });
- }
-
- ux1ResearchCommand(command) {
- return this.storage.transactionSync(() => {
- if (["ux1_begin_job", "ux1_record_dispatch", "ux1_lookup_job", "ux1_claim_job", "ux1_finish_job"].includes(command?.action)) {
- return ux1MutateJob(this.sql, command);
- }
- const login = String(command?.login || "");
- if (!/^[a-z0-9-]{1,39}$/.test(login)) throw new HttpError("ux1_login_invalid", 400);
- const row = ux1SelectSlot(this.sql, login);
- const found = ux1SlotPayload(row);
- if (command.action === "ux1_read") return found;
- if (command.action === "ux1_save") {
- if (!Number.isSafeInteger(command.expected_revision) || command.expected_revision < 0) throw new HttpError("ux1_revision_required", 400);
- if ((row ? Number(row.revision) : 0) !== command.expected_revision) throw new HttpError("ux1_revision_conflict", 409);
- if (typeof command.draft_json !== "string" || typeof command.fingerprint !== "string" || command.draft_json.length > 16384) {
- throw new HttpError("ux1_invalid_body", 400);
- }
- if (row && row.draft_json === command.draft_json && row.fingerprint === command.fingerprint) return { ...found, unchanged: true };
- const revision = (row ? Number(row.revision) : 0) + 1;
- this.sql.exec(
- `INSERT INTO ux1_research_slot (login, revision, draft_json, fingerprint, preview_json, intent_json)
- VALUES (?, ?, ?, ?, NULL, NULL)
- ON CONFLICT(login) DO UPDATE SET revision = excluded.revision, draft_json = excluded.draft_json,
- fingerprint = excluded.fingerprint, preview_json = NULL, intent_json = NULL`,
- login, revision, command.draft_json, command.fingerprint,
- );
- return { ...ux1SlotPayload(ux1SelectSlot(this.sql, login)), unchanged: false };
- }
- if (command.action === "ux1_store_preview") {
- if (!row || Number(row.revision) !== command.expected_revision || row.fingerprint !== command.fingerprint) throw new HttpError("ux1_preview_conflict", 409);
- if (typeof command.preview_json !== "string" || command.preview_json.length > 65536) throw new HttpError("ux1_invalid_body", 400);
- this.sql.exec("UPDATE ux1_research_slot SET preview_json = ? WHERE login = ? AND revision = ?", command.preview_json, login, Number(row.revision));
- return { ...found, preview_json: command.preview_json };
- }
- if (command.action === "ux1_save_intent") {
- if (!row || Number(row.revision) !== command.expected_revision || row.fingerprint !== command.fingerprint || !row.preview_json) {
- throw new HttpError("ux1_intent_conflict", 409);
- }
- if (row.intent_json) {
- const existing = JSON.parse(row.intent_json);
- if (existing.revision === Number(row.revision) && existing.fingerprint === row.fingerprint) return { ...found, duplicate: true };
- }
- if (typeof command.intent_json !== "string" || command.intent_json.length > 4096) throw new HttpError("ux1_invalid_body", 400);
- this.sql.exec("UPDATE ux1_research_slot SET intent_json = ? WHERE login = ? AND revision = ?", command.intent_json, login, Number(row.revision));
- return { ...found, intent_json: command.intent_json, duplicate: false };
- }
- if (command.action === "ux1_clear_preview") {
- if (!row) return found;
- if (Number(row.revision) !== command.expected_revision || row.fingerprint !== command.fingerprint) return found;
- this.sql.exec("UPDATE ux1_research_slot SET preview_json = NULL WHERE login = ? AND revision = ? AND fingerprint = ?", login, Number(row.revision), row.fingerprint);
- return { ...found, preview_json: null };
- }
- throw new HttpError("unsupported_ux1_action", 400);
- });
- }
-}
-
-async function startLogin(request, env) {
- requireEnv(env, "GITHUB_CLIENT_ID");
- const url = new URL(request.url);
- const state = randomToken();
- const authorizeUrl = new URL("https://github.com/login/oauth/authorize");
- authorizeUrl.searchParams.set("client_id", env.GITHUB_CLIENT_ID);
- authorizeUrl.searchParams.set("redirect_uri", `${url.origin}/callback`);
- authorizeUrl.searchParams.set("scope", "read:user read:org");
- authorizeUrl.searchParams.set("state", state);
- return redirect(authorizeUrl.toString(), {
- "Set-Cookie": cookie(OAUTH_STATE_COOKIE, state, 600),
- });
-}
-
-async function finishLogin(request, env) {
- requireEnv(env, "GITHUB_CLIENT_ID");
- requireEnv(env, "GITHUB_CLIENT_SECRET");
- requireEnv(env, "SESSION_SECRET");
-
- const url = new URL(request.url);
- const code = url.searchParams.get("code") || "";
- const state = url.searchParams.get("state") || "";
- const cookies = parseCookies(request.headers.get("Cookie") || "");
- if (!code || !state || cookies[OAUTH_STATE_COOKIE] !== state) {
- return html(renderMessage("登录失败", "OAuth state 校验失败,请重新登录。"), 400, clearOAuthCookie());
- }
-
- const tokenStage = await runLoginGithubStage("token_exchange", () => fetchWithTimeout("https://github.com/login/oauth/access_token", {
- method: "POST",
- headers: {
- Accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- client_id: env.GITHUB_CLIENT_ID,
- client_secret: env.GITHUB_CLIENT_SECRET,
- code,
- redirect_uri: `${url.origin}/callback`,
- }),
- }, GITHUB_LOGIN_REQUEST_TIMEOUT_MS));
- if (tokenStage.timedOut) return loginTimeoutResponse("token_exchange");
- const tokenResponse = tokenStage.value;
- const tokenPayload = await tokenResponse.json();
- const tokenPayloadIsObject = tokenPayload !== null && typeof tokenPayload === "object";
- if (!tokenResponse.ok || !tokenPayloadIsObject || !tokenPayload.access_token) {
- const status = Number.isSafeInteger(tokenResponse?.status) ? tokenResponse.status : null;
- const allowedOauthErrors = new Set([
- "incorrect_client_credentials",
- "redirect_uri_mismatch",
- "bad_verification_code",
- "unverified_user_email",
- ]);
- const errorCategory = tokenPayloadIsObject && typeof tokenPayload.error === "string"
- && allowedOauthErrors.has(tokenPayload.error)
- ? tokenPayload.error
- : "unknown";
- console.warn("github_token_exchange_failed", {
- http_status: status,
- error_category: errorCategory,
- });
- const statusLabel = status === null ? "不可用" : String(status);
- return html(
- renderMessage("登录失败", `GitHub 凭证交换未成功(HTTP ${statusLabel},类别:${errorCategory})。请从登录入口重新开始。`),
- 502,
- clearOAuthCookie(),
- );
- }
-
- const userStage = await runLoginGithubStage("user_lookup", () => fetchWithTimeout("https://api.github.com/user", {
- headers: githubHeaders(tokenPayload.access_token),
- }, GITHUB_LOGIN_REQUEST_TIMEOUT_MS));
- if (userStage.timedOut) return loginTimeoutResponse("user_lookup");
- const userResponse = userStage.value;
- const user = await userResponse.json();
- const login = String(user.login || "").toLowerCase();
- if (!userResponse.ok || !login) {
- return html(renderMessage("登录失败", "无法读取 GitHub 用户。"), 502, clearOAuthCookie());
- }
-
- const authConfig = await loadAuthConfig(env);
- const orgStage = await runLoginGithubStage("organization_lookup", () => fetchGithubOrgLogins(
- tokenPayload.access_token,
- GITHUB_LOGIN_REQUEST_TIMEOUT_MS,
- ));
- if (orgStage.timedOut) return loginTimeoutResponse("organization_lookup");
- const orgLogins = orgStage.value;
- if (!isAllowedPrincipal(login, orgLogins, authConfig)) {
- return html(renderMessage("没有权限", `${login} 不在允许登录名单或组织中。`), 403, clearOAuthCookie());
- }
-
- const session = await makeSession(login, authorizedOrgLogins(orgLogins, authConfig), env);
- return redirect("/", {
- "Set-Cookie": [
- cookie(SESSION_COOKIE, session, SESSION_TTL_SECONDS),
- clearCookie(OAUTH_STATE_COOKIE),
- ],
- });
-}
-
-async function runLoginGithubStage(stage, operation) {
- const startedAt = Date.now();
- try {
- return { timedOut: false, value: await operation() };
- } catch (error) {
- if (error?.message !== "GitHub request timed out") throw error;
- console.warn("github_login_request_timed_out", {
- stage,
- timeout_ms: GITHUB_LOGIN_REQUEST_TIMEOUT_MS,
- elapsed_ms: Math.max(0, Date.now() - startedAt),
- });
- return { timedOut: true };
- }
-}
-
-function loginTimeoutResponse(stage) {
- const stageLabels = {
- token_exchange: "登录凭证交换",
- user_lookup: "读取用户身份",
- organization_lookup: "核对组织权限",
- };
- const stageLabel = stageLabels[stage] || "登录请求处理";
- return html(
- renderMessage("登录超时", `${stageLabel}超时,请从登录入口重新开始。此回调链接已失效,请勿复用。`),
- 504,
- clearOAuthCookie(),
- );
-}
-
-const deskAuth = createDeskAuth({ readSession, requireSameOrigin });
-
-async function sessionPayload(request, env) {
- const session = await readSession(request, env);
- return {
- authenticated: Boolean(session),
- login: session?.login || null,
- allowed: Boolean(session?.allowed),
- admin: Boolean(session?.admin),
- server_time: new Date().toISOString(),
- };
-}
-
-async function adminConfigResponse(request, env) {
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- return json(await buildAdminState(session, env));
-}
-
-async function saveAdminConfig(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "STRATEGY_SWITCH_CONFIG KV binding is required to save admin config" }, 400);
- }
-
- let raw;
- try {
- raw = await request.json();
- } catch (error) {
- return json({ ok: false, error: "request body must be valid JSON" }, 400);
- }
- const bootstrapAdmins = parseLoginList(env.STRATEGY_SWITCH_ADMIN_LOGINS || "", "STRATEGY_SWITCH_ADMIN_LOGINS");
- const bootstrapAdminOrgs = parseOrgList(env.STRATEGY_SWITCH_ADMIN_ORGS || "", "STRATEGY_SWITCH_ADMIN_ORGS");
- const allowedLogins = normalizeLoginList(raw.allowed_logins, "allowed_logins");
- const allowedOrgs = normalizeOrgList(raw.allowed_orgs, "allowed_orgs");
- const submittedAdmins = normalizeLoginList(raw.admin_logins, "admin_logins");
- const submittedAdminOrgs = normalizeOrgList(raw.admin_orgs, "admin_orgs");
- const effectiveAdmins = uniqueStrings([...bootstrapAdmins, ...submittedAdmins]);
- const effectiveAdminOrgs = uniqueStrings([...bootstrapAdminOrgs, ...submittedAdminOrgs]);
- if (!effectiveAdmins.includes(session.login) && !hasOrgMatch(session.orgs, effectiveAdminOrgs)) {
- throw new Error("current admin login or org must remain in admin config");
- }
- const authConfig = {
- allowed_logins: uniqueStrings([...allowedLogins, ...effectiveAdmins]),
- allowed_orgs: allowedOrgs,
- admin_logins: effectiveAdmins,
- admin_orgs: effectiveAdminOrgs,
- };
- const accountOptions = normalizeAccountOptionsInput(raw.account_options, "account_options");
-
- if (hasRuntimeInstanceStore(env)) {
- const instances = await runtimeInstanceCommand(env);
- if (!instances.initialized || canonicalResearchTaskJson(accountOptions) !== canonicalResearchTaskJson(normalizeAccountOptionsPayload(instances.account_options))) {
- throw new HttpError("runtime_instances_managed_separately", 409);
- }
- }
- await writeConfigJson(env, AUTH_CONFIG_KEY, authConfig);
- if (!hasRuntimeInstanceStore(env)) await writeConfigJson(env, ACCOUNT_OPTIONS_KEY, validateAccountOptionsSchemaOrThrow(accountOptions));
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: session.login,
- action: "save_config",
- allowed_count: authConfig.allowed_logins.length,
- allowed_org_count: authConfig.allowed_orgs.length,
- admin_count: authConfig.admin_logins.length,
- admin_org_count: authConfig.admin_orgs.length,
- account_counts: accountCounts(accountOptions),
- });
- return json(await buildAdminState(session, env));
-}
-
-async function riskProfileBindingsResponse(request, env) {
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- const bindingState = await loadRiskProfileBindings(env);
- if (bindingState.error) {
- return json({
- ok: false,
- error: "risk profile bindings are unavailable",
- reason: bindingState.error,
- no_order: true,
- execution_authority_granted: false,
- }, bindingState.status || 409);
- }
- return json({
- ok: true,
- revision: bindingState.revision,
- bindings: bindingState.bindings,
- tier_bindings: bindingState.bindings.map((binding) => riskTierBindingView({
- scope_id: binding.scope_id,
- platform: binding.platform,
- target_name: binding.target_name,
- binding,
- revision: bindingState.revision,
- })),
- configured_targets: riskProfileBindingTargets(bindingState.account_options || {}),
- no_order: true,
- execution_authority_granted: false,
- });
-}
-
-async function saveRiskProfileBindings(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- let raw;
- try {
- raw = await request.json();
- } catch {
- return json({ ok: false, error: "request body must be valid JSON" }, 400);
- }
- if (!hasRuntimeInstanceStore(env)) {
- try {
- await buildRiskProfileBindings({ bindings: raw?.bindings }, (await loadLegacyAccountOptionsConfig(env)).options || {}, session.login);
- } catch (error) {
- return json({ ok: false, error: error.message || "risk profile bindings are invalid" }, 400);
- }
- return json({ ok: false, error: "runtime_instances_not_bound", no_order: true, execution_authority_granted: false }, 503);
- }
- const legacy = await readRiskProfileLegacy(env);
- let observed;
- try {
- observed = await runtimeInstanceCommand(env, { action: "risk_profile_read", actor: session.login, legacy });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
- if (!Number.isSafeInteger(raw?.expected_revision)) return json({ ok: false, error: "risk_profile_revision_required" }, 400);
- if (raw.expected_revision !== observed.revision) return json({ ok: false, error: "risk_profile_revision_conflict" }, 409);
- let bindings;
- try {
- bindings = await buildRiskProfileBindings({ bindings: raw.bindings }, observed.account_options, session.login);
- } catch (error) {
- return json({ ok: false, error: error.message || "risk profile bindings are invalid" }, 400);
- }
- let saved;
- try {
- saved = await runtimeInstanceCommand(env, {
- action: "risk_profile_replace",
- actor: session.login,
- expected_revision: observed.revision,
- bindings,
- legacy,
- });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
- if (hasConfigStore(env)) {
- await mirrorConfigJson(env, RISK_PROFILE_BINDINGS_KEY, {
- schema_version: RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION,
- bindings: saved.bindings,
- });
- }
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: session.login,
- action: "save_risk_profile_bindings",
- binding_count: saved.bindings.length,
- });
- } catch { /* audit failure does not undo the durable object decision */ }
- return json({
- ok: true,
- revision: saved.revision,
- bindings: saved.bindings,
- configured_targets: riskProfileBindingTargets(saved.account_options || {}),
- no_order: true,
- execution_authority_granted: false,
- });
-}
-
-async function consoleRunControls(_request, env, account, session) {
- return runControls(account, session, {
- dispatchAvailable: Boolean(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
- platformControl: ["ibkr", "schwab"].includes(account.platform)
- ? () => readPlatformRuntimeControl(env, account.platform, account.target_name) : null,
- stopReady: async () => {
- if (account.platform === "longbridge" && account.target_name === "hk") {
- if (account.key !== "hk") return false;
- await loadHkStopAccount(env);
- const { record } = await runtimeInstanceCommand(env, { action: "hk_stop_read" });
- return !record || !["reserved", "accepted", "unknown", "stopped"].includes(record.phase);
- }
- const config = await loadAccountOptionsConfig(env);
- if (!account.target_name || (config.options?.[account.platform] || []).filter(a => a.target_name === account.target_name).length !== 1) return false;
- const inputs = { ...account, platform: account.platform };
- const values = Object.fromEntries(["deployment_selector", "account_scope", "account_selector", "service_name"]
- .map(field => [field, inputs[field] || defaultInputValue(field, inputs)]));
- return Object.values(values).every(Boolean) && String(values.account_selector).split(",").some(value => value.trim());
- },
- resumeTarget: async () => {
- const repository = platformRepositories(env).binance;
- const config = await loadAccountOptionsConfig(env);
- if (repository !== "QuantStrategyLab/BinancePlatform" || !account.target_name ||
- (config.options?.binance || []).filter(a => a.target_name === account.target_name).length !== 1 ||
- resolvedVariableScope(account.variable_scope, { ...account, platform: "binance" }) !== "repository") return null;
- const variables = await fetchGithubVariables(env.RUNTIME_SETTINGS_DISPATCH_TOKEN, repository, "repository", "");
- return binanceResumeTarget(Object.fromEntries(variables), account);
- },
- profileState: async () => {
- if (!hasRuntimeInstanceStore(env)) return { reason: "runtime_instances_not_bound" };
- const observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor: session.login, platform: account.platform, key: account.key });
- const draft = observed.draft;
- if (draft?.status === "identity_conflict") return { reason: "account_settings_identity_conflict" };
- const next = draft?.overrides?.strategy_profile;
- if (draft?.status !== "current" || typeof next !== "string" || Object.keys(draft.overrides).length !== 1 ||
- !accountSettingsIdentityIsComplete(observed.identity) ||
- canonicalResearchTaskJson(draft.identity) !== canonicalResearchTaskJson(observed.identity)) return { reason: "profile_draft_required" };
- if (isDcaProfile(next)) return { reason: "profile_only_required" };
- const profiles = await loadAccountDraftProfiles(env);
- if (!accountDraftStrategyChoices(account.platform, observed.config, profiles).some(p => p.profile === next && !p.dca_supported)) return { reason: "profile_not_selectable" };
- const readback = await accountSettingsProfileRuntimeReadback(env, observed);
- if (!readback) return { reason: "runtime_readback_unavailable" };
- if (readback.runtime_target_enabled !== "false") return { reason: "runtime_target_not_disabled" };
- if (!readback.strategy_profile || readback.strategy_profile === next || isDcaProfile(readback.strategy_profile)) return { reason: "current_profile_conflict" };
- const history = await runtimeInstanceCommand(env, { action: "console_settings_history", actor: session.login, platform: account.platform, key: account.key });
- if (history.approvals.some(row => row.status === "claimed" || (row.status === "approved" &&
- row.identity_json === canonicalResearchTaskJson(observed.identity) && Number(row.instance_revision) === observed.instance_revision &&
- Number(row.draft_revision) === draft.revision && row.old_profile === readback.strategy_profile && row.new_profile === next)))
- return { reason: "profile_application_pending" };
- return { ready: true };
- },
- });
-}
-
-function accountSettingsOperations(admin, optionSupported) {
- const allowed = Boolean(admin);
- return {
- save_draft: allowed,
- save_draft_reason: allowed ? "available" : "admin_required",
- save_risk_preference: allowed,
- save_risk_preference_reason: allowed ? "available" : "admin_required",
- save_declaration: allowed,
- save_declaration_reason: allowed ? "available" : "admin_required",
- save_option_draft: allowed && optionSupported === true,
- save_option_draft_reason: !allowed ? "admin_required" : optionSupported === true ? "available" : "option_overlay_not_defined",
- apply_strategy: false,
- activation: false,
- reason: "strategy_application_not_connected",
- apply_strategy_reason: "strategy_application_not_connected",
- activation_reason: "strategy_application_not_connected",
- };
-}
-
-function accountSettingsPayload(observed, effective, admin, extras = {}) {
- const optionSupported = extras.pendingStrategy ? extras.pendingOptionSupported === true : extras.currentOptionSupported === true;
- return {
- ok: true,
- platform: observed.platform,
- key: observed.key,
- instance_revision: observed.instance_revision,
- identity: observed.identity,
- effective,
- effective_read: extras.effectiveRead,
- draft: observed.draft,
- declaration: observed.declaration,
- strategy_options: Array.isArray(extras.strategyOptions) ? extras.strategyOptions : [],
- current_option_supported: extras.currentOptionSupported === true,
- risk: {
- revision: observed.risk.revision,
- scope_id: observed.risk.scope_id,
- preference: observed.risk.preference,
- },
- tier_binding: riskTierBindingView({
- scope_id: observed.risk.scope_id,
- platform: observed.platform,
- target_name: observed.identity?.target_name || null,
- binding: observed.risk.binding || null,
- revision: observed.risk.revision,
- }),
- operations: accountSettingsOperations(admin, optionSupported),
- adopted: false,
- no_order: true,
- execution_authority_granted: false,
- current_dca_supported: extras.currentDcaSupported === true,
- };
-}
-
-async function accountSettingsResponse(request, env) {
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- const url = new URL(request.url);
- const platform = url.searchParams.get("platform") || "";
- const key = url.searchParams.get("key") || "";
- if (!SUPPORTED_PLATFORMS.includes(platform) || !key) return json({ ok: false, error: "account_settings_account_required" }, 400);
- if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "runtime_instances_not_bound", no_order: true, execution_authority_granted: false }, 503);
- const legacy = await readRiskProfileLegacy(env);
- let observed;
- try {
- observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor: session.login, platform, key, legacy });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
- return json(await presentAccountSettings(env, observed, session.admin));
-}
-
-async function presentAccountSettings(env, observed, admin) {
- const { effective, effectiveRead } = await effectiveAccountSettings(env, observed);
- const profiles = await loadAccountDraftProfiles(env);
- const strategyOptions = profiles ? accountDraftStrategyChoices(observed.platform, observed.config, profiles) : [];
- const conflict = observed.draft?.status === "identity_conflict";
- const pending = !conflict && typeof observed.draft?.overrides?.strategy_profile === "string" ? observed.draft.overrides.strategy_profile : "";
- const trusted = effective.strategy_profile?.status === "known" && typeof effective.strategy_profile.value === "string" ? effective.strategy_profile.value : "";
- return accountSettingsPayload(observed, effective, admin, {
- effectiveRead,
- strategyOptions,
- pendingStrategy: Boolean(pending),
- pendingOptionSupported: Boolean(pending) && optionOverlayDraftAllowed(observed.platform, profiles, pending),
- currentOptionSupported: Boolean(trusted) && optionOverlayDraftAllowed(observed.platform, profiles, trusted),
- currentDcaSupported: dcaDraftSupported(observed.platform, profiles, trusted),
- });
-}
-
-async function loadAccountDraftProfiles(env) {
- try {
- return await loadStrategyProfilesConfig(env);
- } catch {
- return null;
- }
-}
-
-function profileDefinesOptionOverlay(profiles, profileId) {
- if (!Array.isArray(profiles) || typeof profileId !== "string" || !profileId) return false;
- const found = profiles.find((item) => sameStrategyProfile(item?.profile, profileId));
- return found?.option_overlay_enabled === true;
-}
-
-function optionOverlayDraftAllowed(platform, profiles, profileId) {
- return PLATFORM_CONFIG[platform]?.option_overlay === true && profileDefinesOptionOverlay(profiles, profileId);
-}
-
-function dcaDraftSupported(platform, profiles, profileId) {
- if (!profileId || !Array.isArray(profiles)) return false;
- if (!DCA_SUPPORTED_PLATFORMS.has(platform) || !isDcaProfile(profileId)) return false;
- return profiles.some((item) => sameStrategyProfile(item?.profile, profileId));
-}
-
-function accountDraftStrategyChoices(platform, accountOption, profiles) {
- if (!Array.isArray(profiles)) return [];
- let domains = [];
- try {
- domains = supportedDomainsForAccount(platform, accountOption || {});
- } catch {
- return [];
- }
- const choices = [];
- const allowsDryRunOnly = accountOption?.default_execution_mode === "dry_run"
- && supportedExecutionModesForPlatform(platform).includes("dry_run");
- for (const profile of profiles) {
- if (!profile || typeof profile.profile !== "string" || !profile.profile) continue;
- if (profile.domain_explicit !== true || profile.lifecycle_stage === "frozen" || isFrozenStrategyProfile(profile)) continue;
- if (!profile.domain || !domains.includes(profile.domain)) continue;
- const modes = Array.isArray(profile.allowed_execution_modes) ? profile.allowed_execution_modes : [];
- if (!modes.some((mode) => mode === "paper" || mode === "live"
- || (allowsDryRunOnly && mode === "dry_run"))) continue;
- try {
- assertDcaPlatform(platform, profile.profile);
- } catch {
- continue;
- }
- choices.push({
- profile: profile.profile,
- label: profile.label || profile.profile,
- label_zh: profile.label_zh || profile.label || profile.profile,
- label_en: profile.label_en || profile.label || profile.profile,
- domain: profile.domain,
- // Existing catalog declarations only, never broker or execution permission.
- lifecycle_stage: typeof profile.lifecycle_stage === "string" ? profile.lifecycle_stage : null,
- allowed_execution_modes: Array.isArray(profile.allowed_execution_modes) && profile.allowed_execution_modes.length ? [...profile.allowed_execution_modes] : null,
- can_switch_live: typeof profile.can_switch_live === "boolean" ? profile.can_switch_live : null,
- blocked_live_reason: typeof profile.blocked_live_reason === "string" ? profile.blocked_live_reason : null,
- option_overlay_enabled: profile.option_overlay_enabled === true,
- dca_supported: dcaDraftSupported(platform, profiles, profile.profile),
- });
- }
- return choices;
-}
-
-function assertAccountDraftPatch(profiles, observed, patch, trustedProfile, options = {}) {
- if (!patch || Array.isArray(patch) || typeof patch !== "object") throw new HttpError("invalid_account_setting_overrides", 400);
- const choices = profiles ? accountDraftStrategyChoices(observed.platform, observed.config, profiles) : [];
- const rebuilding = observed.draft?.status === "identity_conflict" && options.acknowledgeIdentityConflict === true;
- const stored = observed.draft?.overrides && typeof observed.draft.overrides === "object" && !Array.isArray(observed.draft.overrides) ? observed.draft.overrides : {};
- const current = rebuilding ? {} : stored;
- const touchesStrategy = Object.prototype.hasOwnProperty.call(patch, "strategy_profile");
- const touchesOption = Object.prototype.hasOwnProperty.call(patch, "option_overlay_enabled");
- const touchesDcaMode = Object.prototype.hasOwnProperty.call(patch, "dca_mode");
- const touchesDcaBase = Object.prototype.hasOwnProperty.call(patch, "dca_base_investment_usd");
- if (touchesDcaMode !== touchesDcaBase) throw new HttpError("account_settings_dca_rejected", 400);
- if (touchesDcaMode && (patch.dca_mode === null) !== (patch.dca_base_investment_usd === null)) {
- throw new HttpError("account_settings_dca_rejected", 400);
- }
- if (touchesDcaMode && patch.dca_mode !== null && patch.dca_mode !== "fixed" && patch.dca_mode !== "smart") {
- throw new HttpError("invalid_account_setting_overrides", 400);
- }
- if (touchesDcaBase && patch.dca_base_investment_usd !== null && !accountSettingPositiveAmount(patch.dca_base_investment_usd)) {
- throw new HttpError("invalid_account_setting_overrides", 400);
- }
- if (!profiles && (touchesDcaMode || touchesDcaBase)) throw new HttpError("account_settings_dca_rejected", 400);
- if (touchesStrategy && patch.strategy_profile !== null) {
- const allowedChoice = choices.some((item) => sameStrategyProfile(item.profile, patch.strategy_profile));
- const currentEditable = sameStrategyProfile(patch.strategy_profile, trustedProfile) && dcaDraftSupported(observed.platform, profiles, patch.strategy_profile);
- if (typeof patch.strategy_profile !== "string" || (!allowedChoice && !currentEditable)) {
- throw new HttpError("account_settings_strategy_rejected", 400);
- }
- }
- if (!touchesStrategy && !touchesOption && !touchesDcaMode && !touchesDcaBase) return;
- const bound = touchesStrategy
- ? patch.strategy_profile || trustedProfile || ""
- : (typeof current.strategy_profile === "string" && current.strategy_profile ? current.strategy_profile : trustedProfile || "");
- const supports = optionOverlayDraftAllowed(observed.platform, profiles, bound);
- if (touchesOption && patch.option_overlay_enabled !== null && (typeof patch.option_overlay_enabled !== "boolean" || !supports)) {
- throw new HttpError("account_settings_option_rejected", 400);
- }
- const nextOption = touchesOption
- ? patch.option_overlay_enabled
- : (Object.prototype.hasOwnProperty.call(current, "option_overlay_enabled") ? current.option_overlay_enabled : undefined);
- if ((nextOption === true || nextOption === false) && !supports) throw new HttpError("account_settings_option_strategy_conflict", 400);
- // Other setting groups can be edited on a DCA account without rebinding its strategy.
- if (!touchesStrategy && !touchesDcaMode && !touchesDcaBase) return;
- const previous = typeof current.strategy_profile === "string" && current.strategy_profile ? current.strategy_profile : trustedProfile || "";
- const next = touchesStrategy
- ? (patch.strategy_profile === null ? trustedProfile || "" : String(patch.strategy_profile || ""))
- : previous;
- const mergedMode = touchesDcaMode ? patch.dca_mode : (Object.prototype.hasOwnProperty.call(current, "dca_mode") ? current.dca_mode : null);
- const mergedBase = touchesDcaBase ? patch.dca_base_investment_usd : (Object.prototype.hasOwnProperty.call(current, "dca_base_investment_usd") ? current.dca_base_investment_usd : null);
- const hasMergedDca = (mergedMode !== null && mergedMode !== undefined) || (mergedBase !== null && mergedBase !== undefined);
- if (!dcaDraftSupported(observed.platform, profiles, next)) {
- if (hasMergedDca) throw new HttpError("account_settings_dca_rejected", 400);
- if (!sameStrategyProfile(previous, next) && dcaDraftSupported(observed.platform, profiles, previous)
- && (!touchesDcaMode || patch.dca_mode !== null || !touchesDcaBase || patch.dca_base_investment_usd !== null)) {
- throw new HttpError("account_settings_dca_rejected", 400);
- }
- return;
- }
- if (touchesDcaMode || touchesDcaBase) {
- const clearingDca = patch.dca_mode === null && patch.dca_base_investment_usd === null;
- const boundToProfile = sameStrategyProfile(patch.strategy_profile, next);
- const clearingCurrentBinding = patch.strategy_profile === null && clearingDca;
- if (!touchesStrategy || (!boundToProfile && !clearingCurrentBinding)) {
- throw new HttpError("account_settings_dca_rejected", 400);
- }
- }
- if (!sameStrategyProfile(previous, next) || touchesDcaMode || touchesDcaBase) {
- if (!touchesDcaMode || !touchesDcaBase) throw new HttpError("account_settings_dca_rejected", 400);
- }
-}
-
-async function saveCombinedAccountDraft(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- let raw;
- try { raw = await readBoundedJson(request, 16 * 1024); } catch (error) { return json({ ok: false, error: "invalid_account_setting_overrides" }, error.status || 400); }
- const allowed = ["platform", "key", "identity", "expected_draft_revision", "acknowledge_identity_conflict", "overrides"];
- if (!raw || Array.isArray(raw) || Object.keys(raw).some(key => !allowed.includes(key)) || !Object.hasOwn(raw, "overrides")) return json({ ok: false, error: "invalid_account_setting_overrides" }, 400);
- return saveAccountSettings(new Request(request.url, { method: "POST", headers: request.headers, body: JSON.stringify(raw) }), env);
-}
-
-async function saveAccountSettings(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- let raw;
- try { raw = await request.json(); } catch { return json({ ok: false, error: "request body must be valid JSON" }, 400); }
- const platform = raw?.platform;
- const key = raw?.key;
- if (!SUPPORTED_PLATFORMS.includes(platform) || typeof key !== "string" || !key) return json({ ok: false, error: "account_settings_account_required" }, 400);
- if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "runtime_instances_not_bound", no_order: true, execution_authority_granted: false }, 503);
- const legacy = await readRiskProfileLegacy(env);
- let observed;
- try {
- observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor: session.login, platform, key, legacy });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
- const wantsDraft = Object.prototype.hasOwnProperty.call(raw, "overrides");
- const wantsRisk = Object.prototype.hasOwnProperty.call(raw, "risk_preference");
- const wantsDeclaration = Object.prototype.hasOwnProperty.call(raw, "declaration");
- if ((wantsDraft || wantsRisk || wantsDeclaration) && (!raw.identity || Array.isArray(raw.identity) || typeof raw.identity !== "object")) {
- return json({ ok: false, error: "account_settings_identity_required" }, 400);
- }
- if ((wantsDraft || wantsRisk || wantsDeclaration) && canonicalResearchTaskJson(raw.identity) !== canonicalResearchTaskJson(observed.identity)) {
- return json({ ok: false, error: "account_settings_identity_conflict" }, 409);
- }
- const command = { action: "account_settings_save", actor: session.login, platform, key, legacy };
- if (wantsDraft || wantsRisk || wantsDeclaration) command.identity = raw.identity;
- if (wantsDeclaration) {
- if (!Number.isSafeInteger(raw.expected_declaration_revision) || raw.expected_declaration_revision !== observed.declaration.revision) return json({ ok: false, error: "account_settings_declaration_revision_conflict" }, 409);
- command.declaration = raw.declaration;
- command.expected_declaration_revision = raw.expected_declaration_revision;
- }
- if (wantsDraft) {
- if (!Number.isSafeInteger(raw.expected_draft_revision)) return json({ ok: false, error: "account_settings_draft_revision_required" }, 400);
- if (raw.expected_draft_revision !== observed.draft.revision) return json({ ok: false, error: "account_settings_draft_revision_conflict" }, 409);
- command.overrides = raw.overrides;
- command.expected_draft_revision = observed.draft.revision;
- if (raw.acknowledge_identity_conflict === true) command.acknowledge_identity_conflict = true;
- const profiles = await loadAccountDraftProfiles(env);
- const { effective: beforeEffective } = await effectiveAccountSettings(env, observed);
- const trusted = beforeEffective.strategy_profile?.status === "known" && typeof beforeEffective.strategy_profile.value === "string" ? beforeEffective.strategy_profile.value : "";
- try {
- assertAccountDraftPatch(profiles, observed, raw.overrides, trusted, { acknowledgeIdentityConflict: raw.acknowledge_identity_conflict === true });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 400;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "invalid_account_setting_overrides", no_order: true, execution_authority_granted: false }, status);
- }
- }
- if (wantsRisk) {
- if (!Number.isSafeInteger(raw.expected_risk_revision)) return json({ ok: false, error: "risk_profile_revision_required" }, 400);
- if (raw.expected_risk_revision !== observed.risk.revision) return json({ ok: false, error: "risk_profile_revision_conflict" }, 409);
- command.expected_risk_revision = observed.risk.revision;
- if (raw.risk_preference === null) command.risk_change = "clear";
- else {
- let built;
- try {
- built = await buildRiskProfileBindings(
- { bindings: [{ platform, target_name: observed.identity.target_name, risk_preference: raw.risk_preference }] },
- observed.account_options,
- session.login,
- );
- } catch (error) {
- return json({ ok: false, error: error.message || "risk profile bindings are invalid" }, 400);
- }
- command.risk_change = "set";
- command.binding = built[0];
- }
- }
- if (!Object.prototype.hasOwnProperty.call(command, "overrides") && !Object.prototype.hasOwnProperty.call(command, "risk_change") && !Object.prototype.hasOwnProperty.call(command, "declaration")) {
- return json({ ok: false, error: "account_settings_change_required" }, 400);
- }
- let saved;
- try {
- saved = await runtimeInstanceCommand(env, command);
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
- if (command.risk_change && hasConfigStore(env)) {
- await mirrorConfigJson(env, RISK_PROFILE_BINDINGS_KEY, {
- schema_version: RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION,
- bindings: saved.bindings,
- });
- }
- const changes = accountSettingsAuditChanges(observed, saved, command);
- let auditLogged = false;
- if (changes.length && hasConfigStore(env)) {
- const entry = {
- ts: new Date().toISOString(),
- login: session.login,
- action: "save_account_settings",
- platform,
- key,
- changes,
- };
- if (changes.some((kind) => kind === "cash_draft" || kind === "income_draft" || kind === "option_draft" || kind === "strategy_draft")) entry.draft_revision = saved.draft.revision;
- if (changes.includes("risk_saved") || changes.includes("risk_cleared")) entry.risk_revision = saved.risk.revision;
- if (changes.includes("account_declaration_saved")) entry.declaration_revision = saved.declaration.revision;
- try {
- await appendAuditLog(env, entry);
- auditLogged = true;
- } catch { /* the setting is already stored; a missed audit line must not be saved again */ }
- }
- const presented = await presentAccountSettings(env, saved, true);
- presented.audit_logged = auditLogged;
- return json(presented);
-}
-
-async function approveAccountSettingsProfileApplication(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- let raw;
- try { raw = await request.json(); } catch { return json({ ok: false, error: "request body must be valid JSON" }, 400); }
- const allowedFields = new Set([
- "platform", "key", "request_key", "identity", "expected_instance_revision",
- "expected_draft_revision", "old_profile", "new_profile",
- ]);
- if (!raw || Array.isArray(raw) || typeof raw !== "object" || Object.keys(raw).some((key) => !allowedFields.has(key))) {
- return json({ ok: false, error: "account_settings_profile_application_request_invalid" }, 400);
- }
- if (!SUPPORTED_PLATFORMS.includes(raw.platform) || typeof raw.key !== "string" || !raw.key) {
- return json({ ok: false, error: "account_settings_account_required" }, 400);
- }
- if (!ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(String(raw.request_key || ""))
- || !Number.isSafeInteger(raw.expected_instance_revision) || raw.expected_instance_revision < 0
- || !Number.isSafeInteger(raw.expected_draft_revision) || raw.expected_draft_revision < 0
- || !accountSettingsIdentityIsComplete(raw.identity)) {
- return json({ ok: false, error: "account_settings_profile_application_request_invalid" }, 400);
- }
- const oldProfile = accountSettingsProfileName(raw.old_profile);
- const newProfile = accountSettingsProfileName(raw.new_profile);
- if (!oldProfile || !newProfile || oldProfile === newProfile) {
- return json({ ok: false, error: "account_settings_profile_application_profile_invalid" }, 400);
- }
- if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "runtime_instances_not_bound" }, 503);
-
- const command = {
- action: "account_settings_profile_application_approve",
- actor: session.login,
- platform: raw.platform,
- key: raw.key,
- request_key: raw.request_key,
- identity: raw.identity,
- expected_instance_revision: raw.expected_instance_revision,
- expected_draft_revision: raw.expected_draft_revision,
- old_profile: oldProfile,
- new_profile: newProfile,
- };
- try {
- const prior = await runtimeInstanceCommand(env, {
- action: "account_settings_profile_application_lookup",
- actor: session.login,
- request_key: raw.request_key,
- });
- if (prior.application) {
- const replay = await runtimeInstanceCommand(env, command);
- return json({
- ok: true,
- replayed: true,
- application: replay.application,
- runtime_applied: false,
- variables_updated: false,
- no_order: true,
- execution_authority_granted: false,
- });
- }
-
- const observed = await runtimeInstanceCommand(env, {
- action: "account_settings_read", actor: session.login, platform: raw.platform, key: raw.key,
- });
- if (observed.instance_revision !== raw.expected_instance_revision
- || canonicalResearchTaskJson(observed.identity) !== canonicalResearchTaskJson(raw.identity)) {
- return json({ ok: false, error: "account_settings_profile_application_identity_conflict" }, 409);
- }
- const draft = observed.draft;
- if (draft?.status !== "current" || draft.revision !== raw.expected_draft_revision
- || canonicalResearchTaskJson(draft.identity) !== canonicalResearchTaskJson(observed.identity)
- || Object.keys(draft.overrides || {}).length !== 1
- || draft.overrides?.strategy_profile !== newProfile) {
- return json({ ok: false, error: "account_settings_profile_application_draft_conflict" }, 409);
- }
- if (isDcaProfile(oldProfile) || isDcaProfile(newProfile)) {
- return json({ ok: false, error: "account_settings_profile_application_profile_only_required" }, 409);
- }
- const profiles = await loadAccountDraftProfiles(env);
- const selectable = accountDraftStrategyChoices(raw.platform, observed.config, profiles);
- if (!selectable.some((profile) => profile.profile === newProfile && profile.dca_supported !== true)) {
- return json({ ok: false, error: "account_settings_profile_application_profile_not_selectable" }, 409);
- }
- const readback = await accountSettingsProfileRuntimeReadback(env, observed);
- if (!readback) return json({ ok: false, error: "account_settings_runtime_readback_unavailable" }, 503);
- if (readback.runtime_target_enabled !== "false") {
- return json({ ok: false, error: "account_settings_runtime_target_not_disabled" }, 409);
- }
- if (readback.strategy_profile !== oldProfile) {
- return json({ ok: false, error: "account_settings_profile_application_current_profile_conflict" }, 409);
- }
- command.current_profile = readback.strategy_profile;
- command.runtime_target_enabled = false;
- const approved = await runtimeInstanceCommand(env, command);
- let auditLogged = false;
- if (!approved.replayed && hasConfigStore(env)) {
- try {
- await appendAuditLog(env, {
- ts: approved.application.approved_at,
- login: session.login,
- action: "approve_account_settings_profile_application",
- platform: raw.platform,
- key: raw.key,
- request_key: raw.request_key,
- instance_revision: raw.expected_instance_revision,
- draft_revision: raw.expected_draft_revision,
- old_profile: oldProfile,
- new_profile: newProfile,
- });
- auditLogged = true;
- } catch { /* the durable approval is authoritative if its audit mirror is unavailable */ }
- }
- return json({
- ok: true,
- replayed: approved.replayed === true,
- application: approved.application,
- audit_logged: auditLogged,
- runtime_applied: false,
- variables_updated: false,
- no_order: true,
- execution_authority_granted: false,
- });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "runtime_instances_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
-}
-
-function decodeProfileApplicationJwtPart(value, maxBytes, parseJson = true) {
- if (typeof value !== "string" || value.length === 0 || value.length > maxBytes * 2
- || !/^[A-Za-z0-9_-]+$/.test(value)) throw new HttpError("github_oidc_token_invalid", 401);
- const padded = value.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - value.length % 4) % 4);
- let binary;
- try { binary = atob(padded); } catch { throw new HttpError("github_oidc_token_invalid", 401); }
- if (binary.length > maxBytes) throw new HttpError("github_oidc_token_invalid", 401);
- const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
- if (!parseJson) return { bytes };
- try { return { bytes, value: JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes)) }; }
- catch { throw new HttpError("github_oidc_token_invalid", 401); }
-}
-
-async function readGitHubProfileApplicationJwks() {
- const controller = new AbortController();
- let rejectAbort = () => {};
- const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
- abortPromise.catch(() => {});
- const onAbort = () => rejectAbort(new HttpError("github_oidc_jwks_unavailable", 503));
- controller.signal.addEventListener("abort", onAbort);
- const timeout = setTimeout(() => controller.abort(), ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_TIMEOUT_MS);
- let response;
- try {
- response = await Promise.race([
- fetch(ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_JWKS_URL, {
- method: "GET",
- headers: { Accept: "application/json" },
- redirect: "manual",
- signal: controller.signal,
- }),
- abortPromise,
- ]);
- if (response.status !== 200 || response.redirected) throw new HttpError("github_oidc_jwks_unavailable", 503);
- const contentLength = response.headers.get("Content-Length");
- if (contentLength && (!/^\d+$/.test(contentLength) || Number(contentLength) > ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_JWKS_BYTES)) {
- throw new HttpError("github_oidc_jwks_unavailable", 503);
- }
- const contentType = response.headers.get("Content-Type") || "";
- if (!/^application\/json(?:\s*;|$)/i.test(contentType)) throw new HttpError("github_oidc_jwks_unavailable", 503);
- const text = await readLimitedUtf8Body(response, ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_JWKS_BYTES, controller, abortPromise);
- const jwks = JSON.parse(text);
- if (!jwks || Array.isArray(jwks) || typeof jwks !== "object" || !Array.isArray(jwks.keys) || jwks.keys.length < 1 || jwks.keys.length > 16) {
- throw new HttpError("github_oidc_jwks_unavailable", 503);
- }
- return jwks.keys;
- } catch (error) {
- if (error instanceof HttpError) throw error;
- throw new HttpError("github_oidc_jwks_unavailable", 503);
- } finally {
- clearTimeout(timeout);
- controller.signal.removeEventListener("abort", onAbort);
- }
-}
-
-async function verifyGitHubProfileApplicationToken(request, env) {
- const workflowSha = env.ACCOUNT_SETTINGS_PROFILE_APPLICATION_WORKFLOW_SHA;
- if (typeof workflowSha !== "string" || !/^[a-f0-9]{40}$/.test(workflowSha)) {
- throw new HttpError("github_oidc_workflow_sha_not_configured", 503);
- }
- const authorization = request.headers.get("Authorization") || "";
- const match = /^Bearer ([A-Za-z0-9._~-]+)$/.exec(authorization);
- if (!match || match[1].length > ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_MAX_TOKEN_BYTES) {
- throw new HttpError("github_oidc_token_invalid", 401);
- }
- const parts = match[1].split(".");
- if (parts.length !== 3) throw new HttpError("github_oidc_token_invalid", 401);
- const header = decodeProfileApplicationJwtPart(parts[0], 2048).value;
- const claims = decodeProfileApplicationJwtPart(parts[1], 4096).value;
- const signature = decodeProfileApplicationJwtPart(parts[2], 1024, false).bytes;
- if (!header || Array.isArray(header) || typeof header !== "object"
- || header.alg !== "RS256" || header.typ !== "JWT"
- || typeof header.kid !== "string" || !/^[A-Za-z0-9._-]{1,128}$/.test(header.kid)
- || Object.hasOwn(header, "jku") || Object.hasOwn(header, "x5u") || Object.hasOwn(header, "crit")) {
- throw new HttpError("github_oidc_token_invalid", 401);
- }
- if (!claims || Array.isArray(claims) || typeof claims !== "object"
- || claims.iss !== "https://token.actions.githubusercontent.com"
- || claims.aud !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_AUDIENCE
- || claims.repository !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REPOSITORY
- || claims.ref !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_REF
- || claims.workflow_ref !== ACCOUNT_SETTINGS_PROFILE_APPLICATION_OIDC_WORKFLOW_REF
- || claims.workflow_sha !== workflowSha
- || Object.hasOwn(claims, "job_workflow_ref") || Object.hasOwn(claims, "job_workflow_sha")
- || claims.event_name !== "workflow_dispatch"
- || typeof claims.run_id !== "string" || !/^[1-9]\d{0,19}$/.test(claims.run_id)
- || typeof claims.run_attempt !== "string" || !/^[1-9]\d{0,5}$/.test(claims.run_attempt)) {
- throw new HttpError("github_oidc_token_invalid", 401);
- }
- const now = Math.floor(Date.now() / 1000);
- if (![claims.iat, claims.nbf, claims.exp].every(Number.isSafeInteger)
- || claims.iat > now + 30 || claims.iat < now - 600
- || claims.nbf > now + 30 || claims.nbf > claims.exp
- || claims.exp <= now || claims.exp <= claims.iat || claims.exp - claims.iat > 600) {
- throw new HttpError("github_oidc_token_invalid", 401);
- }
- const keys = await readGitHubProfileApplicationJwks();
- const matches = keys.filter((key) => key?.kid === header.kid);
- if (matches.length !== 1) throw new HttpError("github_oidc_token_invalid", 401);
- const jwk = matches[0];
- if (jwk.kty !== "RSA" || jwk.use !== "sig" || (jwk.alg && jwk.alg !== "RS256")
- || (jwk.key_ops !== undefined && (!Array.isArray(jwk.key_ops) || !jwk.key_ops.includes("verify")))
- || typeof jwk.n !== "string" || typeof jwk.e !== "string") {
- throw new HttpError("github_oidc_token_invalid", 401);
- }
- let valid = false;
- try {
- const publicKey = await crypto.subtle.importKey(
- "jwk", jwk, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"],
- );
- valid = await crypto.subtle.verify(
- "RSASSA-PKCS1-v1_5", publicKey, signature, new TextEncoder().encode(`${parts[0]}.${parts[1]}`),
- );
- } catch { throw new HttpError("github_oidc_token_invalid", 401); }
- if (!valid) throw new HttpError("github_oidc_token_invalid", 401);
- return { runId: claims.run_id, runAttempt: claims.run_attempt };
-}
-
-function accountSettingsProfileApplicationIsFixedHk(application) {
- const identity = application?.identity;
- return application?.platform === "longbridge" && application?.key === "hk"
- && accountSettingsIdentityIsComplete(identity)
- && identity.platform === "longbridge" && identity.key === "hk";
-}
-
-async function claimAccountSettingsProfileApplicationFromGitHub(request, env) {
- if (new URL(request.url).search || !hasRuntimeInstanceStore(env)) {
- return json({ ok: false, error: "account_settings_profile_application_unavailable", no_order: true, execution_authority_granted: false }, 503);
- }
- try {
- const run = await verifyGitHubProfileApplicationToken(request, env);
- const raw = await readGitHubProfileApplicationRequestBody(request);
- if (!ux1ExactKeys(raw, ["request_key"]) || !ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_KEY.test(String(raw.request_key || ""))) {
- return json({ ok: false, error: "account_settings_profile_application_request_invalid", no_order: true, execution_authority_granted: false }, 400);
- }
- const actor = "github-oidc-profile-application";
- const lookup = await runtimeInstanceCommand(env, {
- action: "account_settings_profile_application_lookup", actor, request_key: raw.request_key,
- });
- const application = lookup.application;
- if (!application) return json({ ok: false, error: "account_settings_profile_application_not_found", no_order: true, execution_authority_granted: false }, 404);
- if (!accountSettingsProfileApplicationIsFixedHk(application)) {
- return json({ ok: false, error: "account_settings_profile_application_target_conflict", no_order: true, execution_authority_granted: false }, 409);
- }
- const command = {
- action: "account_settings_profile_application_claim",
- actor,
- request_key: application.request_key,
- identity: application.identity,
- expected_instance_revision: application.instance_revision,
- expected_draft_revision: application.draft_revision,
- old_profile: application.old_profile,
- new_profile: application.new_profile,
- current_profile: application.old_profile,
- runtime_target_enabled: false,
- workflow_run_id: run.runId,
- workflow_run_attempt: run.runAttempt,
- };
- if (application.status === "claimed") {
- const replay = await runtimeInstanceCommand(env, command);
- return json({ ...replay, ok: true });
- }
- if (application.status !== "approved") {
- return json({ ok: false, error: "account_settings_profile_application_conflict", no_order: true, execution_authority_granted: false }, 409);
- }
- const observed = await runtimeInstanceCommand(env, {
- action: "account_settings_read", actor, platform: application.platform, key: application.key,
- });
- if (observed.instance_revision !== application.instance_revision
- || canonicalResearchTaskJson(observed.identity) !== canonicalResearchTaskJson(application.identity)) {
- return json({ ok: false, error: "account_settings_profile_application_identity_conflict", no_order: true, execution_authority_granted: false }, 409);
- }
- const draft = observed.draft;
- if (draft?.status !== "current" || draft.revision !== application.draft_revision
- || canonicalResearchTaskJson(draft.identity) !== canonicalResearchTaskJson(application.identity)
- || Object.keys(draft.overrides || {}).length !== 1
- || draft.overrides?.strategy_profile !== application.new_profile) {
- return json({ ok: false, error: "account_settings_profile_application_draft_conflict", no_order: true, execution_authority_granted: false }, 409);
- }
- const variableScope = resolveVariableScope(application.platform, observed.config);
- const githubEnvironment = resolveGithubEnvironment(application.platform, observed.config, variableScope);
- const repository = platformRepositories(env)?.[application.platform];
- if (repository !== "QuantStrategyLab/LongBridgePlatform"
- || variableScope !== "environment"
- || githubEnvironment !== "longbridge-hk") {
- return json({ ok: false, error: "account_settings_profile_application_target_conflict", no_order: true, execution_authority_granted: false }, 409);
- }
- const readback = await accountSettingsProfileRuntimeReadback(env, observed, {
- repository, variableScope, githubEnvironment,
- });
- if (!readback) return json({ ok: false, error: "account_settings_runtime_readback_unavailable", no_order: true, execution_authority_granted: false }, 503);
- if (readback.runtime_target_enabled !== "false" || readback.strategy_profile !== application.old_profile) {
- return json({ ok: false, error: "account_settings_profile_application_runtime_conflict", no_order: true, execution_authority_granted: false }, 409);
- }
- const claimed = await runtimeInstanceCommand(env, command);
- return json({ ...claimed, ok: true });
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return json({ ok: false, error: error instanceof HttpError ? error.message : "account_settings_profile_application_unavailable", no_order: true, execution_authority_granted: false }, status);
- }
-}
-
-async function readGitHubProfileApplicationRequestBody(request) {
- const contentLength = request.headers.get("Content-Length");
- if (contentLength && (!/^\d+$/.test(contentLength) || Number(contentLength) > ACCOUNT_SETTINGS_PROFILE_APPLICATION_MAX_BODY_BYTES)) {
- throw new HttpError("account_settings_profile_application_body_too_large", 413);
- }
- const controller = new AbortController();
- let rejectAbort = () => {};
- const abortPromise = new Promise((_, reject) => { rejectAbort = reject; });
- abortPromise.catch(() => {});
- const onAbort = () => rejectAbort(new HttpError("account_settings_profile_application_body_timeout", 408));
- controller.signal.addEventListener("abort", onAbort);
- const timeout = setTimeout(() => controller.abort(), ACCOUNT_SETTINGS_PROFILE_APPLICATION_REQUEST_TIMEOUT_MS);
- try {
- const text = await readLimitedUtf8Body(request, ACCOUNT_SETTINGS_PROFILE_APPLICATION_MAX_BODY_BYTES, controller, abortPromise);
- try { return JSON.parse(text); } catch { throw new HttpError("request body must be valid JSON", 400); }
- } catch (error) {
- if (error instanceof HttpError) throw error;
- if (String(error?.message || "") === "ux1_calculator_body_limit") {
- throw new HttpError("account_settings_profile_application_body_too_large", 413);
- }
- throw new HttpError("account_settings_profile_application_body_invalid", 400);
- } finally {
- clearTimeout(timeout);
- controller.signal.removeEventListener("abort", onAbort);
- }
-}
-
-function accountSettingsAuditChanges(before, after, requested) {
- const changes = [];
- const left = before?.draft?.overrides && typeof before.draft.overrides === "object" && !Array.isArray(before.draft.overrides) ? before.draft.overrides : {};
- const right = after?.draft?.overrides && typeof after.draft.overrides === "object" && !Array.isArray(after.draft.overrides) ? after.draft.overrides : {};
- const patch = requested?.overrides && typeof requested.overrides === "object" && !Array.isArray(requested.overrides) ? requested.overrides : {};
- const stored = (record, name) => Object.prototype.hasOwnProperty.call(record, name) ? record[name] : undefined;
- const asked = (name) => Object.prototype.hasOwnProperty.call(patch, name);
- if (["reserved_cash_floor", "reserved_cash_ratio"].some(asked) && ["reserved_cash_floor", "reserved_cash_ratio"].some((name) => stored(left, name) !== stored(right, name))) changes.push("cash_draft");
- if (asked("income_layer_enabled") && stored(left, "income_layer_enabled") !== stored(right, "income_layer_enabled")) changes.push("income_draft");
- if (asked("option_overlay_enabled") && stored(left, "option_overlay_enabled") !== stored(right, "option_overlay_enabled")) changes.push("option_draft");
- const strategyDraftChanged = (asked("strategy_profile") && stored(left, "strategy_profile") !== stored(right, "strategy_profile"))
- || ((asked("dca_mode") || asked("dca_base_investment_usd")) && ["dca_mode", "dca_base_investment_usd"].some((name) => stored(left, name) !== stored(right, name)));
- if (strategyDraftChanged) changes.push("strategy_draft");
- if (requested?.declaration && before?.declaration?.revision !== after?.declaration?.revision) changes.push("account_declaration_saved");
- const beforePreference = before?.risk?.preference || null;
- const afterPreference = after?.risk?.preference || null;
- if ((requested?.risk_change === "set" || requested?.risk_change === "clear") && beforePreference !== afterPreference) changes.push(afterPreference ? "risk_saved" : "risk_cleared");
- return changes;
-}
-
-async function buildAdminState(session, env) {
- const authConfig = await loadAuthConfig(env);
- const accountConfig = await loadAccountOptionsConfig(env);
- const riskProfileBindingState = await loadRiskProfileBindings(env);
- const runtimeInstances = hasRuntimeInstanceStore(env) ? await runtimeInstanceCommand(env) : null;
- let runtimeInstanceStrategies = [];
- if (runtimeInstances) {
- try {
- runtimeInstanceStrategies = (await loadStrategyProfilesConfig(env)).filter((item) => !isFrozenStrategyProfile(item) && (item.allowed_execution_modes || []).includes("dry_run")).map((item) => ({ profile: item.profile, label: item.label, domain: item.domain }));
- } catch {
- // Catalog failure affects draft authoring, never existing instance
- // readback, retirement requests, or `/api/admin/config` readback.
- }
- }
- return {
- ok: true,
- session: { login: session.login, admin: true },
- kvAvailable: hasConfigStore(env),
- authConfig,
- accountOptions: accountConfig.options || {},
- accountOptionSource: accountConfig.source,
- riskProfileBindings: riskProfileBindingState.bindings,
- riskProfileRevision: riskProfileBindingState.revision,
- riskProfileBindingsError: riskProfileBindingState.error,
- riskProfileBindingTargets: riskProfileBindingTargets(riskProfileBindingState.account_options || accountConfig.options || {}),
- auditLog: await loadAuditLog(env),
- runtimeInstances,
- runtimeInstanceStrategies,
- runtimeInstanceStrategiesAvailable: runtimeInstanceStrategies.length > 0,
- };
-}
-
-async function loadPlatformMeta(env = {}) {
- // Use the same bundled configuration as routing and capability validation.
- // Fetching GitHub main here could mix a newer catalog with an older Worker.
- const merged = Object.fromEntries(Object.entries(PLATFORM_META)
- .map(([platform, meta]) => [platform, { ...meta }]));
- const hidden = new Set(String(env.STRATEGY_SWITCH_HIDDEN_PLATFORMS || "")
- .split(",").map((value) => value.trim().toLowerCase()).filter(Boolean));
- for (const [platform, meta] of Object.entries(merged)) {
- meta.console_visible = !hidden.has(platform);
- }
- return merged;
-}
-
-// In-memory cache for the lifetime of this Worker isolate.
-let _memCurrentStrategies = null;
-let _memCurrentStrategiesTs = 0;
-let _memRefreshing = false; // prevent concurrent background refreshes
-
-// KV free tier caps writes at 1,000/day account-wide and the */5 cron plus every
-// background refresh reaches this helper, so a write is paid for only when the
-// rendered content changed or the stored entry needs its ts bumped to stay inside
-// the fresh window that cold isolates serve from.
-// current_strategies_cache carries per-account execution_evidence.observed_at
-// stamped with new Date() (see accountExecutionEvidence callers), so whole-payload
-// byte equality can never hold; the comparison drops those stamps and keeps the
-// stored value untouched for readers.
-
-// readConfigJson reports a damaged value as `STRATEGY_SWITCH_CONFIG. must be
-// valid JSON`. Only that shape is a cache miss; a KV read that failed for any other
-// reason is an outage and has to reach the caller instead of being mistaken for an
-// empty cache — the difference is what keeps cold isolates from fanning out to
-// GitHub on every request while the store is unhealthy.
-function isConfigJsonParseError(error) {
- return /^STRATEGY_SWITCH_CONFIG\.[^\s]+ must be valid JSON$/.test(String(error?.message || ""));
-}
-
-async function readCurrentStrategiesCacheEntry(env) {
- try {
- return await readConfigJson(env, CURRENT_STRATEGIES_CACHE_KEY);
- } catch (error) {
- if (!isConfigJsonParseError(error)) throw error;
- return null;
- }
-}
-
-async function writeCurrentStrategiesCache(env, payload, ts) {
- if (env.STRATEGY_SWITCH_RUNTIME_INSTANCES) {
- try {
- await directoryCommand(env, { action: "cache", payload, ts });
- return;
- } catch (error) {
- // Receiver-first compatibility only; a real storage failure remains loud.
- if (error.message !== "kv_directory_legacy_receiver" && error.message !== "kv_directory_invalid_request") throw error;
- }
- }
- const signature = currentStrategiesSignature(payload);
- // A damaged stored value must not wedge the cache; this is the only path that can
- // overwrite it, so the comparison reads through the same repair-aware helper.
- const cached = await readCurrentStrategiesCacheEntry(env);
- if (cached?.data && currentStrategiesSignature(cached.data) === signature
- && cached.ts && ts - cached.ts < CURRENT_STRATEGIES_KV_BUMP_MS) {
- return;
- }
- await writeConfigJson(env, CURRENT_STRATEGIES_CACHE_KEY, { ts, data: payload });
-}
-
-// loadCurrentStrategiesSafely answers with evidence-only account entries whenever
-// GitHub timed out or threw, so a payload whose every account is exactly that
-// shape carries no strategy information and must not be served as fresh.
-function isDegradedCurrentStrategies(payload) {
- const accounts = Object.values(payload || {}).flatMap(options => Object.values(options || {}));
- if (!accounts.length) return false;
- return accounts.every(account => account && typeof account === "object"
- && Object.keys(account).length === 1
- && account.execution_evidence?.status === "read_failed");
-}
-
-async function configPayload(request, env, ctx) {
- const session = await readSession(request, env);
- const meta = await loadPlatformMeta(env);
- if (!session?.allowed) return { accountOptions: null, platformMeta: meta };
- const accountConfig = await loadAccountOptionsConfig(env);
- const strategyProfiles = await loadStrategyProfilesConfig(env);
-
- const currentStrategies = await readCurrentStrategies(accountConfig.options, env, ctx);
-
- return {
- accountOptions: accountConfig.options,
- accountOptionsRevision: accountConfig.revision ?? null,
- runtimeDailyBindings: runtimeDailyReadModelEnabled(env) ? await runtimeDailyPublicBindings(env, accountConfig.options) : [],
- platformRepositories: platformRepositories(env),
- platformMeta: meta,
- strategyProfiles,
- currentStrategies,
- };
-}
-
-async function readCurrentStrategies(accountOptions, env, ctx) {
- let currentStrategies = null;
- let cacheFresh = false;
-
- // 1) In-memory cache
- if (_memCurrentStrategies) {
- const age = Date.now() - _memCurrentStrategiesTs;
- if (age < CURRENT_STRATEGIES_MEMO_TTL_MS) {
- currentStrategies = _memCurrentStrategies;
- cacheFresh = true;
- } else if (age < CURRENT_STRATEGIES_STALE_TTL_MS) {
- currentStrategies = _memCurrentStrategies;
- // stale — trigger background refresh below
- }
- }
-
- // 2) KV cache
- if (!currentStrategies && hasConfigStore(env)) {
- const cached = await readCurrentStrategiesCacheEntry(env);
- if (cached?.ts && cached.data) {
- const age = Date.now() - cached.ts;
- // A degraded entry stays inside the freshness window but is never *fresh*:
- // the next request must revalidate instead of serving a read_failed payload
- // for the whole 30 minutes.
- if (age < CURRENT_STRATEGIES_KV_FRESH_MS && !isDegradedCurrentStrategies(cached.data)) {
- currentStrategies = cached.data;
- cacheFresh = true;
- } else if (age < CURRENT_STRATEGIES_STALE_TTL_MS) {
- currentStrategies = cached.data;
- // stale — trigger background refresh below
- }
- if (currentStrategies && !_memCurrentStrategies) {
- _memCurrentStrategies = currentStrategies;
- _memCurrentStrategiesTs = cached.ts;
- }
- }
- }
-
- // 3) Background refresh when stale (return old data immediately)
- if (currentStrategies && !cacheFresh && !_memRefreshing && hasConfigStore(env) && ctx) {
- _memRefreshing = true;
- ctx.waitUntil((async () => {
- try {
- const fresh = await loadCurrentStrategiesSafely(accountOptions, env);
- _memCurrentStrategies = fresh;
- _memCurrentStrategiesTs = Date.now();
- await writeCurrentStrategiesCache(env, fresh, _memCurrentStrategiesTs);
- } catch { /* keep stale data */ }
- finally { _memRefreshing = false; }
- })());
- }
-
- // 4) Complete miss — must wait for GitHub
- if (!currentStrategies) {
- currentStrategies = await loadCurrentStrategiesSafely(accountOptions, env);
- _memCurrentStrategies = currentStrategies;
- _memCurrentStrategiesTs = Date.now();
- if (hasConfigStore(env) && ctx) {
- ctx.waitUntil(writeCurrentStrategiesCache(env, currentStrategies, _memCurrentStrategiesTs));
- }
- }
-
- return currentStrategies;
-}
-
-async function strategyProfilesPayload(env) {
- return {
- strategyProfiles: await loadStrategyProfilesConfig(env),
- platformMeta: await loadPlatformMeta(env),
- };
-}
-
-async function runtimeCatalogResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- // This is a generated gate catalog, not a deployment observation. Keeping
- // the distinction in the response makes it unsuitable as an accidental
- // substitute for the independently refreshed control-plane/evidence views.
- return json(RUNTIME_CATALOG_PROJECTION);
-}
-
-async function loadCurrentStrategies(accountOptions, env) {
- const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
- if (!token || !accountOptions) return executionEvidenceFallback(accountOptions, "not_connected");
- const repositories = platformRepositories(env);
-
- const variableCache = new Map();
- const readVariable = async (repository, scope, githubEnvironment, name) => {
- const cacheKey = [repository, scope, githubEnvironment || ""].join("|");
- if (!variableCache.has(cacheKey)) {
- variableCache.set(cacheKey, (async () => {
- let status = "ok";
- const values = await fetchGithubVariables(token, repository, scope, githubEnvironment, {
- reportReadErrors: true, onReadFailure: reason => { status = reason; },
- });
- return { values, status };
- })());
- }
- const result = await variableCache.get(cacheKey);
- return result.values?.get(name) || "";
- };
-
- readVariable.readStatus = async (repository, scope, githubEnvironment) =>
- (await variableCache.get([repository, scope, githubEnvironment || ""].join("|")))?.status || "ok";
- const currentStrategies = {};
- // Process platforms sequentially: each platform's account list is also
- // processed one at a time (not Promise.all). This keeps GitHub API
- // concurrency low enough to avoid secondary rate limiting.
- for (const platform of SUPPORTED_PLATFORMS) {
- const platformStrategies = await loadStrategiesForPlatform(platform, accountOptions, repositories, readVariable);
- if (Object.keys(platformStrategies).length) currentStrategies[platform] = platformStrategies;
- // 100ms gap between platforms to respect GitHub secondary rate limit
- await new Promise((r) => setTimeout(r, 100));
- }
- return currentStrategies;
-}
-
-async function loadStrategiesForPlatform(platform, accountOptions, repositories, readVariable) {
- const options = Array.isArray(accountOptions[platform]) ? accountOptions[platform] : [];
- if (!options.length) return {};
- const repository = repositories[platform];
- if (!repository) return executionEvidenceFallback({ [platform]: options }, "not_connected")[platform];
-
- // Process accounts sequentially within each platform to stay within
- // GitHub's concurrent request budget per token (~30 burst limit).
- const platformStrategies = {};
- for (const option of options) {
- let status = "ok";
- const trackedRead = async (...args) => {
- const value = await readVariable(...args);
- const result = await readVariable.readStatus?.(...args.slice(0, 3));
- if (result && result !== "ok") status = result;
- return value;
- };
- const current = await resolveCurrentStrategyForAccount({
- platform,
- option,
- optionsCount: options.length,
- repository,
- readVariable: trackedRead,
- });
- platformStrategies[option.key] = { ...current,
- execution_evidence: accountExecutionEvidence(option, current || {}, { status, observedAt: new Date().toISOString() }) };
- }
- return platformStrategies;
-}
-
-function executionEvidenceFallback(accountOptions, status) {
- return Object.fromEntries(Object.entries(accountOptions || {}).map(([platform, options]) => [platform,
- Object.fromEntries(options.map(option => [option.key, {
- execution_evidence: accountExecutionEvidence(option, {}, { status, observedAt: new Date().toISOString() }),
- }]))]));
-}
-
-async function loadCurrentStrategiesSafely(accountOptions, env) {
- try {
- return await withTimeout(
- loadCurrentStrategies(accountOptions, env),
- CURRENT_STRATEGIES_TIMEOUT_MS,
- executionEvidenceFallback(accountOptions, "read_failed"),
- );
- } catch {
- return executionEvidenceFallback(accountOptions, "read_failed");
- }
-}
-
-function withTimeout(promise, timeoutMs, fallback) {
- let timeoutId;
- const timeout = new Promise((resolve) => {
- timeoutId = setTimeout(() => resolve(fallback), timeoutMs);
- });
- return Promise.race([promise, timeout]).finally(() => clearTimeout(timeoutId));
-}
-
-async function fetchWithTimeout(resource, init = {}, timeoutMs = GITHUB_API_TIMEOUT_MS, fetchImpl = fetch) {
- const controller = new AbortController();
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
- try {
- return await fetchImpl(resource, { ...init, signal: controller.signal });
- } catch (error) {
- if (error?.name === "AbortError") throw new Error("GitHub request timed out");
- throw error;
- } finally {
- clearTimeout(timeoutId);
- }
-}
-
-async function resolveCurrentStrategyForAccount({ platform, option, optionsCount, repository, readVariable }) {
- const serviceTargetsValue = usesServiceTargetsAsRuntimeSource(platform)
- ? await readVariable(repository, "repository", "", "CLOUD_RUN_SERVICE_TARGETS_JSON")
- : "";
- const serviceTarget = runtimeTargetFromServiceTargets(serviceTargetsValue, platform, option);
- const serviceTargetProfile = cleanCurrentStrategy(serviceTarget?.strategy_profile);
- const serviceTargetReservedCashPayload = reservedCashPayloadFromObject(platform, serviceTarget);
- const serviceTargetIncomeLayerPayload = incomeLayerPayloadFromObject(serviceTarget);
- const serviceTargetOptionOverlayPayload = optionOverlayPayloadFromObject(serviceTarget);
- let serviceTargetRuntimeTargetEnabledPayload = runtimeTargetEnabledPayloadFromObject(serviceTarget);
- if (serviceTarget && !Object.keys(serviceTargetRuntimeTargetEnabledPayload).length) {
- const variableScope = resolveVariableScope(platform, option);
- serviceTargetRuntimeTargetEnabledPayload = await readRuntimeTargetEnabledVariable({
- repository, variableScope,
- githubEnvironment: resolveGithubEnvironment(platform, option, variableScope), readVariable,
- });
- }
- const serviceTargetDcaPayload = dcaPayloadFromObject(serviceTarget);
- const serviceTargetCashOnlyPayload = cashOnlyPayloadFromObject(platform, serviceTarget);
- if (serviceTargetProfile) {
- return {
- strategy_profile: serviceTargetProfile,
- ...runtimeModePayload(serviceTarget),
- strategy_execution: strategyTargetExecution(serviceTarget),
- ...serviceTargetReservedCashPayload,
- ...serviceTargetIncomeLayerPayload,
- ...serviceTargetOptionOverlayPayload,
- ...serviceTargetRuntimeTargetEnabledPayload,
- ...serviceTargetCashOnlyPayload,
- ...dcaPayloadForProfile(serviceTargetProfile, serviceTargetDcaPayload),
- source: "CLOUD_RUN_SERVICE_TARGETS_JSON",
- variable_scope: "repository",
- };
- }
- if (
- Object.keys(serviceTargetReservedCashPayload).length ||
- Object.keys(serviceTargetIncomeLayerPayload).length ||
- Object.keys(serviceTargetOptionOverlayPayload).length ||
- Object.keys(serviceTargetCashOnlyPayload).length ||
- Object.keys(serviceTargetRuntimeTargetEnabledPayload).length
- ) {
- return {
- ...runtimeModePayload(serviceTarget),
- strategy_execution: strategyTargetExecution(serviceTarget),
- ...serviceTargetReservedCashPayload,
- ...serviceTargetIncomeLayerPayload,
- ...serviceTargetOptionOverlayPayload,
- ...serviceTargetCashOnlyPayload,
- ...serviceTargetRuntimeTargetEnabledPayload,
- source: "CLOUD_RUN_SERVICE_TARGETS_JSON",
- variable_scope: "repository",
- };
- }
-
- const variableScope = resolveVariableScope(platform, option);
- const githubEnvironment = resolveGithubEnvironment(platform, option, variableScope);
- const reservedCashPayloadPromise = readReservedCashVariables({
- platform,
- repository,
- variableScope,
- githubEnvironment,
- readVariable,
- });
- const incomeLayerPayloadPromise = readIncomeLayerVariables({
- repository,
- variableScope,
- githubEnvironment,
- readVariable,
- });
- const optionOverlayPayloadPromise = readOptionOverlayVariables({
- repository,
- variableScope,
- githubEnvironment,
- readVariable,
- });
- const runtimeTargetEnabledPayloadPromise = readRuntimeTargetEnabledVariable({
- repository,
- variableScope,
- githubEnvironment,
- readVariable,
- });
- const dcaPayloadPromise = readDcaVariables({
- repository,
- variableScope,
- githubEnvironment,
- readVariable,
- });
- const cashOnlyPayloadPromise = readCashOnlyVariables({
- platform,
- repository,
- variableScope,
- githubEnvironment,
- readVariable,
- });
- // All fields share one scoped variable-list read; missing fields are not retried.
- const runtimeTargetValue = await readVariable(repository, variableScope, githubEnvironment, "RUNTIME_TARGET_JSON");
- const [
- reservedCashPayload,
- incomeLayerPayload,
- optionOverlayPayload,
- runtimeTargetEnabledPayload,
- dcaPayload,
- cashOnlyPayload,
- ] = await Promise.all([
- reservedCashPayloadPromise,
- incomeLayerPayloadPromise,
- optionOverlayPayloadPromise,
- runtimeTargetEnabledPayloadPromise,
- dcaPayloadPromise,
- cashOnlyPayloadPromise,
- ]);
- const runtimeTarget = parseJsonObject(runtimeTargetValue);
- const runtimeTargetMatches = runtimeTarget && runtimeTargetMatchesAccount(runtimeTarget, platform, option);
- const runtimeTargetProfile = runtimeTargetMatches ? cleanCurrentStrategy(runtimeTarget.strategy_profile) : "";
- if (runtimeTargetProfile) {
- let resumeTarget = null;
- if (platform === "binance" && repository === "QuantStrategyLab/BinancePlatform" && variableScope === "repository") {
- const values = { RUNTIME_TARGET_JSON: runtimeTargetValue };
- for (const name of ["RUNTIME_TARGET_ENABLED", "BINANCE_RECOVERY_CONTROL_ENABLED", "BINANCE_DRY_RUN", "STRATEGY_PROFILE", "CLOUD_RUN_SERVICE_TARGETS_JSON"]) {
- values[name] = await readVariable(repository, variableScope, githubEnvironment, name);
- }
- resumeTarget = await binanceResumeTarget(values, option);
- }
- return {
- strategy_profile: runtimeTargetProfile,
- ...(resumeTarget ? { binance_resume_target_sha256: resumeTarget.runtime_target_sha256 } : {}),
- ...runtimeModePayload(runtimeTarget),
- strategy_execution: strategyTargetExecution(runtimeTarget),
- ...reservedCashPayload,
- ...incomeLayerPayload,
- ...optionOverlayPayload,
- ...runtimeTargetEnabledPayload,
- ...dcaPayloadForProfile(runtimeTargetProfile, dcaPayload),
- ...cashOnlyPayload,
- source: "RUNTIME_TARGET_JSON",
- variable_scope: variableScope,
- github_environment: githubEnvironment || "",
- };
- }
-
- if (variableScope === "environment" || optionsCount <= 1) {
- const profileValue = await readVariable(repository, variableScope, githubEnvironment, "STRATEGY_PROFILE");
- const profile = cleanCurrentStrategy(profileValue);
- if (profile) {
- const current = {
- strategy_profile: profile,
- ...reservedCashPayload,
- ...incomeLayerPayload,
- ...optionOverlayPayload,
- ...runtimeTargetEnabledPayload,
- ...dcaPayloadForProfile(profile, dcaPayload),
- ...cashOnlyPayload,
- source: "STRATEGY_PROFILE",
- variable_scope: variableScope,
- github_environment: githubEnvironment || "",
- };
- if (variableScope === "environment" && normalizeMatchValue(option?.target_name) === "paper") {
- current.execution_mode = "paper";
- }
- return current;
- }
- }
-
- if (
- Object.keys(reservedCashPayload).length ||
- Object.keys(incomeLayerPayload).length ||
- Object.keys(optionOverlayPayload).length ||
- Object.keys(runtimeTargetEnabledPayload).length ||
- Object.keys(cashOnlyPayload).length
- ) {
- return {
- ...reservedCashPayload,
- ...incomeLayerPayload,
- ...optionOverlayPayload,
- ...runtimeTargetEnabledPayload,
- ...cashOnlyPayload,
- source: Object.keys(reservedCashPayload).length
- ? "RESERVED_CASH_VARIABLES"
- : (Object.keys(incomeLayerPayload).length
- ? "INCOME_LAYER_VARIABLES"
- : (Object.keys(runtimeTargetEnabledPayload).length
- ? "RUNTIME_TARGET_ENABLED_VARIABLE"
- : (Object.keys(optionOverlayPayload).length
- ? "OPTION_OVERLAY_VARIABLES"
- : "CASH_ONLY_EXECUTION_VARIABLE"))),
- variable_scope: variableScope,
- github_environment: githubEnvironment || "",
- };
- }
-
- return null;
-}
-
-function usesServiceTargetsAsRuntimeSource(platform) {
- return ["ibkr", "schwab", "firstrade"].includes(platform);
-}
-
-function logout(request) {
- requireSameOrigin(request, { requireOrigin: true });
- return json({ ok: true }, 200, {
- "Set-Cookie": clearCookie(SESSION_COOKIE),
- });
-}
-
-function hkStopSourceIdentity(config, item = {}) {
- const source = config || {};
- const selector = source.account_selector;
- const selectors = Array.isArray(selector)
- ? selector.map((value) => String(value).trim()).filter(Boolean)
- : String(selector || "").split(",").map((value) => value.trim()).filter(Boolean);
- const broker = source.broker_environment;
- return {
- key: String(source.key || item.key || ""),
- target_name: String(source.target_name || ""),
- platform_id: "longbridge",
- deployment_selector: String(source.deployment_selector || "").trim(),
- account_selector: selectors,
- account_scope: String(source.account_scope || "").trim(),
- service_name: String(source.service_name || "").trim(),
- variable_scope: source.variable_scope === "environment" ? "environment" : "",
- github_environment: String(source.github_environment || "").trim(),
- broker_environment: broker === "live" || broker === "paper" ? broker : null,
- runtime_status_target_id: String(source.runtime_status_target_id || "").trim(),
- };
-}
-
-function hkStopDigestOrEmpty(value) {
- return typeof value === "string" && /^[0-9a-f]{64}$/.test(value) ? value : "";
-}
-
-function hkStopExactObject(value, keys) {
- return Boolean(value) && !Array.isArray(value) && typeof value === "object"
- && Object.keys(value).length === keys.length
- && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
-}
-
-function normalizeHkStopResult(raw, env) {
- const expectedProject = env?.HK_STOP_GCP_PROJECT_ID;
- if (typeof expectedProject !== "string" || !/^[a-z][a-z0-9-]{4,61}[a-z0-9]$/.test(expectedProject)) {
- throw new HttpError("hk_stop_project_not_configured", 503);
- }
- const top = ["schema_version", "request_id", "source_revision", "source_identity_sha256", "target_id", "runtime_identity_sha256", "producer", "observed_at", "readback", "no_order", "in_flight_state", "retirement_complete"];
- const producerKeys = ["repository", "workflow_path", "run_id", "run_attempt", "head_sha"];
- const readbackKeys = ["project", "region", "service", "revision_name", "runtime_enabled", "scheduler_state", "scheduler_count", "scheduler_set_sha256", "complete"];
- if (!hkStopExactObject(raw, top)
- || raw.schema_version !== "qsl_hk_stop_result.v1"
- || !HK_STOP_REQUEST_ID.test(String(raw.request_id || ""))
- || !Number.isSafeInteger(raw.source_revision) || raw.source_revision < 0
- || !hkStopDigestOrEmpty(raw.source_identity_sha256) || !hkStopDigestOrEmpty(raw.runtime_identity_sha256)
- || raw.target_id !== HK_STOP_TARGET_ID
- || !hkStopExactObject(raw.producer, producerKeys)
- || raw.producer.repository !== "QuantStrategyLab/LongBridgePlatform"
- || raw.producer.workflow_path !== ".github/workflows/stop-hk-runtime.yml"
- || !/^(0|[1-9][0-9]*)$/.test(raw.producer.run_id)
- || raw.producer.run_attempt !== 1
- || !/^[0-9a-f]{40}$/.test(raw.producer.head_sha)
- || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/.test(raw.observed_at)
- || !hkStopExactObject(raw.readback, readbackKeys)
- || raw.readback.project !== expectedProject
- || raw.readback.region !== "asia-east2"
- || raw.readback.service !== "longbridge-quant-hk-service"
- || typeof raw.readback.revision_name !== "string"
- || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(raw.readback.revision_name)
- || raw.readback.runtime_enabled !== false
- || raw.readback.scheduler_state !== "paused"
- || !Number.isSafeInteger(raw.readback.scheduler_count) || raw.readback.scheduler_count < 1
- || !hkStopDigestOrEmpty(raw.readback.scheduler_set_sha256)
- || raw.readback.complete !== true
- || raw.no_order !== true
- || raw.in_flight_state !== "unknown"
- || raw.retirement_complete !== false) {
- throw new HttpError("hk_stop_result_rejected", 400);
- }
- return {
- schema_version: raw.schema_version,
- request_id: String(raw.request_id).toLowerCase(),
- source_revision: raw.source_revision,
- source_identity_sha256: raw.source_identity_sha256,
- target_id: raw.target_id,
- runtime_identity_sha256: raw.runtime_identity_sha256,
- producer: {
- repository: raw.producer.repository,
- workflow_path: raw.producer.workflow_path,
- run_id: raw.producer.run_id,
- run_attempt: raw.producer.run_attempt,
- head_sha: raw.producer.head_sha,
- },
- observed_at: raw.observed_at,
- readback: { ...raw.readback },
- no_order: true,
- in_flight_state: "unknown",
- retirement_complete: false,
- };
-}
-
-async function acceptHkStopResult(request, env) {
- requireDedicatedExecutionEvidenceSyncToken(request, env);
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const result = normalizeHkStopResult(await readBoundedJson(request, 8192), env);
- const recorded = await runtimeInstanceCommand(env, {
- action: "hk_stop_accept_result",
- result,
- now: new Date().toISOString(),
- });
- return json({
- ok: true,
- replayed: recorded.replayed === true,
- phase: "stopped",
- stop_confirmed: true,
- platform_applied: false,
- request_succeeded: false,
- in_flight_state: "unknown",
- });
-}
-
-function hkStopIdentityComplete(identity) {
- return identity?.key === "hk"
- && identity.target_name === "hk"
- && identity.platform_id === "longbridge"
- && identity.deployment_selector
- && identity.account_selector?.length
- && identity.account_scope === "HK"
- && identity.service_name === "longbridge-quant-hk-service"
- && identity.variable_scope === "environment"
- && identity.github_environment === "longbridge-hk";
-}
-
-function presentHkStop(record, observation, repository) {
- const dispatchResult = record?.dispatch_result || null;
- return {
- ok: true,
- configured: false,
- platform_applied: false,
- request_succeeded: false,
- stop_confirmed: record?.phase === "stopped",
- in_flight_state: "unknown",
- reused: record?.reused === true,
- persisted: record?.persisted !== false,
- request_id: record?.request_id || null,
- phase: record?.phase || null,
- dispatch_result: dispatchResult,
- action: record ? "stop" : null,
- requested_at: record?.requested_at || null,
- updated_at: record?.updated_at || null,
- workflow_run_id: null,
- workflow_run_attempt: null,
- actions_url: dispatchResult === "accepted"
- ? `https://github.com/${repository}/actions/workflows/manual-runtime-stop.yml`
- : null,
- runtime_observation: observation || { status: "unknown", request_succeeded: false },
- };
-}
-
-async function hkStopObservation() {
- // Lifecycle snapshots identify a target id, not this stop request's account.
- // A fresh disabled snapshot can belong to an older identity, so it stays unknown.
- return { status: "unknown", request_succeeded: false };
-}
-
-async function loadHkStopAccount(env) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const loaded = await loadAccountOptionsConfig(env);
- if (loaded.source !== "durable_object" || !Number.isSafeInteger(loaded.revision)) {
- throw new HttpError("hk_stop_source_unavailable", 409);
- }
- const matches = (loaded.options?.longbridge || []).filter((item) => item.key === "hk" && item.target_name === "hk");
- if (matches.length !== 1) throw new HttpError("stop requires one configured target", 400);
- const identity = hkStopSourceIdentity(matches[0], { key: "hk" });
- if (!hkStopIdentityComplete(identity)) throw new HttpError("hk_stop_identity_incomplete", 400);
- return { revision: loaded.revision, identity };
-}
-
-async function runtimeControlSource(env, platform, targetName) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const source = await loadAccountOptionsConfig(env);
- if (source.source !== "durable_object" || !Number.isSafeInteger(source.revision)) throw new HttpError("runtime_control_source_unavailable", 409);
- const matches = (source.options?.[platform] || []).filter(item => item.target_name === targetName);
- if (matches.length !== 1) throw new HttpError("runtime_control_identity_incomplete", 409);
- const item = matches[0];
- const identity = accountSettingsIdentity({ platform, key: item.key, config: item });
- if (!runtimeControlIdentityIsComplete(identity)) throw new HttpError("runtime_control_identity_incomplete", 409);
- return { item, identity, revision: source.revision };
-}
-
-function presentRuntimeControl(record) {
- let reason = null;
- try { reason = record?.result_json ? JSON.parse(record.result_json).reason || null : null; } catch { /* invalid persisted result stays unclassified */ }
- return { ok: record?.phase !== "rejected", request_id: record?.request_id || null, action: record?.action || null,
- phase: record?.phase || null, updated_at: record?.updated_at || null,
- unavailable_reason: reason || (record?.phase === "unknown" ? "runtime_control_result_unavailable" : null),
- platform_applied: record?.phase === "applied" };
-}
-
-async function readPlatformRuntimeControl(env, platform, targetName) {
- const source = await runtimeControlSource(env, platform, targetName);
- const args = { platform, key: source.item.key };
- let { record } = await runtimeInstanceCommand(env, { action: "runtime_control_read", ...args });
- if (record && ["reserved", "accepted", "unknown", "partial"].includes(record.phase)) {
- const result = await readRuntimeControlReceipt({ repository: env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY,
- token: env.RUNTIME_SETTINGS_DISPATCH_TOKEN, requestId: record.request_id, operation: record.action,
- runId: record.workflow_run_id, requestedAt: record.requested_at });
- if (result.run_id && !record.workflow_run_id) {
- ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_record", ...args,
- request_id: record.request_id, phase: "unknown", run_id: result.run_id }));
- }
- if (result.platform_run_id && record.workflow_run_id) {
- ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_capture", ...args,
- request_id: record.request_id, run_id: record.workflow_run_id, platform_run_id: result.platform_run_id, reason: result.reason }));
- }
- if (["applied", "partial", "protected", "rejected"].includes(result.status) && record.workflow_run_id) {
- ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_resolve", ...args,
- request_id: record.request_id, phase: result.status, run_id: record.workflow_run_id, reason: result.reason }));
- }
- }
- let details = {};
- try { details = JSON.parse(record?.result_json || "{}"); } catch { /* retain unknown */ }
- if (record && ["accepted", "unknown", "partial"].includes(record.phase) && details.check_id && !details.check_complete) {
- const checked = await readRuntimeControlReceipt({ repository: env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY,
- token: env.RUNTIME_SETTINGS_DISPATCH_TOKEN, requestId: record.request_id, operation: record.action,
- checkId: details.check_id, runId: details.check_run_id, requestedAt: details.check_requested_at });
- if (checked.run_id) {
- ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_record_check", ...args,
- request_id: record.request_id, check_id: details.check_id, run_id: checked.run_id, complete: checked.complete === true }));
- }
- if (["applied", "partial", "protected", "rejected"].includes(checked.status) && checked.complete
- && checked.platform_run_id === details.platform_run_id) {
- ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_resolve", ...args,
- request_id: record.request_id, phase: checked.status, run_id: record.workflow_run_id,
- check_id: details.check_id, check_run_id: checked.run_id, reason: checked.reason }));
- }
- }
- return presentRuntimeControl(record);
-}
-
-function runtimeControlStopRequest(env, platform, targetName, source) {
- const item = source.item;
- const inputs = { ...item, platform, target_name: targetName };
- const github = { repository: platformRepositories(env)[platform], variable_scope: resolvedVariableScope(item.variable_scope, inputs) };
- if (github.variable_scope === "environment") github.environment = item.github_environment;
- return { target_id: `${platform}/${targetName}`, github, runtime_target: {
- platform_id: platform, deployment_selector: source.identity.deployment_selector,
- account_selector: source.identity.account_selector.split(',').map(value => value.trim()).filter(Boolean),
- account_scope: source.identity.account_scope, service_name: source.identity.service_name,
- } };
-}
-
-async function dispatchPlatformControlReadback(env, raw) {
- if (raw.confirm !== "READ_ONLY" || !["ibkr", "schwab"].includes(raw.platform)
- || Object.keys(raw).some(key => !["platform", "target_name", "operation", "confirm"].includes(key))) throw new HttpError("runtime_control_request_invalid", 400);
- const targetName = cleanSlug(raw.target_name, "target_name");
- const source = await runtimeControlSource(env, raw.platform, targetName);
- const args = { platform: raw.platform, key: source.item.key };
- // Reconcile the original QRS run first. The platform run ID can only come
- // from its validated safe artifact and never from the client.
- await readPlatformRuntimeControl(env, raw.platform, targetName);
- let { record } = await runtimeInstanceCommand(env, { action: "runtime_control_read", ...args });
- if (!record || !["accepted", "unknown", "partial"].includes(record.phase)) return json(presentRuntimeControl(record));
- const checkId = crypto.randomUUID();
- const begun = await runtimeInstanceCommand(env, { action: "runtime_control_begin_check", ...args, request_id: record.request_id, check_id: checkId });
- if (begun.state !== "reserved") return json(presentRuntimeControl(begun.record));
- record = begun.record;
- const details = JSON.parse(record.result_json || "{}");
- let runId = null, rejected = false;
- try {
- const response = await fetchWithTimeout(`https://api.github.com/repos/${env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY}/actions/workflows/manual-runtime-stop.yml/dispatches`, {
- method: "POST", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN), body: JSON.stringify({ ref: "main", return_run_details: true,
- inputs: { stop_request: JSON.stringify(runtimeControlStopRequest(env, raw.platform, targetName, source)), apply: "false", confirm: "READ_ONLY", apply_hk_stop: "false",
- runtime_control_mode: "readback", runtime_control_operation: record.action, runtime_control_request_id: record.request_id,
- runtime_control_check_id: checkId, runtime_control_platform_run_id: details.platform_run_id } }),
- });
- if (response.status === 200) {
- const body = await response.json();
- if (Number.isSafeInteger(body.workflow_run_id) && body.workflow_run_id > 0) runId = String(body.workflow_run_id);
- } else if (response.status >= 400 && response.status < 500 && response.status !== 429) rejected = true;
- } catch { /* Readback outcome may be unknown; next explicit refresh reads the same check. */ }
- if (runId || rejected) ({ record } = await runtimeInstanceCommand(env, { action: "runtime_control_record_check", ...args,
- request_id: record.request_id, check_id: checkId, run_id: runId, complete: rejected, reason: rejected ? "readback_dispatch_rejected" : null }));
- return json(presentRuntimeControl(record));
-}
-
-async function dispatchPlatformRuntimeControl(env, raw) {
- if (raw.confirm !== "CONTROL_ONLY" || !["ibkr", "schwab"].includes(raw.platform)
- || !["enable", "disable"].includes(raw.operation)
- || Object.keys(raw).some(key => !["platform", "target_name", "operation", "request_id", "confirm"].includes(key))) throw new HttpError("runtime_control_request_invalid", 400);
- const targetName = cleanSlug(raw.target_name, "target_name");
- const requestId = raw.request_id || crypto.randomUUID();
- if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("runtime_control_request_invalid", 400);
- const source = await runtimeControlSource(env, raw.platform, targetName);
- const args = { platform: raw.platform, key: source.item.key };
- const claimed = await runtimeInstanceCommand(env, { action: "runtime_control_claim", ...args, identity: source.identity,
- source_revision: source.revision, request_id: requestId, operation: raw.operation });
- if (claimed.state !== "reserved") {
- const body = presentRuntimeControl(claimed.record);
- return json(claimed.state === "blocked" ? { ...body, ok: false, error: "runtime_control_pending" } : body, claimed.state === "blocked" ? 409 : 200);
- }
- const stopRequest = runtimeControlStopRequest(env, raw.platform, targetName, source);
- let phase = "unknown", runId = null;
- try {
- const response = await fetchWithTimeout(`https://api.github.com/repos/${env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY}/actions/workflows/manual-runtime-stop.yml/dispatches`, {
- method: "POST", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN), body: JSON.stringify({ ref: "main", return_run_details: true,
- inputs: { stop_request: JSON.stringify(stopRequest), apply: "true", confirm: "CONTROL_ONLY", apply_hk_stop: "false",
- runtime_control_operation: raw.operation, runtime_control_request_id: requestId } }),
- });
- if (response.status === 200) {
- const body = await response.json();
- if (Number.isSafeInteger(body.workflow_run_id) && body.workflow_run_id > 0) { phase = "accepted"; runId = String(body.workflow_run_id); }
- } else if (response.status >= 400 && response.status < 500 && response.status !== 429) phase = "rejected";
- } catch { /* Outcome may already have occurred; never resend. */ }
- try {
- const recorded = await runtimeInstanceCommand(env, { action: "runtime_control_record", ...args, request_id: requestId, phase, run_id: runId });
- return json(presentRuntimeControl(recorded.record), recorded.record?.phase === "rejected" ? 502 : 200);
- } catch { return json({ ...presentRuntimeControl(claimed.record), phase: "unknown" }); }
-}
-
-async function readRuntimeStop(request, env, url) {
- requireSameOrigin(request);
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- const platform = url.searchParams.get("platform");
- const targetName = url.searchParams.get("target_name");
- if (["ibkr", "schwab"].includes(platform) && targetName) return json(await readPlatformRuntimeControl(env, platform, targetName));
- if (platform !== "longbridge" || targetName !== "hk") {
- return json({
- ok: true, configured: false, platform_applied: false, request_succeeded: false,
- phase: null, runtime_observation: { status: "unknown", request_succeeded: false },
- });
- }
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const stored = await runtimeInstanceCommand(env, { action: "hk_stop_read" });
- const observation = await hkStopObservation(env, stored.record);
- const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
- return json(presentHkStop(stored.record, observation, repository));
-}
-
-async function dispatchHkRuntimeStop(env, raw) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const requestId = raw.request_id ? String(raw.request_id).trim().toLowerCase() : crypto.randomUUID();
- if (!HK_STOP_REQUEST_ID.test(requestId)) throw new HttpError("invalid_hk_stop_request_id", 400);
- const source = await loadHkStopAccount(env);
- const identity = source.identity;
- const identityJson = canonicalResearchTaskJson(identity);
- const runtimeJson = canonicalResearchTaskJson({
- platform_id: identity.platform_id,
- deployment_selector: identity.deployment_selector,
- account_selector: identity.account_selector,
- account_scope: identity.account_scope,
- service_name: identity.service_name,
- });
- const claimed = await runtimeInstanceCommand(env, {
- action: "hk_stop_claim",
- request_id: requestId,
- action_name: "stop",
- source_revision: source.revision,
- identity: source.identity,
- source_identity_sha256: await sha256Hex(identityJson),
- runtime_identity_sha256: await sha256Hex(runtimeJson),
- });
- const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
- if (claimed.state !== "reserved") {
- const observation = await hkStopObservation(env, claimed.record);
- const body = presentHkStop({ ...claimed.record, reused: true }, observation, repository);
- if (claimed.state === "blocked") return json({ ...body, ok: false, error: "hk_stop_request_pending" }, 409);
- return json(body);
- }
- const stored = claimed.record;
- const stopRequest = {
- target_id: HK_STOP_TARGET_ID,
- github: {
- repository: "QuantStrategyLab/LongBridgePlatform",
- variable_scope: "environment",
- environment: identity.github_environment,
- },
- runtime_target: {
- platform_id: "longbridge",
- deployment_selector: identity.deployment_selector,
- account_selector: identity.account_selector,
- account_scope: identity.account_scope,
- service_name: identity.service_name,
- },
- correlation: {
- request_id: stored.request_id,
- source_revision: stored.source_revision,
- source_identity_sha256: stored.source_identity_sha256,
- },
- };
- let outcome = "unknown";
- try {
- const response = await fetchWithTimeout(`https://api.github.com/repos/${repository}/actions/workflows/manual-runtime-stop.yml/dispatches`, {
- method: "POST",
- headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
- body: JSON.stringify({
- ref: env.RUNTIME_SETTINGS_REF || "main",
- inputs: {
- stop_request: JSON.stringify(stopRequest),
- apply: "true",
- confirm: "STOP_ONLY",
- apply_hk_stop: "true",
- },
- }),
- });
- if (response.status === 204) outcome = "accepted";
- else if (response.status >= 400 && response.status < 500) outcome = "rejected";
- } catch {
- outcome = "unknown";
- }
- try {
- const recorded = await runtimeInstanceCommand(env, {
- action: "hk_stop_record",
- request_id: claimed.record.request_id,
- phase: outcome,
- });
- const observation = await hkStopObservation(env, recorded.record);
- return json(presentHkStop(recorded.record, observation, repository));
- } catch {
- const observation = { status: "unknown", request_succeeded: false };
- return json(presentHkStop({ ...claimed.record, phase: "reserved", dispatch_result: null, persisted: false }, observation, repository));
- }
-}
-
-async function dispatchRuntimeStop(request, env) {
- requireEnv(env, "RUNTIME_SETTINGS_DISPATCH_TOKEN");
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- const raw = await request.json();
- if (raw && !Array.isArray(raw) && typeof raw === "object" && ["ibkr", "schwab"].includes(raw.platform) && raw.operation === "inspect")
- return await dispatchPlatformControlReadback(env, raw);
- if (raw && !Array.isArray(raw) && typeof raw === "object" && ["ibkr", "schwab"].includes(raw.platform) && raw.operation)
- return await dispatchPlatformRuntimeControl(env, raw);
- const hkStop = raw && !Array.isArray(raw) && raw.platform === "longbridge" && raw.target_name === "hk";
- const allowedKeys = hkStop ? ["platform", "target_name", "confirm", "request_id"] : ["platform", "target_name", "confirm"];
- if (!raw || Array.isArray(raw) || typeof raw !== "object"
- || Object.keys(raw).some((key) => !allowedKeys.includes(key))
- || raw.confirm !== "STOP_ONLY") {
- throw new HttpError("stop accepts only platform, target_name and STOP_ONLY confirmation", 400);
- }
- const platform = cleanChoice(raw.platform, SUPPORTED_PLATFORMS, "platform");
- const targetName = cleanSlug(raw.target_name, "target_name");
- if (platform === "longbridge" && targetName === "hk") return await dispatchHkRuntimeStop(env, raw);
- const accountConfig = await loadAccountOptionsConfig(env);
- const matches = (accountConfig.options?.[platform] || []).filter((item) => item.target_name === targetName);
- if (matches.length !== 1) throw new HttpError("stop requires one configured target", 400);
- // Derive routing only from protected account configuration, not form edits.
- // The workflow independently checks this identity against current variables.
- const inputs = { ...matches[0], platform, target_name: targetName };
- inputs.variable_scope = resolvedVariableScope(inputs.variable_scope, inputs);
- for (const field of ["deployment_selector", "account_scope", "account_selector", "service_name", "github_environment"]) {
- inputs[field] = inputs[field] || defaultInputValue(field, inputs);
- }
- const identity = {
- platform_id: platform,
- deployment_selector: inputs.deployment_selector,
- account_selector: String(inputs.account_selector || "").split(",").map((item) => item.trim()).filter(Boolean),
- account_scope: inputs.account_scope,
- service_name: inputs.service_name,
- };
- if (!identity.deployment_selector || !identity.account_selector.length || !identity.account_scope || !identity.service_name) {
- throw new HttpError("stop target identity is incomplete", 400);
- }
- const github = { repository: platformRepositories(env)[platform], variable_scope: inputs.variable_scope };
- if (github.variable_scope === "environment") github.environment = inputs.github_environment;
- const stopRequest = { target_id: `${platform}/${targetName}`, github, runtime_target: identity };
- const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
- const workflow = "manual-runtime-stop.yml";
- try {
- const response = await fetchWithTimeout(`https://api.github.com/repos/${repository}/actions/workflows/${workflow}/dispatches`, {
- method: "POST",
- headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
- body: JSON.stringify({
- ref: env.RUNTIME_SETTINGS_REF || "main",
- inputs: { stop_request: JSON.stringify(stopRequest), apply: "true", confirm: "STOP_ONLY" },
- }),
- });
- if (!response.ok) throw new Error("dispatch failed");
- } catch {
- return json({ ok: false, error: "stop dispatch unverified; check the existing run before retrying" }, 502);
- }
- return json({
- ok: true, configured: false, platform_applied: false,
- actions_url: `https://github.com/${repository}/actions/workflows/${workflow}`,
- });
-}
-
-async function binanceResumeTarget(values, option) {
- const target = parseJsonObject(values.RUNTIME_TARGET_JSON);
- const continuity = target?.live_continuity;
- if (values.RUNTIME_TARGET_ENABLED !== "false" || values.BINANCE_RECOVERY_CONTROL_ENABLED !== "true"
- || !["", "false"].includes(values.BINANCE_DRY_RUN || "")
- || !["", "crypto_live_pool_rotation"].includes(values.STRATEGY_PROFILE || "")
- || values.CLOUD_RUN_SERVICE_TARGETS_JSON
- || target?.platform_id !== "binance" || target.strategy_profile !== "crypto_live_pool_rotation"
- || target.execution_mode !== "live" || target.dry_run_only !== false
- || continuity?.baseline_kind !== "legacy_authorized"
- || !["RECONCILE_ONLY", "ACTIVE_LKG"].includes(continuity?.state)
- || typeof continuity.baseline_id !== "string" || !continuity.baseline_id.trim()
- || typeof continuity.captured_at !== "string" || !continuity.captured_at.trim()
- || !/^[a-f0-9]{64}$/.test(continuity.baseline_target_sha256 || "")) return null;
- const inputs = { ...option, platform: "binance" };
- const identity = { platform_id: "binance" };
- for (const field of ["deployment_selector", "account_selector", "account_scope", "service_name"]) {
- const value = inputs[field] || defaultInputValue(field, inputs);
- identity[field] = field === "account_selector"
- ? String(value || "").split(",").map((item) => item.trim()).filter(Boolean) : value;
- if (!value || JSON.stringify(identity[field]) !== JSON.stringify(target[field])) return null;
- }
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(values.RUNTIME_TARGET_JSON));
- return {
- runtime_target: identity,
- runtime_target_sha256: [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join(""),
- };
-}
-
-async function dispatchBinanceResume(request, env) {
- requireEnv(env, "RUNTIME_SETTINGS_DISPATCH_TOKEN");
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- const raw = await request.json();
- if (!raw || Array.isArray(raw) || typeof raw !== "object"
- || Object.keys(raw).some((key) => !["platform", "target_name", "runtime_target_sha256", "confirm"].includes(key))
- || raw.platform !== "binance" || raw.confirm !== "RESUME_EXISTING"
- || typeof raw.runtime_target_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(raw.runtime_target_sha256)) {
- throw new HttpError("resume accepts only the existing Binance target and RESUME_EXISTING confirmation", 400);
- }
- const config = await loadAccountOptionsConfig(env);
- const matches = (config.options?.binance || []).filter((item) => item.target_name === raw.target_name);
- const repository = platformRepositories(env).binance;
- if (matches.length !== 1 || repository !== "QuantStrategyLab/BinancePlatform"
- || resolvedVariableScope(matches[0].variable_scope, { ...matches[0], platform: "binance" }) !== "repository") {
- throw new HttpError("resume requires one configured Binance repository target", 400);
- }
- let target;
- try {
- const variables = await fetchGithubVariables(env.RUNTIME_SETTINGS_DISPATCH_TOKEN, repository, "repository", "");
- target = await binanceResumeTarget(Object.fromEntries(variables), matches[0]);
- } catch {
- return json({ ok: false, error: "resume source unavailable; no request submitted" }, 502);
- }
- if (!target || target.runtime_target_sha256 !== raw.runtime_target_sha256) {
- return json({ ok: false, error: "existing recovery configuration changed or unavailable; refresh before continuing" }, 409);
- }
- // Only the external switch is requested. The platform's private ACTIVE_LKG
- // validator remains mandatory; a console confirmation cannot activate it.
- const resumeRequest = { target_id: `binance/${matches[0].target_name}`,
- github: { repository, variable_scope: "repository" }, ...target };
- const settingsRepository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
- const workflow = "manual-binance-resume.yml";
- try {
- const response = await fetchWithTimeout(`https://api.github.com/repos/${settingsRepository}/actions/workflows/${workflow}/dispatches`, {
- method: "POST", headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
- body: JSON.stringify({ ref: "main", inputs: { resume_request: JSON.stringify(resumeRequest), apply: "true", confirm: "RESUME_EXISTING" } }),
- });
- if (!response.ok) throw new Error("dispatch failed");
- } catch {
- return json({ ok: false, error: "resume dispatch unverified; check the existing run before retrying" }, 502);
- }
- return json({ ok: true, configured: false, platform_applied: false,
- actions_url: `https://github.com/${settingsRepository}/actions/workflows/${workflow}` });
-}
-
-async function dispatchSwitch(request, env) {
- requireEnv(env, "RUNTIME_SETTINGS_DISPATCH_TOKEN");
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
-
- const rawInput = await request.json();
- const inputs = normalizeSwitchInputs(rawInput);
- assertSwitchIntent(inputs);
- if (inputs.live_continuity_state !== "NONE") {
- return json({
- ok: false,
- error: "legacy continuity recovery requires the private reconciliation recovery controller; manual switch cannot restore execution",
- }, 409);
- }
- const accountConfig = await loadAccountOptionsConfig(env);
- const accountOption = assertConfiguredAccount(inputs, accountConfig.options);
- assertStrategyAllowedForAccount(inputs, accountOption, await loadStrategyProfilesConfig(env));
- if (!SWITCH_ACTIVATION_CONNECTED) {
- return json({
- ok: false,
- error: "账户应用尚未接通,系统未提交变更",
- workflow_dispatched: false,
- }, 409);
- }
- const repository = env.RUNTIME_SETTINGS_REPO || DEFAULT_REPOSITORY;
- const workflow = env.RUNTIME_SETTINGS_WORKFLOW || DEFAULT_WORKFLOW;
- const apiUrl = `https://api.github.com/repos/${repository}/actions/workflows/${workflow}/dispatches`;
- const response = await fetchWithTimeout(apiUrl, {
- method: "POST",
- headers: githubHeaders(env.RUNTIME_SETTINGS_DISPATCH_TOKEN),
- body: JSON.stringify({
- ref: env.RUNTIME_SETTINGS_REF || "main",
- inputs,
- }),
- });
-
- if (!response.ok) {
- const text = await response.text();
- return json({ ok: false, error: `GitHub dispatch failed: ${text.slice(0, 600)}` }, 502);
- }
-
- return json({
- ok: true,
- repository,
- workflow,
- actions_url: `https://github.com/${repository}/actions/workflows/${workflow}`,
- account_options_sync: {
- synced: false,
- deferred: true,
- reason: "workflow_success_required",
- },
- inputs,
- });
-}
-
-async function syncDefaultStrategyForAccount(env, accountOptions, inputs, session) {
- if (hasRuntimeInstanceStore(env)) {
- try {
- await runtimeInstanceCommand(env, { action: "sync_defaults", actor: session?.login || "github-actions", inputs });
- return { synced: true, audit_logged: true };
- } catch (error) {
- return { synced: false, reason: error instanceof HttpError ? error.message : "runtime_instances_unavailable" };
- }
- }
- if (!hasConfigStore(env)) return { synced: false, reason: "kv_not_bound" };
- try {
- const { options, changed } = updateAccountOptionsDefaultStrategy(accountOptions, inputs);
- let auditLogged = false;
- if (changed) {
- await writeConfigJson(env, ACCOUNT_OPTIONS_KEY, validateAccountOptionsSchemaOrThrow(options));
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: session?.login || "",
- action: "sync_default_strategy",
- platform: inputs.platform,
- target_name: inputs.target_name,
- strategy_profile: inputs.strategy_profile,
- });
- auditLogged = true;
- } catch {
- auditLogged = false;
- }
- }
- return { synced: true, changed, audit_logged: auditLogged };
- } catch (error) {
- return { synced: false, error: error.message || "account option sync failed" };
- }
-}
-
-async function syncAccountDefaultResponse(request, env) {
- requireInternalSyncToken(request, env);
- let rawInput;
- try {
- rawInput = await request.json();
- } catch {
- return json({ ok: false, error: "request body must be valid JSON" }, 400);
- }
- let inputs;
- try {
- inputs = normalizeSwitchInputs(rawInput);
- } catch (error) {
- if (isFrozenStrategyProfile({ profile: rawInput?.strategy_profile })) {
- throw new HttpError("frozen strategy requires valid continuity input", 409);
- }
- throw error;
- }
- const accountConfig = await loadAccountOptionsConfig(env);
- const strategyProfiles = await loadStrategyProfilesConfig(env);
- const strategy = strategyProfiles.find((item) => sameStrategyProfile(item.profile, inputs.strategy_profile));
- if (!strategy) throw new Error(`strategy ${inputs.strategy_profile} is not configured`);
-
- let accountOptions = accountConfig.options;
- let accountOption = configuredAccountForInputs(inputs, accountOptions);
- let registeredLegacyContinuityAccount = false;
- if (!accountOption) {
- if (isFrozenStrategyProfile(strategy)) throw new HttpError(`strategy ${inputs.strategy_profile} is frozen for new selection`, 409);
- if (hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instance_registration_requires_management", 409);
- const registration = registerLegacyContinuityAccount(env, accountOptions, inputs, strategy);
- accountOptions = registration.options;
- accountOption = registration.account;
- registeredLegacyContinuityAccount = registration.registered;
- if (registeredLegacyContinuityAccount) {
- await writeConfigJson(env, ACCOUNT_OPTIONS_KEY, validateAccountOptionsSchemaOrThrow(accountOptions));
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "github-actions",
- action: "register_legacy_continuity_account",
- platform: inputs.platform,
- target_name: inputs.target_name,
- strategy_profile: inputs.strategy_profile,
- live_continuity_state: inputs.live_continuity_state,
- });
- } catch {
- // The routing registration is still valid if its non-critical audit
- // append fails; callers receive the registration result below.
- }
- }
- }
- if (!accountOption) throw new Error("switch inputs do not match configured account options");
- if (isFrozenStrategyProfile(strategy) && !sameStrategyProfile(accountOption.default_strategy_profile, inputs.strategy_profile)) {
- throw new HttpError(`strategy ${inputs.strategy_profile} requires an existing matching account default`, 409);
- }
- assertStrategyAllowedForAccount(inputs, accountOption, strategyProfiles);
- const result = await syncDefaultStrategyForAccount(env, accountOptions, inputs, {
- login: "github-actions",
- });
- const kvSyncSkipped = result.reason === "kv_not_bound";
- const accountOptionsSync = kvSyncSkipped ? { ...result, skipped: true } : result;
- return json(
- {
- ok: result.synced || kvSyncSkipped,
- account_options_sync: accountOptionsSync,
- legacy_continuity_account_registered: registeredLegacyContinuityAccount,
- },
- result.synced || kvSyncSkipped ? 200 : 500,
- );
-}
-
-function requireInternalSyncToken(request, env) {
- const expected = env.STRATEGY_SWITCH_SYNC_TOKEN || env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
- if (!expected) throw new HttpError("internal sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("internal sync token is invalid", 401);
-}
-
-async function syncStrategyProfilesResponse(request, env) {
- requireInternalSyncToken(request, env);
- const result = await syncStrategyProfilesConfig(env, { login: "github-actions" });
- const kvSyncSkipped = result.reason === "kv_not_bound";
- const strategyProfilesSync = kvSyncSkipped ? { ...result, skipped: true } : result;
- return json(
- {
- ok: result.synced || kvSyncSkipped,
- strategy_profiles_sync: strategyProfilesSync,
- strategy_profiles_count: result.count,
- },
- result.synced || kvSyncSkipped ? 200 : 500,
- );
-}
-
-async function syncStrategyHealthResponse(request, env) {
- requireDedicatedStrategyHealthSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "strategy health KV is not configured" }, 503);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, STRATEGY_HEALTH_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid strategy health payload" }, error.status || 400);
- }
-
- let snapshot;
- try {
- snapshot = normalizeStrategyHealthSnapshot(raw, "strategy health snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid strategy health payload" }, 400);
- }
-
- await writeConfigJson(env, STRATEGY_HEALTH_SNAPSHOT_KEY, snapshot);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "strategy-health-sync",
- action: "sync_strategy_health",
- schema_version: snapshot.schema_version,
- strategy_count: snapshot.summary.strategy_count,
- data_status: snapshot.data_status,
- });
- } catch {
- // Snapshot delivery remains successful; audit data must never expose the payload.
- }
- return json({
- ok: true,
- schema_version: snapshot.schema_version,
- strategy_count: snapshot.summary.strategy_count,
- generated_at: snapshot.generated_at,
- });
-}
-
-async function strategyHealthResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json(emptyStrategyHealthPayload("snapshot_unavailable"));
-
- let snapshot;
- try {
- const stored = await readConfigJson(env, STRATEGY_HEALTH_SNAPSHOT_KEY);
- if (!stored) return json(emptyStrategyHealthPayload("snapshot_unavailable"));
- snapshot = normalizeStrategyHealthSnapshot(stored, STRATEGY_HEALTH_SNAPSHOT_KEY);
- } catch {
- return json(emptyStrategyHealthPayload("snapshot_invalid"));
- }
-
- const ttlSeconds = strategyHealthStaleTtlSeconds(env);
- const freshnessTimestamps = [snapshot.generated_at, snapshot.computed_at]
- .filter(Boolean)
- .map((value) => Date.parse(value));
- const freshnessAt = freshnessTimestamps.length ? Math.min(...freshnessTimestamps) : Number.NaN;
- const now = Date.now();
- const futureBeyondClockSkew = Number.isFinite(freshnessAt) && freshnessAt > now + 5 * 60 * 1000;
- const ageSeconds = futureBeyondClockSkew
- ? Number.POSITIVE_INFINITY
- : Number.isFinite(freshnessAt)
- ? Math.max(0, (now - freshnessAt) / 1000)
- : Number.POSITIVE_INFINITY;
- if (["ready", "partial"].includes(snapshot.data_status) && ageSeconds > ttlSeconds) {
- snapshot.data_status = "stale";
- }
- return json(snapshot);
-}
-
-async function humanDecisionRequestKey({ requestId, kind, actor, subjectId, materialKey, action, target }) {
- if (requestId !== undefined && requestId !== null && requestId !== "") {
- const text = String(requestId).trim();
- if (!/^[A-Za-z0-9._:-]{1,128}$/.test(text)) throw new HttpError("invalid request_id", 400);
- return `id:${kind}:${text}`;
- }
- const digest = await calculateOwnerDecisionSha256({
- actor, kind, subject_id: subjectId, material_key: materialKey, action, target: target || null,
- });
- return `fp:${digest}`;
-}
-
-async function researchPromotionMaterialKey(ticket) {
- return calculateOwnerDecisionSha256({
- ticket_id: ticket.ticket_id,
- strategy_profile: ticket.strategy_profile,
- domain: ticket.domain,
- proposed_params: ticket.proposed_params,
- shadow_passed: ticket.shadow_passed,
- shadow_evidence_kind: ticket.shadow_evidence_kind,
- });
-}
-
-// The legacy six-field material key remains the durable terminal index. This
-// independent versioned snapshot binds all saved producer review content without
-// rekeying historical records or hashing post-decision/observation-only fields.
-function researchPromotionReviewMaterial(ticket) {
- return {
- schema_version: "qsl_promotion_review_material.v2",
- ticket_id: ticket.ticket_id, strategy_profile: ticket.strategy_profile, domain: ticket.domain,
- proposed_params: ticket.proposed_params, shadow_passed: ticket.shadow_passed,
- shadow_evidence_kind: ticket.shadow_evidence_kind,
- drift_status: ticket.drift_status, drift_score: ticket.drift_score,
- budget: ticket.budget, search_iterations: ticket.search_iterations,
- suggested_risk_profile: ticket.suggested_risk_profile,
- notification_subject: ticket.notification_subject, notification_body: ticket.notification_body,
- notes: ticket.notes, research_summary: ticket.research_summary || null,
- };
-}
-const RESEARCH_PROMOTION_REVIEW_INVALID = "research_promotion_review_material_invalid";
-class ResearchPromotionReviewMaterialError extends HttpError {
- constructor() { super(RESEARCH_PROMOTION_REVIEW_INVALID, 400); }
-}
-async function researchPromotionReviewBinding(ticket) {
- let canonical;
- try {
- canonical = canonicalResearchTaskJson(researchPromotionReviewMaterial(ticket));
- } catch (error) {
- // Only canonical data validation is recoverable per ticket. Hash/storage
- // failures must not be relabelled as invalid material or a healthy queue.
- if (error?.message === "research task must use finite JSON values"
- || error?.message === "research task must use JSON values") throw new ResearchPromotionReviewMaterialError();
- throw error;
- }
- return { schema_version: "qsl_promotion_review_binding.v2", review_sha256: await sha256Hex(canonical) };
-}
-function promotionReviewBindingsMatch(left, right) {
- return left?.schema_version === "qsl_promotion_review_binding.v2" && right?.schema_version === left.schema_version
- && /^[0-9a-f]{64}$/.test(left.review_sha256) && left.review_sha256 === right.review_sha256;
-}
-function promotionMaterialReviewBinding(row) {
- try {
- const binding = JSON.parse(row?.summary_json || "{}").review_binding;
- return promotionReviewBindingsMatch(binding, binding) ? { schema_version: "qsl_promotion_review_binding.v2", review_sha256: binding.review_sha256 } : null;
- } catch { return null; }
-}
-
-async function recoveryDecisionMaterialKey(recovery) {
- if (recovery.mode === "initial_enrollment") return calculateOwnerDecisionSha256({
- mode: recovery.mode, recovery_id: recovery.recovery_id,
- candidate_sha256: recovery.candidate?.candidate_sha256 || recovery.candidate_sha256,
- facts_sha256: recovery.candidate?.facts_sha256 || recovery.facts_sha256,
- });
- return calculateOwnerDecisionSha256({
- recovery_id: recovery.recovery_id,
- candidate_sha256: recovery.candidate_sha256,
- dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
- });
-}
-
-async function mirrorConfigJson(env, key, value) {
- try {
- await writeConfigJson(env, key, value);
- return true;
- } catch {
- return false;
- }
-}
-
-async function readLegacyConfig(env, key) {
- try {
- return { value: await readConfigJson(env, key), blocked: false, unreadable: false };
- } catch (error) {
- if (String(error?.message || "").includes("must be valid JSON")) return { value: null, blocked: true, unreadable: false };
- return { value: null, blocked: false, unreadable: true };
- }
-}
-
-function humanDecisionTimestamp(value) {
- return String(value || new Date().toISOString()).replace(/\.\d{3}Z$/, "Z");
-}
-
-// Actionable material expires when the evidence that produced it would itself be
-// stale. A missing or future-dated anchor yields null, which callers treat as
-// "not actionable" rather than inventing authority.
-function controlPlaneDecisionExpiryAt(snapshot, ttlSeconds, now = Date.now()) {
- const timestamps = [snapshot?.generated_at, snapshot?.computed_at]
- .filter(Boolean)
- .map((value) => Date.parse(value))
- .filter((value) => Number.isFinite(value));
- if (!timestamps.length) return null;
- const observedAt = Math.min(...timestamps);
- if (observedAt > now + 5 * 60 * 1000) return null;
- return observedAt + ttlSeconds * 1000;
-}
-
-function reconciliationRecoveryDecisionExpiryAt(recovery, source, ttlSeconds, now = Date.now()) {
- const sourceExpiry = controlPlaneDecisionExpiryAt(source, ttlSeconds, now);
- if (sourceExpiry == null) return null;
- const observedAt = Date.parse(recovery.mode === "initial_enrollment"
- ? recovery.candidate?.last_observed_at
- : recovery.last_observed_at);
- if (!Number.isFinite(observedAt) || observedAt > now + 5 * 60 * 1000) return null;
- return Math.min(sourceExpiry, observedAt + ttlSeconds * 1000);
-}
-
-async function publishHumanOwnerMaterials(env, snapshot, sourceId) {
- const ownerCandidates = (snapshot.candidates || []).filter(isOwnerDecisionCandidate);
- if (!ownerCandidates.length && !hasRuntimeInstanceStore(env)) return { ok: true, skipped: true };
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const expiresAtMs = controlPlaneDecisionExpiryAt(snapshot, controlPlaneStaleTtlSeconds(env));
- const grouped = new Map();
- for (const candidate of ownerCandidates) {
- const list = grouped.get(candidate.candidate_id) || [];
- list.push(candidate);
- grouped.set(candidate.candidate_id, list);
- }
- const materials = [];
- const duplicateSubjectIds = [];
- for (const [subjectId, list] of grouped) {
- if (list.length > 1) duplicateSubjectIds.push(subjectId);
- const candidate = list[0];
- const materialKey = await ownerDecisionCandidateEvidenceSha256(candidate);
- const legacyRead = await readLegacyConfig(env, ownerDecisionCurrentKey(subjectId));
- if (legacyRead.unreadable) throw new HttpError("human_decision_legacy_unreadable", 503);
- let legacy = null;
- if (legacyRead.blocked) legacy = { blocked: true };
- else if (legacyRead.value) {
- try {
- const intent = await normalizeOwnerDecisionIntent(legacyRead.value, ownerDecisionCurrentKey(subjectId));
- if (intent.candidate_id !== subjectId || intent.candidate_evidence_sha256 !== materialKey) legacy = { blocked: true };
- else {
- legacy = {
- record: {
- action: intent.decision,
- actor: intent.decided_by,
- decided_at: intent.decided_at,
- material_key: materialKey,
- target_json: canonicalResearchTaskJson({ decision: intent.decision }),
- payload: intent,
- },
- };
- }
- } catch {
- legacy = { blocked: true };
- }
- }
- materials.push({
- subject_id: subjectId,
- material_key: materialKey,
- summary_json: JSON.stringify({ candidate_id: subjectId }),
- eligible: list.length === 1 && candidate.freshness?.status === "fresh",
- expires_at_ms: expiresAtMs,
- legacy,
- });
- }
- return runtimeInstanceCommand(env, {
- action: "owner_sync_materials",
- actor: "control-plane-sync",
- source_id: sourceId,
- updated_at: humanDecisionTimestamp(),
- now_ms: Date.now(),
- replace_source: true,
- materials,
- duplicate_subject_ids: duplicateSubjectIds,
- });
-}
-
-function recoveryMaterialEligible(recovery, sourceFreshness, evidenceFreshness) {
- if (recovery.mode === "initial_enrollment") return sourceFreshness?.data_status === "ready" && evidenceFreshness?.data_status === "ready"
- && Object.values(recovery.candidate.coverage).every(status => status === "complete");
- return sourceFreshness?.data_status === "ready"
- && evidenceFreshness?.data_status === "ready"
- && recovery.readiness === "awaiting_human_confirmation"
- && recovery.reconciliation_state === "RECONCILE_ONLY"
- && !recovery.blocker_codes.length
- && recovery.dual_review.evidence_binding_sha256 === recovery.candidate_sha256
- && recovery.evidence_sample_count >= 1;
-}
-
-async function publishHumanRecoveryMaterials(env, source) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const ttlSeconds = reconciliationRecoveryStaleTtlSeconds(env);
- const now = Date.now();
- const sourceFreshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
- const grouped = new Map();
- for (const recovery of source.recoveries || []) {
- const list = grouped.get(recovery.recovery_id) || [];
- list.push(recovery);
- grouped.set(recovery.recovery_id, list);
- }
- const materials = [];
- const duplicateSubjectIds = [];
- for (const [subjectId, list] of grouped) {
- if (list.length > 1) duplicateSubjectIds.push(subjectId);
- const recovery = list[0];
- const evidenceFreshness = reconciliationRecoveryEvidenceFreshness(recovery, sourceFreshness, ttlSeconds, now);
- const materialKey = await recoveryDecisionMaterialKey(recovery);
- const legacyRead = recovery.mode === "initial_enrollment" ? { unreadable: false, blocked: false, value: null }
- : await readLegacyConfig(env, reconciliationRecoveryConfirmationCurrentKey(subjectId));
- if (legacyRead.unreadable) throw new HttpError("human_decision_legacy_unreadable", 503);
- let legacy = null;
- if (legacyRead.blocked) legacy = { blocked: true };
- else if (legacyRead.value) {
- try {
- const confirmation = await normalizeReconciliationRecoveryConfirmation(legacyRead.value, reconciliationRecoveryConfirmationCurrentKey(subjectId));
- if (confirmation.recovery_id !== subjectId || confirmation.candidate_sha256 !== recovery.candidate_sha256 || confirmation.dual_review_binding_sha256 !== recovery.dual_review.evidence_binding_sha256) {
- legacy = { blocked: true };
- } else {
- legacy = {
- record: {
- action: "approve",
- actor: confirmation.confirmed_by,
- decided_at: confirmation.confirmed_at,
- material_key: materialKey,
- target_json: canonicalResearchTaskJson({ decision: "approve" }),
- payload: confirmation,
- },
- };
- }
- } catch {
- legacy = { blocked: true };
- }
- }
- materials.push({
- subject_id: subjectId,
- material_key: materialKey,
- summary_json: JSON.stringify({ recovery_id: subjectId }),
- eligible: list.length === 1 && recoveryMaterialEligible(recovery, sourceFreshness, evidenceFreshness),
- expires_at_ms: reconciliationRecoveryDecisionExpiryAt(recovery, source, ttlSeconds, now),
- legacy,
- });
- }
- return runtimeInstanceCommand(env, {
- action: "recovery_sync_materials",
- actor: "reconciliation-recovery-source-sync",
- source_id: source.source_id,
- updated_at: humanDecisionTimestamp(),
- now_ms: Date.now(),
- replace_source: true,
- materials,
- duplicate_subject_ids: duplicateSubjectIds,
- });
-}
-
-async function publishHumanPromotionMaterial(env, ticket, existing) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const materialKey = await researchPromotionMaterialKey(ticket);
- let legacy = null;
- if (existing && (existing.state === "human_accepted" || existing.state === "human_rejected")) {
- const existingKey = await researchPromotionMaterialKey(existing);
- const actor = String(existing.human_decision_actor || "").trim();
- if (!actor || !existing.human_decided_at || existingKey !== materialKey) legacy = { blocked: true };
- else {
- legacy = {
- record: {
- action: existing.state === "human_accepted" ? "accept" : "reject",
- actor,
- decided_at: existing.human_decided_at,
- material_key: materialKey,
- target_json: canonicalResearchTaskJson({
- selected_account: existing.selected_account || null,
- confirmation: {
- target_platform: existing.confirmation_target_platform,
- execution_mode: existing.confirmation_execution_mode,
- risk_profile: existing.confirmation_risk_profile,
- },
- }),
- payload: { ticket: existing, selected_account: existing.selected_account || null, proposed_params: existing.proposed_params },
- },
- };
- }
- }
- return runtimeInstanceCommand(env, {
- action: "promotion_sync_materials",
- actor: "research-promotion-ticket-sync",
- source_id: "research-promotion",
- updated_at: humanDecisionTimestamp(),
- now_ms: Date.now(),
- replace_source: false,
- materials: [{
- subject_id: ticket.ticket_id,
- material_key: materialKey,
- summary_json: JSON.stringify({
- ticket_id: ticket.ticket_id,
- strategy_profile: ticket.strategy_profile,
- domain: ticket.domain,
- review_binding: await researchPromotionReviewBinding(ticket),
- }),
- eligible: true,
- expires_at_ms: Date.now() + controlPlaneStaleTtlSeconds(env) * 1000,
- legacy,
- }],
- });
-}
-
-// A fixed projection of the durable terminal record, never a request echo or KV fallback.
-async function humanDecisionReceipt(record, expected) {
- const invalid = () => { throw new HttpError("human_decision_receipt_unavailable", 503); };
- const text = (value, max) => typeof value === "string" && value.length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
- const actions = { owner: ["approve_limited_live_canary", "keep_parked"], recovery: ["approve", "reject"], promotion: ["accept", "reject"] };
- if (!record || !actions[record.kind]?.includes(record.action) || !text(record.subject_id, 256)
- || !/^[0-9a-f]{64}$/.test(record.material_key) || !text(record.actor, 100)
- || !text(record.decided_at, 40) || !Number.isFinite(Date.parse(record.decided_at))
- || record.kind !== expected.kind || record.subject_id !== expected.subject_id || record.material_key !== expected.material_sha256) invalid();
- let target;
- try { target = JSON.parse(record.target_json); } catch { invalid(); }
- let projection;
- if (record.kind === "promotion") {
- const account = target?.selected_account;
- const confirmation = target?.confirmation;
- if (account != null && (!SUPPORTED_PLATFORMS.includes(account.platform) || !text(account.key, 128))) invalid();
- if (confirmation != null && (!SUPPORTED_PLATFORMS.includes(confirmation.target_platform)
- || !["live", "paper", "dry_run"].includes(confirmation.execution_mode)
- || !RESEARCH_PROMOTION_RISK_PROFILES.includes(confirmation.risk_profile))) invalid();
- if (record.action === "accept" && (!account || !confirmation || account.platform !== confirmation.target_platform)) invalid();
- if (record.payload?.ticket?.live_authority_granted !== false || record.payload?.ticket?.human_decision !== record.action
- || record.payload?.ticket?.ticket_id !== record.subject_id || record.payload.ticket.human_decided_at !== record.decided_at
- || await researchPromotionMaterialKey(record.payload.ticket) !== record.material_key
- || canonicalResearchTaskJson(record.payload.selected_account ?? null) !== canonicalResearchTaskJson(account ?? null)
- || canonicalResearchTaskJson(record.payload.confirmation ?? null) !== canonicalResearchTaskJson(confirmation ?? null)) invalid();
- projection = {
- selected_account: account ? { platform: account.platform, key: account.key } : null,
- confirmation: confirmation ? { target_platform: confirmation.target_platform, execution_mode: confirmation.execution_mode, risk_profile: confirmation.risk_profile } : null,
- };
- } else {
- if (target?.decision !== record.action || record.payload?.no_order !== true || record.payload?.execution_authority_granted !== false) invalid();
- const payload = record.payload;
- if (record.kind === "owner") {
- if (payload.schema_version !== "qsl_owner_decision_intent.v1" || payload.candidate_id !== record.subject_id
- || payload.candidate_evidence_sha256 !== record.material_key || payload.decision !== record.action
- || payload.decided_by !== record.actor || payload.decided_at !== record.decided_at
- || payload.decision_sha256 !== await calculateOwnerDecisionSha256(payload)) invalid();
- } else if (payload.mode === "initial_enrollment") {
- const approval = record.action === "approve";
- if (payload.schema_version !== (approval ? "qsl_initial_enrollment_confirmation.v1" : "qsl_initial_enrollment_rejection.v1")
- || payload.recovery_id !== record.subject_id || (approval ? payload.confirmed_by : payload.decided_by) !== record.actor
- || (approval ? payload.confirmed_at : payload.decided_at) !== record.decided_at || (!approval && payload.decision !== "reject")
- || (approval && payload.confirmation_sha256 !== await calculateReconciliationRecoveryConfirmationSha256(payload))
- || await recoveryDecisionMaterialKey(payload) !== record.material_key) invalid();
- } else {
- const approval = record.action === "approve";
- if (payload.schema_version !== (approval ? "qsl_reconciliation_recovery_confirmation.v1" : "qsl_reconciliation_recovery_rejection.v1")
- || payload.recovery_id !== record.subject_id || (approval ? payload.confirmed_by : payload.decided_by) !== record.actor
- || (approval ? payload.confirmed_at : payload.decided_at) !== record.decided_at || (!approval && payload.decision !== "reject")
- || await recoveryDecisionMaterialKey({ recovery_id: payload.recovery_id, candidate_sha256: payload.candidate_sha256, dual_review: { evidence_binding_sha256: payload.dual_review_binding_sha256 } }) !== record.material_key) invalid();
- }
- projection = { decision: target.decision };
- }
- // Extra stored target fields must not be silently dropped into an apparently matching receipt.
- if (canonicalResearchTaskJson(target) !== canonicalResearchTaskJson(projection)) invalid();
- let reviewBinding = null;
- if (record.kind === "promotion" && record.payload?.review_binding !== undefined) {
- const material = record.payload.review_material;
- if (material?.schema_version !== "qsl_promotion_review_material.v2" || material.ticket_id !== record.subject_id
- || await researchPromotionMaterialKey(material) !== record.material_key
- || !promotionReviewBindingsMatch(record.payload.review_binding, { schema_version: "qsl_promotion_review_binding.v2", review_sha256: await calculateOwnerDecisionSha256(material) })) invalid();
- reviewBinding = { schema_version: "qsl_promotion_review_binding.v2", review_sha256: record.payload.review_binding.review_sha256 };
- }
- const receipt = {
- schema_version: reviewBinding ? "qsl_human_decision_receipt.v2" : "qsl_human_decision_receipt.v1",
- ...(reviewBinding ? { review_binding: reviewBinding } : {}),
- kind: record.kind, subject_id: record.subject_id, material_sha256: record.material_key,
- action: record.action, target: projection, decided_at: record.decided_at, decided_by: record.actor,
- no_order: true, execution_authority_granted: false,
- };
- return { ...receipt, receipt_sha256: await calculateOwnerDecisionSha256(receipt) };
-}
-
-async function exactHumanDecisionResponse(request, env, session, kind) {
- const params = new URL(request.url).searchParams;
- if (!params.has("decision_subject_id") && !params.has("decision_material_sha256")) return null;
- requireSameOrigin(request);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- const subjectId = params.get("decision_subject_id");
- const material = params.get("decision_material_sha256");
- if (params.getAll("decision_subject_id").length !== 1 || params.getAll("decision_material_sha256").length !== 1
- || !subjectId || subjectId.length > 256 || /[\u0000-\u001f\u007f]/.test(subjectId) || !/^[0-9a-f]{64}$/.test(material || "")) {
- return json({ ok: false, error: "human_decision_lookup_invalid" }, 400);
- }
- try {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- const result = await runtimeInstanceCommand(env, {
- action: `${kind}_read`, actor: session.login, subject_id: subjectId, exact_material_key: material, now_ms: Date.now(),
- });
- if (result.ok !== true || result.exact_material_key !== material || !Object.prototype.hasOwnProperty.call(result, "decision")) {
- throw new HttpError("human_decision_receipt_unavailable", 503);
- }
- const receipt = result.decision === null ? null : await humanDecisionReceipt(result.decision, { kind, subject_id: subjectId, material_sha256: material });
- return json({ ok: true, decision_readback: {
- schema_version: "qsl_human_decision_readback.v1", source: "durable_human_decision_record",
- kind, subject_id: subjectId, requested_material_sha256: material, observed_at: new Date().toISOString(),
- lookup_status: receipt ? "found" : "not_found", receipt, current_material: result.current_material,
- } });
- } catch {
- // Unreadable authority is never reported as a completed empty lookup.
- return json({ ok: false, error: "human_decision_receipt_unavailable" }, 503);
- }
-}
-
-async function readHumanDecisionAuthority(env, kind, subjectId) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- return runtimeInstanceCommand(env, { action: `${kind}_read`, actor: `${kind}-decision-read`, subject_id: subjectId });
-}
-
-// A safe projection of durable material authority. It carries only digests and
-// server-side expiry; raw provider payloads and credentials never enter a read model.
-function humanDecisionAuthorityView(authority) {
- if (!authority || typeof authority !== "object") return null;
- const materialKey = /^[0-9a-f]{64}$/.test(authority.material_key || "") ? authority.material_key : null;
- const expiresAt = typeof authority.expires_at === "string" && Number.isFinite(Date.parse(authority.expires_at))
- ? authority.expires_at
- : null;
- return {
- material_sha256: materialKey,
- expires_at: expiresAt,
- eligible: typeof authority.eligible === "boolean" ? authority.eligible : null,
- blocked: authority.blocked === true,
- unavailable: authority.migrated === false,
- source: "durable_human_decision_material",
- };
-}
-
-function overlayPromotionDecision(ticket, authority) {
- if (!authority || authority.migrated === false) return ticket;
- const current = authority.eligible === true && authority.blocked !== true ? authority.decision : null;
- if (current?.payload?.ticket && (current.action === "accept" || current.action === "reject")) {
- return normalizeResearchPromotionTicket(current.payload.ticket, "human decision ticket");
- }
- if (ticket.state !== "human_accepted" && ticket.state !== "human_rejected") return ticket;
- return normalizeResearchPromotionTicket({
- ...ticket,
- state: "awaiting_human",
- human_decision: "",
- human_decided_at: "",
- confirmation_target_platform: "",
- confirmation_execution_mode: "",
- confirmation_risk_profile: "",
- }, "human decision ticket");
-}
-
-async function promotionTicketWithAuthority(env, ticket) {
- const authority = await readHumanDecisionAuthority(env, "promotion", ticket.ticket_id);
- return overlayPromotionDecision(ticket, authority);
-}
-
-async function syncControlPlaneResponse(request, env) {
- requireDedicatedControlPlaneSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "control plane KV is not configured" }, 503);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, CONTROL_PLANE_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid control plane payload" }, error.status || 400);
- }
-
- let snapshot;
- try {
- snapshot = normalizeControlPlaneSnapshot(raw, "control plane snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid control plane payload" }, 400);
- }
- try {
- await publishHumanOwnerMaterials(env, snapshot, "control-plane-snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "owner decision material unavailable" }, error.status || 503);
- }
-
- await writeConfigJson(env, CONTROL_PLANE_SNAPSHOT_KEY, snapshot);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "control-plane-sync",
- action: "sync_control_plane",
- schema_version: snapshot.schema_version,
- candidate_count: snapshot.summary.candidate_count,
- data_status: snapshot.data_status,
- });
- } catch {
- // A successful snapshot must not expose its payload through audit failures.
- }
- return json({
- ok: true,
- schema_version: snapshot.schema_version,
- candidate_count: snapshot.summary.candidate_count,
- generated_at: snapshot.generated_at,
- });
-}
-
-async function syncControlPlaneSourceResponse(request, env) {
- const validationOnly = requireControlPlaneSourceSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "control plane KV is not configured" }, 503);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, CONTROL_PLANE_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid control plane source payload" }, error.status || 400);
- }
-
- let source;
- try {
- source = normalizeControlPlaneSourceSnapshot(raw, "control plane source snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid control plane source payload" }, 400);
- }
-
- if (validationOnly) {
- const candidate = source.candidates[0];
- const runId = candidate?.candidate_id?.match(/^soxl_three_asset_mid_weight_validation_([1-9][0-9]*)$/)?.[1];
- if (
- source.source_id !== "aiaudit.soxl_manual_validation" ||
- source.candidates.length !== 1 || !runId ||
- candidate.candidate_kind !== "individual" || candidate.domain !== "us_equity" ||
- candidate.lifecycle.stage !== "P3" || candidate.lifecycle.status !== "parked" ||
- candidate.recommendation.code !== "park" || candidate.evidence.p3_evidence_id !== runId
- ) {
- return json({ ok: false, error: "validation publisher scope mismatch" }, 403);
- }
- }
- try {
- await publishHumanOwnerMaterials(env, source, source.source_id);
- } catch (error) {
- return json({ ok: false, error: error.message || "owner decision material unavailable" }, error.status || 503);
- }
-
- await writeConfigJson(env, controlPlaneSourceKey(source.source_id), source);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "control-plane-source-sync",
- action: "sync_control_plane_source",
- source_id: source.source_id,
- schema_version: source.schema_version,
- candidate_count: source.candidates.length,
- data_status: source.data_status,
- });
- } catch {
- // The source snapshot is accepted independently of an optional audit write.
- }
- return json({
- ok: true,
- source_id: source.source_id,
- schema_version: source.schema_version,
- candidate_count: source.candidates.length,
- generated_at: source.generated_at,
- });
-}
-
-async function controlPlaneResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- return json(await currentControlPlanePayload(env));
-}
-
-async function currentControlPlanePayload(env) {
- if (!hasConfigStore(env)) return emptyControlPlanePayload("snapshot_unavailable");
-
- const sourceSnapshot = await aggregateControlPlaneSources(env);
- if (sourceSnapshot) return sourceSnapshot;
-
- let snapshot;
- try {
- const stored = await readConfigJson(env, CONTROL_PLANE_SNAPSHOT_KEY);
- if (!stored) return emptyControlPlanePayload("snapshot_unavailable");
- snapshot = normalizeControlPlaneSnapshot(stored, CONTROL_PLANE_SNAPSHOT_KEY);
- } catch {
- return emptyControlPlanePayload("snapshot_invalid");
- }
-
- const freshness = controlPlaneResearchSnapshotFreshness(
- snapshot,
- controlPlaneStaleTtlSeconds(env),
- Date.now(),
- );
- snapshot.data_status = freshness.data_status;
- return snapshot;
-}
-
-function isOwnerDecisionCandidate(candidate) {
- return candidate?.lifecycle?.stage === "P6"
- && candidate.lifecycle.status === "owner_decision_required"
- && candidate.recommendation?.code === "owner_live_decision";
-}
-
-function currentOwnerDecisionCandidate(controlPlane, candidateId) {
- if (controlPlane?.data_status !== "ready") {
- throw new HttpError("current control-plane evidence is not ready", 409);
- }
- const candidate = controlPlane.candidates.find((item) => item.candidate_id === candidateId);
- if (!candidate || !isOwnerDecisionCandidate(candidate)) {
- throw new HttpError("candidate is not awaiting an owner decision", 409);
- }
- if (candidate.freshness?.status !== "fresh") {
- throw new HttpError("candidate evidence is not fresh", 409);
- }
- return candidate;
-}
-
-function normalizeOwnerDecisionRequest(payload) {
- const value = assertRequiredAndOptionalFields(payload, [
- "candidate_id", "decision", "candidate_evidence_sha256",
- ], ["request_id"], "owner decision request");
- return {
- candidate_id: normalizeControlPlaneIdentifier(value.candidate_id, "owner decision request.candidate_id", false),
- decision: cleanChoice(value.decision, OWNER_DECISION_CHOICES, "owner decision request.decision"),
- candidate_evidence_sha256: normalizeResearchTaskDigest(
- value.candidate_evidence_sha256,
- "owner decision request.candidate_evidence_sha256",
- ),
- request_id: value.request_id,
- };
-}
-
-async function ownerDecisionCandidateEvidenceSha256(candidate) {
- return await calculateOwnerDecisionSha256({
- candidate_id: candidate.candidate_id,
- candidate_kind: candidate.candidate_kind,
- domain: candidate.domain,
- lifecycle: candidate.lifecycle,
- evidence: candidate.evidence,
- recommendation: { code: candidate.recommendation?.code || "none" },
- });
-}
-
-async function buildOwnerDecisionIntent({ candidate, decision, decidedBy, candidateEvidenceSha256, decidedAt }) {
- const intent = {
- schema_version: OWNER_DECISION_INTENT_SCHEMA_VERSION,
- candidate_id: candidate.candidate_id,
- candidate_kind: candidate.candidate_kind,
- domain: candidate.domain,
- decision,
- decided_at: decidedAt,
- decided_by: decidedBy,
- candidate_evidence_sha256: candidateEvidenceSha256,
- no_order: true,
- execution_authority_granted: false,
- decision_sha256: "",
- };
- intent.decision_sha256 = await calculateOwnerDecisionSha256(intent);
- return await normalizeOwnerDecisionIntent(intent, "owner decision intent");
-}
-
-async function normalizeOwnerDecisionIntent(payload, fieldName) {
- const value = assertExactFields(payload, [
- "schema_version", "candidate_id", "candidate_kind", "domain", "decision", "decided_at", "decided_by",
- "candidate_evidence_sha256", "no_order", "execution_authority_granted", "decision_sha256",
- ], fieldName);
- if (value.schema_version !== OWNER_DECISION_INTENT_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const intent = {
- schema_version: OWNER_DECISION_INTENT_SCHEMA_VERSION,
- candidate_id: normalizeControlPlaneIdentifier(value.candidate_id, `${fieldName}.candidate_id`, false),
- candidate_kind: cleanChoice(value.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${fieldName}.candidate_kind`),
- domain: cleanChoice(value.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.domain`),
- decision: cleanChoice(value.decision, OWNER_DECISION_CHOICES, `${fieldName}.decision`),
- decided_at: normalizeResearchTaskTimestamp(value.decided_at, `${fieldName}.decided_at`),
- decided_by: cleanGithubLogin(value.decided_by, `${fieldName}.decided_by`),
- candidate_evidence_sha256: normalizeResearchTaskDigest(
- value.candidate_evidence_sha256,
- `${fieldName}.candidate_evidence_sha256`,
- ),
- no_order: value.no_order,
- execution_authority_granted: value.execution_authority_granted,
- decision_sha256: normalizeResearchTaskDigest(value.decision_sha256, `${fieldName}.decision_sha256`),
- };
- if (intent.no_order !== true || intent.execution_authority_granted !== false) {
- throw new Error(`${fieldName} must remain no-order and non-executable`);
- }
- if (intent.decision_sha256 !== await calculateOwnerDecisionSha256(intent)) {
- throw new Error(`${fieldName}.decision_sha256 mismatch`);
- }
- return intent;
-}
-
-async function calculateOwnerDecisionSha256(payload) {
- const material = { ...payload };
- delete material.decision_sha256;
- const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function readOwnerDecisionIntent(env, candidateId, materialKey) {
- let authority;
- try {
- authority = await readHumanDecisionAuthority(env, "owner", candidateId);
- } catch (error) {
- return { intent: null, authority: null, error: error.message || "runtime_instances_unavailable" };
- }
- const authorityView = humanDecisionAuthorityView(authority);
- if (authority.blocked) return { intent: null, authority: authorityView, error: "owner_decision_legacy_blocked" };
- if (authority.decision && authority.material_key === materialKey && authority.decision.payload?.no_order === true && authority.decision.payload?.execution_authority_granted === false) {
- return { intent: authority.decision.payload, authority: authorityView, error: null };
- }
- if (authority.migrated === false) {
- try {
- const stored = await readConfigJson(env, ownerDecisionCurrentKey(candidateId));
- if (!stored) return { intent: null, authority: authorityView, error: null };
- const intent = await normalizeOwnerDecisionIntent(stored, ownerDecisionCurrentKey(candidateId));
- if (materialKey && intent.candidate_evidence_sha256 !== materialKey) return { intent: null, authority: authorityView, error: null };
- return { intent, authority: authorityView, error: null, read_only: true };
- } catch {
- return { intent: null, authority: authorityView, error: "owner_decision_intent_invalid" };
- }
- }
- return { intent: null, authority: authorityView, error: null };
-}
-
-function ownerDecisionArchiveKey(candidateId, decisionSha256) {
- return `${OWNER_DECISION_INTENT_PREFIX}${candidateId}:${decisionSha256}`;
-}
-
-function ownerDecisionCurrentKey(candidateId) {
- return `${OWNER_DECISION_CURRENT_PREFIX}${candidateId}`;
-}
-
-function emptyOwnerDecisionQueue(errorCode, controlPlane = null) {
- return {
- schema_version: OWNER_DECISION_QUEUE_SCHEMA_VERSION,
- data_status: controlPlane?.data_status === "stale" ? "stale" : "unavailable",
- computed_at: controlPlane?.computed_at || null,
- candidates: [],
- policy: {
- admin_required: true,
- current_evidence_required: true,
- execution_authority_granted: false,
- no_order: true,
- notice: "网页只记录所有者决定意图;不会下单、变更资金或启用实盘。",
- },
- errors: uniqueStrings([...(controlPlane?.errors || []), errorCode]),
- };
-}
-
-async function ownerDecisionQueueResponse(request, env) {
- return ownerDecisionQueueResponseImpl(request, env, {
- json,
- readSession,
- exactHumanDecisionResponse,
- hasConfigStore,
- currentControlPlanePayload,
- isOwnerDecisionCandidate,
- ownerDecisionCandidateEvidenceSha256,
- readOwnerDecisionIntent,
- emptyOwnerDecisionQueue,
- uniqueStrings,
- OWNER_DECISION_MAX_CANDIDATES,
- OWNER_DECISION_QUEUE_SCHEMA_VERSION,
- });
-}
-
-async function recordOwnerDecisionResponse(request, env) {
- return recordOwnerDecisionResponseImpl(request, env, {
- json,
- requireSameOrigin,
- readSession,
- hasConfigStore,
- readBoundedJson,
- normalizeOwnerDecisionRequest,
- currentControlPlanePayload,
- currentOwnerDecisionCandidate,
- ownerDecisionCandidateEvidenceSha256,
- humanDecisionTimestamp,
- buildOwnerDecisionIntent,
- canonicalResearchTaskJson,
- humanDecisionRequestKey,
- runtimeInstanceCommand,
- humanDecisionReceipt,
- mirrorConfigJson,
- ownerDecisionArchiveKey,
- ownerDecisionCurrentKey,
- appendAuditLog,
- });
-}
-
-// Recovery snapshots contain digest-bound review metadata. Initial enrollment
-// additionally carries bounded broker facts for the authenticated review;
-// raw receipts remain in the platform's protected source, and confirmation
-// records intent without granting execution authority.
-async function initialEnrollmentAccountOption(env, item) {
- if (!await initialEnrollmentBindingsMatch(item.candidate, item.facts)
- || item.candidate.platform_id.toLowerCase() !== "ibkr"
- || item.facts.observed_at !== item.candidate.first_observed_at
- || item.facts.observed_at !== item.candidate.last_observed_at) throw new HttpError("initial_enrollment_invalid", 409);
- const config = await loadAccountOptionsConfig(env);
- const configured = await loadAccountFactsBindings(env, { propagateReadErrors: true });
- const bindings = (configured?.bindings || []).filter(binding => binding.platform === "ibkr" && binding.target_id === item.target_id);
- const options = (config.options?.ibkr || []).filter(option => bindings.length === 1 && option.key === bindings[0].account_key);
- if (options.length !== 1 || bindings.length !== 1 || !accountFactsOptionMatchesBinding(options[0], bindings[0])
- || await initialEnrollmentDigest({ account_ids: [bindings[0].account_selector] }, true) !== item.candidate.account_scope_sha256) {
- throw new HttpError("initial_enrollment_identity_mismatch", 409);
- }
- return options[0];
-}
-
-async function syncReconciliationRecoverySourceResponse(request, env) {
- requireDedicatedReconciliationRecoverySyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "reconciliation recovery KV is not configured" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, RECONCILIATION_RECOVERY_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid reconciliation recovery payload" }, error.status || 400);
- }
- let source;
- try {
- source = normalizeReconciliationRecoverySourceSnapshot(raw, "reconciliation recovery source snapshot");
- for (const recovery of source.recoveries) if (recovery.mode === "initial_enrollment") await initialEnrollmentAccountOption(env, recovery);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid reconciliation recovery payload" }, 400);
- }
- try {
- await publishHumanRecoveryMaterials(env, source);
- } catch (error) {
- return json({ ok: false, error: error.message || "reconciliation recovery material unavailable" }, error.status || 503);
- }
- await writeConfigJson(env, reconciliationRecoverySourceKey(source.source_id), source);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "reconciliation-recovery-source-sync",
- action: "sync_reconciliation_recovery_source",
- source_id: source.source_id,
- schema_version: source.schema_version,
- recovery_count: source.recoveries.length,
- data_status: source.data_status,
- });
- } catch {
- // The source is still safely stored even if the rolling convenience log
- // cannot be updated.
- }
- return json({
- ok: true,
- source_id: source.source_id,
- schema_version: source.schema_version,
- recovery_count: source.recoveries.length,
- generated_at: source.generated_at,
- });
-}
-
-async function reconciliationRecoveryResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- const exact = await exactHumanDecisionResponse(request, env, session, "recovery");
- if (exact) return exact;
- if (!hasConfigStore(env)) return json(emptyReconciliationRecoveryPayload("snapshot_unavailable"));
- return json(decorateQueue(await aggregateReconciliationRecoverySources(env), "recoveries", "reconciliation_recovery"));
-}
-
-async function syncBinancePrivateScopeResponse(request, env) {
- requireDedicatedReconciliationRecoverySyncToken(request, env);
- const store = configStore(env);
- if (!store) {
- return json({ ok: false, error: "binance_private_scope_storage_unavailable" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, BINANCE_PRIVATE_SCOPE_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: "invalid_binance_private_scope_payload" }, error.status === 413 ? 413 : 400);
- }
- let report;
- try {
- report = normalizeBinancePrivateScopeReport(raw, { requireIngestFreshness: true });
- } catch {
- return json({ ok: false, error: "invalid_binance_private_scope_payload" }, 400);
- }
- try {
- await store.put(BINANCE_PRIVATE_SCOPE_KEY, JSON.stringify(report), {
- expirationTtl: BINANCE_PRIVATE_SCOPE_WRITE_TTL_SECONDS,
- });
- } catch {
- return json({ ok: false, error: "binance_private_scope_storage_unavailable" }, 503);
- }
- return json({
- ok: true,
- observed_at: report.observed_at,
- source_run_id: report.source_run_id,
- asset_count: report.assets.length,
- });
-}
-
-async function trustedBinanceFactsBinding(env, readiness = null) {
- const text = String(env.BINANCE_ACCOUNT_FACTS_BINDING_JSON || "");
- if (!text) return null;
- let binding;
- try { binding = normalizeBinanceFactsBinding(JSON.parse(text)); }
- catch { throw new BinanceFactsError("binance_account_facts_binding_invalid", 503); }
- await assertBinanceFactsSourceBinding(binding);
- if (readiness) readiness.binding_valid = true;
- let config;
- try { config = await loadAccountOptionsConfig(env); }
- catch {
- throw new BinanceFactsError("binance_account_facts_account_options_unavailable", 503);
- }
- if (readiness) readiness.account_options_readable = true;
- const options = config.options?.binance || [];
- const matchCount = options.filter(option => binanceFactsOptionMatches(option, binding)).length;
- if (matchCount !== 1) {
- throw new BinanceFactsError("binance_account_facts_binding_unmatched", 409);
- }
- if (readiness) readiness.unique_match = true;
- return binding;
-}
-
-function binanceFactsErrorResponse(error) {
- return json({ ok: false, error: error instanceof BinanceFactsError
- ? error.code : "binance_account_facts_unavailable" }, error instanceof BinanceFactsError ? error.status : 503);
-}
-
-function binanceFactsSyncAuthorizationResponse(request, env) {
- const token = String(env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN || "");
- const otherTokens = ["ACCOUNT_FACTS_SYNC_TOKEN", "IBKR_ACCOUNT_FACTS_SYNC_TOKEN", "SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN", "FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN",
- "RECONCILIATION_RECOVERY_SYNC_TOKEN", "RECONCILIATION_RECOVERY_CONTROLLER_TOKEN", "STRATEGY_SWITCH_SYNC_TOKEN"];
- if (!token || otherTokens.some(name => env[name] && env[name] === token)) {
- return json({ ok: false, error: "binance_account_facts_token_unavailable" }, 503);
- }
- if ((request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] !== token) {
- return json({ ok: false, error: "binance_account_facts_token_invalid" }, 401);
- }
- return null;
-}
-
-async function binanceDigestSnapshotResponse(request, env, url) {
- const token = env.BINANCE_DIGEST_READ_TOKEN;
- const otherTokens = ["BINANCE_ACCOUNT_FACTS_SYNC_TOKEN", "ACCOUNT_FACTS_SYNC_TOKEN", "IBKR_ACCOUNT_FACTS_SYNC_TOKEN",
- "SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN", "FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN", "RECONCILIATION_RECOVERY_SYNC_TOKEN",
- "RECONCILIATION_RECOVERY_CONTROLLER_TOKEN", "STRATEGY_SWITCH_SYNC_TOKEN", "SESSION_SECRET"];
- if (typeof token !== "string" || !/^[A-Za-z0-9_-]{32,256}$/.test(token)
- || otherTokens.some(name => env[name] === token)) {
- return json({ ok: false, error: "digest_snapshot_read_unavailable" }, 503);
- }
- if (request.headers.get("Authorization") !== `Bearer ${token}`) {
- return json({ ok: false, error: "digest_snapshot_read_unauthorized" }, 401);
- }
- const day = url.searchParams.get("business_day");
- const start = Date.parse(`${day}T06:00:00+08:00`);
- const end = start + 86400000;
- if (!/^\d{4}-\d{2}-\d{2}$/.test(day || "") || !Number.isFinite(start)
- || new Date(start + 8 * 3600000).toISOString().slice(0, 10) !== day || end > Date.now()) {
- return json({ ok: false, error: "digest_snapshot_window_invalid" }, 400);
- }
- try {
- const binding = await trustedBinanceFactsBinding(env);
- if (!binding || !configStore(env)) throw new Error("digest_snapshot_read_unavailable");
- const retained = await runtimeInstanceCommand(env, {
- action: "binance_detail_read", binding, date: day, business_day: true,
- });
- if (retained?.ok !== true) throw new Error("digest_snapshot_read_unavailable");
- // The existing latest cache can supply a snapshot from before this
- // retention path was released, provided it still matches the window.
- const raw = retained.report ?? await readConfigJson(env, `${BINANCE_FACTS_KEY}:${binding.source_binding.id}`);
- if (!raw) return json({ ok: false, error: "digest_snapshot_missing" }, 404);
- const report = normalizeBinanceAccountFacts(raw, binding);
- const observedFrom = Date.parse(report.observed_started_at);
- const observedUntil = Date.parse(report.observed_finished_at);
- if (observedFrom < start || observedUntil >= end) {
- return json({ ok: false, error: "digest_snapshot_missing" }, 404);
- }
- const valuation = report.wallet_valuation;
- const wallet = url.searchParams.get("include_valuation") === "1" && valuation?.status === "available"
- ? { wallet_valuation: {
- amount: valuation.amount, currency: valuation.currency, as_of: valuation.observed_at,
- } }
- : {};
- return json({ ok: true, business_day: day, account_key: binding.account_key,
- target_id: binding.target_id, as_of: report.observed_finished_at,
- holdings: report.assets.map(({ asset, quantity }) => ({ asset, quantity })), ...wallet });
- } catch {
- return json({ ok: false, error: "digest_snapshot_read_unavailable" }, 503);
- }
-}
-
-async function binanceAccountFactsReadinessResponse(request, env) {
- const authError = binanceFactsSyncAuthorizationResponse(request, env);
- if (authError) return authError;
- const readiness = { binding_valid: false, account_options_readable: false, unique_match: false };
- try {
- const binding = await trustedBinanceFactsBinding(env, readiness);
- if (!binding) throw new BinanceFactsError("binance_account_facts_binding_missing", 503);
- return json({ ok: true, ready: true, ...readiness });
- } catch (error) {
- return json({ ok: false, ready: false, ...readiness,
- error: error instanceof BinanceFactsError ? error.code : "binance_account_facts_unavailable" },
- error instanceof BinanceFactsError ? error.status : 503);
- }
-}
-
-async function syncBinanceAccountFactsResponse(request, env) {
- const authError = binanceFactsSyncAuthorizationResponse(request, env);
- if (authError) return authError;
- try {
- const binding = await trustedBinanceFactsBinding(env);
- if (!binding) throw new BinanceFactsError("binance_account_facts_binding_missing", 503);
- const raw = await readBoundedJson(request, BINANCE_FACTS_MAX_BYTES);
- const report = normalizeBinanceAccountFacts(raw, binding, { ingest: true });
- const store = configStore(env);
- if (!store) throw new BinanceFactsError("binance_account_facts_storage_unavailable", 503);
- if (!hasRuntimeInstanceStore(env)) throw new BinanceFactsError("binance_account_facts_history_storage_unavailable", 503);
- const storageKey = `${BINANCE_FACTS_KEY}:${binding.source_binding.id}`;
- const previous = await readConfigJson(env, storageKey);
- let unchanged = false;
- if (previous) {
- const validPrevious = normalizeBinanceAccountFacts(previous, binding);
- const incomingTime = Date.parse(report.observed_finished_at);
- const previousTime = Date.parse(validPrevious.observed_finished_at);
- if (incomingTime < previousTime || (incomingTime === previousTime
- && canonicalJson(report) !== canonicalJson(validPrevious))) {
- throw new BinanceFactsError("binance_account_facts_observation_conflict", 409);
- }
- unchanged = incomingTime === previousTime;
- }
- try {
- const detail = await runtimeInstanceCommand(env, {
- action: "binance_detail_put", binding, report, date: report.observed_finished_at.slice(0, 10),
- });
- if (detail.readback_verified !== true) throw new Error("binance_detail_readback_failed");
- const history = binanceWalletHistoryEntry(report, binding);
- await runtimeInstanceCommand(env, {
- action: "binance_wallet_history_put",
- account_key: binding.account_key,
- storage_account_key: binanceWalletHistoryStorageKey(binding),
- target_id: binding.target_id,
- account_scope: binding.account_scope,
- source_binding_id: binding.source_binding.id,
- history,
- });
- } catch {
- throw new BinanceFactsError("binance_account_facts_history_storage_unavailable", 503);
- }
- if (unchanged) return json({ ok: true, status: "unchanged" });
- await store.put(storageKey, JSON.stringify(report), { expirationTtl: 2 * 24 * 60 * 60 });
- return json({ ok: true, status: "published", observed_finished_at: report.observed_finished_at,
- asset_count: report.assets.length });
- } catch (error) {
- if (error?.status === 413) return json({ ok: false, error: "binance_account_facts_payload_too_large" }, 413);
- return binanceFactsErrorResponse(error);
- }
-}
-
-async function binanceDetailArchiveResponse(request, env, url) {
- const authError = binanceFactsSyncAuthorizationResponse(request, env);
- if (authError) return authError;
- try {
- const binding = await trustedBinanceFactsBinding(env);
- if (!binding) throw new Error("binding_missing");
- const result = await runtimeInstanceCommand(env, {
- action: "binance_detail_read", binding, date: url.searchParams.get("date"),
- });
- return json(result, result.report ? 200 : 404);
- } catch {
- return json({ ok: false, error: "binance_detail_archive_unavailable" }, 503);
- }
-}
-
-async function binanceWalletHistoryResponse(request, env, url) {
- if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "account_facts_store_unavailable" }, 503);
- try {
- const binding = await trustedBinanceFactsBinding(env);
- if (!binding) throw new BinanceFactsError("binance_account_facts_binding_missing", 503);
- if (url.searchParams.get("account_key") !== binding.account_key) {
- throw new BinanceFactsError("binance_account_facts_binding_unmatched", 409);
- }
- let historicalBindings;
- try {
- const encoded = String(env.BINANCE_ACCOUNT_FACTS_HISTORY_BINDINGS_JSON || "[]");
- historicalBindings = await assertBinanceFactsHistoryBindings(JSON.parse(encoded), binding);
- } catch {
- throw new BinanceFactsError("binance_account_facts_history_bindings_invalid", 503);
- }
- const buckets = [];
- for (const sourceBinding of [binding, ...historicalBindings]) {
- const stored = await runtimeInstanceCommand(env, {
- action: "binance_wallet_history_read",
- account_key: binding.account_key,
- storage_account_key: binanceWalletHistoryStorageKey(sourceBinding),
- target_id: binding.target_id,
- account_scope: binding.account_scope,
- source_binding_id: sourceBinding.source_binding.id,
- });
- buckets.push({ binding: sourceBinding, days: Array.isArray(stored.days) ? stored.days : [] });
- }
- return json(projectBinanceWalletHistoryFromSources(buckets, binding, historicalBindings));
- } catch (error) {
- const allowedErrors = new Set([
- "binance_account_facts_binding_invalid", "binance_account_facts_account_options_unavailable",
- "binance_account_facts_binding_unmatched", "binance_account_facts_binding_missing",
- "binance_wallet_history_identity_mismatch", "binance_wallet_history_stored_invalid",
- "binance_wallet_history_conflict", "binance_account_facts_history_bindings_invalid",
- ]);
- const code = allowedErrors.has(error?.code || error?.message)
- ? (error.code || error.message) : "binance_wallet_history_unavailable";
- return json({ ok: false, error: code }, error?.status || 503);
- }
-}
-
-async function binanceAccountFactsResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- try {
- const binding = await trustedBinanceFactsBinding(env);
- if (!binding) return json({ ok: true, report_status: "unavailable", report: null });
- const raw = await readConfigJson(env, `${BINANCE_FACTS_KEY}:${binding.source_binding.id}`);
- if (!raw) return json({ ok: true, report_status: "missing", report: null });
- const report = projectBinanceAccountFacts(raw, binding);
- if (!report) return json({ ok: true, report_status: "expired", report: null });
- return json({ ok: true, report_status: "available", report });
- } catch { return json({ ok: true, report_status: "unavailable", report: null }); }
-}
-
-async function binancePrivateScopeResponse(request, env) {
- const session = await readSession(request, env);
- if (!session) return json({ ok: false, error: "login required" }, 401);
- if (!session.allowed || !session.admin) return json({ ok: false, error: "admin required" }, 403);
- if (!hasConfigStore(env)) return json({ ok: true, report: null });
- try {
- const raw = await readConfigJson(env, BINANCE_PRIVATE_SCOPE_KEY);
- if (!raw) return json({ ok: true, report: null });
- const report = normalizeBinancePrivateScopeReport(raw);
- const ageMs = Date.now() - Date.parse(report.observed_at);
- if (ageMs > BINANCE_PRIVATE_SCOPE_READ_MAX_AGE_MS || ageMs < -BINANCE_PRIVATE_SCOPE_FUTURE_SKEW_MS) {
- return json({ ok: true, report: null });
- }
- return json({ ok: true, report });
- } catch {
- return json({ ok: true, report: null });
- }
-}
-
-// This is a least-privilege service-to-service read for a platform-owned
-// controller. It deliberately returns only the current, redacted digest
-// binding and immutable human receipt; broker state remains in the platform.
-async function reconciliationRecoveryControllerReadResponse(request, env, url) {
- requireDedicatedReconciliationRecoveryControllerToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "reconciliation recovery KV is not configured" }, 503);
- }
- let recoveryId;
- try {
- recoveryId = normalizeControlPlaneIdentifier(
- url.searchParams.get("recovery_id") || "",
- "reconciliation recovery controller recovery_id",
- false,
- );
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid recovery_id" }, 400);
- }
- const dashboard = await aggregateReconciliationRecoverySources(env);
- let recovery;
- try {
- recovery = currentReconciliationRecoveryRequest(dashboard, recoveryId);
- } catch (error) {
- return json({ ok: false, error: error.message || "reconciliation recovery is unavailable" }, error.status || 409);
- }
- const entry = dashboard.recoveries.find((item) => item.recovery?.recovery_id === recoveryId);
- if (!entry?.confirmation) {
- return json({ ok: false, error: "reconciliation recovery has no current confirmation" }, 404);
- }
- if (recovery.mode === "initial_enrollment") return json({ ok: true, schema_version: "qsl_initial_enrollment_controller_read.v1",
- recovery: { mode: recovery.mode, recovery_id: recovery.recovery_id, candidate_sha256: recovery.candidate_sha256, facts_sha256: recovery.facts_sha256 },
- confirmation: entry.confirmation, policy: { no_order: true, execution_authority_granted: false, controller_must_reverify: true } });
- return json({
- ok: true,
- schema_version: RECONCILIATION_RECOVERY_CONTROLLER_READ_SCHEMA_VERSION,
- recovery: {
- recovery_id: recovery.recovery_id,
- platform: recovery.platform,
- strategy_profile: recovery.strategy_profile,
- environment: recovery.environment,
- reconciliation_state: recovery.reconciliation_state,
- candidate_sha256: recovery.candidate_sha256,
- dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
- evidence_sample_count: recovery.evidence_sample_count,
- first_observed_at: recovery.first_observed_at,
- last_observed_at: recovery.last_observed_at,
- },
- confirmation: entry.confirmation,
- policy: {
- no_order: true,
- execution_authority_granted: false,
- controller_must_reverify: true,
- },
- });
-}
-
-function currentReconciliationRecoveryRequest(dashboard, recoveryId) {
- const entry = dashboard?.recoveries?.find((item) => item.recovery?.recovery_id === recoveryId);
- if (entry?.recovery?.mode !== "initial_enrollment" && dashboard?.data_status !== "ready") {
- throw new HttpError("current reconciliation recovery evidence is not ready", 409);
- }
- if (!entry || entry.freshness?.data_status !== "ready") {
- throw new HttpError("reconciliation recovery request is not fresh", 409);
- }
- const recovery = entry.recovery;
- if (recovery.mode === "initial_enrollment") {
- if (recovery.readiness !== "awaiting_human_confirmation" || recovery.blocker_codes.length) throw new HttpError("initial_enrollment_incomplete", 409);
- return recovery;
- }
- if (
- recovery.readiness !== "awaiting_human_confirmation" ||
- recovery.reconciliation_state !== "RECONCILE_ONLY" ||
- recovery.blocker_codes.length ||
- recovery.dual_review.evidence_binding_sha256 !== recovery.candidate_sha256 ||
- recovery.evidence_sample_count < 1
- ) {
- throw new HttpError("reconciliation recovery request is not eligible for confirmation", 409);
- }
- return recovery;
-}
-
-function normalizeReconciliationRecoveryConfirmationRequest(payload) {
- if (payload?.mode === "initial_enrollment") {
- const value = assertRequiredAndOptionalFields(payload, ["mode", "recovery_id", "candidate_sha256", "facts_sha256"], ["decision", "request_id"], "initial enrollment confirmation request");
- const decision = value.decision ?? "approve";
- if (!["approve", "reject"].includes(decision)) throw new Error("initial enrollment decision unsupported");
- return { mode: "initial_enrollment", recovery_id: normalizeControlPlaneIdentifier(value.recovery_id, "recovery_id", false),
- candidate_sha256: normalizeResearchTaskDigest(value.candidate_sha256, "candidate_sha256"),
- facts_sha256: normalizeResearchTaskDigest(value.facts_sha256, "facts_sha256"), decision, request_id: value.request_id };
- }
- const value = assertRequiredAndOptionalFields(payload, [
- "recovery_id", "candidate_sha256", "dual_review_binding_sha256",
- ], ["decision", "request_id"], "reconciliation recovery confirmation request");
- const decision = Object.prototype.hasOwnProperty.call(value, "decision") ? value.decision : "approve";
- if (decision !== "approve" && decision !== "reject") {
- throw new Error("reconciliation recovery confirmation request.decision is unsupported");
- }
- return {
- recovery_id: normalizeControlPlaneIdentifier(value.recovery_id, "reconciliation recovery confirmation request.recovery_id", false),
- candidate_sha256: normalizeResearchTaskDigest(
- value.candidate_sha256,
- "reconciliation recovery confirmation request.candidate_sha256",
- ),
- dual_review_binding_sha256: normalizeResearchTaskDigest(
- value.dual_review_binding_sha256,
- "reconciliation recovery confirmation request.dual_review_binding_sha256",
- ),
- decision,
- request_id: value.request_id,
- };
-}
-
-async function calculateReconciliationRecoveryConfirmationSha256(payload) {
- const material = { ...payload };
- delete material.confirmation_sha256;
- const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function buildReconciliationRecoveryConfirmation({ recovery, confirmedBy, confirmedAt }) {
- const confirmation = {
- schema_version: RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION,
- recovery_id: recovery.recovery_id,
- candidate_sha256: recovery.candidate_sha256,
- dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
- confirmed_at: confirmedAt,
- confirmed_by: confirmedBy,
- no_order: true,
- execution_authority_granted: false,
- confirmation_sha256: "",
- };
- confirmation.confirmation_sha256 = await calculateReconciliationRecoveryConfirmationSha256(confirmation);
- return await normalizeReconciliationRecoveryConfirmation(confirmation, "reconciliation recovery confirmation");
-}
-
-async function normalizeReconciliationRecoveryConfirmation(payload, fieldName) {
- const value = assertExactFields(payload, [
- "schema_version", "recovery_id", "candidate_sha256", "dual_review_binding_sha256", "confirmed_at", "confirmed_by",
- "no_order", "execution_authority_granted", "confirmation_sha256",
- ], fieldName);
- if (value.schema_version !== RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const confirmation = {
- schema_version: RECONCILIATION_RECOVERY_CONFIRMATION_SCHEMA_VERSION,
- recovery_id: normalizeControlPlaneIdentifier(value.recovery_id, `${fieldName}.recovery_id`, false),
- candidate_sha256: normalizeResearchTaskDigest(value.candidate_sha256, `${fieldName}.candidate_sha256`),
- dual_review_binding_sha256: normalizeResearchTaskDigest(
- value.dual_review_binding_sha256,
- `${fieldName}.dual_review_binding_sha256`,
- ),
- confirmed_at: normalizeResearchTaskTimestamp(value.confirmed_at, `${fieldName}.confirmed_at`),
- confirmed_by: cleanGithubLogin(value.confirmed_by, `${fieldName}.confirmed_by`),
- no_order: value.no_order,
- execution_authority_granted: value.execution_authority_granted,
- confirmation_sha256: normalizeResearchTaskDigest(value.confirmation_sha256, `${fieldName}.confirmation_sha256`),
- };
- if (confirmation.no_order !== true || confirmation.execution_authority_granted !== false) {
- throw new Error(`${fieldName} must remain no-order and non-executable`);
- }
- if (confirmation.confirmation_sha256 !== await calculateReconciliationRecoveryConfirmationSha256(confirmation)) {
- throw new Error(`${fieldName}.confirmation_sha256 mismatch`);
- }
- return confirmation;
-}
-
-function reconciliationRecoveryConfirmationArchiveKey(recoveryId, confirmationSha256) {
- return `${RECONCILIATION_RECOVERY_CONFIRMATION_PREFIX}${recoveryId}:${confirmationSha256}`;
-}
-
-function reconciliationRecoveryConfirmationCurrentKey(recoveryId) {
- return `${RECONCILIATION_RECOVERY_CURRENT_PREFIX}${recoveryId}`;
-}
-
-async function readReconciliationRecoveryConfirmation(env, recoveryId) {
- let authority;
- try {
- authority = await readHumanDecisionAuthority(env, "recovery", recoveryId);
- } catch (error) {
- return { confirmation: null, rejection: null, authority: null, error: error.message || "runtime_instances_unavailable" };
- }
- const authorityView = humanDecisionAuthorityView(authority);
- if (authority.migrated === false) {
- try {
- const stored = await readConfigJson(env, reconciliationRecoveryConfirmationCurrentKey(recoveryId));
- if (!stored) return { confirmation: null, rejection: null, authority: authorityView, error: null };
- return {
- confirmation: await normalizeReconciliationRecoveryConfirmation(
- stored,
- reconciliationRecoveryConfirmationCurrentKey(recoveryId),
- ),
- rejection: null,
- authority: authorityView,
- error: null,
- read_only: true,
- };
- } catch {
- return { confirmation: null, rejection: null, authority: authorityView, error: "reconciliation_recovery_confirmation_invalid" };
- }
- }
- if (authority.blocked) return { confirmation: null, rejection: null, authority: authorityView, error: "reconciliation_recovery_legacy_blocked" };
- if (authority.eligible !== true) return { confirmation: null, rejection: null, authority: authorityView, error: null };
- if (authority.decision?.action === "reject") {
- const payload = authority.decision.payload;
- if (payload?.decision === "reject" && payload?.no_order === true && payload?.execution_authority_granted === false) {
- return { confirmation: null, rejection: payload, authority: authorityView, error: null };
- }
- return { confirmation: null, rejection: null, authority: authorityView, error: null };
- }
- if (authority.decision?.action === "approve" && authority.decision.payload?.no_order === true && authority.decision.payload?.execution_authority_granted === false) {
- return { confirmation: authority.decision.payload, rejection: null, authority: authorityView, error: null };
- }
- return { confirmation: null, rejection: null, authority: authorityView, error: null };
-}
-
-async function recordInitialEnrollmentDecision(env, session, requested, recovery) {
- if (recovery.mode !== "initial_enrollment" || requested.candidate_sha256 !== recovery.candidate_sha256
- || requested.facts_sha256 !== recovery.facts_sha256) return json({ ok: false, error: "initial_enrollment_changed" }, 409);
- const decidedAt = humanDecisionTimestamp();
- const materialKey = await recoveryDecisionMaterialKey(recovery);
- const base = { mode: "initial_enrollment", recovery_id: recovery.recovery_id,
- candidate_sha256: recovery.candidate_sha256, facts_sha256: recovery.facts_sha256,
- no_order: true, execution_authority_granted: false };
- const payload = requested.decision === "approve"
- ? { schema_version: "qsl_initial_enrollment_confirmation.v1", ...base, confirmed_at: decidedAt, confirmed_by: session.login }
- : { schema_version: "qsl_initial_enrollment_rejection.v1", ...base, decision: "reject", decided_at: decidedAt, decided_by: session.login };
- if (requested.decision === "approve") payload.confirmation_sha256 = await calculateReconciliationRecoveryConfirmationSha256(payload);
- const target = { decision: requested.decision };
- try {
- const requestKey = await humanDecisionRequestKey({ requestId: requested.request_id, kind: "recovery", actor: session.login,
- subjectId: recovery.recovery_id, materialKey, action: requested.decision, target });
- const recorded = await runtimeInstanceCommand(env, { action: "recovery_decide", actor: session.login,
- subject_id: recovery.recovery_id, material_key: materialKey, action_name: requested.decision,
- request_key: requestKey, target_json: canonicalResearchTaskJson(target), decided_at: decidedAt, now_ms: Date.now(), payload });
- const decisionReceipt = await humanDecisionReceipt(recorded.record, { kind: "recovery", subject_id: recovery.recovery_id, material_sha256: materialKey });
- return json({ ok: true, confirmation: recorded.record?.action === "approve" ? recorded.record.payload : null,
- rejection: recorded.record?.action === "reject" ? recorded.record.payload : null, decision_receipt: decisionReceipt, replayed: recorded.replayed === true });
- } catch (error) { return json({ ok: false, error: error.message || "initial_enrollment_unavailable" }, error.status || 503); }
-}
-
-async function recordReconciliationRecoveryConfirmationResponse(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "STRATEGY_SWITCH_CONFIG KV binding is required" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, 4 * 1024);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid reconciliation recovery confirmation" }, error.status || 400);
- }
- let requested;
- try {
- requested = normalizeReconciliationRecoveryConfirmationRequest(raw);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid reconciliation recovery confirmation" }, 400);
- }
- const dashboard = await aggregateReconciliationRecoverySources(env);
- let recovery;
- try {
- recovery = currentReconciliationRecoveryRequest(dashboard, requested.recovery_id);
- } catch (error) {
- return json({ ok: false, error: error.message || "reconciliation recovery confirmation is unavailable" }, error.status || 409);
- }
- if (requested.mode === "initial_enrollment") return recordInitialEnrollmentDecision(env, session, requested, recovery);
- if (recovery.mode === "initial_enrollment" ||
- requested.candidate_sha256 !== recovery.candidate_sha256 ||
- requested.dual_review_binding_sha256 !== recovery.dual_review.evidence_binding_sha256
- ) {
- return json({ ok: false, error: "reconciliation evidence changed; reload the review before confirming" }, 409);
- }
- const decidedAt = humanDecisionTimestamp();
- const materialKey = await recoveryDecisionMaterialKey(recovery);
- const confirmation = requested.decision === "approve"
- ? await buildReconciliationRecoveryConfirmation({ recovery, confirmedBy: session.login, confirmedAt: decidedAt })
- : null;
- const rejection = requested.decision === "reject" ? {
- schema_version: "qsl_reconciliation_recovery_rejection.v1",
- recovery_id: recovery.recovery_id,
- candidate_sha256: recovery.candidate_sha256,
- dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
- decision: "reject",
- decided_at: decidedAt,
- decided_by: session.login,
- no_order: true,
- execution_authority_granted: false,
- } : null;
- const target = { decision: requested.decision };
- let requestKey;
- try {
- requestKey = await humanDecisionRequestKey({
- requestId: requested.request_id,
- kind: "recovery",
- actor: session.login,
- subjectId: recovery.recovery_id,
- materialKey,
- action: requested.decision,
- target,
- });
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid reconciliation recovery confirmation" }, error.status || 400);
- }
- let recorded;
- try {
- recorded = await runtimeInstanceCommand(env, {
- action: "recovery_decide",
- actor: session.login,
- subject_id: recovery.recovery_id,
- material_key: materialKey,
- action_name: requested.decision,
- request_key: requestKey,
- target_json: canonicalResearchTaskJson(target),
- decided_at: decidedAt,
- now_ms: Date.now(),
- payload: confirmation || rejection,
- });
- } catch (error) {
- return json({ ok: false, error: error.message || "reconciliation recovery confirmation is unavailable" }, error.status || 503);
- }
- const decisionReceipt = await humanDecisionReceipt(recorded.record, { kind: "recovery", subject_id: recovery.recovery_id, material_sha256: materialKey });
- const recordedPayload = recorded.record.payload;
- if (recorded.record?.action === "approve") {
- await mirrorConfigJson(env, reconciliationRecoveryConfirmationArchiveKey(recovery.recovery_id, recordedPayload.confirmation_sha256), recordedPayload);
- await mirrorConfigJson(env, reconciliationRecoveryConfirmationCurrentKey(recovery.recovery_id), recordedPayload);
- }
- let auditLogged = false;
- try {
- await appendAuditLog(env, {
- ts: recorded.record?.decided_at || decidedAt,
- login: session.login,
- action: "record_reconciliation_recovery_confirmation",
- recovery_id: recovery.recovery_id,
- candidate_sha256: recovery.candidate_sha256,
- dual_review_binding_sha256: recovery.dual_review.evidence_binding_sha256,
- confirmation_sha256: recordedPayload.confirmation_sha256 || "",
- decision: recorded.record?.action || requested.decision,
- no_order: true,
- execution_authority_granted: false,
- });
- auditLogged = true;
- } catch {
- // The immutable confirmation remains available to a future private
- // controller even if the rolling audit log is unavailable.
- }
- return json({
- ok: true,
- confirmation: recorded.record?.action === "approve" ? recordedPayload : null,
- rejection: recorded.record?.action === "reject" ? recordedPayload : null,
- decision_receipt: decisionReceipt,
- audit_logged: auditLogged,
- replayed: recorded.replayed === true,
- });
-}
-
-async function aggregateReconciliationRecoverySources(env) {
- const sources = await readReconciliationRecoverySources(env);
- if (!sources.length) return emptyReconciliationRecoveryPayload("snapshot_unavailable");
- const ttlSeconds = reconciliationRecoveryStaleTtlSeconds(env);
- const now = Date.now();
- const recoveries = [];
- const recoveryIds = new Set();
- const duplicateRecoveryIds = new Set();
- const errors = [];
- const timestamps = [];
- let hasReadySource = false;
- let hasStaleSource = false;
- let hasStaleRecoveryEvidence = false;
- for (const source of sources) {
- const sourceFreshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
- if (source.generated_at) timestamps.push(source.generated_at);
- if (source.computed_at) timestamps.push(source.computed_at);
- if (sourceFreshness.data_status === "ready") hasReadySource = true;
- if (sourceFreshness.data_status === "stale") {
- hasStaleSource = true;
- errors.push("reconciliation_recovery_source_stale");
- }
- for (const recovery of source.recoveries) {
- if (recoveryIds.has(recovery.recovery_id)) {
- duplicateRecoveryIds.add(recovery.recovery_id);
- errors.push("reconciliation_recovery_duplicate_recovery");
- continue;
- }
- recoveryIds.add(recovery.recovery_id);
- const freshness = reconciliationRecoveryEvidenceFreshness(recovery, sourceFreshness, ttlSeconds, now);
- if (freshness.data_status === "stale") {
- hasStaleRecoveryEvidence = true;
- errors.push("reconciliation_recovery_evidence_stale");
- }
- const result = await readReconciliationRecoveryConfirmation(env, recovery.recovery_id);
- if (result.error) errors.push(result.error);
- if (recovery.mode === "initial_enrollment") {
- const option = await initialEnrollmentAccountOption(env, recovery);
- const incomplete = Object.entries(recovery.candidate.coverage).filter(([, status]) => status !== "complete").map(([name]) => `initial_enrollment_${name}_incomplete`);
- const view = { ...recovery, platform: "ibkr", strategy_profile: recovery.candidate.strategy_profile,
- target_name: option.target_name, account_key: option.key, candidate_sha256: recovery.candidate.candidate_sha256,
- facts_sha256: recovery.candidate.facts_sha256, first_observed_at: recovery.candidate.first_observed_at,
- last_observed_at: recovery.candidate.last_observed_at,
- readiness: incomplete.length ? "blocked" : "awaiting_human_confirmation", blocker_codes: incomplete };
- const matches = decision => decision?.mode === "initial_enrollment"
- && decision.candidate_sha256 === view.candidate_sha256 && decision.facts_sha256 === view.facts_sha256;
- const confirmation = matches(result.confirmation) ? result.confirmation : null;
- const rejection = matches(result.rejection) ? result.rejection : null;
- const presentation = recoveryMaterialPresentation({ source, recovery: view, confirmation, rejection, decisionError: result.error });
- presentation.label = { zh: "首次登记确认", en: "Initial enrollment" };
- presentation.material_kind = "initial_enrollment";
- recoveries.push({ source_id: source.source_id, freshness, recovery: view, confirmation, rejection, presentation,
- decision_authority: result.authority || null,
- decision_binding: { kind: "recovery", subject_id: view.recovery_id, material_sha256: await recoveryDecisionMaterialKey(recovery) } });
- continue;
- }
- const confirmation = result.confirmation
- && result.confirmation.candidate_sha256 === recovery.candidate_sha256
- && result.confirmation.dual_review_binding_sha256 === recovery.dual_review.evidence_binding_sha256
- ? result.confirmation
- : null;
- const rejection = result.rejection
- && result.rejection.candidate_sha256 === recovery.candidate_sha256
- && result.rejection.dual_review_binding_sha256 === recovery.dual_review.evidence_binding_sha256
- ? result.rejection
- : null;
- recoveries.push({ source_id: source.source_id, freshness, recovery, confirmation, rejection,
- presentation: recoveryMaterialPresentation({ source, recovery, confirmation, rejection, decisionError: result.error }),
- decision_authority: result.authority || null,
- decision_binding: { kind: "recovery", subject_id: recovery.recovery_id, material_sha256: await recoveryDecisionMaterialKey(recovery) },
- });
- }
- errors.push(...source.errors);
- }
- const uniqueRecoveries = recoveries
- .filter((entry) => !duplicateRecoveryIds.has(entry.recovery.recovery_id))
- .sort((left, right) => left.recovery.recovery_id.localeCompare(right.recovery.recovery_id));
- const dataStatus = hasStaleSource || hasStaleRecoveryEvidence
- ? "stale"
- : (hasReadySource ? "ready" : "unavailable");
- return {
- schema_version: RECONCILIATION_RECOVERY_DASHBOARD_SCHEMA_VERSION,
- generated_at: earliestControlPlaneTimestamp(timestamps),
- computed_at: earliestControlPlaneTimestamp(timestamps),
- data_status: dataStatus,
- summary: {
- recovery_count: uniqueRecoveries.length,
- awaiting_human_confirmation: uniqueRecoveries.filter((entry) =>
- entry.freshness.data_status === "ready" &&
- entry.recovery.readiness === "awaiting_human_confirmation" &&
- !entry.confirmation &&
- !entry.rejection,
- ).length,
- blocked: uniqueRecoveries.filter((entry) => entry.recovery.readiness === "blocked").length,
- confirmed: uniqueRecoveries.filter((entry) => Boolean(entry.confirmation)).length,
- },
- recoveries: uniqueRecoveries,
- current_reconciliation_observation: currentReconciliationObservationPresentation(),
- policy: {
- human_confirmation_required: true,
- current_evidence_required: true,
- no_order: true,
- execution_authority_granted: false,
- notice: "恢复确认只记录与双审摘要绑定的人工意图;私有控制器仍须重新核验后才可恢复既有执行。",
- },
- errors: uniqueStrings(errors),
- };
-}
-
-async function readReconciliationRecoverySources(env) {
- const store = configStore(env);
- if (!store) return [];
- let listing;
- try {
- listing = await directoryList(env, RECONCILIATION_RECOVERY_SOURCE_PREFIX, RECONCILIATION_RECOVERY_MAX_SOURCES);
- } catch (error) {
- return [emptyReconciliationRecoverySourceSnapshot(sourceListFailure(error, "reconciliation_recovery_source_list_unavailable"))];
- }
- const keys = Array.isArray(listing?.keys) ? listing.keys : [];
- const sources = [];
- for (const entry of keys.slice(0, RECONCILIATION_RECOVERY_MAX_SOURCES)) {
- const key = typeof entry?.name === "string" ? entry.name : "";
- if (!key.startsWith(RECONCILIATION_RECOVERY_SOURCE_PREFIX)) continue;
- try {
- const stored = await readConfigJson(env, key);
- if (!stored) throw new Error("indexed_record_unavailable");
- const source = normalizeReconciliationRecoverySourceSnapshot(stored, key);
- for (const recovery of source.recoveries) if (recovery.mode === "initial_enrollment") await initialEnrollmentAccountOption(env, recovery);
- sources.push(source);
- } catch {
- sources.push(emptyReconciliationRecoverySourceSnapshot("reconciliation_recovery_source_invalid"));
- }
- }
- return sources;
-}
-
-function reconciliationRecoverySourceKey(sourceId) {
- return `${RECONCILIATION_RECOVERY_SOURCE_PREFIX}${sourceId}`;
-}
-
-function runtimeDailyReadModelEnabled(env) {
- return String(env.RUNTIME_DAILY_READ_MODEL_ENABLED || "") === "true";
-}
-
-function runtimeDailyDisabledResponse() {
- return json({ ok: false, error: "runtime_daily_disabled" }, 404);
-}
-
-function runtimeDailyKey(businessDate, target = RUNTIME_DAILY_TARGET) {
- return `${RUNTIME_DAILY_KEY_PREFIX}${target.target_key}:${businessDate}`;
-}
-
-function runtimeDailyToday(now = Date.now()) {
- return runtimeDailyBusinessDate(now);
-}
-
-function runtimeDailyCalendarDate(value) {
- if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return null;
- const [year, month, day] = value.split("-").map(Number);
- const utc = new Date(Date.UTC(year, month - 1, day));
- if (utc.getUTCFullYear() !== year || utc.getUTCMonth() !== month - 1 || utc.getUTCDate() !== day) return null;
- return value;
-}
-
-function runtimeDailyInstant(value) {
- if (typeof value !== "string") return null;
- const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,9})?(Z|[+-](\d{2}):(\d{2}))$/.exec(value);
- if (!match) return null;
- const year = Number(match[1]);
- const month = Number(match[2]);
- const day = Number(match[3]);
- const hour = Number(match[4]);
- const minute = Number(match[5]);
- const second = Number(match[6]);
- if (hour > 23 || minute > 59 || second > 59) return null;
- if (match[7] !== "Z" && (Number(match[8]) > 23 || Number(match[9]) > 59)) return null;
- const utc = new Date(Date.UTC(year, month - 1, day));
- if (utc.getUTCFullYear() !== year || utc.getUTCMonth() !== month - 1 || utc.getUTCDate() !== day) return null;
- const parsed = Date.parse(value);
- return Number.isFinite(parsed) ? parsed : null;
-}
-
-function runtimeDailyExactKeys(value, keys) {
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
- const present = Object.keys(value);
- return present.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
-}
-
-function runtimeDailyBoundedText(value, max) {
- if (typeof value !== "string" || !value || value.length > max) return false;
- if (/[\u0000-\u001f\u007f]/.test(value)) return false;
- const lowered = value.toLowerCase();
- return !["secret", "token", "password", "bearer", "traceback", "/users/", "/home/"].some((marker) => lowered.includes(marker));
-}
-
-function runtimeDailyChoice(value, allowed) {
- return typeof value === "string" && allowed.includes(value);
-}
-
-function runtimeDailyReject(code) {
- throw new HttpError(code, 400);
-}
-
-function runtimeDailyOptionalInstant(value, observedMs) {
- if (value === null) return null;
- const parsed = runtimeDailyInstant(value);
- if (parsed === null) runtimeDailyReject("invalid_runtime_daily_time");
- if (parsed > observedMs + RUNTIME_DAILY_FUTURE_SKEW_MS) runtimeDailyReject("runtime_daily_future_observation");
- return parsed;
-}
-
-function runtimeDailyScheduleInstants(schedule, observedMs) {
- const latest = schedule.latest_due_at === null ? null : runtimeDailyInstant(schedule.latest_due_at);
- const next = schedule.next_due_at === null ? null : runtimeDailyInstant(schedule.next_due_at);
- const grace = schedule.grace_ends_at === null ? null : runtimeDailyInstant(schedule.grace_ends_at);
- if (schedule.latest_due_at !== null && latest === null) runtimeDailyReject("invalid_runtime_daily_time");
- if (schedule.next_due_at !== null && next === null) runtimeDailyReject("invalid_runtime_daily_time");
- if (schedule.grace_ends_at !== null && grace === null) runtimeDailyReject("invalid_runtime_daily_time");
- // latest_due is the last cron time already reached. next_due and grace_ends are plans.
- if (latest !== null && latest > observedMs + RUNTIME_DAILY_FUTURE_SKEW_MS) runtimeDailyReject("invalid_runtime_daily_time");
- if (next !== null && next <= observedMs) runtimeDailyReject("invalid_runtime_daily_time");
- if (latest !== null && next !== null && next <= latest) runtimeDailyReject("invalid_runtime_daily_time");
- if (latest !== null && grace !== null && grace < latest) runtimeDailyReject("invalid_runtime_daily_time");
-}
-
-// These additional constraints describe only the merged Schwab projector. The
-// original LongBridge key sets, time tolerance and receipt protocol stay intact.
-function validateSchwabRuntimeDailyRun(run, observedMs, started, finished) {
- const evidence = run.evidence;
- const confirmations = {
- not_due: ["not_applicable"], no_action: ["not_applicable"], no_signal: ["not_applicable"], no_rebalance: ["not_applicable"],
- risk_blocked: ["not_applicable"], submitted: ["not_observed"], broker_acknowledged: ["acknowledged"],
- partially_filled: ["partially_filled"], filled: ["filled"], reconciliation_required: ["reconciliation_required"],
- failed: ["not_applicable", "not_observed", "reconciliation_required"],
- };
- if ((run.run_id !== null && !/^run\.[0-9a-f]{32}$/.test(run.run_id))
- || run.source_object !== null || run.source_objects.length !== 0 || run.object_updated_at !== null
- || run.execution_lane === "paper" || run.run_time_known !== (started !== null || finished !== null)) runtimeDailyReject("invalid_runtime_daily_run");
- if ((started !== null && started > observedMs) || (finished !== null && finished > observedMs)) runtimeDailyReject("invalid_runtime_daily_time");
- if (run.report_status !== null && !["ok", "skipped", "success", "completed", "no_action", "error", "failed", "failure", "cancelled", "canceled", "timed_out"].includes(run.report_status)) runtimeDailyReject("invalid_runtime_daily_run");
- if (evidence.execution_status !== null && !["no_op", "no_action", "no_signal", "no_rebalance", "skipped", "outside_market_hours", "submitted", "pending_reconciliation", "reconciliation_required", "unknown", "unknown_order", "blocked", "risk_blocked", "error", "failed", "failure", "dry_run", "previewed", "partial", "partially_filled", "filled", "completed"].includes(evidence.execution_status)) runtimeDailyReject("invalid_runtime_daily_run");
- if (!runtimeDailyChoice(evidence.receipt_state, ["valid", "missing", "invalid"])) runtimeDailyReject("invalid_runtime_daily_run");
- if (evidence.receipt_state === "valid") {
- if (typeof evidence.receipt_id !== "string" || !/^execution-receipt\.[0-9a-f]{32}$/.test(evidence.receipt_id)
- || started === null || finished === null
- || !Object.prototype.hasOwnProperty.call(confirmations, evidence.receipt_outcome)
- || !confirmations[evidence.receipt_outcome].includes(evidence.receipt_broker_confirmation)) runtimeDailyReject("invalid_runtime_daily_run");
- } else if (evidence.receipt_id !== null || evidence.receipt_outcome !== null || evidence.receipt_broker_confirmation !== null) runtimeDailyReject("invalid_runtime_daily_run");
- const completedReceipt = { no_submission: "no_action", no_signal: "no_signal", no_rebalance: "no_rebalance", filled: "filled" };
- if (Object.prototype.hasOwnProperty.call(completedReceipt, run.activity)
- && (evidence.receipt_state !== "valid" || evidence.receipt_outcome !== completedReceipt[run.activity]
- || !["ok", "skipped", "success", "completed", "no_action"].includes(run.report_status)
- || run.execution_lane !== "live" || runtimeDailyRunIssue(run) !== null)) runtimeDailyReject("runtime_daily_summary_conflict");
- if (["no_submission", "no_signal", "no_rebalance"].includes(run.activity)
- && (evidence.broker_submission_done !== false || evidence.action_done === true || evidence.orders_pending_count !== 0
- || (evidence.execution_status !== null && !["no_op", "no_action", "no_signal", "no_rebalance", "skipped", "outside_market_hours", "completed"].includes(evidence.execution_status)))) runtimeDailyReject("runtime_daily_summary_conflict");
-}
-
-function validateSchwabRuntimeDailySummary(raw, record, runs, observedMs) {
- if (raw.completeness !== (record.completeness === "complete" ? "complete" : "incomplete")) runtimeDailyReject("runtime_daily_summary_conflict");
- const runSignatures = new Map();
- for (const run of runs) {
- if (run.run_id === null) continue;
- const signature = canonicalResearchTaskJson(run);
- const previous = runSignatures.get(run.run_id);
- if (previous !== undefined && previous !== signature && !record.conflicts.includes(run.run_id)) runtimeDailyReject("runtime_daily_summary_conflict");
- runSignatures.set(run.run_id, signature);
- }
- const incomplete = raw.read_errors.length > 0 || record.conflicts.length > 0 || record.schedule.state === "unevaluable"
- || record.excluded_reports.some(item => item.reason !== "other_business_date")
- || runs.some(run => run.run_id === null || run.evidence.receipt_state !== "valid" || !run.run_time_known);
- if (record.completeness === "complete" && incomplete) runtimeDailyReject("runtime_daily_summary_conflict");
- // A run that only finishes after the due time cannot prove that due cycle.
- // This is a receiver invariant of the existing producer, not a new scheduler.
- const latest = runtimeDailyInstant(record.schedule.latest_due_at);
- const covering = latest === null ? [] : runs.filter(run => {
- const started = runtimeDailyInstant(run.started_at), finished = runtimeDailyInstant(run.finished_at);
- return started !== null && finished !== null && started >= latest && finished <= observedMs
- && runtimeDailyToday(started) === record.business_date;
- });
- const quiet = ["no_submission", "no_signal", "no_rebalance"];
- if ([...quiet, "filled", ...RUNTIME_DAILY_SCHEDULE_ONLY].includes(record.status)
- && record.completeness !== "complete") runtimeDailyReject("runtime_daily_summary_conflict");
- if ([...quiet, "filled"].includes(record.status)) {
- if (record.kind !== "run" || covering.length === 0 || covering.some(run => run.execution_lane !== "live")) runtimeDailyReject("runtime_daily_summary_conflict");
- if (quiet.includes(record.status) && (!['due', 'within_grace'].includes(record.schedule.state)
- || covering.some(run => run.activity !== record.status))) runtimeDailyReject("runtime_daily_summary_conflict");
- if (record.status === "filled" && !covering.some(run => run.activity === "filled")) runtimeDailyReject("runtime_daily_summary_conflict");
- }
- if (RUNTIME_DAILY_SCHEDULE_ONLY.includes(record.status)
- && (record.kind !== "schedule" || record.schedule.state !== record.status || covering.length > 0)) runtimeDailyReject("runtime_daily_summary_conflict");
-}
-
-function validateSchwabRuntimeDailySchedule(schedule, observedMs) {
- const { state, reason, publication_grace_ended: ended, expected_window: window } = schedule;
- const latest = schedule.latest_due_at === null ? null : runtimeDailyInstant(schedule.latest_due_at);
- const next = schedule.next_due_at === null ? null : runtimeDailyInstant(schedule.next_due_at);
- const grace = schedule.grace_ends_at === null ? null : runtimeDailyInstant(schedule.grace_ends_at);
- const reasons = { due: ["publication_grace_ended"], within_grace: ["publication_grace_open"],
- not_due: ["before_schedule", "no_cron_on_business_date"], market_closed: ["market_closed"],
- outside_window: ["outside_expected_window"], unevaluable: ["schedule_missing", "schedule_invalid"] };
- if (!reasons[state]?.includes(reason)
- || (latest !== null && (latest > observedMs || runtimeDailyToday(latest) !== schedule.business_date))
- || (next !== null && (next <= observedMs || runtimeDailyToday(next) !== schedule.business_date))) runtimeDailyReject("invalid_runtime_daily_projection");
- let valid;
- if (state === "unevaluable") valid = latest === null && next === null && grace === null && ended === null && window === "unspecified";
- else if (state === "due" || state === "within_grace") valid = latest !== null && grace !== null && next === null && window !== "outside"
- && (state === "due" ? ended === true && grace <= observedMs : ended === false && grace > observedMs);
- else if (state === "not_due") valid = latest === null && grace === null && ended === null && window !== "outside"
- && ((reason === "before_schedule") === (next !== null));
- else if (state === "market_closed") valid = latest !== null && grace === null && ended === null;
- else valid = window === "outside" && ended === null && ((latest === null) === (grace === null)) && !(grace !== null && next !== null);
- if (!valid) runtimeDailyReject("invalid_runtime_daily_projection");
-}
-
-function normalizeRuntimeDailyRun(run, observedMs, target) {
- if (!runtimeDailyExactKeys(run, [
- "run_id", "source_object", "source_objects", "started_at", "finished_at", "object_updated_at",
- "report_status", "execution_lane", "activity", "run_time_known", "evidence",
- ])) runtimeDailyReject("invalid_runtime_daily_run");
- if (run.run_id !== null && !runtimeDailyBoundedText(run.run_id, 120)) runtimeDailyReject("invalid_runtime_daily_run");
- if (run.source_object !== null && !runtimeDailyBoundedText(run.source_object, 512)) runtimeDailyReject("invalid_runtime_daily_run");
- if (!Array.isArray(run.source_objects) || run.source_objects.length > 8 || run.source_objects.some((item) => !runtimeDailyBoundedText(item, 512))) {
- runtimeDailyReject("invalid_runtime_daily_run");
- }
- const started = runtimeDailyOptionalInstant(run.started_at, observedMs);
- const finished = runtimeDailyOptionalInstant(run.finished_at, observedMs);
- runtimeDailyOptionalInstant(run.object_updated_at, observedMs);
- if (started !== null && finished !== null && finished < started) runtimeDailyReject("invalid_runtime_daily_time");
- if (run.report_status !== null && !runtimeDailyBoundedText(run.report_status, 64)) runtimeDailyReject("invalid_runtime_daily_run");
- if (!runtimeDailyChoice(run.execution_lane, RUNTIME_DAILY_LANES) || !runtimeDailyChoice(run.activity, RUNTIME_DAILY_ACTIVITIES)) {
- runtimeDailyReject("invalid_runtime_daily_run");
- }
- if (typeof run.run_time_known !== "boolean") runtimeDailyReject("invalid_runtime_daily_run");
- const evidenceKeys = [
- "execution_status", "broker_submission_done", "action_done", "orders_pending_count", "errors_present",
- "receipt_outcome", "receipt_broker_confirmation",
- ];
- if (target.platform === "schwab") evidenceKeys.push("receipt_state", "receipt_id");
- if (!runtimeDailyExactKeys(run.evidence, evidenceKeys)) runtimeDailyReject("invalid_runtime_daily_run");
- const evidence = run.evidence;
- if (evidence.execution_status !== null && !runtimeDailyBoundedText(evidence.execution_status, 64)) runtimeDailyReject("invalid_runtime_daily_run");
- for (const field of ["broker_submission_done", "action_done"]) {
- if (evidence[field] !== null && typeof evidence[field] !== "boolean") runtimeDailyReject("invalid_runtime_daily_run");
- }
- if (evidence.orders_pending_count !== null && (!Number.isInteger(evidence.orders_pending_count) || evidence.orders_pending_count < 0 || evidence.orders_pending_count > 100000)) {
- runtimeDailyReject("invalid_runtime_daily_run");
- }
- if (typeof evidence.errors_present !== "boolean") runtimeDailyReject("invalid_runtime_daily_run");
- for (const field of ["receipt_outcome", "receipt_broker_confirmation"]) {
- if (evidence[field] !== null && !runtimeDailyBoundedText(evidence[field], 64)) runtimeDailyReject("invalid_runtime_daily_run");
- }
- if (target.platform === "schwab") validateSchwabRuntimeDailyRun(run, observedMs, started, finished);
- return {
- run_id: run.run_id,
- source_object: run.source_object,
- source_objects: [...run.source_objects],
- started_at: run.started_at,
- finished_at: run.finished_at,
- object_updated_at: run.object_updated_at,
- report_status: run.report_status,
- execution_lane: run.execution_lane,
- activity: run.activity,
- run_time_known: run.run_time_known,
- evidence: { ...evidence },
- };
-}
-
-function normalizeRuntimeDailyProjection(raw, now = Date.now(), registeredTarget = null) {
- if (!runtimeDailyExactKeys(raw, ["platform", "observed_at", "completeness", "read_errors", "records", "unmatched_reports"])) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- const target = registeredTarget || runtimeDailyTarget(raw.platform);
- if (target && raw.platform !== target.platform) runtimeDailyReject("invalid_runtime_daily_target");
- if (!target || !runtimeDailyChoice(raw.completeness, ["complete", "incomplete"])) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- const observedMs = runtimeDailyInstant(raw.observed_at);
- if (observedMs === null) runtimeDailyReject("invalid_runtime_daily_time");
- if (observedMs > now + RUNTIME_DAILY_FUTURE_SKEW_MS) runtimeDailyReject("runtime_daily_future_observation");
- if (!Array.isArray(raw.read_errors) || raw.read_errors.length > RUNTIME_DAILY_MAX_LIST || raw.read_errors.some((item) => !runtimeDailyBoundedText(item, 120))) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (!Array.isArray(raw.records) || raw.records.length !== 1) runtimeDailyReject("invalid_runtime_daily_target");
- if (!Array.isArray(raw.unmatched_reports) || raw.unmatched_reports.length > RUNTIME_DAILY_MAX_LIST) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- const record = raw.records[0];
- if (!runtimeDailyExactKeys(record, [
- "platform", "target_key", "target", "business_date", "timezone", "observed_at", "status", "kind",
- "completeness", "execution_lane", "schedule", "runs", "excluded_reports", "conflicts", "fills",
- ])) runtimeDailyReject("invalid_runtime_daily_projection");
- if (record.platform !== target.platform || record.target_key !== target.target_key || record.timezone !== RUNTIME_DAILY_TIMEZONE) {
- runtimeDailyReject(record.timezone === RUNTIME_DAILY_TIMEZONE ? "invalid_runtime_daily_target" : "invalid_runtime_daily_timezone");
- }
- if (!runtimeDailyExactKeys(record.target, ["service", "strategy_profile", "account_scope"])) runtimeDailyReject("invalid_runtime_daily_target");
- if (record.target.service !== target.service || record.target.strategy_profile !== target.strategy_profile || record.target.account_scope !== target.account_scope) {
- runtimeDailyReject("invalid_runtime_daily_target");
- }
- const businessDate = runtimeDailyCalendarDate(record.business_date);
- if (!businessDate || businessDate > runtimeDailyToday(now)) runtimeDailyReject("invalid_runtime_daily_date");
- if (target.platform === "schwab" && businessDate > runtimeDailyToday(observedMs)) runtimeDailyReject("invalid_runtime_daily_date");
- if (record.observed_at !== raw.observed_at) runtimeDailyReject("invalid_runtime_daily_time");
- if (!runtimeDailyChoice(record.status, RUNTIME_DAILY_STATUSES) || !runtimeDailyChoice(record.kind, RUNTIME_DAILY_KINDS)) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (!runtimeDailyChoice(record.completeness, ["complete", "incomplete", "insufficient"]) || !runtimeDailyChoice(record.execution_lane, RUNTIME_DAILY_LANES)) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (!runtimeDailyExactKeys(record.schedule, [
- "state", "business_date", "timezone", "latest_due_at", "next_due_at", "grace_ends_at",
- "publication_grace_ended", "expected_window", "reason",
- ])) runtimeDailyReject("invalid_runtime_daily_projection");
- const schedule = record.schedule;
- if (!runtimeDailyChoice(schedule.state, RUNTIME_DAILY_SCHEDULE_STATES) || schedule.business_date !== businessDate || schedule.timezone !== RUNTIME_DAILY_TIMEZONE) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- runtimeDailyScheduleInstants(schedule, observedMs);
- if (schedule.publication_grace_ended !== null && typeof schedule.publication_grace_ended !== "boolean") {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (!runtimeDailyChoice(schedule.expected_window, ["unspecified", "inside", "outside"])) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (schedule.reason !== null && !runtimeDailyBoundedText(schedule.reason, 120)) runtimeDailyReject("invalid_runtime_daily_projection");
- if (target.platform === "schwab") validateSchwabRuntimeDailySchedule(schedule, observedMs);
- if (!Array.isArray(record.runs) || record.runs.length > RUNTIME_DAILY_MAX_RUNS) runtimeDailyReject("runtime_daily_run_limit");
- const runs = record.runs.map((run) => normalizeRuntimeDailyRun(run, observedMs, target));
- if (!Array.isArray(record.excluded_reports) || record.excluded_reports.length > RUNTIME_DAILY_MAX_LIST) runtimeDailyReject("invalid_runtime_daily_projection");
- const excluded = record.excluded_reports.map((item) => {
- const keys = Object.keys(item || {});
- const allowed = keys.length === 3 ? ["run_id", "reason", "business_date"] : ["run_id", "reason"];
- if (!runtimeDailyExactKeys(item, allowed) || !runtimeDailyBoundedText(item.reason, 64)) runtimeDailyReject("invalid_runtime_daily_projection");
- if (item.run_id !== null && !runtimeDailyBoundedText(item.run_id, 120)) runtimeDailyReject("invalid_runtime_daily_projection");
- if (allowed.length === 3 && runtimeDailyCalendarDate(item.business_date) === null) runtimeDailyReject("invalid_runtime_daily_date");
- if (target.platform === "schwab" && (allowed.length !== 2
- || !runtimeDailyChoice(item.reason, ["missing_run_time", "invalid_run_time", "inverted_run_time", "future_run_time", "other_business_date"])
- || (item.run_id !== null && !/^run\.[0-9a-f]{32}$/.test(item.run_id)))) runtimeDailyReject("invalid_runtime_daily_projection");
- return allowed.length === 3
- ? { run_id: item.run_id, reason: item.reason, business_date: item.business_date }
- : { run_id: item.run_id, reason: item.reason };
- });
- if (!Array.isArray(record.conflicts) || record.conflicts.length > RUNTIME_DAILY_MAX_LIST || record.conflicts.some((item) => !runtimeDailyBoundedText(item, 160))) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (["no_submission", "no_signal", "no_rebalance", "filled", ...RUNTIME_DAILY_SCHEDULE_ONLY].includes(record.status)
- && (record.conflicts.length || runs.some(run => runtimeDailyRunIssue(run) !== null))) {
- runtimeDailyReject("runtime_daily_summary_conflict");
- }
- if (!runtimeDailyExactKeys(record.fills, ["source", "records", "count"]) || record.fills.source !== "not_connected" || record.fills.count !== null || !Array.isArray(record.fills.records) || record.fills.records.length !== 0) {
- runtimeDailyReject("invalid_runtime_daily_fills");
- }
- const unmatched = raw.unmatched_reports.map((item) => {
- if (target.platform === "schwab") {
- if (!runtimeDailyExactKeys(item, ["reason"]) || !runtimeDailyChoice(item.reason, ["invalid_report", "wrong_platform", "wrong_target", "invalid_source_object"])) runtimeDailyReject("invalid_runtime_daily_projection");
- return { reason: item.reason };
- }
- if (!runtimeDailyExactKeys(item, ["run_id", "platform", "service", "strategy_profile", "account_scope", "reason"])) {
- runtimeDailyReject("invalid_runtime_daily_projection");
- }
- for (const field of ["platform", "service", "strategy_profile", "account_scope", "reason"]) {
- if (item[field] !== null && !runtimeDailyBoundedText(item[field], 120)) runtimeDailyReject("invalid_runtime_daily_projection");
- }
- if (item.run_id !== null && !runtimeDailyBoundedText(item.run_id, 120)) runtimeDailyReject("invalid_runtime_daily_projection");
- return { ...item };
- });
- if (target.platform === "schwab") {
- if (raw.read_errors.some(item => !["report_read_error", "coverage_unconfirmed", "report_rejected"].includes(item))
- || record.conflicts.some(item => !/^run\.[0-9a-f]{32}$/.test(item))
- || record.execution_lane === "paper") runtimeDailyReject("invalid_runtime_daily_projection");
- const lanes = new Set(runs.map(run => run.execution_lane));
- if (record.execution_lane !== (lanes.size === 1 ? runs[0].execution_lane : "insufficient")) runtimeDailyReject("invalid_runtime_daily_projection");
- validateSchwabRuntimeDailySummary(raw, record, runs, observedMs);
- }
- return {
- platform: target.platform,
- observed_at: raw.observed_at,
- completeness: raw.completeness,
- read_errors: [...raw.read_errors],
- records: [{
- platform: target.platform,
- target_key: target.target_key,
- target: { ...record.target },
- business_date: businessDate,
- timezone: RUNTIME_DAILY_TIMEZONE,
- observed_at: raw.observed_at,
- status: record.status,
- kind: record.kind,
- completeness: record.completeness,
- execution_lane: record.execution_lane,
- schedule: { ...schedule },
- runs,
- excluded_reports: excluded,
- conflicts: [...record.conflicts],
- fills: { source: "not_connected", records: [], count: null },
- }],
- unmatched_reports: unmatched,
- };
-}
-
-async function runtimeDailyTrustedBinding(env, target, accountOptions = null) {
- const config = accountOptions ? { options: accountOptions } : await loadAccountOptionsConfig(env);
- const accountKey = runtimeDailyBoundAccountKey(config?.options, target.platform);
- if (!accountKey) return null;
- if (target.platform === "longbridge") return { accountKey, fingerprint: null };
- // The payload never supplies this identity. Reuse the protected account-facts
- // contract rather than inferring a physical account from service/live labels.
- const bindings = await loadAccountFactsBindings(env, { propagateReadErrors: true });
- const matches = (bindings?.bindings || []).filter(item => item.platform === target.platform
- && item.service_name === target.service && item.account_scope === target.account_scope);
- const option = config.options.schwab.find(item => item.key === accountKey);
- if (matches.length !== 1 || !accountFactsOptionMatchesBinding(option, matches[0])) return null;
- return { accountKey, sourceBindingId: matches[0].source_binding.id,
- fingerprint: await sha256Hex(canonicalResearchTaskJson({ target, binding: matches[0] })) };
-}
-
-// A protected registration opts an account into this read model; account-facts
-// bindings alone do not register a daily source or authorize a publisher.
-async function runtimeDailyRegisteredBindings(env, accountOptions) {
- if (!hasConfigStore(env)) throw Error("runtime_daily_bindings_store_unavailable");
- const registry = await readConfigJson(env, "runtime_daily_bindings");
- if (registry === null) return [];
- if (!runtimeDailyExactKeys(registry, ["schema_version", "bindings"])
- || registry.schema_version !== "qsl_runtime_daily_bindings.v1" || !Array.isArray(registry.bindings) || registry.bindings.length > 64)
- throw Error("runtime_daily_bindings_invalid");
- if (!registry.bindings.length) return [];
- const facts = await loadAccountFactsBindings(env, { propagateReadErrors: true });
- const entries = registry.bindings.map(item => {
- const platform = item?.platform || "ibkr";
- const keys = ["account_key", "target_id", "source_binding_id", "strategy_profile", "target_key", ...(Object.hasOwn(item || {}, "platform") ? ["platform"] : [])];
- if (!runtimeDailyExactKeys(item, keys) || !["ibkr", "longbridge", "firstrade", "binance"].includes(platform)
- || !runtimeDailyBoundedText(item.account_key, 120) || !runtimeDailyBoundedText(item.target_id, 120)
- || typeof item.source_binding_id !== "string" || !/^[a-f0-9]{64}$/.test(item.source_binding_id)
- || !runtimeDailyBoundedText(item.strategy_profile, 120)) throw Error("runtime_daily_bindings_invalid");
- const target = parseRuntimeDailyTargetKey(item.target_key, platform);
- if (!target || (platform === "ibkr" && item.target_key.split("|").length !== 4)
- || target.strategy_profile !== item.strategy_profile
- || ![target.service, target.strategy_profile, target.account_scope].every(value => /^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/.test(value)))
- throw Error("runtime_daily_bindings_invalid");
- return { item, target, platform };
- });
- let binance = null, binanceReadFailed = false;
- if (entries.some(entry => entry.platform === "binance")) {
- try { binance = await trustedBinanceFactsBinding(env); }
- catch { binanceReadFailed = true; }
- }
- return Promise.all(entries.map(async ({ item, target, platform }) => {
- if (platform === "binance" && binanceReadFailed) return { platform, target_key: item.target_key, account_key: item.account_key, status: "read_failed" };
- const collision = entries.some(other => other.item !== item && (other.item.account_key === item.account_key && other.platform === platform
- || other.item.target_key === item.target_key || other.item.target_id === item.target_id
- || other.item.source_binding_id === item.source_binding_id));
- const resolved = platform === "binance" ? {ok: Boolean(binance), binding: binance}
- : resolveTrustedAccountFactsBinding(facts, item.target_id, item.source_binding_id);
- const options = (accountOptions?.[platform] || []).filter(option => option.key === item.account_key);
- const b = resolved.binding;
- const optionMatches = Boolean(b) && (platform === "binance" ? options.length === 1 && binanceFactsOptionMatches(options[0], b)
- : options.length === 1 && accountFactsOptionMatchesBinding(options[0], b));
- const binding = resolved.ok && b.platform === platform && b.account_key === item.account_key
- && b.target_id === item.target_id && b.source_binding.id === item.source_binding_id && optionMatches
- && (target.service === b.service_name || (platform === "binance" && b.service_name === ""))
- && (target.account_scope === b.account_scope || (platform === "longbridge" && target.account_scope === "hk" && b.account_scope === "HK")) ? b : null;
- const sharedPhysicalAccount = platform === "ibkr" && binding && entries.some(other => other.platform === "ibkr" && other.item !== item && other.item.account_key !== item.account_key
- && facts?.bindings.some(otherBinding => otherBinding.platform === "ibkr" && otherBinding.account_key === other.item.account_key
- && otherBinding.account_selector === binding.account_selector));
- if (collision || !binding || sharedPhysicalAccount) return { platform, target_key: item.target_key, account_key: item.account_key, status: "conflict" };
- return { platform, target_key: item.target_key, account_key: item.account_key, status: "bound", target,
- sourceBindingId: item.source_binding_id,
- fingerprint: await sha256Hex(canonicalResearchTaskJson({ target, registration: item, binding })) };
- }));
-}
-
-async function runtimeDailyPublicBindings(env, accountOptions, readRegistered = () => runtimeDailyRegisteredBindings(env, accountOptions)) {
- const legacy = await Promise.all(Object.values(RUNTIME_DAILY_TARGETS).map(async target => {
- try {
- const binding = await runtimeDailyTrustedBinding(env, target, accountOptions);
- return { platform: target.platform, target_key: target.target_key, account_key: binding?.accountKey || null,
- status: binding ? "bound" : "unresolved" };
- } catch {
- return { platform: target.platform, target_key: target.target_key, account_key: null, status: "read_failed" };
- }
- }));
- try {
- const registered = await readRegistered();
- return [...legacy, ...registered.map(({ platform, target_key, account_key, status }) => ({ platform, target_key, account_key, status }))];
- } catch {
- return [...legacy, { platform: "ibkr", target_key: "", account_key: null, status: "read_failed" }];
- }
-}
-
-function runtimeDailyStoredProjection(raw, target, binding) {
- if (target.platform === "longbridge" && !binding.fingerprint) return raw;
- if (!runtimeDailyExactKeys(raw, ["binding_fingerprint", "projection"])) throw new HttpError("runtime_daily_record_invalid", 503);
- if (raw.binding_fingerprint !== binding.fingerprint) throw new HttpError("runtime_daily_binding_changed", 409);
- return raw.projection;
-}
-
-function runtimeDailyUnattributedResponse() {
- return json({ ok: false, error: "runtime_daily_account_unattributed" }, 409);
-}
-
-function runtimeDailyPublicRecord(record) {
- return {
- target_key: record.target_key,
- service: record.target.service,
- strategy_profile: record.target.strategy_profile,
- account_scope: record.target.account_scope,
- business_date: record.business_date,
- timezone: record.timezone,
- observed_at: record.observed_at,
- status: record.status,
- kind: record.kind,
- completeness: record.completeness,
- execution_lane: record.execution_lane,
- schedule: {
- state: record.schedule.state,
- business_date: record.schedule.business_date,
- timezone: record.schedule.timezone,
- latest_due_at: record.schedule.latest_due_at,
- next_due_at: record.schedule.next_due_at,
- grace_ends_at: record.schedule.grace_ends_at,
- publication_grace_ended: record.schedule.publication_grace_ended,
- expected_window: record.schedule.expected_window,
- // Only Schwab's validated, fixed closed-session facts may reach health UI.
- // Legacy LongBridge reasons remain private bounded diagnostic text.
- ...(record.platform === "schwab" && ["no_cron_on_business_date", "market_closed"].includes(record.schedule.reason)
- ? { reason: record.schedule.reason } : {}),
- },
- runs: record.runs.map((run) => ({
- run_id: run.run_id,
- started_at: run.started_at,
- finished_at: run.finished_at,
- activity: run.activity,
- execution_lane: run.execution_lane,
- errors_present: run.evidence.errors_present,
- ...(record.platform === "schwab" ? { issue: runtimeDailyRunIssue(run) } : {}),
- })),
- conflict_count: record.conflicts.length,
- excluded_count: record.excluded_reports.length,
- };
-}
-
-// The directory contains only successfully discovered or registered record keys.
-// Unknown coverage remains null; it must never look like an empty history.
-async function runtimeDailyHistory(env, target) {
- const prefix = `${RUNTIME_DAILY_KEY_PREFIX}${target.target_key}:`;
- try {
- const listing = await directoryList(env, prefix, RUNTIME_DAILY_HISTORY_PAGE * RUNTIME_DAILY_HISTORY_MAX_PAGES);
- const dates = listing.keys.map(entry => runtimeDailyCalendarDate(entry.name.slice(prefix.length))).filter(Boolean).sort();
- return { available_from: dates[0] || null, available_through: dates.at(-1) || null,
- stored_days: dates.length, truncated: false };
- } catch {
- return null;
- }
-}
-
-function runtimeDailyReadSummary(status, reason, observedRunCount = null) {
- return {
- source: "stored_runtime_daily_projection", status, reason,
- observed_run_count: observedRunCount,
- total_run_count: status === "complete" ? observedRunCount : null,
- };
-}
-
-function runtimeDailyReadStatus(stored, now) {
- const record = stored.records[0];
- // Preserve partial observations without turning their length into a day total.
- // Read completeness and execution outcome/freshness are separate facts.
- const complete = stored.completeness === "complete" && record.completeness === "complete"
- && !stored.read_errors.length && !stored.unmatched_reports.length && !record.conflicts.length
- && record.kind !== "incomplete" && !["read_incomplete", "missing_report", "insufficient", "conflict"].includes(record.status);
- const observedMs = runtimeDailyInstant(stored.observed_at);
- const today = record.business_date === runtimeDailyToday(now);
- let dataStatus = "historical";
- if (today) {
- const fresh = observedMs !== null && observedMs <= now + RUNTIME_DAILY_FUTURE_SKEW_MS && now - observedMs <= RUNTIME_DAILY_STALE_MS;
- dataStatus = fresh ? "fresh" : "stale";
- }
- return {
- data_status: dataStatus,
- read_summary: runtimeDailyReadSummary(complete ? "complete" : "partial",
- complete ? null : "runtime_daily_incomplete", record.runs.length),
- read_error_count: stored.read_errors.length,
- // These producer codes contain no object paths, identities or exception text.
- // Unknown legacy diagnostics remain private and retain an explicit error.
- read_error_codes: stored.read_errors.map(error => {
- if (["report_read_error", "coverage_unconfirmed", "report_rejected", "read_failed", "read_truncated", "list_failed"].includes(error)) return error;
- if (error === "listing truncated") return "listing_truncated";
- if (error === "runtime_target_enabled_schedule_unverified") return "schedule_unverified";
- if (error === "runtime_target_disabled") return "target_disabled";
- return "source_read_error";
- }),
- unmatched_count: stored.unmatched_reports.length,
- record: runtimeDailyPublicRecord(record),
- fills: { source: "not_connected", records: [], count: null },
- };
-}
-
-async function syncRuntimeDailyResponse(request, env) {
- if (!runtimeDailyReadModelEnabled(env)) return runtimeDailyDisabledResponse();
- const ibkrToken = String(env.IBKR_RUNTIME_DAILY_SYNC_TOKEN || "");
- const supplied = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
- const isIbkr = !!ibkrToken && supplied === ibkrToken && supplied !== String(env.EXECUTION_EVIDENCE_SYNC_TOKEN || "");
- if (isIbkr && [env.ACCOUNT_FACTS_SYNC_TOKEN,
- env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN, env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN,
- env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN, env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
- env.STRATEGY_SWITCH_SYNC_TOKEN, env.RECONCILIATION_RECOVERY_SYNC_TOKEN,
- env.RECONCILIATION_RECOVERY_CONTROLLER_TOKEN, env.CYCLE_HEALTH_PROVISIONER_TOKEN]
- .some(value => value && String(value) === ibkrToken)) {
- throw new HttpError("runtime_daily_token_ambiguous", 503);
- }
- if (!isIbkr) requireDedicatedExecutionEvidenceSyncToken(request, env);
- if (!hasConfigStore(env)) return json({ ok: false, error: "runtime daily KV is not configured" }, 503);
- let raw;
- try {
- raw = await readBoundedJson(request, RUNTIME_DAILY_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid_runtime_daily_projection" }, error.status || 400);
- }
- let target, binding, projection;
- try {
- const configured = String(env.IBKR_RUNTIME_DAILY_TARGET_KEY || "");
- let authorized;
- try { authorized = configured.startsWith("[") || configured.startsWith("{") ? JSON.parse(configured) : [configured]; }
- catch { throw new HttpError("runtime_daily_target_unauthorized", 403); }
- const isGroups = authorized && !Array.isArray(authorized) && typeof authorized === "object";
- if (isGroups && !runtimeDailyExactKeys(authorized, ["ibkr", "execution"])) throw new HttpError("runtime_daily_target_unauthorized", 403);
- const allowed = isGroups ? authorized[isIbkr ? "ibkr" : "execution"] : isIbkr ? authorized : [];
- if (!Array.isArray(allowed) || allowed.length > 64 || new Set(allowed).size !== allowed.length
- || allowed.some(key => typeof key !== "string" || !parseRuntimeDailyTargetKey(key, isIbkr ? "ibkr" : "longbridge")
- || (isIbkr && key.split("|").length !== 4))) throw new HttpError("runtime_daily_target_unauthorized", 403);
- const registeredRequest = raw?.records?.length === 1 && allowed.includes(raw.records[0]?.target_key);
- if (isIbkr || registeredRequest) {
- if (!registeredRequest || (isIbkr ? raw?.platform !== "ibkr" : raw?.platform === "ibkr")) throw new HttpError("runtime_daily_target_unauthorized", 403);
- const options = (await loadAccountOptionsConfig(env)).options;
- const matches = (await runtimeDailyRegisteredBindings(env, options)).filter(item => item.target_key === raw.records[0].target_key && item.platform === raw.platform);
- if (matches.length !== 1 || matches[0].status !== "bound") return runtimeDailyUnattributedResponse();
- target = matches[0].target;
- binding = { accountKey: matches[0].account_key, fingerprint: matches[0].fingerprint, sourceBindingId: matches[0].sourceBindingId };
- } else {
- projection = normalizeRuntimeDailyProjection(raw);
- target = runtimeDailyTarget(projection.platform);
- binding = await runtimeDailyTrustedBinding(env, target);
- }
- }
- catch (error) {
- if (error instanceof HttpError) throw error;
- return json({ ok: false, error: "runtime_daily_read_failed" }, 503);
- }
- if (!binding) return runtimeDailyUnattributedResponse();
- if (!projection) projection = normalizeRuntimeDailyProjection(raw, Date.now(), target);
- if (target.platform === "schwab" || binding.sourceBindingId) {
- // Reuse the existing protected source_binding.id, not a new identity or a
- // body-supplied account. This also guards a new day with no cached fingerprint.
- const sourceBindingId = request.headers.get("X-QSL-Source-Binding-ID");
- if (typeof sourceBindingId !== "string" || !/^[0-9a-f]{64}$/.test(sourceBindingId)) {
- return json({ ok: false, error: "runtime_daily_source_binding_invalid" }, 400);
- }
- if (sourceBindingId !== binding.sourceBindingId) {
- return json({ ok: false, error: "runtime_daily_source_binding_mismatch" }, 409);
- }
- }
- const accountKey = binding.accountKey;
- const businessDate = projection.records[0].business_date;
- const store = configStore(env);
- const key = runtimeDailyKey(businessDate, target);
- const storedText = await store.get(key);
- if (storedText !== null && storedText !== undefined) {
- let storedRaw;
- let storedProjection;
- try {
- storedRaw = JSON.parse(storedText);
- storedProjection = normalizeRuntimeDailyProjection(runtimeDailyStoredProjection(storedRaw, target, binding), Date.now(), target);
- } catch (error) {
- if (error.message === "runtime_daily_binding_changed") return json({ ok: false, error: error.message }, 409);
- return json({ ok: false, error: "runtime_daily_existing_record_invalid" }, 409);
- }
- if (storedProjection.records[0].business_date !== businessDate || storedProjection.platform !== target.platform
- || storedProjection.records[0].target_key !== target.target_key) {
- return json({ ok: false, error: "runtime_daily_existing_record_invalid" }, 409);
- }
- const storedObservedAt = runtimeDailyInstant(storedProjection.observed_at);
- const incomingObservedAt = runtimeDailyInstant(projection.observed_at);
- if (storedObservedAt === null || incomingObservedAt === null) {
- return json({ ok: false, error: "runtime_daily_existing_record_invalid" }, 409);
- }
- if (incomingObservedAt < storedObservedAt) {
- return json({ ok: false, error: "runtime_daily_stale_observation" }, 409);
- }
- if (incomingObservedAt === storedObservedAt) {
- if (canonicalResearchTaskJson(projection) === canonicalResearchTaskJson(storedProjection)) {
- return json({
- ok: true,
- stored: true,
- business_date: businessDate,
- platform: target.platform,
- target_key: target.target_key,
- account_key: accountKey,
- ...(binding.fingerprint && target.platform !== "schwab" ? { observed_at: projection.observed_at } : {}),
- });
- }
- return json({ ok: false, error: "runtime_daily_observation_conflict" }, 409);
- }
- }
- await writeConfigJson(env, key, binding.fingerprint
- ? { binding_fingerprint: binding.fingerprint, projection } : projection);
- return json({
- ok: true,
- stored: true,
- business_date: businessDate,
- platform: target.platform,
- target_key: target.target_key,
- account_key: accountKey,
- ...(binding.fingerprint && target.platform !== "schwab" ? { observed_at: projection.observed_at } : {}),
- });
-}
-
-async function runtimeDailyResponse(request, env, url, context = null) {
- if (!runtimeDailyReadModelEnabled(env)) return runtimeDailyDisabledResponse();
- const session = await (context ? context.readSession() : readSession(request, env));
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json({ ok: false, error: "runtime daily KV is not configured" }, 503);
- const platforms = url.searchParams.getAll("platform");
- const accounts = url.searchParams.getAll("account_key");
- if (platforms.length > 1 || accounts.length > 1 || url.searchParams.getAll("date").length !== 1
- || (platforms.length !== accounts.length)) return json({ ok: false, error: "invalid_runtime_daily_selection" }, 400);
- // Legacy date-only reads always mean PAPER, never the first configured target.
- let target = platforms.length ? runtimeDailyTarget(platforms[0]) : RUNTIME_DAILY_TARGET;
- if ((!target && !["ibkr", "firstrade", "binance"].includes(platforms[0])) || (accounts.length && !runtimeDailyBoundedText(accounts[0], 120))) return json({ ok: false, error: "invalid_runtime_daily_selection" }, 400);
- const historyOptions = url.searchParams.getAll("include_history");
- if (historyOptions.length > 1 || historyOptions.some(value => !["true", "false"].includes(value)))
- return json({ ok: false, error: "invalid_runtime_daily_selection" }, 400);
- const includeHistory = historyOptions[0] !== "false";
- const businessDate = runtimeDailyCalendarDate(url.searchParams.get("date"));
- if (!businessDate || businessDate > runtimeDailyToday()) return json({ ok: false, error: "invalid_runtime_daily_date" }, 400);
- let binding;
- try {
- const config = await (context ? context.readOptions() : loadAccountOptionsConfig(env));
- const matches = accounts.length ? (await (context ? context.readRegistered() : runtimeDailyRegisteredBindings(env, config.options)))
- .filter(item => item.platform === platforms[0] && item.account_key === accounts[0]) : [];
- if (matches.length) {
- if (matches.length !== 1 || matches[0].status !== "bound") return runtimeDailyUnattributedResponse();
- binding = { accountKey: matches[0].account_key, fingerprint: matches[0].fingerprint };
- target = matches[0].target;
- } else if (platforms[0] === "ibkr" || !target) return runtimeDailyUnattributedResponse();
- else binding = await runtimeDailyTrustedBinding(env, target, config.options);
- }
- catch { return json({ ok: false, error: "runtime_daily_read_failed" }, 503); }
- if (!binding || (accounts.length && accounts[0] !== binding.accountKey)) return runtimeDailyUnattributedResponse();
- const accountKey = binding.accountKey;
- let stored;
- try {
- stored = await readConfigJson(env, runtimeDailyKey(businessDate, target));
- } catch {
- return json({ ok: false, error: "runtime_daily_read_failed",
- read_summary: runtimeDailyReadSummary("read_failed", "runtime_daily_read_failed") }, 503);
- }
- const base = {
- ok: true,
- date: businessDate,
- timezone: RUNTIME_DAILY_TIMEZONE,
- account_key: accountKey,
- platform: target.platform,
- target_key: target.target_key,
- history: includeHistory ? await runtimeDailyHistory(env, target) : null,
- };
- if (stored === null || stored === undefined) {
- return json({ ...base, data_status: "unavailable", record: null, fills: null, read_error_count: 0, unmatched_count: 0,
- read_summary: runtimeDailyReadSummary("no_data", "runtime_daily_record_missing") });
- }
- let projection;
- try {
- projection = normalizeRuntimeDailyProjection(runtimeDailyStoredProjection(stored, target, binding), Date.now(), target);
- } catch (error) {
- if (error.message === "runtime_daily_binding_changed") return json({ ok: false, error: error.message }, 409);
- return json({ ok: false, error: "runtime_daily_record_invalid",
- read_summary: runtimeDailyReadSummary("read_failed", "runtime_daily_record_invalid") }, 503);
- }
- if (projection.records[0].business_date !== businessDate || projection.platform !== target.platform
- || projection.records[0].target_key !== target.target_key) {
- return json({ ok: false, error: "runtime_daily_record_invalid",
- read_summary: runtimeDailyReadSummary("read_failed", "runtime_daily_record_invalid") }, 503);
- }
- return json({ ...base, ...runtimeDailyReadStatus(projection, Date.now()) });
-}
-
-async function syncExecutionEvidenceSourceResponse(request, env) {
- requireDedicatedExecutionEvidenceSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "execution evidence KV is not configured" }, 503);
- }
-
- const receiptId = request.headers.get("X-QSL-Execution-Evidence-Receipt");
- if (receiptId !== null && !/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(receiptId)) {
- return json({ ok: false, error: "invalid execution evidence receipt identifier" }, 400);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, EXECUTION_EVIDENCE_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid execution evidence payload" }, error.status || 400);
- }
-
- let source;
- try {
- source = normalizeExecutionEvidenceSourceSnapshot(raw, "execution evidence source snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid execution evidence payload" }, 400);
- }
-
- await writeConfigJson(env, executionEvidenceSourceKey(source.source_id), source);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "execution-evidence-source-sync",
- action: "sync_execution_evidence_source",
- source_id: source.source_id,
- schema_version: source.schema_version,
- deployment_count: source.deployments.length,
- data_status: source.data_status,
- ...(receiptId === null ? {} : { receipt_id: receiptId }),
- });
- } catch {
- // The source snapshot is accepted independently of optional audit retention.
- }
- return json({
- ok: true,
- source_id: source.source_id,
- schema_version: source.schema_version,
- deployment_count: source.deployments.length,
- generated_at: source.generated_at,
- ...(receiptId === null ? {} : { receipt_id: receiptId }),
- });
-}
-
-async function executionEvidenceResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json(emptyExecutionEvidencePayload("snapshot_unavailable"));
- return json(await aggregateExecutionEvidenceSources(env));
-}
-
-async function aggregateExecutionEvidenceSources(env) {
- const sources = await readExecutionEvidenceSources(env);
- if (!sources.length) return emptyExecutionEvidencePayload("snapshot_unavailable");
-
- const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
- const now = Date.now();
- const deployments = [];
- const deploymentIds = new Set();
- const duplicateDeploymentIds = new Set();
- const errors = [];
- const timestamps = [];
- let hasReadySource = false;
- let hasStaleSource = false;
-
- for (const source of sources) {
- const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
- if (source.generated_at) timestamps.push(source.generated_at);
- if (source.computed_at) timestamps.push(source.computed_at);
- if (freshness.data_status === "ready") hasReadySource = true;
- if (freshness.data_status === "stale") {
- hasStaleSource = true;
- errors.push("execution_evidence_source_stale");
- }
- for (const deployment of source.deployments) {
- if (deploymentIds.has(deployment.deployment_id)) {
- duplicateDeploymentIds.add(deployment.deployment_id);
- errors.push("execution_evidence_duplicate_deployment");
- continue;
- }
- deploymentIds.add(deployment.deployment_id);
- deployments.push({ source_id: source.source_id, freshness, deployment });
- }
- errors.push(...source.errors);
- }
-
- const uniqueDeployments = deployments.filter((entry) => !duplicateDeploymentIds.has(entry.deployment.deployment_id));
- const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
- return {
- schema_version: EXECUTION_EVIDENCE_DASHBOARD_SCHEMA_VERSION,
- generated_at: earliestControlPlaneTimestamp(timestamps),
- computed_at: earliestControlPlaneTimestamp(timestamps),
- data_status: dataStatus,
- summary: normalizeExecutionEvidenceSummary(uniqueDeployments.map((entry) => entry.deployment)),
- deployments: uniqueDeployments,
- policy: {
- execution_evidence_read_only: true,
- p6_owner_decision_required: true,
- limited_live_canary_active: false,
- notice: "执行证据按策略、平台和执行通道分别记录;它不授权订单或实盘。",
- },
- errors: uniqueStrings(errors),
- };
-}
-
-async function readExecutionEvidenceSources(env) {
- const store = configStore(env);
- if (!store) return [];
- let listing;
- try {
- listing = await directoryList(env, EXECUTION_EVIDENCE_SOURCE_PREFIX, EXECUTION_EVIDENCE_MAX_SOURCES);
- } catch {
- return [emptyExecutionEvidenceSourceSnapshot("execution_evidence_source_list_unavailable")];
- }
- const keys = Array.isArray(listing?.keys) ? listing.keys : [];
- const sources = [];
- for (const entry of keys.slice(0, EXECUTION_EVIDENCE_MAX_SOURCES)) {
- const key = typeof entry?.name === "string" ? entry.name : "";
- if (!key.startsWith(EXECUTION_EVIDENCE_SOURCE_PREFIX)) continue;
- try {
- const stored = await readConfigJson(env, key);
- if (!stored) throw new Error("indexed_record_unavailable");
- sources.push(normalizeExecutionEvidenceSourceSnapshot(stored, key));
- } catch {
- sources.push(emptyExecutionEvidenceSourceSnapshot("execution_evidence_source_invalid"));
- }
- }
- return sources;
-}
-
-function executionEvidenceSourceKey(sourceId) {
- return `${EXECUTION_EVIDENCE_SOURCE_PREFIX}${sourceId}`;
-}
-
-function runtimeTargetLifecycleAuditState(source, ttlSeconds, now) {
- if (!source) return null;
- const state = structuredClone(source);
- state.freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now).data_status;
- delete state.generated_at;
- delete state.computed_at;
- for (const target of state.targets) {
- if (target.deployment?.observed_at) {
- target.deployment.observed_at = controlPlaneSnapshotFreshness({
- data_status: "ready", computed_at: target.deployment.observed_at,
- }, ttlSeconds, now).data_status;
- }
- }
- return JSON.stringify(state);
-}
-
-async function syncRuntimeTargetLifecycleSourceResponse(request, env) {
- // This publisher has the same narrow scope as execution evidence: sanitized
- // platform status only, never credentials, accounts, orders, or commands.
- requireDedicatedExecutionEvidenceSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "runtime target lifecycle KV is not configured" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, RUNTIME_TARGET_LIFECYCLE_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid runtime target lifecycle payload" }, error.status || 400);
- }
- let source;
- try {
- source = normalizeRuntimeTargetLifecycleSourceSnapshot(raw, "runtime target lifecycle source snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid runtime target lifecycle payload" }, 400);
- }
- const sourceKey = runtimeTargetLifecycleSourceKey(source.source_id);
- let previous = null;
- try {
- previous = normalizeRuntimeTargetLifecycleSourceSnapshot(await readConfigJson(env, sourceKey));
- } catch {
- // Missing/unreadable history must not prevent a fresh, valid observation.
- }
- // Always retain the new evidence timestamps. Only the optional rolling audit
- // skips unchanged polling records; operator actions are audited separately.
- await writeConfigJson(env, sourceKey, source);
- try {
- const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
- const now = Date.now();
- if (runtimeTargetLifecycleAuditState(previous, ttlSeconds, now) !== runtimeTargetLifecycleAuditState(source, ttlSeconds, now)) {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "runtime-target-lifecycle-source-sync",
- action: "sync_runtime_target_lifecycle_source",
- source_id: source.source_id,
- schema_version: source.schema_version,
- target_count: source.targets.length,
- data_status: source.data_status,
- });
- }
- } catch {
- // A valid no-order snapshot remains useful when convenience audit retention fails.
- }
- await maybeAutoDispatchAccountDiagnosis(env, source);
- return json({
- ok: true,
- source_id: source.source_id,
- schema_version: source.schema_version,
- target_count: source.targets.length,
- generated_at: source.generated_at,
- });
-}
-
-async function runtimeReadbackResponse(request, env, url) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
- if ([...url.searchParams.keys()].some(key => key !== "scope") || url.searchParams.getAll("scope").length !== 1
- || !/^[a-z0-9_-]+:[a-zA-Z0-9_.-]+$/.test(url.searchParams.get("scope") || ""))
- return json({ ok: false, error: "invalid_runtime_scope" }, 400);
- const scope = url.searchParams.get("scope");
- try {
- const config = await loadAccountOptionsConfig(env);
- const accounts = Object.entries(config.options || {}).flatMap(([platform, rows]) => rows.map(row => ({ ...row, platform })));
- const matches = accounts.filter(row => `${row.platform}:${row.key}` === scope);
- if (!matches.length) return json({ ok: false, error: "runtime_scope_not_found" }, 404);
- if (matches.length !== 1) return json({ ok: false, error: "runtime_binding_conflict" }, 409);
- if (!hasConfigStore(env)) return json({ ok: false, error: "runtime_readback_unavailable" }, 503);
- const snapshot = await aggregateRuntimeTargetLifecycleSources(env);
- if (snapshot.errors?.some(code => /source_list_unavailable|source_invalid/.test(code)))
- return json({ ok: false, error: "runtime_readback_failed" }, 503);
- return json(runtimeReadbackProjection(matches[0], accounts, snapshot));
- } catch {
- return json({ ok: false, error: "runtime_readback_failed" }, 503);
- }
-}
-
-async function runtimeTargetLifecycleResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json(emptyRuntimeTargetLifecyclePayload("snapshot_unavailable"));
- return json(await aggregateRuntimeTargetLifecycleSources(env));
-}
-
-function requireAccountDiagnosisToken(request, env) {
- const expected = String(env.ACCOUNT_DIAGNOSIS_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("account diagnosis sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("account diagnosis sync token is invalid", 401);
-}
-
-function accountDiagnosisRequestId(value) {
- const text = String(value || "").trim().toLowerCase();
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(text)) {
- throw new HttpError("invalid_account_diagnosis_request_id", 400);
- }
- return text;
-}
-
-function accountDiagnosisChecks(entry, dataStatus) {
- const target = entry?.target?.target || {};
- const monitoring = entry?.target?.monitoring || {};
- const deployment = entry?.target?.deployment || {};
- return {
- configured_state: ["enabled", "disabled"].includes(target.configured_state) ? target.configured_state : "unknown",
- runtime_enabled: typeof deployment.runtime_enabled === "boolean" ? deployment.runtime_enabled : null,
- scheduler_state: ["enabled", "paused"].includes(deployment.scheduler_state) ? deployment.scheduler_state : "unknown",
- runtime_guard: ["pass", "attention", "unavailable"].includes(monitoring.runtime_guard) ? monitoring.runtime_guard : "unavailable",
- execution_heartbeat: ["pass", "attention", "unavailable", "not_due", "not_applicable"].includes(monitoring.execution_heartbeat)
- ? monitoring.execution_heartbeat : "unavailable",
- freshness: ["ready", "stale", "unavailable"].includes(entry?.freshness?.data_status)
- ? entry.freshness.data_status : (dataStatus === "ready" ? "unavailable" : dataStatus),
- };
-}
-
-function accountDiagnosisHasConfirmedAttention(checks) {
- return ["ready", "stale"].includes(checks.freshness)
- && (checks.freshness === "stale" || (checks.configured_state !== "disabled" && checks.runtime_enabled === false)
- || (checks.configured_state === "enabled" && checks.scheduler_state === "paused")
- || checks.runtime_guard === "attention" || checks.execution_heartbeat === "attention");
-}
-
-function accountDiagnosisStateFingerprint(targetId, checks) {
- return `${targetId}:${JSON.stringify(checks)}`;
-}
-
-function accountDiagnosisTargetSpec(platform, targetId) {
- const spec = ACCOUNT_DIAGNOSIS_TARGETS[String(targetId || "").trim()];
- return spec && (platform == null || spec.platform === platform) ? spec : null;
-}
-
-async function accountDiagnosisAccount(env, platform, key) {
- let config;
- try {
- config = await loadAccountOptionsConfig(env);
- } catch {
- throw accountDiagnosisConflict("account_diagnosis_config_unavailable");
- }
- const options = Array.isArray(config.options?.[platform])
- ? config.options[platform].filter(item => item?.key === key) : [];
- if (options.length === 0) throw accountDiagnosisConflict("account_diagnosis_account_not_found");
- if (options.length !== 1) throw accountDiagnosisConflict("account_diagnosis_account_not_unique");
- const account = options[0];
- const targetId = String(account.runtime_status_target_id || "").trim();
- if (!accountDiagnosisTargetSpec(platform, targetId)) throw accountDiagnosisConflict("account_diagnosis_target_not_admitted");
- const allIdentityMatches = Object.entries(config.options || {}).flatMap(([itemPlatform, items]) =>
- (Array.isArray(items) ? items : []).filter(item => String(item?.runtime_status_target_id || "").trim() === targetId)
- .map(item => ({ platform: itemPlatform, key: item.key })));
- if (allIdentityMatches.length !== 1 || allIdentityMatches[0].platform !== platform || allIdentityMatches[0].key !== key) {
- throw accountDiagnosisConflict("account_diagnosis_identity_conflict");
- }
- return { platform, key, account, targetId, config };
-}
-
-async function accountDiagnosisContext(env, platform, key) {
- const identity = await accountDiagnosisAccount(env, platform, key);
- if (!hasConfigStore(env)) throw accountDiagnosisConflict("account_diagnosis_lifecycle_store_unavailable");
- const sources = await readRuntimeTargetLifecycleSources(env);
- const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
- const matches = [];
- for (const source of sources) {
- const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, Date.now());
- for (const target of source.targets) {
- if (target.target_id === identity.targetId && target.target.platform === identity.platform) {
- matches.push({ target, freshness, observedAt: source.computed_at || source.generated_at });
- }
- }
- }
- if (matches.length === 0) {
- throw accountDiagnosisConflict("account_diagnosis_lifecycle_match_missing");
- }
- if (matches.length !== 1) {
- throw accountDiagnosisConflict("account_diagnosis_lifecycle_match_ambiguous");
- }
- const entry = matches[0];
- let checks;
- try {
- checks = accountDiagnosisChecks(entry, entry.freshness.data_status);
- } catch {
- throw accountDiagnosisConflict("account_diagnosis_schema_incompatible");
- }
- if (!checks || typeof checks !== "object") {
- throw accountDiagnosisConflict("account_diagnosis_schema_incompatible");
- }
- if (!["ready", "stale"].includes(checks.freshness)) throw accountDiagnosisConflict("account_diagnosis_source_unavailable");
- const observedAt = entry.observedAt;
- if (!observedAt) throw accountDiagnosisConflict("account_diagnosis_observation_missing");
- return {
- platform, key, targetId: identity.targetId, checks, observedAt,
- stateFingerprint: accountDiagnosisStateFingerprint(identity.targetId, checks),
- attention: accountDiagnosisHasConfirmedAttention(checks),
- };
-}
-
-function accountDiagnosisPublicTask(task, recheckStatus = task?.recheck_dispatch_state) {
- if (!task) return null;
- return {
- request_id: task.request_id,
- platform: task.platform,
- key: task.key,
- target_id: task.target_id,
- trigger: task.trigger,
- status: task.status,
- summary: task.summary || "",
- reason_code: task.reason_code || "",
- dispatch_state: task.dispatch_state,
- recheck_status: recheckStatus,
- created_at: task.created_at,
- updated_at: task.updated_at,
- };
-}
-
-async function accountDiagnosisRecheckStatus(env, task) {
- if (!task || task.status !== "succeeded" || task.recheck_dispatch_state !== "sent") {
- return task?.recheck_dispatch_state || "not_requested";
- }
- const resultAt = Date.parse(task.updated_at);
- if (!Number.isFinite(resultAt)) return "sent";
- try {
- const sources = await readRuntimeTargetLifecycleSources(env);
- const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
- const matches = [];
- for (const source of sources) {
- const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, Date.now());
- const observedAt = source.computed_at || source.generated_at;
- if (freshness.data_status !== "ready" || !observedAt || Date.parse(observedAt) <= resultAt) continue;
- for (const target of source.targets) {
- if (target.target_id === task.target_id && target.target.platform === task.platform) {
- matches.push({ target, freshness, observedAt });
- }
- }
- }
- if (matches.length !== 1) return "sent";
- const checks = accountDiagnosisChecks(matches[0], matches[0].freshness.data_status);
- if (checks.freshness !== "ready" || checks.runtime_guard === "unavailable" || checks.execution_heartbeat === "unavailable"
- || checks.runtime_enabled === null || checks.scheduler_state === "unknown") return "unavailable";
- if (checks.configured_state === "enabled") {
- return checks.runtime_enabled === true && checks.scheduler_state === "enabled"
- && checks.runtime_guard === "pass" && ["pass", "not_due"].includes(checks.execution_heartbeat) ? "passed" : "attention";
- }
- if (checks.configured_state === "disabled") {
- return checks.runtime_enabled === false && checks.scheduler_state === "paused"
- && checks.runtime_guard === "pass" && checks.execution_heartbeat === "not_applicable" ? "passed" : "attention";
- }
- return "unavailable";
- } catch {
- return "sent";
- }
-}
-
-function accountDiagnosisInternalTask(task) {
- return {
- request_id: task.request_id,
- platform: task.platform,
- key: task.key,
- target_id: task.target_id,
- trigger: task.trigger,
- observed_at: task.observed_at,
- checks: task.checks,
- status: task.status,
- };
-}
-
-function accountDiagnosisNativeContext(env) {
- try {
- const binding = JSON.parse(env.ACCOUNT_DIAGNOSIS_NATIVE_BINDING_JSON || "null");
- const expected = ["schema_version", "project", "resource", "audience", "provider", "profile", "model", "worker"];
- if (!binding || Object.keys(binding).sort().join() !== expected.sort().join()
- || binding.schema_version !== "qrs.account-diagnosis-native.v1"
- || binding.project !== "QuantStrategyLab/QuantRuntimeSettings"
- || expected.filter(key => key !== "schema_version").some(key => typeof binding[key] !== "string"
- || !binding[key] || binding[key].length > 200 || /\s/.test(binding[key]))
- || binding.profile.length > 100 || binding.profile.includes(":")) throw Error();
- const url = new URL(binding.resource);
- if (url.protocol !== "https:" || !url.hostname || url.username || url.password || url.search || url.hash
- || binding.resource.endsWith("/")) throw Error();
- const transport = env.ACCOUNT_DIAGNOSIS_NATIVE_TRANSPORT;
- // This seam carries existing approved submit/read authentication. Neither
- // an old GitHub dispatch token nor the QRS callback token can substitute it.
- if (!transport || typeof transport.fetch !== "function") throw Error();
- return { binding, transport };
- } catch {
- throw new HttpError("account_diagnosis_native_not_configured", 503);
- }
-}
-
-function accountDiagnosisNativeRequest(task, binding) {
- const input = accountDiagnosisInternalTask(task);
- const properties = { status: { enum: ["succeeded", "failed", "unknown"] },
- summary: { type: "string", minLength: 1, maxLength: ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS },
- reason_code: { enum: ACCOUNT_DIAGNOSIS_REASON_CODES }, advisory_only: { const: true },
- execution_authority_granted: { const: false } };
- return { mode: "agent", profile: binding.profile, model: binding.model,
- objective: "Diagnose only the supplied account/runtime availability checks. Return an advisory report, not a health or execution approval. Do not access accounts, change configuration, repair, trade, deploy, publish, or notify.",
- materials: [input], timeout_seconds: 600,
- output_schema: { type: "object", additionalProperties: false, required: Object.keys(properties), properties } };
-}
-
-async function accountDiagnosisNativeIO(context, method, path, body, headers = {}) {
- const controller = new AbortController();
- const timer = setTimeout(() => controller.abort(), 10000);
- try {
- const response = await context.transport.fetch(new Request(context.binding.resource + path, {
- method, redirect: "manual", signal: controller.signal,
- headers: { "Content-Type": "application/json", ...headers },
- ...(body === undefined ? {} : { body: JSON.stringify(body) }),
- }));
- if (!response.ok || !response.body) throw Error();
- const reader = response.body.getReader();
- const chunks = [];
- let length = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- length += value.length;
- if (length > 64 * 1024) { await reader.cancel(); throw Error(); }
- chunks.push(value);
- }
- const bytes = new Uint8Array(length);
- let offset = 0;
- for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.length; }
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
- } catch {
- throw new HttpError("account_diagnosis_native_outcome_unknown", 502);
- } finally {
- clearTimeout(timer);
- }
-}
-
-async function accountDiagnosisNativeStop(env, context, task) {
- const reserved = await runtimeInstanceCommand(env, { action: "diagnosis_native_cancel", actor: "native-diagnosis-caller",
- request_id: task.request_id, updated_at: new Date().toISOString() });
- if (reserved.send_cancel) {
- try { await accountDiagnosisNativeIO(context, "POST", `/v1/tasks/${encodeURIComponent(reserved.task.native.task_id)}/cancel`, {}); } catch { /* Unknown cancellation is never retried. */ }
- }
- return reserved;
-}
-
-async function accountDiagnosisNativeReadback(env, context, task, record, cancelRequested = false) {
- const native = task.native;
- if (!native || canonicalResearchTaskJson(native.binding) !== canonicalResearchTaskJson(context.binding)) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- const taskId = record?.id;
- const validId = typeof taskId === "string" && /^[A-Za-z0-9_-]{1,200}$/.test(taskId);
- if (!validId || (native.task_id && taskId !== native.task_id)
- || record.owner !== native.binding.project || record.provider !== native.binding.provider
- || record.result_kind !== "advisory" || record.revision !== 1
- || !Number.isFinite(record.deadline) || (native.task_deadline !== null && native.task_deadline !== record.deadline)
- || await sha256Hex(canonicalResearchTaskJson(record.request ?? null)) !== native.request_sha256) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- const next = structuredClone(native);
- next.task_id = taskId;
- next.task_deadline = record.deadline;
- if (record.worker !== null && record.worker !== undefined || record.attempt !== null && record.attempt !== undefined) {
- if (record.worker !== native.binding.worker || typeof record.attempt !== "string" || !record.attempt || record.attempt.length > 200) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- const claim = [record.worker, record.attempt, record.revision];
- if (native.claim && canonicalResearchTaskJson(native.claim) !== canonicalResearchTaskJson(claim)) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- next.claim = claim;
- } else if (native.claim) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- const expired = Date.now() / 1000 >= Math.min(native.deadline, record.deadline);
- let status = "queued", summary = "", reason = "", terminal = false;
- const negativeTerminal = ["failed", "invalid_output", "cancelled"].includes(record.status);
- if (((cancelRequested || expired || native.cancel_requested || native.cancel_sent) && !negativeTerminal)
- || record.status === "cancel_requested" || record.status === "outcome_unknown") {
- status = "unknown";
- next.phase = "hold";
- } else if (["queued", "submitting", "running"].includes(record.status)) {
- status = record.status === "running" ? "running" : "queued";
- if (status === "running" && !next.claim) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- next.phase = "pending";
- } else if (record.status === "completed") {
- const output = record.output;
- if (!next.claim || !output || Object.keys(output).sort().join() !== "advisory_only,execution_authority_granted,reason_code,status,summary"
- || !["succeeded", "failed", "unknown"].includes(output.status)
- || typeof output.summary !== "string" || !output.summary.trim() || output.summary.length > ACCOUNT_DIAGNOSIS_SUMMARY_MAX_CHARS
- || !ACCOUNT_DIAGNOSIS_REASON_CODES.includes(output.reason_code)
- || output.advisory_only !== true || output.execution_authority_granted !== false) {
- throw new HttpError("invalid_account_diagnosis_result", 400);
- }
- next.output_sha256 = await sha256Hex(canonicalResearchTaskJson(output));
- next.phase = "terminal";
- status = output.status; summary = output.summary.trim(); reason = output.reason_code;
- terminal = true;
- } else if (["failed", "invalid_output", "cancelled"].includes(record.status)) {
- next.phase = "terminal"; status = "failed"; terminal = true;
- summary = "Native diagnosis did not produce an accepted advisory result."; reason = "invalid_response";
- } else {
- throw new HttpError("invalid_account_diagnosis_result", 400);
- }
- // All terminal adoption is still bounded by the original operation deadline.
- if (terminal && status === "succeeded" && Date.now() / 1000 >= Math.min(native.deadline, record.deadline)) {
- return accountDiagnosisNativeStop(env, context, { ...task, native: next });
- }
- if (terminal) next.receipt = await sha256Hex(canonicalResearchTaskJson({ task_id: taskId, claim: next.claim,
- revision: record.revision, request_sha256: next.request_sha256, output_sha256: next.output_sha256,
- native_status: record.status, status, summary, reason }));
- const saved = await runtimeInstanceCommand(env, { action: "diagnosis_native_save", actor: "native-diagnosis-caller",
- request_id: task.request_id, native: next, status, summary, reason_code: reason, updated_at: new Date().toISOString() });
- if ((cancelRequested || native.cancel_requested || expired) && !terminal) return accountDiagnosisNativeStop(env, context, saved.task);
- if (terminal && status === "succeeded" && saved.changed) {
- // Durable result persistence may itself cross expiry; no recheck then.
- if (Date.now() / 1000 >= Math.min(native.deadline, record.deadline)) {
- return accountDiagnosisNativeStop(env, context, saved.task);
- }
- try {
- await dispatchAccountDiagnosisRecheck(env, saved.task);
- await runtimeInstanceCommand(env, { action: "diagnosis_mark_recheck", actor: "native-diagnosis-caller",
- request_id: task.request_id, recheck_dispatch_state: "sent", updated_at: new Date().toISOString() });
- } catch {
- await runtimeInstanceCommand(env, { action: "diagnosis_mark_recheck", actor: "native-diagnosis-caller",
- request_id: task.request_id, recheck_dispatch_state: "unknown", updated_at: new Date().toISOString() });
- }
- }
- return saved;
-}
-
-async function reconcileAccountDiagnosis(env, requestId, cancel = false) {
- const context = accountDiagnosisNativeContext(env);
- const current = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "native-diagnosis-caller", request_id: requestId });
- let task = current.task;
- if (!task?.native) throw new HttpError("account_diagnosis_legacy_retired", 409);
- if (canonicalResearchTaskJson(task.native.binding) !== canonicalResearchTaskJson(context.binding)) {
- throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- }
- if (task.native.phase === "terminal") return { ...current, changed: false };
- if (cancel) {
- const stopped = await accountDiagnosisNativeStop(env, context, task);
- task = stopped.task;
- if (task.native.receipt || task.native.task_id) return stopped;
- }
- if (task.native.task_id && (Date.now() / 1000 >= Math.min(task.native.deadline, task.native.task_deadline ?? Infinity)
- || (task.native.cancel_requested && !task.native.cancel_sent))) return accountDiagnosisNativeStop(env, context, task);
- try {
- let taskId = task.native.task_id;
- if (!taskId) {
- const found = await accountDiagnosisNativeIO(context, "GET", "/v1/tasks/lookup", undefined,
- { "Idempotency-Key": task.native.operation_key, "X-Request-SHA256": task.native.request_sha256 });
- if (!found || Object.keys(found).join() !== "id" || typeof found.id !== "string" || !/^[A-Za-z0-9_-]{1,200}$/.test(found.id)) {
- throw new HttpError("account_diagnosis_native_outcome_unknown", 502);
- }
- taskId = found.id;
- }
- const record = await accountDiagnosisNativeIO(context, "GET", `/v1/tasks/${encodeURIComponent(taskId)}`);
- if (record.id !== taskId) throw accountDiagnosisConflict("account_diagnosis_native_binding_conflict");
- return accountDiagnosisNativeReadback(env, context, task, record, cancel);
- } catch (error) {
- // A read/validation failure retains the original obligation beyond24h.
- try {
- await runtimeInstanceCommand(env, { action: "diagnosis_native_save", actor: "native-diagnosis-caller",
- request_id: requestId, native: { ...task.native, phase: "hold" }, status: "unknown", summary: "", reason_code: "",
- updated_at: new Date().toISOString() });
- } catch { /* Never overwrite a concurrently accepted immutable terminal receipt. */ }
- throw error;
- }
-}
-
-async function dispatchAccountDiagnosis(env, requestId) {
- const context = accountDiagnosisNativeContext(env);
- const current = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "native-diagnosis-caller", request_id: requestId });
- const request = accountDiagnosisNativeRequest(current.task, context.binding);
- const native = { version: "qrs.native-diagnosis.v1", binding: context.binding, request,
- input_sha256: await sha256Hex(canonicalResearchTaskJson(request.materials)),
- request_sha256: await sha256Hex(canonicalResearchTaskJson(request)), operation_key: "qrs-account-diagnosis:" + requestId,
- deadline: Date.now() / 1000 + 600, task_id: null, task_deadline: null, claim: null,
- output_sha256: null, receipt: null, cancel_requested: false, cancel_sent: false, phase: "intent" };
- const intent = await runtimeInstanceCommand(env, { action: "diagnosis_native_intent", actor: "native-diagnosis-caller",
- request_id: requestId, native, updated_at: new Date().toISOString() });
- if (!intent.created) return intent; // Never replay POST, even after a lost reply.
- if (Date.now() / 1000 >= intent.task.native.deadline) return accountDiagnosisNativeStop(env, context, intent.task);
- const record = await accountDiagnosisNativeIO(context, "POST", "/v1/tasks", request,
- { "Idempotency-Key": native.operation_key });
- return accountDiagnosisNativeReadback(env, context, intent.task, record);
-}
-
-function accountDiagnosisAutoEnabled(env) {
- return String(env[ACCOUNT_DIAGNOSIS_AUTO_ENABLED_ENV] || "").toLowerCase() === "true";
-}
-
-async function accountDiagnosisIdentityForTarget(env, targetId) {
- const spec = accountDiagnosisTargetSpec(null, targetId);
- if (!spec) return null;
- let config;
- try {
- config = await loadAccountOptionsConfig(env);
- } catch {
- return null;
- }
- const matches = Object.entries(config.options || {}).flatMap(([platform, items]) =>
- (Array.isArray(items) ? items : [])
- .filter(item => String(item?.runtime_status_target_id || "").trim() === targetId)
- .map(item => ({ platform, key: item.key })));
- if (matches.length !== 1 || matches[0].platform !== spec.platform) return null;
- try {
- return await accountDiagnosisAccount(env, matches[0].platform, matches[0].key);
- } catch {
- return null;
- }
-}
-
-async function maybeAutoDispatchAccountDiagnosis(env, source) {
- if (!accountDiagnosisAutoEnabled(env)) return;
- try { accountDiagnosisNativeContext(env); } catch { return; }
- const now = Date.now();
- const freshness = controlPlaneSnapshotFreshness(source, executionEvidenceStaleTtlSeconds(env), now);
- if (freshness.data_status !== "ready") return;
- const observedAt = source.computed_at || source.generated_at;
- if (!observedAt) return;
- for (const [targetId, spec] of Object.entries(ACCOUNT_DIAGNOSIS_TARGETS)) {
- try {
- const matchingTargets = source.targets.filter(item =>
- item.target_id === targetId && item.target?.platform === spec.platform);
- if (matchingTargets.length !== 1) continue;
- const target = matchingTargets[0];
- const checks = accountDiagnosisChecks({ target, freshness }, freshness.data_status);
- if (checks.configured_state !== "enabled" || !accountDiagnosisHasConfirmedAttention(checks)) continue;
- const identity = await accountDiagnosisIdentityForTarget(env, targetId);
- if (!identity) continue;
- const createdAt = new Date().toISOString();
- const requestId = crypto.randomUUID();
- const created = await runtimeInstanceCommand(env, {
- action: "diagnosis_create", actor: "runtime-target-lifecycle-source-sync", request_id: requestId,
- platform: identity.platform, key: identity.key, target_id: identity.targetId, trigger: "incident",
- observed_at: observedAt, checks, state_fingerprint: accountDiagnosisStateFingerprint(identity.targetId, checks),
- created_at: createdAt, now, auto_source: "source_sync",
- });
- if (!created.created) continue;
- try {
- await dispatchAccountDiagnosis(env, requestId);
- await runtimeInstanceCommand(env, {
- action: "diagnosis_mark_dispatch", actor: "runtime-target-lifecycle-source-sync",
- request_id: requestId, dispatch_state: "sent", updated_at: new Date().toISOString(),
- });
- } catch {
- await runtimeInstanceCommand(env, {
- action: "diagnosis_mark_dispatch", actor: "runtime-target-lifecycle-source-sync",
- request_id: requestId, dispatch_state: "unknown", updated_at: new Date().toISOString(),
- });
- }
- } catch {
- // One target's unavailable identity or dispatch must not affect the other targets.
- }
- }
-}
-
-async function dispatchAccountDiagnosisRecheck(env, task) {
- const token = String(env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
- if (!token) throw new HttpError("account_diagnosis_recheck_unavailable", 503);
- const spec = accountDiagnosisTargetSpec(task?.platform, task?.target_id);
- if (!spec) throw accountDiagnosisConflict("account_diagnosis_target_not_admitted");
- const url = `https://api.github.com/repos/${spec.recheckRepository}/actions/workflows/${spec.recheckWorkflow}/dispatches`;
- const body = task.platform === "longbridge"
- ? { ref: "main", inputs: { target: task.target_id.slice("longbridge.".length) } }
- : { ref: "main" };
- const response = await fetchWithTimeout(url, {
- method: "POST",
- headers: githubHeaders(token),
- body: JSON.stringify(body),
- });
- if (!response.ok) throw new HttpError("account_diagnosis_recheck_unverified", 502);
-}
-
-async function accountDiagnosisResponse(request, env, url) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "account_diagnosis_storage_unavailable" }, 503);
- if (request.method === "GET") {
- const params = [...url.searchParams.keys()].sort();
- if (params.join(",") !== "key,platform") return json({ ok: false, error: "account_diagnosis_query_required" }, 400);
- try {
- const identity = await accountDiagnosisAccount(env, url.searchParams.get("platform"), url.searchParams.get("key"));
- const result = await runtimeInstanceCommand(env, { action: "diagnosis_latest", actor: session.login, platform: identity.platform, key: identity.key });
- const recheckStatus = await accountDiagnosisRecheckStatus(env, result.task);
- return json({ ok: true, account: { platform: identity.platform, key: identity.key, target_id: identity.targetId }, task: accountDiagnosisPublicTask(result.task, recheckStatus) });
- } catch (error) {
- if (error instanceof HttpError) return json(accountDiagnosisErrorPayload(error), error.status);
- return json({ ok: false, error: "account_diagnosis_unavailable", reason_code: "account_diagnosis_unavailable" }, 503);
- }
- }
- if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
- try { requireSameOrigin(request, { requireOrigin: true }); } catch (error) { return json({ ok: false, error: error.message }, error.status || 403); }
- let raw;
- try { raw = await readBoundedJson(request, ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES); } catch (error) {
- return json({ ok: false, error: error.message || "invalid_account_diagnosis_request" }, error.status || 400);
- }
- if (!raw || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).sort().join(",") !== "key,platform,trigger") {
- return json({ ok: false, error: "invalid_account_diagnosis_request" }, 400);
- }
- if (!ACCOUNT_DIAGNOSIS_TRIGGERS.includes(raw.trigger)) return json({ ok: false, error: "invalid_account_diagnosis_trigger" }, 400);
- try { accountDiagnosisNativeContext(env); } catch { return json({ ok: false, error: "account_diagnosis_native_not_configured" }, 503); }
- try {
- const context = await accountDiagnosisContext(env, raw.platform, raw.key);
- if (raw.trigger === "incident" && !context.attention) {
- return json(accountDiagnosisErrorPayload(accountDiagnosisConflict("account_diagnosis_incident_requires_attention")), 409);
- }
- const requestId = crypto.randomUUID();
- const createdAt = new Date().toISOString();
- const created = await runtimeInstanceCommand(env, {
- action: "diagnosis_create", actor: session.login, request_id: requestId,
- platform: context.platform, key: context.key, target_id: context.targetId, trigger: raw.trigger,
- observed_at: context.observedAt, checks: context.checks, state_fingerprint: context.stateFingerprint, created_at: createdAt, now: Date.now(),
- });
- if (!created.created) return json({ ok: true, deduplicated: true, request_id: created.task.request_id, status: created.task.status, task: accountDiagnosisPublicTask(created.task) }, 200);
- try {
- await dispatchAccountDiagnosis(env, requestId);
- await runtimeInstanceCommand(env, { action: "diagnosis_mark_dispatch", actor: session.login, request_id: requestId, dispatch_state: "sent", updated_at: new Date().toISOString() });
- } catch (error) {
- await runtimeInstanceCommand(env, { action: "diagnosis_mark_dispatch", actor: session.login, request_id: requestId, dispatch_state: "unknown", updated_at: new Date().toISOString() });
- const latest = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: session.login, request_id: requestId });
- return json({ ok: false, error: error.message || "account_diagnosis_dispatch_unverified", request_id: latest.task.request_id, status: latest.task.status, task: accountDiagnosisPublicTask(latest.task) }, error.status || 502);
- }
- const latest = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: session.login, request_id: requestId });
- return json({ ok: true, status: "queued", request_id: latest.task.request_id, task: accountDiagnosisPublicTask(latest.task) }, 202);
- } catch (error) {
- if (error instanceof HttpError) return json(accountDiagnosisErrorPayload(error), error.status);
- return json({ ok: false, error: "account_diagnosis_unavailable", reason_code: "account_diagnosis_unavailable" }, 503);
- }
-}
-
-async function accountDiagnosisInternalResponse(request, env, url) {
- try { requireAccountDiagnosisToken(request, env); } catch (error) { return json({ ok: false, error: error.message }, error.status || 401); }
- if (!hasRuntimeInstanceStore(env)) return json({ ok: false, error: "account_diagnosis_storage_unavailable" }, 503);
- if (url.search) return json({ ok: false, error: "invalid_account_diagnosis_request" }, 400);
- let requestId;
- try { requestId = accountDiagnosisRequestId(url.pathname.slice(ACCOUNT_DIAGNOSIS_INTERNAL_PREFIX.length)); } catch (error) {
- return json({ ok: false, error: error.message }, error.status || 400);
- }
- if (request.method === "GET") {
- try {
- const result = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "aab-account-diagnosis", request_id: requestId });
- return json(accountDiagnosisInternalTask(result.task));
- } catch (error) {
- return json({ ok: false, error: error.message || "account_diagnosis_request_not_found" }, error.status || 404);
- }
- }
- if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
- let raw;
- try { raw = await readBoundedJson(request, ACCOUNT_DIAGNOSIS_MAX_BODY_BYTES); } catch (error) {
- return json({ ok: false, error: error.message || "invalid_account_diagnosis_request" }, error.status || 400);
- }
- if (!raw || typeof raw !== "object" || Array.isArray(raw) || raw.request_id !== requestId) {
- return json({ ok: false, error: "invalid_account_diagnosis_request" }, 400);
- }
- try {
- if (Object.keys(raw).sort().join() !== "action,request_id" || !["readback", "cancel"].includes(raw.action)) {
- throw new HttpError("invalid_account_diagnosis_result", 400);
- }
- const result = await reconcileAccountDiagnosis(env, requestId, raw.action === "cancel");
- const latest = await runtimeInstanceCommand(env, { action: "diagnosis_read", actor: "native-diagnosis-caller", request_id: requestId });
- return json({ ok: true, replayed: !result.changed, recheck_status: latest.task.recheck_dispatch_state,
- task: accountDiagnosisPublicTask(latest.task) });
- } catch (error) {
- if (error instanceof HttpError) return json(accountDiagnosisErrorPayload(error), error.status);
- return json({ ok: false, error: "account_diagnosis_native_outcome_unknown" }, 502);
- }
-}
-
-function projectRuntimeAccountState(entry) {
- const base = { scope: "monitoring_only", limit: "not_trading_or_books" };
- const target = entry?.target || {};
- const monitoring = target.monitoring || {};
- const disposition = target.disposition || {};
- const deployment = target.deployment;
- const sourceFresh = entry?.freshness?.data_status === "ready";
- const deploymentFresh = Boolean(deployment?.observed_at) && entry?.deployment_freshness?.data_status === "ready";
- let activation = "unknown";
- if (deploymentFresh && deployment.runtime_enabled === true && deployment.scheduler_state === "enabled") activation = "enabled";
- else if (deploymentFresh && deployment.runtime_enabled === false && deployment.scheduler_state === "paused") activation = "disabled";
- const configured = target.target?.configured_state;
- const retainedFault = monitoring.runtime_guard === "attention"
- || monitoring.execution_heartbeat === "attention"
- || disposition.code === "parked";
- if (retainedFault) return { ...base, health: "abnormal", activation, reason: "retained_attention" };
- if ((configured === "enabled" && activation === "disabled") || (configured === "disabled" && activation === "enabled")) {
- return { ...base, health: "abnormal", activation, reason: "config_inconsistent" };
- }
- if (monitoring.execution_heartbeat === "not_due") {
- return { ...base, health: "unknown", activation, reason: "check_not_due" };
- }
- const enabledAgrees = configured === "enabled"
- && activation === "enabled"
- && monitoring.runtime_guard === "pass"
- && monitoring.execution_heartbeat === "pass"
- && disposition.code === "continue_enabled_monitoring";
- const disabledAgrees = configured === "disabled"
- && activation === "disabled"
- && monitoring.runtime_guard === "pass"
- && monitoring.execution_heartbeat === "not_applicable"
- && disposition.code === "continue_disabled_validation";
- if (sourceFresh && (enabledAgrees || disabledAgrees)) {
- return { ...base, health: "normal", activation, reason: "monitoring_agrees" };
- }
- let reason = "evidence_insufficient";
- if (!sourceFresh) reason = "source_not_fresh";
- else if (!deployment) reason = "deployment_missing";
- else if (!deploymentFresh) reason = "deployment_not_fresh";
- else if (activation === "unknown") reason = "activation_unconfirmed";
- return { ...base, health: "unknown", activation, reason };
-}
-
-async function aggregateRuntimeTargetLifecycleSources(env) {
- const sources = await readRuntimeTargetLifecycleSources(env);
- if (!sources.length) return emptyRuntimeTargetLifecyclePayload("snapshot_unavailable");
- const ttlSeconds = executionEvidenceStaleTtlSeconds(env);
- const now = Date.now();
- const targets = [];
- const targetIds = new Set();
- const duplicateTargetIds = new Set();
- const errors = [];
- const timestamps = [];
- let hasReadySource = false;
- let hasStaleSource = false;
- for (const source of sources) {
- const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
- if (source.generated_at) timestamps.push(source.generated_at);
- if (source.computed_at) timestamps.push(source.computed_at);
- if (freshness.data_status === "ready") hasReadySource = true;
- if (freshness.data_status === "stale") {
- hasStaleSource = true;
- errors.push("runtime_target_lifecycle_source_stale");
- }
- for (const target of source.targets) {
- if (targetIds.has(target.target_id)) {
- duplicateTargetIds.add(target.target_id);
- errors.push("runtime_target_lifecycle_duplicate_target");
- continue;
- }
- targetIds.add(target.target_id);
- const entry = {
- source_id: source.source_id,
- observed_at: earliestControlPlaneTimestamp([source.generated_at, source.computed_at].filter(Boolean)),
- evidence_valid_for_seconds: ttlSeconds,
- freshness,
- target,
- // A lifecycle source is deliberately no-order. Keep this derived
- // observation separate from the monitoring checks so a green check
- // cannot be mistaken for a broker submission or fill receipt.
- execution_observation: runtimeTargetLifecycleExecutionObservation(target),
- ...(target.deployment ? {deployment_freshness: target.deployment.observed_at
- ? controlPlaneSnapshotFreshness({data_status:"ready", computed_at:target.deployment.observed_at}, ttlSeconds, now)
- : freshness} : {}),
- };
- entry.account_state = projectRuntimeAccountState(entry);
- targets.push(entry);
- }
- errors.push(...source.errors);
- }
- const uniqueTargets = targets.filter((entry) => !duplicateTargetIds.has(entry.target.target_id));
- const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
- return {
- schema_version: RUNTIME_TARGET_LIFECYCLE_DASHBOARD_SCHEMA_VERSION,
- generated_at: earliestControlPlaneTimestamp(timestamps),
- computed_at: earliestControlPlaneTimestamp(timestamps),
- data_status: dataStatus,
- summary: {
- target_count: uniqueTargets.length,
- enabled: uniqueTargets.filter((entry) => entry.target.target.configured_state === "enabled").length,
- disabled: uniqueTargets.filter((entry) => entry.target.target.configured_state === "disabled").length,
- attention: uniqueTargets.filter((entry) => entry.target.disposition.code === "parked").length,
- },
- targets: uniqueTargets,
- policy: {
- lifecycle_status_read_only: true,
- execution_observation_read_only: true,
- no_order: true,
- order_or_fill_evidence: "not_collected",
- notice: "已启用目标持续监控;已停用目标持续进行无执行验证。运行或心跳通过只说明监测正常,不代表已提交订单或已成交。",
- },
- errors: uniqueStrings(errors),
- };
-}
-
-function runtimeTargetLifecycleExecutionObservation(target) {
- const monitoring = target?.monitoring || {};
- const configuredState = target?.target?.configured_state;
- let code = "unavailable";
- if (monitoring.runtime_guard === "attention" || monitoring.execution_heartbeat === "attention") {
- code = "attention";
- } else if (monitoring.runtime_guard === "unavailable" || monitoring.execution_heartbeat === "unavailable") {
- code = "unavailable";
- } else if (configuredState === "disabled") {
- code = "not_applicable";
- } else if (monitoring.execution_heartbeat === "not_due") {
- code = "not_due";
- } else if (monitoring.execution_heartbeat === "pass") {
- code = "monitoring_only";
- }
- return {
- code: cleanChoice(code, RUNTIME_TARGET_LIFECYCLE_EXECUTION_OBSERVATIONS, "runtime target lifecycle execution observation"),
- // The source contract always declares no_order=true. Only the separate
- // execution-receipt chain may later provide an order/fill attestation.
- order_or_fill_evidence: "not_collected",
- };
-}
-
-async function readRuntimeTargetLifecycleSources(env) {
- const store = configStore(env);
- if (!store) return [];
- let listing;
- try {
- listing = await directoryList(env, RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX, RUNTIME_TARGET_LIFECYCLE_MAX_SOURCES);
- } catch {
- return [emptyRuntimeTargetLifecycleSourceSnapshot("runtime_target_lifecycle_source_list_unavailable")];
- }
- const keys = Array.isArray(listing?.keys) ? listing.keys : [];
- const sources = [];
- for (const entry of keys.slice(0, RUNTIME_TARGET_LIFECYCLE_MAX_SOURCES)) {
- const key = typeof entry?.name === "string" ? entry.name : "";
- if (!key.startsWith(RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX)) continue;
- try {
- const stored = await readConfigJson(env, key);
- if (!stored) throw new Error("indexed_record_unavailable");
- sources.push(normalizeRuntimeTargetLifecycleSourceSnapshot(stored, key));
- } catch {
- sources.push(emptyRuntimeTargetLifecycleSourceSnapshot("runtime_target_lifecycle_source_invalid"));
- }
- }
- return sources;
-}
-
-function runtimeTargetLifecycleSourceKey(sourceId) {
- return `${RUNTIME_TARGET_LIFECYCLE_SOURCE_PREFIX}${sourceId}`;
-}
-
-async function syncResearchTaskSourceResponse(request, env) {
- requireDedicatedResearchTaskSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "research task KV is not configured" }, 503);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, RESEARCH_TASK_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research task source payload" }, error.status || 400);
- }
-
- let source;
- try {
- source = await normalizeResearchTaskSourceSnapshot(raw, "research task source snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research task source payload" }, 400);
- }
-
- await writeConfigJson(env, researchTaskSourceKey(source.source_id), source);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "research-task-source-sync",
- action: "sync_research_task_source",
- source_id: source.source_id,
- schema_version: source.schema_version,
- task_count: source.tasks.length,
- data_status: source.data_status,
- });
- } catch {
- // A valid no-order task index does not depend on optional audit retention.
- }
- return json({
- ok: true,
- source_id: source.source_id,
- schema_version: source.schema_version,
- task_count: source.tasks.length,
- generated_at: source.generated_at,
- });
-}
-
-async function researchTaskResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json(emptyResearchTaskPayload("snapshot_unavailable"));
- return json(await aggregateResearchTaskSources(env));
-}
-
-async function aggregateResearchTaskSources(env) {
- const sources = await readResearchTaskSources(env);
- if (!sources.length) return emptyResearchTaskPayload("snapshot_unavailable");
-
- const ttlSeconds = researchTaskStaleTtlSeconds(env);
- const now = Date.now();
- const taskIds = new Set();
- const duplicateTaskIds = new Set();
- const tasks = [];
- const errors = [];
- const timestamps = [];
- let hasReadySource = false;
- let hasStaleSource = false;
-
- for (const source of sources) {
- const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
- if (source.generated_at) timestamps.push(source.generated_at);
- if (source.computed_at) timestamps.push(source.computed_at);
- if (freshness.data_status === "ready") hasReadySource = true;
- if (freshness.data_status === "stale") {
- hasStaleSource = true;
- errors.push("research_task_source_stale");
- }
- for (const task of source.tasks) {
- if (taskIds.has(task.task_id)) {
- duplicateTaskIds.add(task.task_id);
- errors.push("research_task_duplicate_task");
- continue;
- }
- taskIds.add(task.task_id);
- tasks.push({ source_id: source.source_id, freshness, task });
- }
- errors.push(...source.errors);
- }
-
- const uniqueTasks = tasks.filter((entry) => !duplicateTaskIds.has(entry.task.task_id));
- const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
- return {
- schema_version: RESEARCH_TASK_DASHBOARD_SCHEMA_VERSION,
- generated_at: earliestControlPlaneTimestamp(timestamps),
- computed_at: earliestControlPlaneTimestamp(timestamps),
- data_status: dataStatus,
- summary: { task_count: uniqueTasks.length },
- tasks: uniqueTasks,
- policy: {
- research_only: true,
- no_order: true,
- size_zero_required: true,
- p4_p5_p6_authorized: false,
- notice: "研究任务只用于离线、零仓位实验;不会调参、改代码、部署或下单。",
- },
- errors: uniqueStrings(errors),
- };
-}
-
-async function readResearchTaskSources(env) {
- const store = configStore(env);
- if (!store) return [];
- let listing;
- try {
- listing = await directoryList(env, RESEARCH_TASK_SOURCE_PREFIX, RESEARCH_TASK_MAX_SOURCES);
- } catch {
- return [emptyResearchTaskSourceSnapshot("research_task_source_list_unavailable")];
- }
- const keys = Array.isArray(listing?.keys) ? listing.keys : [];
- const sources = [];
- for (const entry of keys.slice(0, RESEARCH_TASK_MAX_SOURCES)) {
- const key = typeof entry?.name === "string" ? entry.name : "";
- if (!key.startsWith(RESEARCH_TASK_SOURCE_PREFIX)) continue;
- try {
- const stored = await readConfigJson(env, key);
- if (!stored) throw new Error("indexed_record_unavailable");
- sources.push(await normalizeResearchTaskSourceSnapshot(stored, key));
- } catch {
- sources.push(emptyResearchTaskSourceSnapshot("research_task_source_invalid"));
- }
- }
- return sources;
-}
-
-function researchTaskSourceKey(sourceId) {
- return `${RESEARCH_TASK_SOURCE_PREFIX}${sourceId}`;
-}
-
-async function aggregateControlPlaneSources(env) {
- const now = Date.now();
- let retirements;
- try {
- const stored = await configStore(env).get(CONTROL_PLANE_SOURCE_RETIREMENTS_KEY);
- retirements = stored === null || stored === undefined
- ? new Map()
- : normalizeControlPlaneSourceRetirements(JSON.parse(stored), now);
- } catch {
- return emptyControlPlanePayload("control_plane_source_retirements_invalid");
- }
- const sources = await readControlPlaneSources(env);
- // A legacy aggregate has no source identity and cannot honor a retirement.
- if (!sources?.length && !retirements.size) return null;
-
- const ttlSeconds = controlPlaneStaleTtlSeconds(env);
- const candidates = [];
- const historicalSources = [];
- const candidateIds = new Set();
- const duplicateCandidateIds = new Set();
- const errors = [];
- const timestamps = [];
- let hasReadySource = false;
- let hasStaleSource = false;
-
- for (const source of sources || []) {
- const sourceFreshness = controlPlaneResearchSnapshotFreshness(source, ttlSeconds, now);
- const retirement = retirements.get(source.source_id);
- if (retirement) {
- historicalSources.push({ retirement, snapshot: source, freshness: sourceFreshness });
- continue;
- }
- if (source.generated_at) timestamps.push(source.generated_at);
- if (source.computed_at) timestamps.push(source.computed_at);
- if (sourceFreshness.data_status === "ready") hasReadySource = true;
- if (sourceFreshness.data_status === "stale") {
- hasStaleSource = true;
- errors.push("control_plane_source_stale");
- }
- for (const candidate of source.candidates) {
- if (candidateIds.has(candidate.candidate_id)) {
- duplicateCandidateIds.add(candidate.candidate_id);
- errors.push("control_plane_duplicate_candidate");
- continue;
- }
- candidateIds.add(candidate.candidate_id);
- candidates.push({
- ...candidate,
- source_id: source.source_id,
- freshness: mergeControlPlaneFreshness(candidate.freshness, sourceFreshness),
- });
- }
- errors.push(...source.errors);
- }
-
- const dataStatus = hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable");
- const uniqueCandidates = candidates.filter((candidate) => !duplicateCandidateIds.has(candidate.candidate_id));
- const uniqueErrors = uniqueStrings(errors);
- return {
- schema_version: "qsl_control_plane_dashboard.v1",
- generated_at: earliestControlPlaneTimestamp(timestamps),
- computed_at: earliestControlPlaneTimestamp(timestamps),
- data_status: dataStatus,
- summary: normalizeControlPlaneSummary(uniqueCandidates),
- attention: normalizeControlPlaneAttention({
- dataStatus,
- candidates: uniqueCandidates,
- errors: uniqueErrors,
- }),
- candidates: uniqueCandidates,
- ...(retirements.size ? { historical_sources: historicalSources } : {}),
- policy: normalizeControlPlanePolicy({
- p4_p5_automation: "not_configured",
- p6_owner_decision_required: true,
- notice: "P1–P3 自动研究已接入;P4/P5 尚未配置,live 仍需所有者明确决定。",
- }, "aggregated control plane policy"),
- errors: uniqueErrors,
- };
-}
-
-function normalizeControlPlaneSourceRetirements(payload, now) {
- const value = assertExactFields(payload, ["schema_version", "retirements"], CONTROL_PLANE_SOURCE_RETIREMENTS_KEY);
- if (value.schema_version !== "qsl_control_plane_source_retirements.v1"
- || !Array.isArray(value.retirements) || value.retirements.length > CONTROL_PLANE_MAX_SOURCES) {
- throw new Error("invalid control plane source retirements");
- }
- const retirements = new Map();
- for (const entry of value.retirements) {
- const item = assertExactFields(entry, ["source_id", "retired_at", "reason"], "source retirement");
- const sourceId = normalizeControlPlaneIdentifier(item.source_id, "source retirement.source_id", false);
- const retiredAt = normalizeStrategyHealthTimestamp(item.retired_at, "source retirement.retired_at");
- const reason = typeof item.reason === "string"
- ? sanitizeStrategyHealthText(item.reason, "source retirement.reason", 240, false, null) : null;
- // "unavailable" is the diagnostic identity for unreadable source records.
- if (sourceId === "unavailable" || retirements.has(sourceId) || Date.parse(retiredAt) > now || !reason) {
- throw new Error("invalid control plane source retirement");
- }
- retirements.set(sourceId, { source_id: sourceId, retired_at: retiredAt, reason });
- }
- return retirements;
-}
-
-async function readControlPlaneSources(env) {
- const store = configStore(env);
- if (!store) return null;
- let listing;
- try {
- listing = await directoryList(env, CONTROL_PLANE_SOURCE_PREFIX, CONTROL_PLANE_MAX_SOURCES);
- } catch (error) {
- return [emptyControlPlaneSourceSnapshot(sourceListFailure(error, "control_plane_source_list_unavailable"))];
- }
- const keys = Array.isArray(listing?.keys) ? listing.keys : [];
- const sources = [];
- for (const entry of keys.slice(0, CONTROL_PLANE_MAX_SOURCES)) {
- const key = typeof entry?.name === "string" ? entry.name : "";
- if (!key.startsWith(CONTROL_PLANE_SOURCE_PREFIX)) continue;
- try {
- const stored = await readConfigJson(env, key);
- if (!stored) throw new Error("indexed_record_unavailable");
- const source = normalizeControlPlaneSourceSnapshot(stored, key);
- if (key !== controlPlaneSourceKey(source.source_id)) throw new Error("control plane source identity mismatch");
- sources.push(source);
- } catch {
- sources.push(emptyControlPlaneSourceSnapshot("control_plane_source_invalid"));
- }
- }
- return sources;
-}
-
-function controlPlaneSourceKey(sourceId) {
- return `${CONTROL_PLANE_SOURCE_PREFIX}${sourceId}`;
-}
-
-async function syncAdaptiveSelectionSourceResponse(request, env) {
- requireDedicatedAdaptiveSelectionSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "adaptive selection KV is not configured" }, 503);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, ADAPTIVE_SELECTION_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid adaptive selection payload" }, error.status || 400);
- }
-
- let source;
- try {
- source = await normalizeAdaptiveSelectionSourceSnapshot(raw, "adaptive selection source snapshot");
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid adaptive selection payload" }, 400);
- }
-
- await writeConfigJson(env, adaptiveSelectionSourceKey(source.source_id), source);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "adaptive-selection-source-sync",
- action: "sync_adaptive_selection_source",
- source_id: source.source_id,
- schema_version: source.schema_version,
- candidate_count: source.decision?.candidates.length || 0,
- data_status: source.data_status,
- no_order: true,
- });
- } catch {
- // This source remains safe and usable if the rolling convenience log fails.
- }
- return json({
- ok: true,
- source_id: source.source_id,
- schema_version: source.schema_version,
- candidate_count: source.decision?.candidates.length || 0,
- generated_at: source.generated_at,
- no_order: true,
- });
-}
-
-async function syncM0ResearchLedgerResponse(request, env) {
- requireDedicatedM0ResearchSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "M0 research ledger KV is not configured" }, 503);
- }
-
- let raw;
- try {
- raw = await readBoundedJson(request, M0_RESEARCH_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid M0 research ledger payload" }, error.status || 400);
- }
-
- let envelope;
- try {
- envelope = await normalizeM0ResearchLedgerTransport(raw, "M0 research ledger transport");
- } catch (error) {
- // Validation deliberately completes before any KV write. A malformed,
- // over-scoped, or digest-mismatched payload can therefore never replace
- // the last known-good current ledger.
- return json({ ok: false, error: error.message || "invalid M0 research ledger payload" }, 400);
- }
-
- const current = await readCurrentM0ResearchLedgerRecord(env);
- if (current) {
- // A retry for the exact immutable source is not a new decision or a
- // second write. Acknowledge it so a lost response cannot make a valid
- // no-order publication look failed, while retaining the guards below.
- if (envelope.source_artifact.sha256 === current.envelope.source_artifact.sha256) {
- return json({
- ok: true,
- schema_version: current.envelope.schema_version,
- source_repository: current.envelope.source_artifact.repository,
- source_revision: current.envelope.source_artifact.revision,
- source_run_id: current.envelope.source_artifact.run_id,
- artifact_id: current.envelope.source_artifact.artifact_id,
- ledger_sha256: current.envelope.ledger_sha256,
- replayed: true,
- no_order: true,
- expires_at: current.expires_at,
- });
- }
- const replayError = m0ResearchLedgerReplayError(current.envelope, envelope);
- if (replayError) return json({ ok: false, error: replayError }, 409);
- }
-
- // Capture once so the persisted interval is exactly the requested physical
- // retention even when the request crosses a wall-clock second boundary.
- const storedNow = new Date();
- const storedAt = utcTimestampSeconds(storedNow);
- const expiresAt = utcTimestampSeconds(new Date(storedNow.getTime() + M0_RESEARCH_RETENTION_SECONDS * 1000));
- const record = {
- schema_version: M0_RESEARCH_STORAGE_SCHEMA_VERSION,
- stored_at: storedAt,
- expires_at: expiresAt,
- envelope,
- };
- try {
- // Archive first: an archive failure must not advance the current pointer.
- // The archive identity is derived exclusively from the verified digest;
- // callers never choose a KV key.
- await writeM0ResearchLedgerRecord(env, m0ResearchLedgerArchiveKey(envelope.ledger_sha256), record);
- await writeM0ResearchLedgerRecord(env, M0_RESEARCH_CURRENT_KEY, record);
- } catch {
- return json({ ok: false, error: "M0 research ledger persistence failed" }, 503);
- }
-
- try {
- await appendAuditLog(env, {
- ts: storedAt,
- login: "m0-research-ledger-sync",
- action: "sync_m0_research_ledger",
- source_repository: envelope.source_artifact.repository,
- source_revision: envelope.source_artifact.revision,
- source_run_id: envelope.source_artifact.run_id,
- artifact_id: envelope.source_artifact.artifact_id,
- ledger_sha256: envelope.ledger_sha256,
- no_order: true,
- });
- } catch {
- // Retention of an optional convenience log must not change a valid,
- // already persisted no-order research ledger.
- }
- return json({
- ok: true,
- schema_version: envelope.schema_version,
- source_repository: envelope.source_artifact.repository,
- source_revision: envelope.source_artifact.revision,
- source_run_id: envelope.source_artifact.run_id,
- artifact_id: envelope.source_artifact.artifact_id,
- ledger_sha256: envelope.ledger_sha256,
- replayed: false,
- no_order: true,
- expires_at: expiresAt,
- });
-}
-
-async function m0ResearchLedgerResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json(emptyM0ResearchDashboardPayload("m0_research_ledger_unavailable"));
- const record = await readCurrentM0ResearchLedgerRecord(env);
- return json(record
- ? projectM0ResearchDashboardForRead(record.envelope.ledger, record.envelope.ledger_sha256)
- : emptyM0ResearchDashboardPayload("m0_research_ledger_unavailable"));
-}
-
-function m0ResearchLedgerReplayError(current, incoming) {
- if (!current || !incoming) return null;
- if (incoming.ledger_sha256 === current.ledger_sha256
- || incoming.source_artifact.sha256 === current.source_artifact.sha256) {
- return "M0 research ledger current replay rejected";
- }
- // Run IDs are closed identifiers rather than an assumed numeric sequence.
- // An equal source/run identity is a replay; ledger time is the portable
- // ordering guard for a different run identifier.
- if (incoming.source_artifact.repository === current.source_artifact.repository
- && incoming.source_artifact.run_id === current.source_artifact.run_id) {
- return "M0 research ledger current replay rejected";
- }
- const incomingTime = Date.parse(incoming.ledger.computed_at);
- const currentTime = Date.parse(current.ledger.computed_at);
- if (Number.isFinite(incomingTime) && Number.isFinite(currentTime) && incomingTime <= currentTime) {
- return "M0 research ledger time rollback rejected";
- }
- return null;
-}
-
-function m0ResearchLedgerArchiveKey(ledgerSha256) {
- return `${M0_RESEARCH_ARCHIVE_PREFIX}${ledgerSha256}`;
-}
-
-async function writeM0ResearchLedgerRecord(env, key, record) {
- const store = configStore(env);
- if (!store) throw new Error("M0 research ledger KV is not configured");
- await store.put(key, JSON.stringify(record), { expirationTtl: M0_RESEARCH_RETENTION_SECONDS });
-}
-
-async function readCurrentM0ResearchLedgerRecord(env) {
- if (!hasConfigStore(env)) return null;
- let stored;
- try {
- stored = await readConfigJson(env, M0_RESEARCH_CURRENT_KEY);
- } catch {
- return null;
- }
- if (!stored) return null;
- try {
- return await normalizeM0ResearchLedgerStorageRecord(stored, "M0 research ledger current record");
- } catch {
- return null;
- }
-}
-
-async function adaptiveSelectionResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!hasConfigStore(env)) return json(emptyAdaptiveSelectionPayload("adaptive_selection_source_unavailable"));
- return json(await aggregateAdaptiveSelectionSources(env));
-}
-
-async function aggregateAdaptiveSelectionSources(env) {
- const sources = await readAdaptiveSelectionSources(env);
- if (!sources.length) return emptyAdaptiveSelectionPayload("adaptive_selection_source_unavailable");
-
- const ttlSeconds = adaptiveSelectionStaleTtlSeconds(env);
- const now = Date.now();
- const selections = [];
- const errors = [];
- const timestamps = [];
- let hasReadySource = false;
- let hasStaleSource = false;
-
- for (const source of sources) {
- const freshness = controlPlaneSnapshotFreshness(source, ttlSeconds, now);
- if (source.generated_at) timestamps.push(source.generated_at);
- if (source.computed_at) timestamps.push(source.computed_at);
- if (freshness.data_status === "ready") hasReadySource = true;
- if (freshness.data_status === "stale") {
- hasStaleSource = true;
- errors.push("adaptive_selection_source_stale");
- }
- if (source.decision) selections.push({ source_id: source.source_id, freshness, decision: source.decision });
- errors.push(...source.errors);
- }
-
- return {
- schema_version: ADAPTIVE_SELECTION_DASHBOARD_SCHEMA_VERSION,
- generated_at: earliestControlPlaneTimestamp(timestamps),
- computed_at: earliestControlPlaneTimestamp(timestamps),
- data_status: hasStaleSource ? "stale" : (hasReadySource ? "ready" : "unavailable"),
- summary: normalizeAdaptiveSelectionSummary(selections),
- selections: selections.sort((left, right) => left.source_id.localeCompare(right.source_id)),
- policy: {
- authority: ADAPTIVE_SELECTION_AUTHORITY,
- no_order: true,
- execution_authority_granted: false,
- notice: "M1 仅展示 Shadow 建议和拒绝原因;不会修改策略、平台、资金、运行状态或订单。",
- },
- errors: uniqueStrings(errors),
- };
-}
-
-async function readAdaptiveSelectionSources(env) {
- const store = configStore(env);
- if (!store) return [];
- let listing;
- try {
- listing = await directoryList(env, ADAPTIVE_SELECTION_SOURCE_PREFIX, ADAPTIVE_SELECTION_MAX_SOURCES);
- } catch {
- return [emptyAdaptiveSelectionSourceSnapshot("adaptive_selection_source_list_unavailable")];
- }
- const keys = Array.isArray(listing?.keys) ? listing.keys : [];
- const sources = [];
- for (const entry of keys.slice(0, ADAPTIVE_SELECTION_MAX_SOURCES)) {
- const key = typeof entry?.name === "string" ? entry.name : "";
- if (!key.startsWith(ADAPTIVE_SELECTION_SOURCE_PREFIX)) continue;
- try {
- const stored = await readConfigJson(env, key);
- if (!stored) throw new Error("indexed_record_unavailable");
- sources.push(await normalizeAdaptiveSelectionSourceSnapshot(stored, key));
- } catch {
- sources.push(emptyAdaptiveSelectionSourceSnapshot("adaptive_selection_source_invalid"));
- }
- }
- return sources;
-}
-
-function adaptiveSelectionSourceKey(sourceId) {
- return `${ADAPTIVE_SELECTION_SOURCE_PREFIX}${sourceId}`;
-}
-
-function controlPlaneSnapshotFreshness(snapshot, ttlSeconds, now) {
- const timestamps = [snapshot.generated_at, snapshot.computed_at]
- .filter(Boolean)
- .map((value) => Date.parse(value));
- const freshnessAt = timestamps.length ? Math.min(...timestamps) : Number.NaN;
- const futureBeyondClockSkew = Number.isFinite(freshnessAt) && freshnessAt > now + 5 * 60 * 1000;
- const ageSeconds = futureBeyondClockSkew
- ? Number.POSITIVE_INFINITY
- : Number.isFinite(freshnessAt)
- ? Math.max(0, Math.round((now - freshnessAt) / 1000))
- : Number.POSITIVE_INFINITY;
- const dataStatus = snapshot.data_status === "ready" && ageSeconds > ttlSeconds
- ? "stale"
- : snapshot.data_status;
- return { data_status: dataStatus, age_seconds: Number.isFinite(ageSeconds) ? ageSeconds : null };
-}
-
-function controlPlaneResearchSnapshotFreshness(snapshot, ttlSeconds, now) {
- if (snapshot.data_status !== "ready") {
- return controlPlaneSnapshotFreshness(snapshot, ttlSeconds, now);
- }
- const timestamps = [snapshot.generated_at, snapshot.computed_at]
- .filter(Boolean)
- .map((value) => Date.parse(value));
- const freshnessAt = timestamps.length ? Math.min(...timestamps) : Number.NaN;
- const futureBeyondClockSkew = Number.isFinite(freshnessAt) && freshnessAt > now + 5 * 60 * 1000;
- const ageSeconds = futureBeyondClockSkew
- ? Number.POSITIVE_INFINITY
- : Number.isFinite(freshnessAt)
- ? Math.max(0, Math.round((now - freshnessAt) / 1000))
- : Number.POSITIVE_INFINITY;
- if (!Number.isFinite(freshnessAt) || futureBeyondClockSkew) {
- return { data_status: "stale", age_seconds: null };
- }
-
- const ttlDeadline = freshnessAt + ttlSeconds * 1000;
- const nextScheduledRefresh = nextControlPlaneResearchScheduleAfter(freshnessAt);
- const scheduledDeadline = nextScheduledRefresh + CONTROL_PLANE_RESEARCH_DELIVERY_GRACE_MS;
- const staleDeadline = Math.max(ttlDeadline, scheduledDeadline);
- return {
- data_status: now > staleDeadline ? "stale" : "ready",
- age_seconds: ageSeconds,
- };
-}
-
-function nextControlPlaneResearchScheduleAfter(freshnessAt) {
- const scheduled = new Date(freshnessAt);
- scheduled.setUTCMinutes(0, 0, 0);
- scheduled.setUTCHours(CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_HOUR);
- if (scheduled.getTime() <= freshnessAt) scheduled.setUTCDate(scheduled.getUTCDate() + 1);
- while (!CONTROL_PLANE_RESEARCH_SCHEDULE_UTC_DAYS.has(scheduled.getUTCDay())) {
- scheduled.setUTCDate(scheduled.getUTCDate() + 1);
- }
- return scheduled.getTime();
-}
-
-// A recently published source must not be able to re-advertise an old
-// reconciliation candidate as current. The private controller independently
-// verifies raw receipts, but the human console also fails closed here.
-function reconciliationRecoveryEvidenceFreshness(recovery, sourceFreshness, ttlSeconds, now) {
- const observedAt = Date.parse(recovery.mode === "initial_enrollment" ? recovery.candidate.last_observed_at : recovery.last_observed_at);
- const futureBeyondClockSkew = Number.isFinite(observedAt) && observedAt > now + 5 * 60 * 1000;
- const evidenceAgeSeconds = futureBeyondClockSkew
- ? Number.POSITIVE_INFINITY
- : Number.isFinite(observedAt)
- ? Math.max(0, Math.round((now - observedAt) / 1000))
- : Number.POSITIVE_INFINITY;
- const ageSeconds = sourceFreshness.age_seconds === null
- ? evidenceAgeSeconds
- : Math.max(sourceFreshness.age_seconds, evidenceAgeSeconds);
- const dataStatus = sourceFreshness.data_status === "ready" && evidenceAgeSeconds <= ttlSeconds
- ? "ready"
- : "stale";
- return { data_status: dataStatus, age_seconds: Number.isFinite(ageSeconds) ? ageSeconds : null };
-}
-
-function mergeControlPlaneFreshness(candidateFreshness, sourceFreshness) {
- const sourceAgeSeconds = sourceFreshness.age_seconds;
- const candidateAge = candidateFreshness.age_seconds;
- const ageSeconds = sourceAgeSeconds === null
- ? candidateAge
- : (candidateAge === null ? sourceAgeSeconds : Math.max(candidateAge, sourceAgeSeconds));
- const status = candidateFreshness.status === "stale" || sourceFreshness.data_status !== "ready"
- ? "stale"
- : candidateFreshness.status;
- return { status, age_seconds: ageSeconds };
-}
-
-function earliestControlPlaneTimestamp(values) {
- const timestamps = values
- .filter(Boolean)
- .map((value) => ({ value, timestamp: Date.parse(value) }))
- .filter((item) => Number.isFinite(item.timestamp))
- .sort((left, right) => left.timestamp - right.timestamp);
- return timestamps[0]?.value || null;
-}
-
-async function readBoundedJson(request, maxBytes) {
- const declaredLength = Number(request.headers.get("Content-Length") || 0);
- if (declaredLength > maxBytes) throw new HttpError("request body is too large", 413);
- const bytes = await request.arrayBuffer();
- if (bytes.byteLength > maxBytes) throw new HttpError("request body is too large", 413);
- try {
- return JSON.parse(new TextDecoder().decode(bytes));
- } catch {
- throw new HttpError("request body must be valid JSON", 400);
- }
-}
-
-function requireDedicatedStrategyHealthSyncToken(request, env) {
- const expected = String(env.STRATEGY_HEALTH_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("strategy health sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("strategy health sync token is invalid", 401);
-}
-
-function requireDedicatedControlPlaneSyncToken(request, env) {
- const expected = String(env.CONTROL_PLANE_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("control plane sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("control plane sync token is invalid", 401);
-}
-
-function requireControlPlaneSourceSyncToken(request, env) {
- const validationToken = String(env.AAB_VALIDATION_SYNC_TOKEN || "");
- const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
- // Check the narrower credential first, including accidental equal bindings.
- if (validationToken && token === validationToken) return true;
- if (validationToken && !env.CONTROL_PLANE_SYNC_TOKEN) {
- throw new HttpError("control plane source sync token is invalid", 401);
- }
- requireDedicatedControlPlaneSyncToken(request, env);
- return false;
-}
-
-function requireDedicatedAdaptiveSelectionSyncToken(request, env) {
- const expected = String(env.ADAPTIVE_SELECTION_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("adaptive selection sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("adaptive selection sync token is invalid", 401);
-}
-
-function requireDedicatedExecutionEvidenceSyncToken(request, env) {
- const expected = String(env.EXECUTION_EVIDENCE_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("execution evidence sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("execution evidence sync token is invalid", 401);
-}
-
-function requireDedicatedAccountFactsSyncToken(request, env) {
- const configured = [
- ["longbridge", String(env.ACCOUNT_FACTS_SYNC_TOKEN || "")],
- [IBKR_ACCOUNT_FACTS_PLATFORM, String(env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN || "")],
- [SCHWAB_ACCOUNT_FACTS_PLATFORM, String(env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN || "")],
- [FIRSTRADE_ACCOUNT_FACTS_PLATFORM, String(env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN || "")],
- ].filter(([, token]) => token);
- const firstradeToken = String(env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN || "");
- if (firstradeToken && [env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN, env.EXECUTION_EVIDENCE_SYNC_TOKEN,
- env.STRATEGY_SWITCH_SYNC_TOKEN, env.RECONCILIATION_RECOVERY_SYNC_TOKEN,
- env.RECONCILIATION_RECOVERY_CONTROLLER_TOKEN, env.CYCLE_HEALTH_PROVISIONER_TOKEN]
- .some(other => other && String(other) === firstradeToken)) {
- throw new HttpError("account_facts_sync_token_ambiguous", 503);
- }
- if (new Set(configured.map(([, token]) => token)).size !== configured.length) {
- throw new HttpError("account_facts_sync_token_ambiguous", 503);
- }
- if (!configured.length) throw new HttpError("account_facts_sync_token_not_configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- const match = configured.find(([, expected]) => token === expected);
- if (match) return match[0];
- throw new HttpError("account_facts_sync_token_invalid", 401);
-}
-
-function accountFactsDisabledResponse() {
- return json({ ok: false, error: "account_facts_disabled" }, 404);
-}
-
-// Sync producers keep only the HTTP status, so a refused push is undiagnosable
-// from their logs. Publish the refusal code, tagged with a fixed endpoint literal
-// from the caller; free-form exception text is classified to "unknown" so payload
-// content, identities and credentials cannot enter the log stream. The response
-// body and status are exactly what this helper already returned.
-function accountFactsErrorResponse(error, endpoint = "read") {
- const code = error instanceof AccountFactsError ? error.code
- : error instanceof HttpError ? error.message
- : error?.message || "invalid_account_facts_history";
- const status = error?.status || 400;
- console.warn("account_facts_refused", {
- endpoint,
- http_status: status,
- error_category: typeof code === "string" && /^[a-z][a-z0-9_]{2,63}$/.test(code) ? code : "unknown",
- });
- return json({ ok: false, error: code }, status);
-}
-
-function requireCycleHealthProvisionToken(request, env) {
- const expected = String(env.STRATEGY_SWITCH_SYNC_TOKEN || env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
- if (!expected) throw new HttpError("cycle_health_provisioner_unavailable", 503);
- const sourceTokens = [
- env.ACCOUNT_FACTS_SYNC_TOKEN, env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN,
- env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN, env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN, env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
- env.EXECUTION_EVIDENCE_SYNC_TOKEN,
- ].filter(Boolean).map(String);
- if (sourceTokens.includes(expected)) throw new HttpError("cycle_health_provisioner_token_alias", 503);
- const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("cycle_health_provisioner_token_invalid", 401);
-}
-
-async function resolveCycleHealthBindingFingerprint(env, targetId, bindingId) {
- const config = await loadAccountOptionsConfig(env);
- const options = Array.isArray(config?.options?.longbridge) ? config.options.longbridge : [];
- const matches = options.filter(o => o.runtime_status_target_id === targetId);
- const allMatches = Object.entries(config.options || {}).flatMap(([platform, items]) =>
- (Array.isArray(items) ? items : []).filter(o => o.runtime_status_target_id === targetId).map(o => ({ platform, key: o.key })));
- if (matches.length !== 1 || allMatches.length !== 1 || allMatches[0].platform !== "longbridge"
- || options.filter(o => o.key === matches[0]?.key).length !== 1) throw new HttpError("cycle_health_option_not_unique", 409);
- const bindings = await loadAccountFactsBindings(env);
- const bound = bindings?.bindings?.filter(b => b.platform === "longbridge" && b.account_key === matches[0].key) || [];
- if (bound.length !== 1 || bound[0].account_scope !== "paper" || bound[0].source_binding.id !== bindingId
- || !accountFactsOptionMatchesBinding(matches[0], bound[0])) throw new HttpError("cycle_health_binding_mismatch", 409);
- return cycleHealthSha256({ binding: bound[0], runtime_status_target_id: targetId });
-}
-
-async function runtimeCycleHealthAdmissionResponse(request, env) {
- try {
- requireCycleHealthProvisionToken(request, env);
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("cycle_health_store_unavailable", 503);
- const raw = await readBoundedJson(request, 8192);
- const fields = ["source_id", "target_id", "configuration_sha256", "required_from", "expected_authority_revision"];
- if (!raw || typeof raw !== "object" || Array.isArray(raw)
- || Object.keys(raw).length !== fields.length || fields.some(field => !Object.hasOwn(raw, field))) {
- throw new HttpError("cycle_health_admission_request_invalid", 400);
- }
- const sourceId = normalizeControlPlaneIdentifier(raw.source_id, "source_id", false);
- const targetId = raw.target_id;
- if (targetId !== "longbridge.paper" || !/^[a-f0-9]{64}$/.test(raw.configuration_sha256 || "")
- || !Number.isSafeInteger(raw.expected_authority_revision) || raw.expected_authority_revision < 0) {
- throw new HttpError("cycle_health_admission_request_invalid", 400);
- }
- const requiredFrom = normalizeCycleInstant(raw.required_from);
- const bindingId = request.headers.get("X-QSL-Source-Binding-ID") || "";
- if (!/^[a-f0-9]{64}$/.test(bindingId)) throw new HttpError("cycle_health_binding_required", 409);
- const bindingFingerprint = await resolveCycleHealthBindingFingerprint(env, targetId, bindingId);
- return json(await runtimeInstanceCommand(env, {
- action: "cycle_health_provision", source_id: sourceId, target_id: targetId,
- binding_fingerprint: bindingFingerprint, configuration_sha256: raw.configuration_sha256,
- required_from: requiredFrom, expected_authority_revision: raw.expected_authority_revision,
- }));
- } catch (error) {
- return json({ ok: false, error: error instanceof HttpError || error instanceof CycleHealthError
- ? error.message : "cycle_health_admission_unavailable" }, error.status || 400);
- }
-}
-
-async function runtimeCycleHealthSourceResponse(request, env) {
- try {
- const platform = requireDedicatedAccountFactsSyncToken(request, env);
- if (platform !== "longbridge") throw new HttpError("cycle_health_token_platform_mismatch", 403);
- const dedicated = String(env.ACCOUNT_FACTS_SYNC_TOKEN || "");
- if ([env.EXECUTION_EVIDENCE_SYNC_TOKEN, env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN].some(t => t && String(t) === dedicated)) {
- throw new HttpError("cycle_health_token_alias", 503);
- }
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("cycle_health_store_unavailable", 503);
- const url = new URL(request.url);
- let source, targetId, sourceId, historyCursor = null;
- const bindingId = request.headers.get("X-QSL-Source-Binding-ID") || "";
- if (!/^[a-f0-9]{64}$/.test(bindingId)) throw new HttpError("cycle_health_binding_required", 409);
- if (request.method === "GET") {
- if ([...url.searchParams.keys()].some(k => !["source_id", "target_id", "history_cursor"].includes(k))
- || url.searchParams.getAll("source_id").length !== 1 || url.searchParams.getAll("target_id").length !== 1
- || url.searchParams.getAll("history_cursor").length > 1) throw new HttpError("cycle_health_invalid_query", 400);
- sourceId = normalizeControlPlaneIdentifier(url.searchParams.get("source_id"), "source_id", false);
- targetId = url.searchParams.get("target_id");
- historyCursor = url.searchParams.get("history_cursor");
- if (historyCursor !== null) {
- if (historyCursor.length > 512) throw new HttpError("cycle_health_history_cursor_invalid", 400);
- }
- } else {
- const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
- if (!Array.isArray(raw?.targets) || raw.targets.length !== 1) throw new HttpError("cycle_health_one_target_required", 400);
- const { cycle_health: health, ...legacyTarget } = raw.targets[0];
- if (!health) throw new HttpError("cycle_health_extension_required", 400);
- // Reuse the lifecycle shape with the companion member removed. The legacy
- // normalizer and legacy POST still reject this extension as before.
- source = normalizeRuntimeTargetLifecycleSourceSnapshot({ ...raw, targets: [legacyTarget] });
- normalizeCycleInstant(raw.generated_at); normalizeCycleInstant(raw.computed_at);
- if (raw.generated_at !== raw.computed_at || source.data_status !== "ready") throw new HttpError("cycle_health_observation_time_mismatch", 400);
- source.generated_at = raw.generated_at; source.computed_at = raw.computed_at;
- if (legacyTarget.deployment?.observed_at !== undefined) {
- source.targets[0].deployment.observed_at = normalizeCycleInstant(legacyTarget.deployment.observed_at);
- if (compareCycleInstants(legacyTarget.deployment.observed_at, raw.computed_at) > 0) throw new HttpError("cycle_health_deployment_chronology", 400);
- }
- const age = Date.now() - Date.parse(source.computed_at);
- if (age > ACCOUNT_FACTS_STALE_MS || age < -ACCOUNT_FACTS_FUTURE_SKEW_MS) throw new HttpError("cycle_health_observation_age", 409);
- targetId = source.targets[0].target_id; sourceId = source.source_id;
- source.targets[0].cycle_health = await normalizeCycleHealth(health, {
- target_id: targetId, source_binding_id: bindingId, observed_at: source.computed_at,
- });
- }
- if (targetId !== "longbridge.paper" || (source && (source.targets[0].target.platform !== "longbridge" || source.targets[0].target.execution_mode !== "paper"))) throw new HttpError("cycle_health_paper_target_required", 403);
- const bindingFingerprint = await resolveCycleHealthBindingFingerprint(env, targetId, bindingId);
- const identity = { source_id: sourceId, target_id: targetId, binding_fingerprint: bindingFingerprint, source_binding_id: bindingId };
- const admission = await runtimeInstanceCommand(env, { ...identity, action: "cycle_health_admission" });
- if (source && source.targets[0].cycle_health.configuration_sha256 !== admission.configuration_sha256) throw new HttpError("cycle_health_configuration_not_admitted", 409);
- const command = { ...identity, ...admission, action: source ? "cycle_health_put" : "cycle_health_read",
- ...(historyCursor ? { history_cursor: historyCursor } : {}) };
- if (source) {
- command.observation = source;
- command.observation_json = canonicalCycleJson(source);
- command.observation_sha256 = await cycleHealthSha256(source);
- command.received_at = new Date().toISOString();
- }
- return json(await runtimeInstanceCommand(env, command));
- } catch (error) {
- return json({ ok: false, error: error instanceof HttpError || error instanceof CycleHealthError ? error.message : "cycle_health_invalid_source" }, error.status || 400);
- }
-}
-
-async function loadAccountFactsBindings(env, { propagateReadErrors = false } = {}) {
- if (!hasConfigStore(env)) {
- if (propagateReadErrors) throw new Error("account_facts_bindings_store_unavailable");
- return null;
- }
- let raw;
- try {
- raw = await readConfigJson(env, ACCOUNT_FACTS_BINDINGS_KEY);
- } catch (error) {
- if (propagateReadErrors) throw error;
- return null;
- }
- if (!raw) return null;
- return normalizeAccountFactsBindings(raw);
-}
-
-async function loadStoredAccountFactsMap(env, accountOptions, bindings) {
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
- const accounts = [];
- const bindingByAccount = new Map(
- (bindings?.bindings || []).map((item) => [`${item.platform}:${item.account_key}`, item]),
- );
- for (const [platform, options] of Object.entries(accountOptions || {})) {
- if (!Array.isArray(options)) continue;
- for (const option of options) {
- if (!option || typeof option.key !== "string" || !option.key) continue;
- const binding = bindingByAccount.get(`${platform}:${option.key}`);
- if (!binding || !accountFactsOptionMatchesBinding(option, binding)) continue;
- accounts.push({
- platform,
- account_key: option.key,
- account_scope: binding.account_scope,
- account_selector: binding.account_selector,
- ...(platform === SCHWAB_ACCOUNT_FACTS_PLATFORM
- ? { broker_account_hash: binding.broker_account_hash }
- : {}),
- ...(platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? { broker_account_id: binding.broker_account_id } : {}),
- target_id: binding.target_id,
- source_binding_id: binding.source_binding.id,
- });
- }
- }
- const listed = await runtimeInstanceCommand(env, {
- action: "account_facts_list",
- accounts,
- });
- const storedByAccount = new Map();
- for (const row of listed.observations || []) {
- if (!row?.platform || !row?.account_key || !row?.payload) continue;
- storedByAccount.set(`${row.platform}:${row.account_key}`, row.payload);
- }
- return storedByAccount;
-}
-
-function periodReturnCommand(binding, action) {
- return { action, platform: "ibkr", account_key: binding.account_key, account_scope: binding.account_scope,
- account_selector: binding.account_selector, target_id: binding.target_id, source_binding_id: binding.source_binding.id,
- ...(binding.history_source_binding_ids ? { history_source_binding_ids: binding.history_source_binding_ids } : {}) };
-}
-
-async function readBoundAccountExecutions(option, env) {
- if (option.platform !== "ibkr" || !accountFactsReadModelEnabled(env)) return null;
- const bindings = await loadAccountFactsBindings(env);
- const matches = (bindings?.bindings || []).filter(binding => binding.platform === option.platform
- && binding.account_key === option.key);
- if (!matches.length) return null;
- if (matches.length !== 1 || !accountFactsOptionMatchesBinding(option, matches[0])) {
- throw new HttpError("execution_account_unattributed", 409);
- }
- const stored = await runtimeInstanceCommand(env, periodReturnCommand(matches[0], "account_executions_read"));
- if (!stored.ok) throw new HttpError("execution_store_unavailable", 503);
- return stored.executions;
-}
-
-async function syncAccountExternalFlowResponse(request, env) {
- if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
- try {
- const platform = requireDedicatedAccountFactsSyncToken(request, env);
- if (!hasConfigStore(env) || !hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
- const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
- const fields = ["schema_version", "target_id", "source_binding_id", "account_scope", "account_selector", "externalFlow"];
- if (!raw || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).length !== fields.length
- || fields.some(key => !Object.hasOwn(raw, key)) || raw.schema_version !== "account_external_flow.v1") {
- throw new HttpError("invalid_external_flow", 400);
- }
- const bindings = await loadAccountFactsBindings(env);
- const resolved = resolveTrustedAccountFactsBinding(bindings, raw.target_id, raw.source_binding_id);
- if (!resolved.ok || resolved.binding.platform !== platform) throw new HttpError("account_facts_identity_mismatch", 409);
- const binding = resolved.binding;
- if (raw.account_scope !== binding.account_scope || raw.account_selector !== binding.account_selector) {
- throw new HttpError("account_facts_identity_mismatch", 409);
- }
- const config = await loadAccountOptionsConfig(env);
- const options = (config.options?.[platform] || []).filter(item => item.key === binding.account_key);
- if (options.length !== 1 || !accountFactsOptionMatchesBinding(options[0], binding)) throw new HttpError("account_facts_account_unattributed", 409);
- const flow = normalizeExternalFlow(raw.externalFlow);
- if (!externalFlowEnabled(env) && !dateOnlyExternalFlow(flow)) throw new HttpError("external_flow_disabled", 409);
- const source = { ibkr: "ibkr_flex", schwab: "schwab_transactions", longbridge: "longbridge_cashflow" }[platform];
- if (!source || flow.windows.some(w => w.source !== source)) throw new HttpError("external_flow_source_mismatch", 409);
- const stored = await runtimeInstanceCommand(env, { action: "account_external_flow_put", platform,
- account_key: binding.account_key, account_scope: binding.account_scope, account_selector: binding.account_selector,
- target_id: binding.target_id, source_binding_id: binding.source_binding.id,
- ...(platform === SCHWAB_ACCOUNT_FACTS_PLATFORM ? { broker_account_hash: binding.broker_account_hash } : {}),
- ...(platform === FIRSTRADE_ACCOUNT_FACTS_PLATFORM ? { broker_account_id: binding.broker_account_id } : {}),
- externalFlow: flow });
- return json({ ok: true, stored: true, unchanged: stored.unchanged === true, readback_verified: stored.readback_verified === true,
- account_key: binding.account_key, window_count: flow.windows.length,
- record_count: new Set(flow.windows.flatMap(w => w.records.map(r => r.source_ref))).size });
- } catch (error) {
- if (error instanceof AccountFactsError || error instanceof HttpError || error?.code?.startsWith("external_flow")
- || error?.code === "invalid_external_flow") return accountFactsErrorResponse(error, "external_flow_sync");
- return json({ ok: false, error: "account_external_flow_unavailable" }, 503);
- }
-}
-
-async function syncAccountExecutionsResponse(request, env) {
- if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
- try {
- if (requireDedicatedAccountFactsSyncToken(request, env) !== "ibkr") throw new HttpError("account_facts_sync_token_platform_mismatch", 403);
- if (!hasConfigStore(env) || !hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
- const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
- const bindings = await loadAccountFactsBindings(env);
- const resolved = resolveTrustedAccountFactsBinding(bindings, raw?.target_id, raw?.source_binding_id);
- if (!resolved.ok || resolved.binding.platform !== "ibkr") throw new HttpError("account_facts_identity_mismatch", 409);
- const binding = resolved.binding;
- const config = await loadAccountOptionsConfig(env);
- const options = (config.options?.ibkr || []).filter(item => item.key === binding.account_key);
- if (options.length !== 1 || !accountFactsOptionMatchesBinding(options[0], binding)) throw new HttpError("account_facts_account_unattributed", 409);
- const payload = normalizeExecutions(raw, { binding });
- if (payload.records.some(row => row.report_ref !== payload.source_ref)) throw new HttpError("invalid_broker_executions", 400);
- const stored = await runtimeInstanceCommand(env, { ...periodReturnCommand(binding, "account_executions_put"), payload });
- return json({ ok: true, stored: true, unchanged: stored.unchanged === true,
- account_key: binding.account_key, period: payload.period, record_count: payload.records.length });
- } catch (error) {
- if (error instanceof AccountFactsError || error instanceof HttpError || error?.code?.startsWith("execution_")
- || error?.code === "invalid_broker_executions") return accountFactsErrorResponse(error, "executions_sync");
- return json({ ok: false, error: "account_executions_unavailable" }, 503);
- }
-}
-
-async function syncAccountPeriodReturnResponse(request, env) {
- if (!accountFactsReadModelEnabled(env)) return accountFactsDisabledResponse();
- try {
- if (requireDedicatedAccountFactsSyncToken(request, env) !== "ibkr") throw new HttpError("account_facts_sync_token_platform_mismatch", 403);
- if (!hasConfigStore(env) || !hasRuntimeInstanceStore(env)) throw new HttpError("account_facts_store_unavailable", 503);
- const raw = await readBoundedJson(request, ACCOUNT_FACTS_MAX_BODY_BYTES);
- const bindings = await loadAccountFactsBindings(env);
- const resolved = resolveTrustedAccountFactsBinding(bindings, raw?.target_id, raw?.source_binding_id);
- if (!resolved.ok || resolved.binding.platform !== "ibkr") throw new HttpError("account_facts_identity_mismatch", 409);
- const binding = resolved.binding;
- const config = await loadAccountOptionsConfig(env);
- const options = (config.options?.ibkr || []).filter(item => item.key === binding.account_key);
- if (options.length !== 1 || !accountFactsOptionMatchesBinding(options[0], binding)) throw new HttpError("account_facts_account_unattributed", 409);
- const payload = normalizeIbkrPeriodReturn(raw, { binding });
- const stored = await runtimeInstanceCommand(env, { ...periodReturnCommand(binding, "account_period_return_put"), payload,
- historical: new URL(request.url).searchParams.get("historical") === "true" });
- return json({ ok: true, stored: true, unchanged: stored.unchanged === true, account_key: binding.account_key,
- period: payload.period, currency: payload.currency, method: payload.method });
- } catch (error) {
- if (error instanceof AccountFactsError || error instanceof HttpError) return accountFactsErrorResponse(error, "period_return_sync");
- return json({ ok: false, error: "account_period_return_unavailable" }, 503);
- }
-}
-
-async function syncAccountFactsResponse(request, env, options) {
- return syncAccountFactsResponseImpl(request, env, {
- json,
- hasConfigStore,
- hasRuntimeInstanceStore,
- loadAccountOptionsConfig,
- loadAccountFactsBindings,
- runtimeInstanceCommand,
- readBoundedJson,
- requireDedicatedAccountFactsSyncToken,
- accountFactsErrorResponse: (error) => accountFactsErrorResponse(
- error, options?.historical ? "history_sync" : "current_sync"),
- }, options);
-}
-
-async function accountFactsResponse(request, env) {
- return accountFactsResponseImpl(request, env, {
- json,
- readSession,
- hasConfigStore,
- hasRuntimeInstanceStore,
- loadAccountOptionsConfig,
- loadAccountFactsBindings: (env) => loadAccountFactsBindings(env, { propagateReadErrors: true }),
- loadStoredAccountFactsMap,
- runtimeInstanceCommand,
- periodReturnCommand,
- accountFactsErrorResponse,
- });
-}
-
-async function accountFactsHistoryResponse(request, env, url) {
- return accountFactsHistoryResponseImpl(request, env, url, {
- json,
- readSession,
- hasConfigStore,
- hasRuntimeInstanceStore,
- loadAccountOptionsConfig,
- loadAccountFactsBindings: (env) => loadAccountFactsBindings(env, { propagateReadErrors: true }),
- runtimeInstanceCommand,
- accountFactsErrorResponse,
- sha256Hex,
- });
-}
-
-function requireDedicatedReconciliationRecoverySyncToken(request, env) {
- const expected = String(env.RECONCILIATION_RECOVERY_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("reconciliation recovery sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("reconciliation recovery sync token is invalid", 401);
-}
-
-function requireDedicatedReconciliationRecoveryControllerToken(request, env) {
- const expected = String(env.RECONCILIATION_RECOVERY_CONTROLLER_TOKEN || "");
- if (!expected) throw new HttpError("reconciliation recovery controller token is not configured", 500);
- if (expected === String(env.RECONCILIATION_RECOVERY_SYNC_TOKEN || "")) {
- throw new HttpError("reconciliation recovery controller token must differ from the source sync token", 500);
- }
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("reconciliation recovery controller token is invalid", 401);
-}
-
-
-
-function requireDedicatedResearchPromotionSyncToken(request, env) {
- const expected = String(env.RESEARCH_PROMOTION_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("research promotion sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("research promotion sync token is invalid", 401);
-}
-
-function researchPromotionTicketKey(ticketId) {
- return `${RESEARCH_PROMOTION_TICKET_PREFIX}${ticketId}`;
-}
-
-function platformSupportsBrokerPaperMode(platform) {
- // Broker paper/sim is distinct from the local dry_run adapter. LongBridge's
- // paper account is currently the only configured broker simulation route.
- return platform === "longbridge";
-}
-
-function supportedBrokerEnvironmentsForPlatform(platform) {
- return platformSupportsBrokerPaperMode(platform) ? [...BROKER_ENVIRONMENTS] : ["live"];
-}
-
-function normalizeBrokerEnvironment(value, fieldName = "broker_environment") {
- const environment = String(value || "").trim();
- if (!BROKER_ENVIRONMENTS.includes(environment)) {
- throw new Error(`${fieldName} must be live or paper`);
- }
- return environment;
-}
-
-function normalizeResearchPromotionRiskProfile(value, fieldName) {
- const profile = String(value || "").trim().toUpperCase();
- if (!RESEARCH_PROMOTION_RISK_PROFILES.includes(profile)) {
- throw new Error(
- `${fieldName} must be CAPITAL_PRESERVATION, BALANCED_COMPOUNDING, or GROWTH_COMPOUNDING`,
- );
- }
- return profile;
-}
-
-function normalizePromotionConfirmation(value, fieldName, { paperSupported }) {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- // Keep exact QPK PromotionConfirmation.to_dict() fields.
- assertExactFields(value, ["target_platform", "execution_mode", "risk_profile"], fieldName);
- const targetPlatform = String(value.target_platform || "").trim();
- const executionMode = String(value.execution_mode || "").trim().toLowerCase();
- const riskProfile = normalizeResearchPromotionRiskProfile(
- value.risk_profile,
- `${fieldName}.risk_profile`,
- );
- if (!targetPlatform) throw new Error(`${fieldName}.target_platform is required`);
- if (!RESEARCH_PROMOTION_EXECUTION_MODES.includes(executionMode)) {
- throw new Error(`${fieldName}.execution_mode must be live or paper`);
- }
- if (executionMode === "paper" && !paperSupported) {
- throw new Error("paper is unavailable for this platform; synthetic matching is not supported");
- }
- return {
- target_platform: targetPlatform,
- execution_mode: executionMode,
- risk_profile: riskProfile,
- };
-}
-
-function validateResearchPromotionSelectedAccount({
- ticket,
- selectedAccount,
- confirmation,
- accountOptions,
- strategyProfiles,
-}) {
- assertExactFields(selectedAccount, ["platform", "key"], "selected_account");
- const platform = cleanChoice(selectedAccount.platform, SUPPORTED_PLATFORMS, "selected_account.platform");
- const key = cleanSlug(selectedAccount.key, "selected_account.key");
- const targetPlatform = String(confirmation?.target_platform || "").trim();
- if (targetPlatform !== platform) {
- throw new HttpError("selected_account platform does not match confirmation target_platform", 409);
- }
- const option = (accountOptions?.[platform] || []).find((item) => item.key === key);
- if (!option) throw new HttpError("selected_account does not match configured account", 409);
- const brokerEnvironment = String(option.broker_environment || "").trim();
- if (!BROKER_ENVIRONMENTS.includes(brokerEnvironment)) {
- throw new HttpError("selected account broker environment is unknown", 409);
- }
- if (!supportedBrokerEnvironmentsForPlatform(platform).includes(brokerEnvironment)) {
- throw new HttpError(`${platform} does not support broker environment ${brokerEnvironment}`, 400);
- }
- if (String(confirmation?.execution_mode || "").trim().toLowerCase() !== brokerEnvironment) {
- throw new HttpError("selected account broker environment does not match confirmation execution_mode", 409);
- }
- const strategy = (Array.isArray(strategyProfiles) ? strategyProfiles : [])
- .find((item) => item.profile === ticket?.strategy_profile);
- if (!strategy) throw new HttpError("selected candidate strategy profile is not configured", 409);
- if (strategy.domain !== ticket?.domain) {
- throw new HttpError("selected candidate strategy domain does not match ticket domain", 409);
- }
- if (!supportedDomainsForAccount(platform, option).includes(ticket.domain)) {
- throw new HttpError("selected account does not support candidate domain", 409);
- }
- if (PLATFORM_CONFIG[platform]?.dry_run_only) {
- throw new HttpError(`${platform} does not support broker execution`, 400);
- }
- assertDcaPlatform(platform, ticket.strategy_profile);
- if (!(strategy.allowed_execution_modes || []).includes(brokerEnvironment)) {
- throw new HttpError(`strategy ${strategy.profile} does not support broker environment ${brokerEnvironment}`, 400);
- }
- // A broker paper/live selection still needs the real adapter path. The
- // account's dry_run default is not an implicit paper capability.
- const adapterMode = cleanExecutionMode(
- option.default_execution_mode || PLATFORM_CONFIG[platform]?.default_execution_mode || "live",
- );
- if (adapterMode !== "live") {
- throw new HttpError("selected account adapter is not configured for broker execution", 400);
- }
- return { platform, key, broker_environment: brokerEnvironment };
-}
-
-function researchPromotionCandidateIdentity(ticket) {
- return {
- strategy_profile: String(ticket?.strategy_profile || ""),
- domain: String(ticket?.domain || ""),
- proposed_params:
- ticket?.proposed_params && typeof ticket.proposed_params === "object" && !Array.isArray(ticket.proposed_params)
- ? ticket.proposed_params
- : {},
- search_iterations: Number(ticket?.search_iterations || 0),
- shadow_evidence_kind: String(ticket?.shadow_evidence_kind || ""),
- };
-}
-
-function researchPromotionCandidatesMatch(left, right) {
- return (
- canonicalResearchTaskJson(researchPromotionCandidateIdentity(left))
- === canonicalResearchTaskJson(researchPromotionCandidateIdentity(right))
- );
-}
-
-function assertResearchPromotionExpectedCandidate(ticket, raw, { requireExpectedParams = false } = {}) {
- if (requireExpectedParams && !Object.prototype.hasOwnProperty.call(raw || {}, "expected_proposed_params")) {
- throw new HttpError("accept requires expected_proposed_params", 400);
- }
- if (!Object.prototype.hasOwnProperty.call(raw || {}, "expected_proposed_params")) return;
- const expected = raw.expected_proposed_params;
- if (!expected || typeof expected !== "object" || Array.isArray(expected)) {
- throw new HttpError("expected_proposed_params must be an object", 400);
- }
- const stored = ticket.proposed_params || {};
- if (canonicalResearchTaskJson(expected) !== canonicalResearchTaskJson(stored)) {
- throw new HttpError("expected_proposed_params does not match stored ticket candidate", 409);
- }
- if (raw.expected_strategy_profile != null) {
- if (String(raw.expected_strategy_profile).trim() !== ticket.strategy_profile) {
- throw new HttpError("expected_strategy_profile does not match stored ticket", 409);
- }
- }
- if (raw.expected_domain != null) {
- if (String(raw.expected_domain).trim() !== ticket.domain) {
- throw new HttpError("expected_domain does not match stored ticket", 409);
- }
- }
-}
-
-const RESEARCH_SUMMARY_HAN = /[\u4e00-\u9fff]/;
-const RESEARCH_SUMMARY_LATIN = /[A-Za-z]/;
-const RESEARCH_SUMMARY_DIGIT = /[0-9\uff10-\uff19]/;
-const RESEARCH_SUMMARY_LOCALE_FIELDS = ["question", "basis", "limits", "suggestion"];
-const RESEARCH_SUMMARY_BINDING_FIELDS = [
- "ticket_id", "strategy_profile", "domain", "proposed_params", "comparison",
- "shadow_evidence_kind", "shadow_passed", "notes",
-];
-const RESEARCH_SUMMARY_NEW_KEYS = ["status", "provider", "model", "scope", "locales", "binding"];
-const RESEARCH_SUMMARY_OLD_KEYS = ["status", "provider", "model", "text"];
-const RESEARCH_SUMMARY_HIDDEN = { status: "unavailable", text: "", provider: "", model: "" };
-
-function researchSummaryExactKeys(value, keys) {
- if (!value || Array.isArray(value) || typeof value !== "object") return false;
- const present = Object.keys(value);
- return present.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
-}
-
-function researchSummaryCodePointLength(text) {
- return Array.from(text).length;
-}
-
-function researchSummarySegment(text, chinese) {
- if (typeof text !== "string" || !text.trim() || researchSummaryCodePointLength(text) > 240) return null;
- if (RESEARCH_SUMMARY_DIGIT.test(text)) return null;
- const hasHan = RESEARCH_SUMMARY_HAN.test(text);
- if (chinese) return hasHan ? text : null;
- if (hasHan || !RESEARCH_SUMMARY_LATIN.test(text)) return null;
- return text;
-}
-
-function sameResearchSummaryMaterial(left, right) {
- return canonicalResearchTaskJson(left) === canonicalResearchTaskJson(right);
-}
-
-function readBilingualResearchPromotionExplanation(ai, material) {
- if (ai.status !== "available" || (ai.provider !== "codex" && ai.provider !== "cursor")) return null;
- if (typeof ai.model !== "string" || !ai.model.trim() || ai.scope !== "candidate") return null;
- const locales = ai.locales;
- if (!researchSummaryExactKeys(locales, ["zh-CN", "en"])) return null;
- const savedLocales = {};
- for (const [name, chinese] of [["zh-CN", true], ["en", false]]) {
- const section = locales[name];
- if (!researchSummaryExactKeys(section, RESEARCH_SUMMARY_LOCALE_FIELDS)) return null;
- const saved = {};
- for (const field of RESEARCH_SUMMARY_LOCALE_FIELDS) {
- const segment = researchSummarySegment(section[field], chinese);
- if (segment == null) return null;
- saved[field] = segment;
- }
- savedLocales[name] = saved;
- }
- if (!researchSummaryExactKeys(ai.binding, RESEARCH_SUMMARY_BINDING_FIELDS)) return null;
- if (!sameResearchSummaryMaterial(ai.binding, material)) return null;
- return {
- status: "available",
- provider: ai.provider,
- model: ai.model,
- scope: "candidate",
- locales: savedLocales,
- binding: JSON.parse(canonicalResearchTaskJson(material)),
- };
-}
-
-function readLegacyResearchPromotionExplanation(ai) {
- const status = String(ai.status || "").trim();
- if (status !== "available" && status !== "unavailable") return null;
- if (typeof ai.text !== "string" || typeof ai.provider !== "string" || typeof ai.model !== "string") return null;
- if (ai.text.length > 2000 || ai.model.length > 120) return null;
- if (status === "available" && (ai.provider !== "codex" || !ai.text.trim())) return null;
- if (status === "unavailable" && ai.provider !== "") return null;
- return {
- status,
- text: ai.text.trim(),
- provider: ai.provider,
- model: ai.model.trim(),
- };
-}
-
-function normalizeSavedResearchPromotionExplanation(ai, material) {
- try {
- if (ai == null) return { ...RESEARCH_SUMMARY_HIDDEN };
- if (researchSummaryExactKeys(ai, RESEARCH_SUMMARY_NEW_KEYS)) {
- return readBilingualResearchPromotionExplanation(ai, material) || { ...RESEARCH_SUMMARY_HIDDEN };
- }
- if (researchSummaryExactKeys(ai, RESEARCH_SUMMARY_OLD_KEYS)) {
- return readLegacyResearchPromotionExplanation(ai) || { ...RESEARCH_SUMMARY_HIDDEN };
- }
- return { ...RESEARCH_SUMMARY_HIDDEN };
- } catch {
- return { ...RESEARCH_SUMMARY_HIDDEN };
- }
-}
-
-function normalizeResearchPromotionSummary(raw, ticket, fieldName = "research_summary") {
- if (raw == null) return null;
- if (!raw || Array.isArray(raw) || typeof raw !== "object") return null;
- try {
- const comparisonForBinding = raw.comparison;
- const identity = raw.identity;
- if (!identity || Array.isArray(identity) || typeof identity !== "object") return null;
- const identityParams = identity.proposed_params;
- if (
- String(identity.strategy_profile || "").trim() !== ticket.strategy_profile
- || String(identity.domain || "").trim() !== ticket.domain
- || !identityParams || Array.isArray(identityParams)
- || canonicalResearchTaskJson(identityParams) !== canonicalResearchTaskJson(ticket.proposed_params || {})
- ) return null;
-
- if (raw.strategy_description != null && typeof raw.strategy_description !== "string") return null;
- const strategyDescription = String(raw.strategy_description || "").trim();
- if (strategyDescription.length > 500) return null;
-
- let plugins = null;
- if (raw.plugins === null) {
- plugins = null;
- } else if (Array.isArray(raw.plugins)) {
- plugins = raw.plugins.map((plugin, index) => {
- if (!plugin || Array.isArray(plugin) || typeof plugin !== "object") {
- throw new Error(`${fieldName}.plugins[${index}] must be an object`);
- }
- if (typeof plugin.id !== "string" || typeof plugin.description !== "string") {
- throw new Error(`${fieldName}.plugins[${index}] must include text fields`);
- }
- const id = plugin.id.trim();
- const description = plugin.description.trim();
- if (id.length > 120 || description.length > 300) throw new Error(`${fieldName}.plugins[${index}] is too long`);
- return { id, description };
- });
- } else if (raw.plugins == null) {
- plugins = null;
- } else {
- return null;
- }
-
- const comparison = raw.comparison == null ? { status: "unavailable" } : raw.comparison;
- if (!comparison || Array.isArray(comparison) || typeof comparison !== "object") return null;
- const comparisonStatus = String(comparison.status || "").trim();
- if (comparisonStatus !== "comparable" && comparisonStatus !== "unavailable") return null;
- const optionalText = (value, name) => {
- if (value == null) return null;
- if (typeof value !== "string") throw new Error(`${fieldName}.${name} must be text or null`);
- const text = value.trim();
- if (text.length > 120) throw new Error(`${fieldName}.${name} is too long`);
- return text;
- };
- const exactCostModel = (value, name) => {
- if (value == null) return null;
- if (typeof value !== "string") throw new Error(`${fieldName}.${name} must be text or null`);
- if (value.length > 120) throw new Error(`${fieldName}.${name} is too long`);
- return value;
- };
- const normalizeMetrics = (value, name) => {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName}.${name} must be an object`);
- }
- const cagr = value.cagr;
- const maxDrawdown = value.max_drawdown;
- if (typeof cagr !== "number" || typeof maxDrawdown !== "number"
- || !Number.isFinite(cagr) || !Number.isFinite(maxDrawdown)
- || cagr < -1 || maxDrawdown < -1 || maxDrawdown > 0) {
- throw new Error(`${fieldName}.${name} must use finite numbers`);
- }
- return { cagr, max_drawdown: maxDrawdown };
- };
- const normalizedComparison = {
- status: comparisonStatus,
- start_date: optionalText(comparison.start_date, "comparison.start_date"),
- end_date: optionalText(comparison.end_date, "comparison.end_date"),
- cost_model: exactCostModel(comparison.cost_model, "comparison.cost_model"),
- baseline: null,
- candidate: null,
- };
- if (comparisonStatus === "comparable") {
- if (!normalizedComparison.start_date || !normalizedComparison.end_date || !normalizedComparison.cost_model?.trim()) return null;
- if (!/^\d{4}-\d{2}-\d{2}$/.test(normalizedComparison.start_date)
- || !/^\d{4}-\d{2}-\d{2}$/.test(normalizedComparison.end_date)) return null;
- const startMillis = Date.parse(`${normalizedComparison.start_date}T00:00:00Z`);
- const endMillis = Date.parse(`${normalizedComparison.end_date}T00:00:00Z`);
- if (!Number.isFinite(startMillis) || !Number.isFinite(endMillis) || startMillis > endMillis) return null;
- normalizedComparison.baseline = normalizeMetrics(comparison.baseline, "comparison.baseline");
- normalizedComparison.candidate = normalizeMetrics(comparison.candidate, "comparison.candidate");
- } else {
- if (comparison.baseline != null) normalizeMetrics(comparison.baseline, "comparison.baseline");
- if (comparison.candidate != null) normalizeMetrics(comparison.candidate, "comparison.candidate");
- }
-
- if (!Array.isArray(raw.limitations) || raw.limitations.length > 8 || raw.limitations.some((item) => typeof item !== "string" || item.length > 300)) return null;
- const aiExplanation = normalizeSavedResearchPromotionExplanation(raw.ai_explanation, {
- ticket_id: ticket.ticket_id,
- strategy_profile: ticket.strategy_profile,
- domain: ticket.domain,
- proposed_params: ticket.proposed_params || {},
- comparison: comparisonForBinding,
- shadow_evidence_kind: ticket.shadow_evidence_kind,
- shadow_passed: ticket.shadow_passed,
- notes: Array.isArray(ticket.notes) ? ticket.notes : [],
- });
-
- return {
- identity: {
- strategy_profile: ticket.strategy_profile,
- domain: ticket.domain,
- proposed_params: ticket.proposed_params || {},
- },
- strategy_description: strategyDescription,
- plugins,
- comparison: normalizedComparison,
- limitations: raw.limitations.map((item) => item.trim()),
- ai_explanation: aiExplanation,
- };
- } catch {
- return null;
- }
-}
-
-function normalizeResearchPromotionTicket(raw, fieldName = "research promotion ticket") {
- if (!raw || Array.isArray(raw) || typeof raw !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- const ticketId = String(raw.ticket_id || "").trim();
- const strategyProfile = String(raw.strategy_profile || "").trim();
- const domain = String(raw.domain || "").trim();
- const state = String(raw.state || "").trim();
- if (!ticketId) throw new Error(`${fieldName}.ticket_id is required`);
- if (!strategyProfile) throw new Error(`${fieldName}.strategy_profile is required`);
- if (!domain) throw new Error(`${fieldName}.domain is required`);
- if (!RESEARCH_PROMOTION_STATES.includes(state)) {
- throw new Error(`${fieldName}.state is unsupported`);
- }
- if (raw.live_authority_granted === true) {
- throw new Error(`${fieldName}.live_authority_granted must remain false`);
- }
- const suggested = normalizeResearchPromotionRiskProfile(
- raw.suggested_risk_profile || DEFAULT_RESEARCH_PROMOTION_RISK_PROFILE,
- `${fieldName}.suggested_risk_profile`,
- );
- const driftStatus = String(raw.drift_status || "");
- const normalizedTicket = {
- schema: RESEARCH_PROMOTION_TICKET_SCHEMA,
- ticket_id: ticketId,
- strategy_profile: strategyProfile,
- domain,
- state,
- drift_status: driftStatus,
- drift_score: driftStatus === "new_research" && raw.drift_score === null
- ? null
- : Number(raw.drift_score || 0),
- created_at: String(raw.created_at || ""),
- updated_at: String(raw.updated_at || ""),
- budget: raw.budget && typeof raw.budget === "object" && !Array.isArray(raw.budget) ? raw.budget : {},
- proposed_params:
- raw.proposed_params && typeof raw.proposed_params === "object" && !Array.isArray(raw.proposed_params)
- ? raw.proposed_params
- : {},
- search_iterations: Number(raw.search_iterations || 0),
- shadow_evidence_kind: String(raw.shadow_evidence_kind || ""),
- // Qualification must never treat string values such as "false" as a
- // passed observation. Keep malformed legacy values unknown and let the
- // application gate reject them.
- shadow_passed: raw.shadow_passed === true ? true : raw.shadow_passed === false ? false : null,
- notification_subject: String(raw.notification_subject || ""),
- notification_body: String(raw.notification_body || ""),
- human_decision: String(raw.human_decision || ""),
- human_decided_at: String(raw.human_decided_at || ""),
- live_authority_granted: false,
- suggested_risk_profile: suggested,
- confirmation_target_platform: String(raw.confirmation_target_platform || ""),
- confirmation_execution_mode: String(raw.confirmation_execution_mode || ""),
- confirmation_risk_profile: String(raw.confirmation_risk_profile || ""),
- notes: Array.isArray(raw.notes) ? raw.notes.map((item) => String(item)) : [],
- };
- const researchSummary = normalizeResearchPromotionSummary(raw.research_summary, normalizedTicket, `${fieldName}.research_summary`);
- if (researchSummary) normalizedTicket.research_summary = researchSummary;
- return normalizedTicket;
-}
-
-function applyResearchPromotionDecision(
- ticket,
- {
- decision,
- confirmation = null,
- paperSupported = false,
- selectedAccount = null,
- accountOptions = null,
- strategyProfiles = null,
- decidedAt = null,
- expectedRaw = null,
- },
-) {
- if (ticket.state !== "awaiting_human") {
- throw new HttpError(`ticket ${ticket.ticket_id} is not awaiting human (state=${ticket.state})`, 409);
- }
- const normalized = String(decision || "").trim().toLowerCase();
- if (normalized !== "accept" && normalized !== "reject") {
- throw new HttpError("decision must be accept or reject", 400);
- }
- assertResearchPromotionExpectedCandidate(ticket, expectedRaw || {}, {
- requireExpectedParams: normalized === "accept",
- });
- const stamp = decidedAt || new Date().toISOString();
- const next = {
- ...ticket,
- human_decision: normalized,
- human_decided_at: stamp,
- live_authority_granted: false,
- updated_at: stamp,
- notes: [...(ticket.notes || [])],
- };
- if (normalized === "accept") {
- if (!confirmation) {
- throw new HttpError(
- "accept requires confirmation (target_platform, execution_mode, risk_profile)",
- 400,
- );
- }
- const confirmed = normalizePromotionConfirmation(confirmation, "confirmation", {
- paperSupported: Boolean(paperSupported),
- });
- if (!selectedAccount) {
- throw new HttpError("accept requires selected_account", 400);
- }
- validateResearchPromotionSelectedAccount({
- ticket,
- selectedAccount,
- confirmation: confirmed,
- accountOptions,
- strategyProfiles,
- });
- next.confirmation_target_platform = confirmed.target_platform;
- next.confirmation_execution_mode = confirmed.execution_mode;
- next.confirmation_risk_profile = confirmed.risk_profile;
- next.state = "human_accepted";
- next.notes.push(
- "human_accepted_intent_only_no_live_authority",
- `confirmation_platform=${confirmed.target_platform}`,
- `confirmation_mode=${confirmed.execution_mode}`,
- `confirmation_risk_profile=${confirmed.risk_profile}`,
- );
- } else {
- next.state = "human_rejected";
- next.notes.push("human_rejected");
- }
- return next;
-}
-
-async function syncResearchPromotionTicketResponse(request, env) {
- requireDedicatedResearchPromotionSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "research promotion KV is not configured" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, RESEARCH_PROMOTION_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research promotion ticket" }, error.status || 400);
- }
- let ticket;
- try {
- ticket = normalizeResearchPromotionTicket(raw);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research promotion ticket" }, 400);
- }
- if (ticket.state !== "awaiting_human") {
- return json(
- { ok: false, error: "research promotion sync only accepts awaiting_human tickets" },
- 400,
- );
- }
- const existingRaw = await readConfigJson(env, researchPromotionTicketKey(ticket.ticket_id));
- let existing = null;
- if (existingRaw) {
- try {
- existing = normalizeResearchPromotionTicket(existingRaw, "stored research promotion ticket");
- } catch (error) {
- return json(
- { ok: false, error: error.message || "invalid stored research promotion ticket" },
- 400,
- );
- }
- }
- let material;
- try {
- material = await publishHumanPromotionMaterial(env, ticket, existing);
- } catch (error) {
- return json({ ok: false, error: error.message || "research promotion material unavailable" }, error.status || 503);
- }
- if (material.identity_conflict) {
- return json(
- { ok: false, error: "refusing to overwrite awaiting_human research promotion ticket with mismatched candidate identity" },
- 409,
- );
- }
- if (material.terminal || material.legacy_blocked) {
- return json(
- { ok: false, error: `refusing to overwrite terminal research promotion ticket state=${material.terminal_state || existing?.state || "human_accepted"}` },
- 409,
- );
- }
- await writeConfigJson(env, researchPromotionTicketKey(ticket.ticket_id), ticket);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: "research-promotion-ticket-sync",
- action: "sync_research_promotion_ticket",
- ticket_id: ticket.ticket_id,
- state: ticket.state,
- suggested_risk_profile: ticket.suggested_risk_profile,
- live_authority_granted: false,
- });
- } catch {
- // Intent sync must not depend on optional audit retention.
- }
- return json({
- ok: true,
- ticket_id: ticket.ticket_id,
- state: ticket.state,
- suggested_risk_profile: ticket.suggested_risk_profile,
- live_authority_granted: false,
- });
-}
-
-async function fetchResearchPromotionTicketResponse(request, env) {
- requireDedicatedResearchPromotionSyncToken(request, env);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "research promotion KV is not configured" }, 503);
- }
- const ticketId = String(new URL(request.url).searchParams.get("ticket_id") || "").trim();
- if (!ticketId) return json({ ok: false, error: "ticket_id is required" }, 400);
- const stored = await readConfigJson(env, researchPromotionTicketKey(ticketId));
- if (!stored) return json({ ok: false, error: "research promotion ticket not found" }, 404);
- let ticket;
- try {
- ticket = normalizeResearchPromotionTicket(stored);
- ticket = await promotionTicketWithAuthority(env, ticket);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid stored research promotion ticket" }, error.status || 400);
- }
- if (ticket.live_authority_granted) {
- return json({ ok: false, error: "refusing to expose live_authority_granted=true" }, 500);
- }
- return json({
- ok: true,
- ticket: attachRiskEnvelopeView(ticket),
- live_authority_granted: false,
- });
-}
-
-async function listResearchPromotionTickets(env) {
- if (!hasConfigStore(env)) return [];
- const store = configStore(env);
- let listing;
- try {
- listing = await directoryList(env, RESEARCH_PROMOTION_TICKET_PREFIX, RESEARCH_PROMOTION_MAX_TICKETS);
- } catch (error) {
- throw new HttpError(sourceListFailure(error, "research_promotion_source_list_unavailable"), 503);
- }
- const keys = listing?.keys || [];
- const tickets = [];
- for (const entry of keys) {
- const key = entry.name || entry;
- if (!String(key).startsWith(RESEARCH_PROMOTION_TICKET_PREFIX)) continue;
- const stored = await readConfigJson(env, key);
- if (!stored) throw new HttpError("kv_directory_record_unavailable", 503);
- try {
- const record = normalizeResearchPromotionTicket(stored, key);
- const authority = await readHumanDecisionAuthority(env, "promotion", record.ticket_id);
- const ticket = attachPromotionQueueReadMetadata(record, overlayPromotionDecision(record, authority), authority);
- if (ticket.live_authority_granted) continue;
- if (ticket.state === "awaiting_human") {
- // Project the same durable observation used by the decision metadata.
- ticket.decision_authority = humanDecisionAuthorityView(authority);
- }
- tickets.push(ticket);
- } catch (error) {
- if (error instanceof HttpError && error.status === 503) throw error;
- // Skip corrupt tickets rather than failing the whole queue.
- }
- }
- tickets.sort((left, right) => String(right.updated_at).localeCompare(String(left.updated_at)));
- return tickets.slice(0, RESEARCH_PROMOTION_MAX_TICKETS);
-}
-
-function attachPromotionQueueReadMetadata(record, ticket, authority) {
- // Reuse the queue's existing material observation. Unknown is not permission;
- // these fixed reasons describe stored intent material flags, not full decision
- // permission, ticket-hash validation, or account application gates.
- const migrated = typeof authority?.migrated === "boolean" ? authority.migrated : null;
- const eligible = migrated === true && typeof authority?.eligible === "boolean" ? authority.eligible : null;
- const blocked = migrated === true && typeof authority?.blocked === "boolean" ? authority.blocked : null;
- const blockerCodes = migrated !== true ? null
- : blocked === true ? ["human_decision_legacy_blocked"]
- : eligible === false ? ["human_decision_material_conflict"]
- : eligible === true && blocked === false ? [] : null;
- return {
- ...ticket,
- decision_material: { migrated, eligible, blocked, blocker_codes: blockerCodes },
- decision_review_binding: authority?.review_binding || null,
- // Timestamps of the already-read KV ticket record, not producer-observed
- // time, freshness, a validity window, or evidence of actual execution.
- ticket_record_timestamps: {
- created_at: typeof record?.created_at === "string" && record.created_at ? record.created_at : null,
- updated_at: typeof record?.updated_at === "string" && record.updated_at ? record.updated_at : null,
- },
- };
-}
-
-async function researchPromotionTicketsResponse(request, env) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- const exact = await exactHumanDecisionResponse(request, env, session, "promotion");
- if (exact) return exact;
- const tickets = [];
- const invalidTickets = [];
- for (const ticket of await listResearchPromotionTickets(env)) {
- let reviewBinding;
- try {
- reviewBinding = await researchPromotionReviewBinding(ticket);
- } catch (error) {
- if (!(error instanceof ResearchPromotionReviewMaterialError)) throw error;
- // Keep a bounded, explicit non-actionable diagnosis; never serialize the
- // invalid numbers as fake zero/null or certify this ticket with a digest.
- invalidTickets.push({
- ticket_id: ticket.ticket_id, strategy_profile: ticket.strategy_profile, state: ticket.state,
- decision_material: { eligible: false, blocked: true, blocker_codes: [RESEARCH_PROMOTION_REVIEW_INVALID] },
- decision_binding: null, live_authority_granted: false, no_order: true,
- });
- continue;
- }
- tickets.push({ ...ticket, decision_binding: {
- kind: "promotion", subject_id: ticket.ticket_id, material_sha256: await researchPromotionMaterialKey(ticket),
- review_binding: promotionReviewBindingsMatch(reviewBinding, ticket.decision_review_binding) ? reviewBinding : null,
- } });
- }
- const awaiting = tickets.filter((ticket) => ticket.state === "awaiting_human");
- const applicationTickets = tickets.filter((ticket) =>
- ticket.state === "awaiting_human" || ticket.state === "human_accepted");
- const accountConfig = await loadAccountOptionsConfig(env);
- const strategyProfiles = await loadStrategyProfilesConfig(env);
- const applications = [];
- for (const ticket of applicationTickets) {
- const preparation = attachResearchPromotionApplicationPreparation(ticket, accountConfig.options, strategyProfiles);
- let application = null;
- if (hasRuntimeInstanceStore(env)) {
- try {
- const stored = await runtimeInstanceCommand(env, { action: "application_latest", actor: session.login, ticket_id: ticket.ticket_id });
- application = publicResearchPromotionApplication(stored.application);
- } catch {
- // Application storage is optional for the research-only queue view.
- }
- }
- applications.push({ ...preparation, application });
- }
- return json({
- schema_version: RESEARCH_PROMOTION_QUEUE_SCHEMA,
- data_status: hasConfigStore(env) ? (invalidTickets.length ? "partial" : "ready") : "unavailable",
- computed_at: new Date().toISOString(),
- tickets: decorateQueue({ tickets: awaiting.map(attachRiskEnvelopeView) }, "tickets", "strategy_promotion").tickets,
- applications,
- ...(invalidTickets.length ? { invalid_tickets: invalidTickets } : {}),
- summary: {
- ticket_count: awaiting.length,
- awaiting_human: awaiting.length,
- application_count: applications.length,
- ...(invalidTickets.length ? { invalid_review_count: invalidTickets.length } : {}),
- },
- policy: {
- admin_required_to_decide: true,
- live_authority_granted: false,
- no_order: true,
- application_dispatch_allowed: false,
- activation_status: "not_connected",
- notice: "网页只记录晋级人工意图;确认不授予实盘权限,也不下单。",
- },
- errors: invalidTickets.length ? [RESEARCH_PROMOTION_REVIEW_INVALID] : [],
- });
-}
-
-const DECISION_POLICY = Object.freeze({
- no_order: true,
- execution_authority_granted: false,
- current_evidence_required: true,
- human_confirmation_required: true,
- notice: "只记录人工决定意图;不会下单、变更资金或启用实盘。",
-});
-
-function decisionInboxSources() {
- return {
- owner: ownerDecisionQueueResponse,
- promotion: researchPromotionTicketsResponse,
- recovery: reconciliationRecoveryResponse,
- credential: (request, env) => credentialMaintenanceResponse(
- request, env, new URL("/api/credential-maintenance", request.url),
- ),
- };
-}
-
-function decodeDecisionApiId(raw) {
- let id;
- try {
- id = decodeURIComponent(String(raw || ""));
- } catch {
- return null;
- }
- const parts = decisionCategoryPart(id);
- if (parts) return { id, category: parts.category, subject_id: parts.subject_id };
- const legacyCredential = /^credential:(.+)$/.exec(id);
- if (!legacyCredential || legacyCredential[1].length > 256 || /[\u0000-\u001f\u007f]/.test(legacyCredential[1])) return null;
- return { id, category: "credential_maintenance", subject_id: legacyCredential[1] };
-}
-
-function decodeOperationApiId(raw) {
- let id;
- try {
- id = decodeURIComponent(String(raw || ""));
- } catch {
- return null;
- }
- const match = /^operation:(owner_decision|strategy_promotion|paper_account_application|reconciliation_recovery|credential_maintenance):(.+)$/.exec(id);
- if (!match || match[2].length > 256 || /[\u0000-\u001f\u007f]/.test(match[2])) return null;
- return { id, category: match[1], subject_id: match[2] };
-}
-
-const DECISION_SOURCE_BY_CATEGORY = Object.freeze({
- owner_decision: "owner",
- strategy_promotion: "promotion",
- paper_account_application: "promotion",
- reconciliation_recovery: "recovery",
- credential_maintenance: "credential",
-});
-
-/**
- * Absence is only proven when the owning source was read. A failed or
- * unavailable source stays a 503 so a missing id never masks a broken read.
- */
-function decisionSourceUnreadable(queue, category) {
- const name = DECISION_SOURCE_BY_CATEGORY[category];
- const source = (queue?.sources || []).find((entry) => entry.source === name);
- if (!source) return true;
- return ["read_failed", "unavailable"].includes(source.status);
-}
-
-// The durable record keeps the operation id in its request key. The id names the
-// recorded intent; a legacy fingerprint key carries no client operation id.
-function recordedDecisionOperationId(record) {
- const match = /^id:(?:owner|promotion|recovery):(.+)$/.exec(
- typeof record?.request_key === "string" ? record.request_key : "",
- );
- return match ? match[1] : null;
-}
-
-// The recorded intent's canonical target: accepted selection for promotion, action elsewhere.
-function decisionIntentTargetJson(category, action, selection) {
- if (category === "strategy_promotion" || category === "paper_account_application") {
- const accepted = action === "accept" ? selection : null;
- return canonicalResearchTaskJson({
- selected_account: accepted?.selected_account ?? null,
- confirmation: accepted?.confirmation ?? null,
- });
- }
- return canonicalResearchTaskJson({ decision: action });
-}
-
-// A terminal item synthesized from the durable record. It keeps the original
-// decision id resolvable after the pending projection drops or recategorizes it.
-function durableDecisionItem(record, parsed, kind, aliasItem = null) {
- const material = /^[0-9a-f]{64}$/.test(record.material_key || "") ? record.material_key : null;
- const reviewSha = /^[0-9a-f]{64}$/.test(record.payload?.review_binding?.review_sha256 || "")
- ? record.payload.review_binding.review_sha256 : null;
- const binding = {
- kind,
- subject_id: record.subject_id,
- material_sha256: material,
- ...(reviewSha ? { review_binding: { schema_version: "qsl_promotion_review_binding.v2", review_sha256: reviewSha } } : {}),
- };
- return {
- id: parsed.id,
- short_id: shortId(parsed.id),
- decision_id: parsed.id,
- category: parsed.category,
- title_key: `decisions.${parsed.category}`,
- revision: decisionRevision(binding, parsed.id),
- actionable: false,
- blocking_reason_codes: ["decision_already_decided"],
- allowed_actions: [],
- request_id_required: false,
- action_endpoint: null,
- decision_state: {
- status: "decided",
- action: record.action,
- decided_at: typeof record.decided_at === "string" ? record.decided_at : null,
- },
- decision_binding: binding,
- operation_reference: aliasItem?.operation_reference
- || decisionOperationReference({}, parsed.category, parsed.subject_id),
- source: "durable_human_decision_record",
- };
-}
-
-async function loadDecisionById(request, env, parsed) {
- // Detail and action routes address one decision by id. Reading the unpaged
- // projection keeps them independent of the presentation page a client last saw.
- const queue = await inbox(request, env, decisionInboxSources(), { paginate: false });
- const item = queue.items.find((entry) => entry.id === parsed.id) || null;
- if (item) return { queue, item, authorityRaw: undefined };
- // A terminal record outlives the pending projection: accepted paper tickets are
- // recategorized and rejected tickets leave the queue, so resolve them durably.
- const kind = decisionKind(parsed.category);
- if (!kind || !hasRuntimeInstanceStore(env)) return { queue, item: null, authorityRaw: undefined };
- let authorityRaw;
- try {
- authorityRaw = await readHumanDecisionAuthority(env, kind, parsed.subject_id);
- } catch {
- throw new HttpError("decision_authority_unavailable", 503);
- }
- const record = authorityRaw?.migrated === false ? null : authorityRaw?.decision;
- if (!record || record.kind !== kind || record.subject_id !== parsed.subject_id)
- return { queue, item: null, authorityRaw };
- const alias = queue.items.find((entry) => entry.decision_binding?.subject_id === parsed.subject_id
- && entry.decision_binding?.kind === kind);
- return { queue, item: durableDecisionItem(record, parsed, kind, alias || null), authorityRaw };
-}
-
-async function readDecisionAuthorityOrNull(env, kind, subjectId) {
- if (!kind) return null;
- if (!hasRuntimeInstanceStore(env)) throw new HttpError("runtime_instances_not_bound", 503);
- return readHumanDecisionAuthority(env, kind, subjectId);
-}
-
-async function decisionReviewResponse(request, env, rawId) {
- if (request.method !== "GET") return json({ ok: false, error: "method_not_allowed" }, 405);
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
- const parsed = decodeDecisionApiId(rawId);
- if (!parsed) return json({ ok: false, error: "decision_id_invalid" }, 400);
- const { queue, item, authorityRaw: loadedAuthority } = await loadDecisionById(request, env, parsed);
- if (!item) {
- if (decisionSourceUnreadable(queue, parsed.category))
- return json({ ok: false, error: "decision_source_unavailable", error_state: queue.error_state || null }, 503);
- return json({ ok: false, error: "decision_not_found" }, 404);
- }
- const kind = decisionKind(parsed.category);
- let authorityRaw;
- try {
- authorityRaw = loadedAuthority !== undefined
- ? loadedAuthority
- : await readDecisionAuthorityOrNull(env, kind, parsed.subject_id);
- } catch {
- return json({ ok: false, error: "decision_authority_unavailable" }, 503);
- }
- const authority = authorityRaw ? humanDecisionAuthorityView(authorityRaw) : null;
- const now = Date.now();
- let receipt = null;
- const errors = [];
- if (authorityRaw?.decision) {
- try {
- receipt = await humanDecisionReceipt(authorityRaw.decision, {
- kind,
- subject_id: parsed.subject_id,
- material_sha256: authorityRaw.decision.material_key,
- });
- } catch {
- errors.push("decision_receipt_unavailable");
- }
- }
- if (authorityRaw?.migrated === false) errors.push("decision_authority_unavailable");
- if (queue.status !== "ok") errors.push("decision_source_partial");
- return json({
- schema_version: DECISION_REVIEW_SCHEMA_VERSION,
- server_time: new Date(now).toISOString(),
- data_status: errors.length ? "partial" : "ready",
- decision_id: item.id,
- decision: item,
- current_eligibility: decisionCurrentEligibility(item, authority, now),
- decision_authority: authority,
- decision_receipt: receipt,
- operation: item.operation_reference,
- policy: DECISION_POLICY,
- tier_policies: riskTierPolicyCatalog(),
- errors: [...new Set(errors)],
- });
-}
-
-function decisionSelection(raw) {
- const selection = raw?.selection;
- if (!selection || Array.isArray(selection) || typeof selection !== "object") return null;
- return {
- confirmation: selection.confirmation && typeof selection.confirmation === "object" && !Array.isArray(selection.confirmation)
- ? selection.confirmation : null,
- selected_account: selection.selected_account && typeof selection.selected_account === "object" && !Array.isArray(selection.selected_account)
- ? selection.selected_account : null,
- };
-}
-
-async function decisionActionResponse(request, env, rawId) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- const parsed = decodeDecisionApiId(rawId);
- if (!parsed) return json({ ok: false, error: "decision_id_invalid" }, 400);
- const supported = DECISION_ACTIONS[parsed.category] || [];
- const kind = decisionKind(parsed.category);
- if (!kind || !supported.length) return json({ ok: false, error: "decision_not_actionable" }, 409);
-
- let raw;
- try {
- raw = await readBoundedJson(request, DECISION_ACTION_MAX_BODY_BYTES);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid decision action" }, error.status || 400);
- }
- if (!raw || Array.isArray(raw) || typeof raw !== "object")
- return json({ ok: false, error: "decision_action_request_invalid" }, 400);
- if (Object.keys(raw).some((key) => !["action", "expected_revision", "expected_expires_at", "request_id", "operation_id", "selection"].includes(key)))
- return json({ ok: false, error: "decision_action_request_invalid" }, 400);
- const action = typeof raw.action === "string" ? raw.action.trim() : "";
- if (!supported.includes(action))
- return json({ ok: false, error: "decision_action_invalid" }, 400);
- if (typeof raw.expected_revision !== "string" || !/^rev[0-9]-[0-9a-z-]{1,64}$/.test(raw.expected_revision))
- return json({ ok: false, error: "decision_revision_required" }, 400);
- const requestId = typeof raw.request_id === "string" ? raw.request_id.trim() : "";
- // The operation id names the intent. It is the durable idempotency key, so a
- // retry with the same id replays and a new intent needs a new id.
- const operationId = decisionOperationId(raw);
- if (!operationId) {
- if (requestId && !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId))
- return json({ ok: false, error: "invalid request_id" }, 400);
- return json({ ok: false, error: "decision_operation_id_invalid" }, 400);
- }
- const operationSha256 = await decisionOperationSha256(parsed.id, raw);
- const selection = decisionSelection(raw);
- if ((parsed.category === "strategy_promotion" || parsed.category === "paper_account_application")
- && action === "accept" && (!selection?.confirmation || !selection?.selected_account))
- return json({ ok: false, error: "decision_selection_required" }, 400);
-
- const { queue, item } = await loadDecisionById(request, env, parsed);
- if (!item) {
- if (decisionSourceUnreadable(queue, parsed.category))
- return json({ ok: false, error: "decision_source_unavailable", error_state: queue.error_state || null }, 503);
- return json({ ok: false, error: "decision_not_found" }, 404);
- }
- const now = Date.now();
- const serverTime = new Date(now).toISOString();
- let authorityRaw;
- try {
- authorityRaw = await readHumanDecisionAuthority(env, kind, parsed.subject_id);
- } catch {
- return json({ ok: false, error: "decision_authority_unavailable", server_time: serverTime }, 503);
- }
- const authority = humanDecisionAuthorityView(authorityRaw);
- const materialKey = item.decision_binding?.material_sha256 || null;
- const existing = authorityRaw?.decision;
- if (existing && materialKey && existing.material_key === materialKey) {
- // The durable request key keeps the operation id that produced the record.
- const recordedOperationId = recordedDecisionOperationId(existing);
- // A retry replays only when the recorded operation id and the complete
- // canonical intent match. Any other intent on the same material conflicts,
- // whether it reuses the id or presents a new one with the same action.
- let recordedTarget = null;
- try {
- recordedTarget = canonicalResearchTaskJson(JSON.parse(existing.target_json || "{}"));
- } catch {
- recordedTarget = null;
- }
- const intentMatches = recordedOperationId !== null && recordedOperationId === operationId
- && recordedTarget !== null
- && recordedTarget === decisionIntentTargetJson(parsed.category, action, selection);
- if (existing.kind !== kind || existing.subject_id !== parsed.subject_id || existing.action !== action
- || !intentMatches) {
- return json({
- ok: false,
- error: "decision_operation_conflict",
- decision_id: item.id,
- operation_id: operationId,
- recorded_operation_id: recordedOperationId,
- server_time: serverTime,
- }, 409);
- }
- const receipt = await humanDecisionReceipt(existing, {
- kind, subject_id: parsed.subject_id, material_sha256: materialKey,
- });
- return json({
- schema_version: DECISION_ACTION_SCHEMA_VERSION,
- ok: true,
- replayed: true,
- decision_id: item.id,
- revision: item.revision,
- action,
- operation_id: operationId,
- operation_sha256: operationSha256,
- decision_receipt: receipt,
- decided_at: existing.decided_at,
- decision_state: { status: "decided", action, decided_at: existing.decided_at },
- operation: item.operation_reference,
- policy: DECISION_POLICY,
- server_time: serverTime,
- });
- }
- if (raw.expected_revision !== item.revision)
- return json({ ok: false, error: "decision_revision_conflict", decision_id: item.id, server_time: serverTime }, 409);
- if (raw.expected_expires_at !== undefined && raw.expected_expires_at !== item.expires_at)
- return json({ ok: false, error: "decision_expiry_changed", decision_id: item.id, server_time: serverTime }, 409);
- if (decisionExpiryState(item.expires_at, now) !== "active")
- return json({ ok: false, error: "decision_expired", decision_id: item.id, server_time: serverTime }, 409);
- if (decisionExpiryState(authority?.expires_at, now) !== "active")
- return json({ ok: false, error: "decision_expired", decision_id: item.id, server_time: serverTime }, 409);
- if (authority?.blocked === true)
- return json({ ok: false, error: "decision_legacy_blocked", decision_id: item.id, server_time: serverTime }, 409);
- if (authority?.eligible === false)
- return json({ ok: false, error: "decision_material_ineligible", decision_id: item.id, server_time: serverTime }, 409);
- if (item.actionable !== true)
- return json({
- ok: false, error: "decision_not_actionable", decision_id: item.id,
- blocking_reason_codes: item.blocking_reason_codes || [], server_time: serverTime,
- }, 409);
- if (!(item.allowed_actions || []).some((entry) => entry.action === action))
- return json({ ok: false, error: "decision_action_not_allowed", decision_id: item.id, server_time: serverTime }, 409);
- if (!materialKey)
- return json({ ok: false, error: "decision_evidence_unavailable", decision_id: item.id, server_time: serverTime }, 409);
-
- let targetPath;
- let innerBody;
- if (parsed.category === "owner_decision") {
- targetPath = "/api/owner-decisions";
- innerBody = {
- candidate_id: parsed.subject_id,
- decision: action,
- candidate_evidence_sha256: materialKey,
- request_id: operationId,
- };
- } else if (parsed.category === "reconciliation_recovery") {
- targetPath = "/api/reconciliation-recovery-confirmations";
- if (item.initial_enrollment) {
- innerBody = {
- mode: "initial_enrollment",
- recovery_id: parsed.subject_id,
- candidate_sha256: item.initial_enrollment.candidate_sha256,
- facts_sha256: item.initial_enrollment.facts_sha256,
- decision: action,
- request_id: operationId,
- };
- } else {
- innerBody = {
- recovery_id: parsed.subject_id,
- candidate_sha256: item.evidence_summary?.candidate_sha256,
- dual_review_binding_sha256: item.evidence_summary?.dual_review_binding_sha256,
- decision: action,
- request_id: operationId,
- };
- }
- } else {
- targetPath = "/api/research-promotion-decisions";
- let ticket;
- try {
- ticket = await loadStoredResearchPromotionTicket(env, parsed.subject_id);
- } catch (error) {
- return json({
- ok: false, error: error.message || "research promotion ticket unavailable",
- decision_id: item.id, server_time: serverTime,
- }, error.status || 503);
- }
- innerBody = {
- ticket_id: parsed.subject_id,
- decision: action,
- expected_proposed_params: ticket.proposed_params,
- expected_material_sha256: materialKey,
- ...(item.decision_binding?.review_binding?.review_sha256
- ? { expected_review_sha256: item.decision_binding.review_binding.review_sha256 } : {}),
- ...(action === "accept" && selection ? {
- confirmation: selection.confirmation,
- selected_account: selection.selected_account,
- } : {}),
- request_id: operationId,
- };
- }
-
- const innerResponse = await ({
- "/api/owner-decisions": recordOwnerDecisionResponse,
- "/api/reconciliation-recovery-confirmations": recordReconciliationRecoveryConfirmationResponse,
- "/api/research-promotion-decisions": recordResearchPromotionDecisionResponse,
- })[targetPath](new Request(new URL(targetPath, request.url), {
- method: "POST",
- headers: new Headers(request.headers),
- body: JSON.stringify(innerBody),
- }), env);
- let payload = null;
- try {
- payload = await innerResponse.json();
- } catch {
- payload = null;
- }
- if (!innerResponse.ok || payload?.ok !== true) {
- return json({
- ...(payload && typeof payload === "object" ? payload : { ok: false, error: "decision_action_unavailable" }),
- schema_version: DECISION_ACTION_SCHEMA_VERSION,
- decision_id: item.id,
- action,
- server_time: serverTime,
- }, innerResponse.status || 503);
- }
- const decidedAt = payload.intent?.decided_at
- || payload.confirmation?.confirmed_at
- || payload.ticket?.human_decided_at
- || null;
- return json({
- schema_version: DECISION_ACTION_SCHEMA_VERSION,
- ok: true,
- replayed: payload.replayed === true,
- decision_id: item.id,
- revision: item.revision,
- action,
- operation_id: operationId,
- operation_sha256: operationSha256,
- decision_receipt: payload.decision_receipt || null,
- decided_at: decidedAt,
- decision_state: { status: "decided", action, decided_at: decidedAt },
- operation: item.operation_reference,
- policy: DECISION_POLICY,
- server_time: serverTime,
- });
-}
-
-function operationDecisionStatus(category, decision, application) {
- const promoted = category === "strategy_promotion" || category === "paper_account_application";
- if (promoted && application) {
- return { status: operationStatusFromApplication(application), reason_code: application.reason_code || null };
- }
- if (!decision) return { status: "unaccepted", reason_code: "decision_pending" };
- // The operation records the human decision; it never implies activation.
- if (promoted) return decision.action === "accept"
- ? { status: "accepted", reason_code: "application_not_created" }
- : { status: "failed", reason_code: "decision_rejected" };
- return { status: "accepted", reason_code: "operation_not_connected" };
-}
-
-async function operationResponse(request, env, rawId) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
- const parsed = decodeOperationApiId(rawId);
- if (!parsed) return json({ ok: false, error: "operation_not_found" }, 404);
- const now = Date.now();
- const serverTime = new Date(now).toISOString();
- const kind = decisionKind(parsed.category);
- if (kind && !hasRuntimeInstanceStore(env))
- return json({ ok: false, error: "runtime_instances_not_bound", server_time: serverTime }, 503);
-
- let authorityRaw = null;
- let ticket = null;
- if (kind) {
- try {
- if (parsed.category === "strategy_promotion" || parsed.category === "paper_account_application") {
- ticket = await loadStoredResearchPromotionTicket(env, parsed.subject_id);
- }
- authorityRaw = await readHumanDecisionAuthority(env, kind, parsed.subject_id);
- } catch (error) {
- return json({
- ok: false, error: error.message || "operation_unavailable",
- operation_id: parsed.id, server_time: serverTime,
- }, error.status || 503);
- }
- }
- let application = null;
- if (kind === "promotion") {
- try {
- const stored = await runtimeInstanceCommand(env, {
- action: "application_latest", actor: session.login, ticket_id: parsed.subject_id,
- });
- application = stored.application || null;
- } catch {
- return json({ ok: false, error: "operation_unavailable", operation_id: parsed.id, server_time: serverTime }, 503);
- }
- }
- const decision = authorityRaw?.decision || null;
- const status = operationDecisionStatus(parsed.category, decision, application);
- const publicApplication = application ? publicResearchPromotionApplication(application) : null;
- return json({
- schema_version: OPERATION_SCHEMA_VERSION,
- server_time: serverTime,
- data_status: "ready",
- operation: {
- id: parsed.id,
- decision_id: `${parsed.category}:${parsed.subject_id}`,
- kind: kind || parsed.category,
- subject_id: parsed.subject_id,
- status: status.status,
- reason_code: status.reason_code,
- activation_status: "not_connected",
- updated_at: publicApplication?.updated_at || decision?.decided_at || ticket?.updated_at || null,
- dispatch: publicApplication ? {
- status: publicApplication.dispatch_state || "unknown",
- workflow_run_id: publicApplication.workflow_run_id || null,
- updated_at: publicApplication.updated_at || null,
- } : null,
- application: publicApplication,
- },
- decision: decision ? {
- material_sha256: /^[0-9a-f]{64}$/.test(decision.material_key || "") ? decision.material_key : null,
- action: decision.action,
- decided_at: decision.decided_at,
- } : null,
- policy: DECISION_POLICY,
- errors: [],
- });
-}
-
-// Event type by normalized projection source. Comparing the normalized source
-// keeps a promotion application from being reported as an account-settings approval.
-function auditEventAction(source, kind) {
- if (source === "durable_human_decision") return `record_${kind}_decision`;
- if (source === "research_promotion_application") return "research_promotion_application";
- if (source === "account_settings_application") return "account_settings_approval";
- return null;
-}
-
-function auditEventSubjectId(row) {
- if (typeof row.ticket_id === "string" && row.ticket_id) return { kind: "strategy_promotion", id: row.ticket_id };
- if (typeof row.recovery_id === "string" && row.recovery_id) return { kind: "reconciliation_recovery", id: row.recovery_id };
- if (typeof row.candidate_id === "string" && row.candidate_id) return { kind: "owner_decision", id: row.candidate_id };
- if (typeof row.platform === "string" && typeof row.key === "string") return { kind: "account_settings", id: `${row.platform}:${row.key}` };
- return null;
-}
-
-async function auditEventsResponse(request, env, url) {
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required", error_state: "unauthorized" }, 401);
- let page;
- try {
- page = auditPageQuery(url);
- } catch {
- return json({ ok: false, error: "invalid_pagination" }, 400);
- }
- const now = Date.now();
- const serverTime = new Date(now).toISOString();
- if (!hasRuntimeInstanceStore(env))
- return json({ ok: false, error: "runtime_instances_not_bound", server_time: serverTime }, 503);
- let rows;
- try {
- const result = await runtimeInstanceCommand(env, {
- action: "console_audit_events", actor: session.login, limit: page.limit + 1, snapshot: page.snapshot, before: page.before,
- });
- if (!Array.isArray(result.rows)) throw Error("invalid_audit_rows");
- rows = result.rows;
- } catch {
- return json({ ok: false, error: "audit_projection_unavailable", server_time: serverTime }, 503);
- }
- const events = [];
- for (const row of rows) {
- const occurredAt = typeof row.occurred_at === "string" && Number.isFinite(Date.parse(row.occurred_at))
- ? row.occurred_at : null;
- if (!occurredAt) return json({ ok: false, error: "audit_projection_invalid" }, 503);
- if (row.source === "credential_rotation") {
- events.push({ id: row.event_id, event_id: row.event_id, occurred_at: occurredAt,
- actor_alias: await actorAlias(row.actor || null), action: row.action,
- subject: { kind: "credential", id: "ibkr_flex" }, operation_id: row.ref ?? null, outcome: row.status });
- continue;
- }
- const source = row.source === "decision" ? "durable_human_decision"
- : row.source === "promotion_application" ? "research_promotion_application"
- : row.source === "account_settings_application" ? "account_settings_application"
- : null;
- if (!source) return json({ ok: false, error: "audit_projection_invalid" }, 503);
- const subject = source === "durable_human_decision"
- ? { kind: `${row.kind}_decision`, id: row.subject_id }
- : source === "research_promotion_application"
- ? { kind: "strategy_promotion", id: row.subject_id }
- : { kind: "account_settings", id: row.subject_id };
- if (typeof subject.id !== "string" || !subject.id || subject.id.length > 256) return json({ ok: false, error: "audit_projection_invalid" }, 503);
- const revision = /^[0-9a-f]{64}$/.test(row.revision || "") ? row.revision : null;
- events.push({
- id: `${source}:${row.ref}`,
- source,
- occurred_at: occurredAt,
- action: auditEventAction(source, row.kind),
- actor_alias: await actorAlias(row.actor || null),
- subject,
- revision,
- outcome: typeof row.status === "string" && row.status.length <= 40 ? row.status : null,
- ref: source === "durable_human_decision"
- ? `/api/decisions/${encodeURIComponent(`${row.kind === "promotion" ? "strategy_promotion" : row.kind === "owner" ? "owner_decision" : "reconciliation_recovery"}:${row.subject_id}`)}`
- : source === "research_promotion_application"
- ? `/api/operations/${encodeURIComponent(`operation:strategy_promotion:${row.subject_id}`)}`
- : null,
- });
- }
- try {
- if (!hasConfigStore(env)) throw Error("audit_log_unavailable");
- const storedLog = await readConfigJson(env, AUDIT_LOG_KEY);
- if (storedLog !== null && !Array.isArray(storedLog)) throw Error("audit_log_invalid");
- const log = storedLog || [];
- const ids = await Promise.all(log.map(row => cycleHealthSha256(row)));
- const occurrences = new Map();
- const aliases = await Promise.all(log.map((row) =>
- actorAlias(typeof row?.login === "string" ? row.login : null)));
- log.forEach((row, index) => {
- if (!row || typeof row !== "object" || Array.isArray(row)) throw Error("audit_log_invalid");
- const occurredAt = typeof row.ts === "string" && Number.isFinite(Date.parse(row.ts)) ? row.ts : null;
- const action = typeof row.action === "string" && row.action.length <= 64 ? row.action : null;
- if (!occurredAt || !action) throw Error("audit_log_invalid");
- const subject = auditEventSubjectId(row);
- const occurrence = occurrences.get(ids[index]) || 0;
- occurrences.set(ids[index], occurrence + 1);
- events.push({
- id: `bounded_audit_log:${ids[index]}:${occurrence}`,
- source: "bounded_audit_log",
- occurred_at: new Date(occurredAt).toISOString(),
- action,
- actor_alias: aliases[index] || null,
- subject,
- revision: null,
- outcome: "recorded",
- ref: null,
- });
- });
- } catch {
- return json({ ok: false, error: "audit_log_unavailable", server_time: serverTime }, 503);
- }
- const seen = new Set();
- const unique = events
- .filter((event) => {
- if (seen.has(event.id)) return false;
- seen.add(event.id);
- return true;
- })
- .filter(event => auditEventInPage(event, page))
- .sort(auditEventOrder);
- const pageEvents = unique.slice(0, page.limit);
- return json({
- schema_version: AUDIT_EVENTS_SCHEMA_VERSION,
- server_time: serverTime,
- data_status: "ready",
- events: pageEvents.map(event => { if (!event.event_id) return event; const { id, ...safe } = event; return safe; }),
- next_cursor: unique.length > page.limit ? auditNextCursor(pageEvents.at(-1), page) : null,
- coverage: "durable_human_decisions_and_application_records_and_bounded_audit_log",
- policy: DECISION_POLICY,
- errors: [],
- });
-}
-
-function attachResearchPromotionApplicationPreparation(ticket, accountOptions, strategyProfiles) {
- const blockers = new Set(["activation_not_connected"]);
- if (ticket?.shadow_passed !== true || !String(ticket?.shadow_evidence_kind || "").trim()) {
- blockers.add("research_evidence_unverified");
- }
- const params = ticket?.proposed_params;
- const strategy = (Array.isArray(strategyProfiles) ? strategyProfiles : [])
- .find((item) => item.profile === ticket.strategy_profile);
- const candidateIdentity = researchCandidateIdentityForStrategy(strategy);
- const applicationAdapter = researchCandidateApplicationAdapter(strategy);
- const candidateParamsBound = candidateIdentity
- ? Boolean(
- params
- && !Array.isArray(params)
- && typeof params === "object"
- && canonicalResearchTaskJson(params) === canonicalResearchTaskJson(candidateIdentity),
- )
- : Boolean(params && !Array.isArray(params) && typeof params === "object" && !Object.keys(params).length);
- if (!candidateParamsBound) {
- blockers.add("candidate_params_unbound");
- }
- if (!strategy) blockers.add("strategy_not_configured");
- if (candidateIdentity && !applicationAdapter) blockers.add("paper_application_adapter_unavailable");
-
- const confirmedPlatform = String(ticket.confirmation_target_platform || "").trim();
- const platforms = confirmedPlatform ? [confirmedPlatform] : SUPPORTED_PLATFORMS;
- const accounts = [];
- for (const platform of strategy ? platforms : []) {
- const options = Array.isArray(accountOptions?.[platform]) ? accountOptions[platform] : [];
- for (const option of options) {
- if (!supportedDomainsForAccount(platform, option).includes(ticket.domain)) continue;
- const accountBlockers = [];
- const configuredExecutionMode = cleanExecutionMode(
- option.default_execution_mode || PLATFORM_CONFIG[platform]?.default_execution_mode || "live",
- );
- if (strategy) {
- try {
- const brokerEnvironment = normalizeBrokerEnvironment(
- option.broker_environment,
- `account_options.${platform}.${option.key}.broker_environment`,
- );
- if (!supportedBrokerEnvironmentsForPlatform(platform).includes(brokerEnvironment)) {
- throw new HttpError(`${platform} does not support broker environment ${brokerEnvironment}`, 400);
- }
- const executionMode = String(
- ticket.confirmation_execution_mode || brokerEnvironment,
- ).trim().toLowerCase();
- validateResearchPromotionSelectedAccount({
- ticket,
- selectedAccount: { platform, key: option.key },
- confirmation: {
- target_platform: platform,
- execution_mode: executionMode,
- risk_profile: ticket.confirmation_risk_profile || ticket.suggested_risk_profile,
- },
- accountOptions,
- strategyProfiles,
- });
- } catch (error) {
- accountBlockers.push(researchPromotionApplicationBlocker(error));
- }
- }
- if (accountBlockers.length) continue;
- accounts.push({
- platform,
- key: option.key,
- label: option.label,
- configured_execution_mode: configuredExecutionMode,
- broker_environment: option.broker_environment,
- preflight_status: accountBlockers.length ? "blocked" : (strategy ? "ready" : "blocked"),
- blocker_codes: [...new Set(accountBlockers)],
- });
- }
- }
- if (!accounts.length) blockers.add("configured_account_missing");
- if (strategy && accounts.length && accounts.every((account) => account.preflight_status !== "ready")) {
- blockers.add("account_preflight_failed");
- }
- const candidateBlockers = [...blockers].filter((code) => code !== "activation_not_connected");
- const previewAccounts = (
- ticket?.state === "human_accepted"
- && ticket?.shadow_passed === true
- && String(ticket?.shadow_evidence_kind || "").trim()
- && candidateIdentity
- && applicationAdapter
- && strategy?.domain === "us_equity"
- && candidateParamsBound
- && candidateBlockers.length === 0
- )
- ? accounts.filter((account) => {
- const option = (accountOptions?.[account.platform] || [])
- .find((item) => item.key === account.key);
- return (
- account.platform === "longbridge"
- && account.broker_environment === "paper"
- && account.configured_execution_mode === "live"
- && String(option?.account_selector || "").trim()
- );
- })
- : [];
- const previewRequest = previewAccounts.length === 1
- ? {
- platform_id: previewAccounts[0].platform,
- account_scope: String(
- (accountOptions?.[previewAccounts[0].platform] || [])
- .find((item) => item.key === previewAccounts[0].key)?.account_selector || "",
- ).trim(),
- strategy_profile: ticket.strategy_profile,
- candidate_id: params.candidate_id,
- config_sha256: params.config_sha256,
- }
- : null;
- return {
- ...attachRiskEnvelopeView(ticket),
- application_preparation: {
- status: "blocked",
- preflight_status: candidateBlockers.length ? "blocked" : "ready",
- activation_status: "not_connected",
- dispatch_allowed: false,
- blocker_codes: [...blockers].sort(),
- account_options: accounts,
- preview_request: previewRequest,
- },
- };
-}
-
-function researchCandidateIdentityForStrategy(strategy) {
- const identity = strategy?.research_candidate_identity;
- return identity && typeof identity === "object" && !Array.isArray(identity) ? identity : null;
-}
-
-function researchCandidateApplicationAdapter(strategy) {
- if (strategy?.profile !== V7_PAPER_PREVIEW_PROFILE) return null;
- return {
- platform: "longbridge",
- account_key: V7_PAPER_APPLICATION_ACCOUNT_KEY,
- workflow_repository: V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY,
- workflow: V7_PAPER_APPLICATION_WORKFLOW,
- };
-}
-
-function researchPromotionApplicationBlocker(error) {
- const message = String(error?.message || error || "").toLowerCase();
- if (message.includes("broker environment is unknown")) return "broker_environment_unknown";
- if (message.includes("does not support broker environment")) return "broker_environment_unsupported";
- if (message.includes("not configured")) return "strategy_not_configured";
- if (message.includes("domain") && message.includes("not supported")) return "strategy_domain_not_supported";
- if (message.includes("live-enabled") || message.includes("blocked for live") || message.includes("does not allow")) {
- return "strategy_execution_not_allowed";
- }
- if (message.includes("configured account")) return "configured_account_mismatch";
- return "account_preflight_failed";
-}
-
-async function recordResearchPromotionDecisionResponse(request, env) {
- requireSameOrigin(request, { requireOrigin: true });
- const session = await readSession(request, env);
- if (!session?.allowed) return json({ ok: false, error: "login required" }, 401);
- if (!session.admin) return json({ ok: false, error: "admin required" }, 403);
- if (!hasConfigStore(env)) {
- return json({ ok: false, error: "STRATEGY_SWITCH_CONFIG KV binding is required" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, 8 * 1024);
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
- }
- const ticketId = String(raw?.ticket_id || "").trim();
- const decision = String(raw?.decision || "").trim().toLowerCase();
- if (!ticketId) return json({ ok: false, error: "ticket_id is required" }, 400);
- const stored = await readConfigJson(env, researchPromotionTicketKey(ticketId));
- if (!stored) return json({ ok: false, error: "research promotion ticket not found" }, 404);
- let ticket;
- try {
- ticket = normalizeResearchPromotionTicket(stored);
- assertResearchPromotionExpectedCandidate(ticket, raw, { requireExpectedParams: decision === "accept" });
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
- }
- const materialKey = await researchPromotionMaterialKey(ticket);
- // Keep the legacy material index stable; the separate review digest binds the complete producer review.
- if (Object.prototype.hasOwnProperty.call(raw, "expected_material_sha256") && raw.expected_material_sha256 !== materialKey) {
- return json({ ok: false, error: "human_decision_material_conflict" }, 409);
- }
- const reviewMaterial = researchPromotionReviewMaterial(ticket);
- const reviewBinding = await researchPromotionReviewBinding(ticket);
- const selectedAccount = raw?.selected_account || null;
- const confirmation = raw?.confirmation || null;
- const target = { selected_account: selectedAccount, confirmation };
- const targetJson = canonicalResearchTaskJson(target);
- let authority;
- try {
- authority = await readHumanDecisionAuthority(env, "promotion", ticket.ticket_id);
- } catch (error) {
- return json({ ok: false, error: error.message || "research promotion decision unavailable" }, error.status || 503);
- }
- if (authority.migrated !== false) {
- if (authority.blocked) return json({ ok: false, error: "human_decision_legacy_blocked" }, 409);
- if (authority.eligible !== true || authority.material_key !== materialKey) {
- return json({ ok: false, error: "human_decision_material_conflict" }, 409);
- }
- const existing = authority.decision;
- if (existing && existing.action === decision && existing.target_json === targetJson && existing.payload?.ticket) {
- if (Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256")
- && (existing.payload.review_binding?.schema_version !== "qsl_promotion_review_binding.v2"
- || raw.expected_review_sha256 !== existing.payload.review_binding.review_sha256)) {
- return json({ ok: false, error: "human_decision_review_binding_unqualified" }, 409);
- }
- return json({
- ok: true,
- ticket: attachRiskEnvelopeView(existing.payload.ticket),
- live_authority_granted: false,
- replayed: true,
- actor: existing.actor,
- decision_receipt: await humanDecisionReceipt(existing, { kind: "promotion", subject_id: ticket.ticket_id, material_sha256: materialKey }),
- });
- }
- if (existing) return json({ ok: false, error: "human_decision_conflict" }, 409);
- }
- if (Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256") && raw.expected_review_sha256 !== reviewBinding.review_sha256) {
- return json({ ok: false, error: "human_decision_review_material_conflict" }, 409);
- }
- const targetPlatform = String(
- raw?.confirmation?.target_platform || ticket.confirmation_target_platform || "",
- ).trim();
- const paperSupported = platformSupportsBrokerPaperMode(targetPlatform);
- const accountConfig = decision === "accept" ? await loadAccountOptionsConfig(env) : null;
- const serverAccountRevision = accountConfig?.source === "durable_object" && Number.isSafeInteger(accountConfig.revision)
- ? accountConfig.revision
- : null;
- const strategyProfiles = decision === "accept" ? await loadStrategyProfilesConfig(env) : null;
- let decided;
- try {
- decided = applyResearchPromotionDecision(ticket, {
- decision,
- confirmation,
- paperSupported,
- selectedAccount,
- accountOptions: accountConfig?.options,
- strategyProfiles,
- decidedAt: new Date().toISOString(),
- expectedRaw: raw,
- });
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
- }
- if (decided.live_authority_granted) {
- return json({ ok: false, error: "refusing to persist live_authority_granted=true" }, 500);
- }
- const preflightRevision = decision === "accept" ? serverAccountRevision : null;
- if (decision === "accept" && Object.prototype.hasOwnProperty.call(raw, "expected_account_revision")
- && Number(raw.expected_account_revision) !== serverAccountRevision) {
- return json({ ok: false, error: "runtime_instance_revision_conflict" }, 409);
- }
- const decidedAt = decided.human_decided_at || humanDecisionTimestamp();
- let requestKey;
- try {
- requestKey = await humanDecisionRequestKey({
- requestId: raw?.request_id,
- kind: "promotion",
- actor: session.login,
- subjectId: ticket.ticket_id,
- materialKey,
- action: decision,
- target,
- });
- } catch (error) {
- return json({ ok: false, error: error.message || "invalid research promotion decision" }, error.status || 400);
- }
- let recorded;
- try {
- recorded = await runtimeInstanceCommand(env, {
- action: "promotion_decide",
- ...(Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256") ? { review_binding: reviewBinding } : {}),
- actor: session.login,
- subject_id: ticket.ticket_id,
- material_key: materialKey,
- action_name: decision,
- request_key: requestKey,
- target_json: canonicalResearchTaskJson(target),
- decided_at: decidedAt,
- now_ms: Date.now(),
- preflight_revision: preflightRevision,
- payload: {
- ticket: decided,
- ...(Object.prototype.hasOwnProperty.call(raw, "expected_review_sha256") ? { review_binding: reviewBinding, review_material: reviewMaterial } : {}),
- selected_account: selectedAccount,
- confirmation,
- proposed_params: ticket.proposed_params,
- },
- });
- } catch (error) {
- return json({ ok: false, error: error.message || "research promotion decision unavailable" }, error.status || 503);
- }
- const decisionReceipt = await humanDecisionReceipt(recorded.record, { kind: "promotion", subject_id: ticket.ticket_id, material_sha256: materialKey });
- const recordedTicket = recorded.record.payload.ticket;
- await mirrorConfigJson(env, researchPromotionTicketKey(recordedTicket.ticket_id), recordedTicket);
- try {
- await appendAuditLog(env, {
- ts: recordedTicket.updated_at,
- login: session.login,
- action: "research_promotion_decision",
- ticket_id: recordedTicket.ticket_id,
- decision: recordedTicket.human_decision,
- confirmation_target_platform: recordedTicket.confirmation_target_platform,
- confirmation_execution_mode: recordedTicket.confirmation_execution_mode,
- confirmation_risk_profile: recordedTicket.confirmation_risk_profile,
- suggested_risk_profile: recordedTicket.suggested_risk_profile,
- live_authority_granted: false,
- });
- } catch {
- // Decision persistence must not depend on optional audit retention.
- }
- return json({
- ok: true,
- ticket: attachRiskEnvelopeView(recordedTicket),
- decision_receipt: decisionReceipt,
- live_authority_granted: false,
- replayed: recorded.replayed === true,
- });
-}
-
-function v7PaperApplicationCandidate(strategy, ticket) {
- if (!researchCandidateApplicationAdapter(strategy)) {
- throw new HttpError("paper application adapter is not configured for candidate", 409);
- }
- if (ticket?.shadow_evidence_kind !== "v7_nonlive_shadow_and_simulated_paper") {
- throw new HttpError("v7_shadow_evidence_kind_not_qualified", 409);
- }
- const notes = Array.isArray(ticket?.notes) ? ticket.notes : [];
- const requiredEvidence = [
- "frozen_v7_forward_financial_gates_passed_research_only",
- "forward_record_sha256",
- "financial_evidence_sha256",
- "p1_manifest_sha256",
- "p4_policy_sha256",
- "baseline_p3_evidence_sha256",
- ];
- if (notes[0] !== requiredEvidence[0] || requiredEvidence.slice(1).some((prefix) =>
- !notes.some((note) => new RegExp(`^${prefix}=[0-9a-f]{64}$`).test(String(note))))) {
- throw new HttpError("v7_shadow_evidence_provenance_incomplete", 409);
- }
- const identity = researchCandidateIdentityForStrategy(strategy);
- if (!identity || ticket?.domain !== "us_equity") {
- throw new HttpError("research_candidate_not_eligible_for_paper_application", 409);
- }
- const params = ticket?.proposed_params;
- if (!params || Array.isArray(params) || typeof params !== "object"
- || canonicalResearchTaskJson(params) !== canonicalResearchTaskJson(identity)) {
- throw new HttpError("candidate_params_unbound", 409);
- }
- return {
- candidate_id: String(identity.candidate_id || ""),
- config_sha256: String(identity.config_sha256 || ""),
- };
-}
-
-async function loadStoredResearchPromotionTicket(env, ticketId) {
- if (!hasConfigStore(env)) throw new HttpError("research promotion KV is not configured", 503);
- const stored = await readConfigJson(env, researchPromotionTicketKey(ticketId));
- if (!stored) throw new HttpError("research promotion ticket not found", 404);
- let ticket;
- try {
- ticket = normalizeResearchPromotionTicket(stored, "stored research promotion ticket");
- } catch (error) {
- throw new HttpError(error.message || "invalid stored research promotion ticket", 409);
- }
- return promotionTicketWithAuthority(env, ticket);
-}
-
-async function qualifyV7PaperApplication(env, { ticketId, selectedAccount, expectedRevision }) {
- assertExactFields(selectedAccount, ["platform", "key"], "selected_account");
- const platform = cleanChoice(selectedAccount.platform, SUPPORTED_PLATFORMS, "selected_account.platform");
- const key = cleanSlug(selectedAccount.key, "selected_account.key");
- if (platform !== "longbridge" || key !== V7_PAPER_APPLICATION_ACCOUNT_KEY) {
- throw new HttpError("only the configured LongBridge paper account is supported", 409);
- }
- if (!V7_PAPER_APPLICATION_TICKET_RE.test(String(ticketId || ""))) {
- throw new HttpError("research promotion ticket is not from the V7 producer", 409);
- }
- if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
- throw new HttpError("runtime instance revision is required", 400);
- }
- const ticket = await loadStoredResearchPromotionTicket(env, ticketId);
- const promotionMaterialKey = await researchPromotionMaterialKey(ticket);
- const promotionAuthority = await readHumanDecisionAuthority(env, "promotion", ticket.ticket_id);
- if (promotionAuthority.blocked || promotionAuthority.eligible !== true || promotionAuthority.decision?.action !== "accept" || promotionAuthority.material_key !== promotionMaterialKey) {
- throw new HttpError("research candidate is not human_accepted", 409);
- }
- const boundAccount = promotionAuthority.decision.payload?.selected_account || {};
- if (boundAccount.platform !== platform || boundAccount.key !== key) {
- throw new HttpError("promotion_account_binding_conflict", 409);
- }
- if (ticket.state !== "human_accepted") throw new HttpError("research candidate is not human_accepted", 409);
- if (ticket.live_authority_granted !== false || ticket.shadow_passed !== true || !String(ticket.shadow_evidence_kind || "").trim()) {
- throw new HttpError("research candidate evidence is not qualified", 409);
- }
- const strategyProfiles = await loadStrategyProfilesConfig(env);
- const strategy = (Array.isArray(strategyProfiles) ? strategyProfiles : [])
- .find((item) => item.profile === ticket.strategy_profile);
- if (!strategy) throw new HttpError("selected candidate strategy profile is not configured", 409);
- const candidate = v7PaperApplicationCandidate(strategy, ticket);
- const state = await runtimeInstanceCommand(env);
- if (!state.initialized) throw new HttpError("runtime instances are not initialized", 409);
- if (state.revision !== expectedRevision) throw new HttpError("runtime instance revision conflict", 409);
- const instance = (state.instances || []).find((item) => item.kind === "existing" && item.platform === platform && item.key === key && item.retirement_status === "none");
- const config = instance?.config;
- if (!config) throw new HttpError("selected LongBridge paper account is unavailable", 409);
- if (String(config.broker_environment || "") !== "paper"
- || String(config.account_selector || "") !== V7_PAPER_APPLICATION_ACCOUNT_SCOPE
- || String(config.service_name || "") !== V7_PAPER_APPLICATION_SERVICE
- || String(config.runtime_status_target_id || "") !== "longbridge.paper"
- || String(config.default_execution_mode || "") !== "live") {
- throw new HttpError("selected LongBridge paper account binding is incomplete", 409);
- }
- const expectedStrategyProfile = String(config.default_strategy_profile || "").trim();
- if (!expectedStrategyProfile) throw new HttpError("selected account strategy profile is unknown", 409);
- validateResearchPromotionSelectedAccount({
- ticket,
- selectedAccount: { platform, key },
- confirmation: {
- target_platform: ticket.confirmation_target_platform,
- execution_mode: ticket.confirmation_execution_mode,
- risk_profile: ticket.confirmation_risk_profile,
- },
- accountOptions: { longbridge: [config] },
- strategyProfiles,
- });
- return {
- ticket,
- strategy,
- candidate,
- promotionMaterialKey,
- revision: state.revision,
- account: {
- platform_id: platform,
- account_key: key,
- account_scope: V7_PAPER_APPLICATION_ACCOUNT_SCOPE,
- account_selector: V7_PAPER_APPLICATION_ACCOUNT_SCOPE,
- service_name: V7_PAPER_APPLICATION_SERVICE,
- broker_environment: "paper",
- expected_strategy_profile: expectedStrategyProfile,
- },
- };
-}
-
-function publicResearchPromotionApplication(application) {
- if (!application) return null;
- const { claim_token: _claimToken, ...publicApplication } = application;
- return publicApplication;
-}
-
-async function dispatchV7PaperApplication(env, applicationId) {
- const token = String(env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
- if (!token) throw new HttpError("paper application dispatch unavailable", 503);
- const url = `https://api.github.com/repos/${V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY}/actions/workflows/${V7_PAPER_APPLICATION_WORKFLOW}/dispatches`;
- const response = await fetchWithTimeout(url, {
- method: "POST",
- headers: githubHeaders(token),
- body: JSON.stringify({ ref: "main", inputs: { application_id: applicationId } }),
- });
- if (!response.ok) throw new HttpError("paper application dispatch unverified", 502);
-}
-
-function applicationIdFromPath(pathname) {
- const value = String(pathname || "").slice("/api/internal/research-promotion-application/".length);
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
- throw new HttpError("invalid application_id", 400);
- }
- return value;
-}
-
-async function researchPromotionApplicationResponse(request, env, url) {
- return researchPromotionApplicationResponseImpl(request, env, url, {
- json,
- readSession,
- requireSameOrigin,
- readBoundedJson,
- runtimeInstanceCommand,
- assertExactFields,
- randomToken,
- qualifyV7PaperApplication,
- dispatchV7PaperApplication,
- publicResearchPromotionApplication,
- isUnsupportedApplicationActionError: (error) => (
- error instanceof HttpError
- && error.message === "unsupported_research_promotion_application_action"
- ),
- V7_PAPER_APPLICATION_MAX_BODY_BYTES,
- V7_PAPER_APPLICATION_SOURCE_COMMIT,
- V7_PAPER_APPLICATION_UES_REVISION,
- });
-}
-
-function validateV7PaperApplicationReadback(application, readback) {
- if (!readback || typeof readback !== "object" || Array.isArray(readback)) return false;
- return readback.application_id === application.application_id
- && readback.platform_id === application.platform_id
- && readback.account_scope === application.account_scope
- && readback.service_name === application.service_name
- && readback.strategy_profile === application.strategy_profile
- && readback.candidate_id === application.candidate_id
- && readback.config_sha256 === application.config_sha256
- && readback.source_commit === application.source_commit
- && readback.ues_revision === application.approved_ues_revision
- && readback.runtime_target_enabled === false
- && typeof readback.revision_name === "string" && readback.revision_name.trim() !== "";
-}
-
-async function researchPromotionApplicationInternalResponse(request, env, url) {
- return researchPromotionApplicationInternalResponseImpl(request, env, url, {
- json,
- requireDedicatedExecutionEvidenceSyncToken,
- hasRuntimeInstanceStore,
- applicationIdFromPath,
- readBoundedJson,
- runtimeInstanceCommand,
- assertExactFields,
- qualifyV7PaperApplication,
- validateV7PaperApplicationReadback,
- V7_PAPER_APPLICATION_MAX_BODY_BYTES,
- V7_PAPER_APPLICATION_WORKFLOW_REPOSITORY,
- V7_PAPER_APPLICATION_WORKFLOW,
- });
-}
-
-function requireDedicatedResearchTaskSyncToken(request, env) {
- const expected = String(env.RESEARCH_TASK_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("research task sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("research task sync token is invalid", 401);
-}
-
-function assertExactFields(value, fields, fieldName) {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- const actual = Object.keys(value).sort();
- const expected = [...fields].sort();
- if (actual.length !== expected.length || actual.some((item, index) => item !== expected[index])) {
- throw new Error(`${fieldName} has invalid fields`);
- }
- return value;
-}
-
-function assertRequiredAndOptionalFields(value, requiredFields, optionalFields, fieldName) {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- const allowed = new Set([...requiredFields, ...optionalFields]);
- const actual = Object.keys(value);
- if (
- requiredFields.some((field) => !Object.prototype.hasOwnProperty.call(value, field))
- || actual.some((field) => !allowed.has(field))
- ) {
- throw new Error(`${fieldName} has invalid fields`);
- }
- return value;
-}
-
-function normalizeResearchTaskIdentity(value, fieldName) {
- const text = String(value || "").trim();
- if (!/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(text)) {
- throw new Error(`${fieldName} must be a stable identity`);
- }
- return text;
-}
-
-function normalizeResearchTaskDigest(value, fieldName, nullable = false) {
- if ((value === null || value === undefined || value === "") && nullable) return null;
- const text = String(value || "").trim();
- if (!/^[0-9a-f]{64}$/.test(text)) throw new Error(`${fieldName} must be a lowercase SHA-256`);
- return text;
-}
-
-function normalizeResearchTaskRevision(value, fieldName) {
- const text = String(value || "").trim();
- if (!/^[0-9a-f]{40}$/.test(text)) throw new Error(`${fieldName} must be a 40-character revision`);
- return text;
-}
-
-function normalizeResearchTaskTimestamp(value, fieldName) {
- const text = String(value || "").trim();
- if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(text) || Number.isNaN(Date.parse(text))) {
- throw new Error(`${fieldName} must be a UTC timestamp`);
- }
- return text;
-}
-
-function normalizeResearchTaskText(value, fieldName, maxLength) {
- const text = String(value || "").trim();
- if (!text || text.length > maxLength || /[<>\\]/.test(text)) throw new Error(`${fieldName} is invalid`);
- if (/\b(?:token|secret|password|credential|api[_ -]?key)\s*[:=]/i.test(text)) {
- throw new Error(`${fieldName} contains sensitive material`);
- }
- return text;
-}
-
-function assertResearchTaskHasNoUnsafeMaterial(value, fieldName = "research task") {
- if (Array.isArray(value)) {
- value.forEach((item, index) => assertResearchTaskHasNoUnsafeMaterial(item, `${fieldName}[${index}]`));
- return;
- }
- if (!value || typeof value !== "object") return;
- for (const [key, nested] of Object.entries(value)) {
- if (key !== "no_order" && /(?:secret|token|password|credential|api[_-]?key|order|fill|capital|account|broker)/i.test(key)) {
- throw new Error(`${fieldName} contains forbidden execution or secret material`);
- }
- assertResearchTaskHasNoUnsafeMaterial(nested, `${fieldName}.${key}`);
- }
-}
-
-function canonicalResearchTaskJson(value) {
- if (value === null) return "null";
- if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
- if (typeof value === "number") {
- if (!Number.isFinite(value)) throw new Error("research task must use finite JSON values");
- return JSON.stringify(value);
- }
- if (Array.isArray(value)) return `[${value.map(canonicalResearchTaskJson).join(",")}]`;
- if (!value || typeof value !== "object") throw new Error("research task must use JSON values");
- return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalResearchTaskJson(value[key])}`).join(",")}}`;
-}
-
-async function sha256Hex(text) {
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function calculateResearchTaskSha256(payload) {
- const material = { ...payload };
- delete material.task_sha256;
- const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function normalizeResearchTask(payload, fieldName) {
- const task = assertExactFields(payload, [
- "schema", "task_id", "created_at", "digest_algorithm", "task_type", "target", "evidence", "experiment", "authority", "task_sha256",
- ], fieldName);
- assertResearchTaskHasNoUnsafeMaterial(task, fieldName);
- if (task.schema !== RESEARCH_TASK_SCHEMA_VERSION) throw new Error(`${fieldName}.schema is unsupported`);
- if (task.digest_algorithm !== "sha256") throw new Error(`${fieldName}.digest_algorithm must be sha256`);
- const target = assertExactFields(task.target, ["candidate_id", "candidate_kind", "domain", "repository", "strategy_revision"], `${fieldName}.target`);
- const evidence = assertExactFields(task.evidence, ["p1_input_digest", "p2_config_digest", "p3_evidence_id", "producer_revision"], `${fieldName}.evidence`);
- const experiment = assertExactFields(task.experiment, ["objective", "hypothesis", "parameter_bounds_sha256", "max_runs", "max_wall_seconds"], `${fieldName}.experiment`);
- const authority = assertExactFields(task.authority, ["research_only", "no_order", "size_zero_required", "p4_p5_p6_authorized"], `${fieldName}.authority`);
- const normalized = {
- schema: RESEARCH_TASK_SCHEMA_VERSION,
- task_id: normalizeResearchTaskIdentity(task.task_id, `${fieldName}.task_id`),
- created_at: normalizeResearchTaskTimestamp(task.created_at, `${fieldName}.created_at`),
- digest_algorithm: "sha256",
- task_type: cleanChoice(task.task_type, RESEARCH_TASK_TYPES, `${fieldName}.task_type`),
- target: {
- candidate_id: normalizeResearchTaskIdentity(target.candidate_id, `${fieldName}.target.candidate_id`),
- candidate_kind: cleanChoice(target.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${fieldName}.target.candidate_kind`),
- domain: cleanChoice(target.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.target.domain`),
- repository: normalizeResearchTaskRepository(target.repository, `${fieldName}.target.repository`),
- strategy_revision: normalizeResearchTaskRevision(target.strategy_revision, `${fieldName}.target.strategy_revision`),
- },
- evidence: {
- p1_input_digest: normalizeResearchTaskDigest(evidence.p1_input_digest, `${fieldName}.evidence.p1_input_digest`, true),
- p2_config_digest: normalizeResearchTaskDigest(evidence.p2_config_digest, `${fieldName}.evidence.p2_config_digest`, true),
- p3_evidence_id: normalizeResearchTaskDigest(evidence.p3_evidence_id, `${fieldName}.evidence.p3_evidence_id`, true),
- producer_revision: normalizeResearchTaskRevision(evidence.producer_revision, `${fieldName}.evidence.producer_revision`),
- },
- experiment: {
- objective: cleanChoice(experiment.objective, RESEARCH_TASK_OBJECTIVES, `${fieldName}.experiment.objective`),
- hypothesis: normalizeResearchTaskText(experiment.hypothesis, `${fieldName}.experiment.hypothesis`, 800),
- parameter_bounds_sha256: normalizeResearchTaskDigest(experiment.parameter_bounds_sha256, `${fieldName}.experiment.parameter_bounds_sha256`, true),
- max_runs: normalizeResearchTaskBound(experiment.max_runs, `${fieldName}.experiment.max_runs`, 100),
- max_wall_seconds: normalizeResearchTaskBound(experiment.max_wall_seconds, `${fieldName}.experiment.max_wall_seconds`, 86400),
- },
- authority: {
- research_only: authority.research_only,
- no_order: authority.no_order,
- size_zero_required: authority.size_zero_required,
- p4_p5_p6_authorized: authority.p4_p5_p6_authorized,
- },
- task_sha256: normalizeResearchTaskDigest(task.task_sha256, `${fieldName}.task_sha256`),
- };
- if (JSON.stringify(normalized.authority) !== JSON.stringify({ research_only: true, no_order: true, size_zero_required: true, p4_p5_p6_authorized: false })) {
- throw new Error(`${fieldName}.authority must be fixed to offline research only`);
- }
- if (normalized.task_sha256 !== await calculateResearchTaskSha256(normalized)) {
- throw new Error(`${fieldName}.task_sha256 mismatch`);
- }
- return normalized;
-}
-
-function normalizeResearchTaskRepository(value, fieldName) {
- const text = String(value || "").trim();
- if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*\/[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(text)) {
- throw new Error(`${fieldName} is invalid`);
- }
- return text;
-}
-
-function normalizeResearchTaskBound(value, fieldName, maximum) {
- if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > maximum) {
- throw new Error(`${fieldName} is outside its safe bound`);
- }
- return value;
-}
-
-async function normalizeResearchTaskSourceSnapshot(payload, fieldName = "research task source snapshot") {
- const source = assertExactFields(payload, ["schema_version", "source_id", "generated_at", "computed_at", "data_status", "tasks", "errors"], fieldName);
- if (source.schema_version !== RESEARCH_TASK_SOURCE_SCHEMA_VERSION) throw new Error(`${fieldName}.schema_version is unsupported`);
- const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- if (!Array.isArray(source.tasks) || source.tasks.length > 100) {
- throw new Error(`${fieldName}.tasks must be an array with at most 100 items`);
- }
- const tasks = [];
- const seen = new Set();
- for (const [index, item] of source.tasks.entries()) {
- const task = await normalizeResearchTask(item, `${fieldName}.tasks[${index}]`);
- if (seen.has(task.task_id)) throw new Error(`${fieldName}.tasks contains duplicate task_id`);
- seen.add(task.task_id);
- tasks.push(task);
- }
- if (dataStatus === "unavailable" && tasks.length) throw new Error(`${fieldName}.tasks must be empty when unavailable`);
- return {
- schema_version: RESEARCH_TASK_SOURCE_SCHEMA_VERSION,
- source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
- generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
- data_status: dataStatus,
- tasks,
- errors: normalizeStrategyHealthErrors(source.errors),
- };
-}
-
-function emptyResearchTaskSourceSnapshot(errorCode) {
- return {
- schema_version: RESEARCH_TASK_SOURCE_SCHEMA_VERSION,
- source_id: "unavailable",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- tasks: [],
- errors: [errorCode],
- };
-}
-
-function emptyResearchTaskPayload(errorCode) {
- return {
- schema_version: RESEARCH_TASK_DASHBOARD_SCHEMA_VERSION,
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { task_count: 0 },
- tasks: [],
- policy: {
- research_only: true,
- no_order: true,
- size_zero_required: true,
- p4_p5_p6_authorized: false,
- notice: "研究任务只用于离线、零仓位实验;不会调参、改代码、部署或下单。",
- },
- errors: [errorCode],
- };
-}
-
-function researchTaskStaleTtlSeconds(env) {
- const configured = Number(env.RESEARCH_TASK_STALE_TTL_SECONDS);
- if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
- return RESEARCH_TASK_DEFAULT_STALE_TTL_SECONDS;
- }
- return Math.floor(configured);
-}
-
-function normalizeStrategyHealthSnapshot(payload, fieldName = "strategy health snapshot") {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- if (payload.schema_version !== "strategy_health_dashboard.v1") {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const status = cleanChoice(payload.data_status || "unavailable", [...STRATEGY_HEALTH_DATA_STATUSES, "partial"], `${fieldName}.data_status`);
- const strategies = status === "unavailable"
- ? []
- : normalizeStrategyHealthStrategies(payload.strategies, fieldName);
- const summary = normalizeStrategyHealthSummary(payload.summary, strategies);
- const errors = normalizeStrategyHealthErrors(payload.errors);
- return {
- schema_version: "strategy_health_dashboard.v1",
- generated_at: normalizeStrategyHealthTimestamp(payload.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(payload.computed_at, `${fieldName}.computed_at`, true),
- data_status: status,
- summary,
- strategies,
- policy: normalizeStrategyHealthPolicy(payload.policy),
- errors,
- };
-}
-
-function normalizeStrategyHealthStrategies(value, fieldName) {
- if (!Array.isArray(value) || value.length > 100) {
- throw new Error(`${fieldName}.strategies must be an array with at most 100 items`);
- }
- const seen = new Set();
- return value.map((item, index) => {
- if (!item || Array.isArray(item) || typeof item !== "object") {
- throw new Error(`${fieldName}.strategies[${index}] must be an object`);
- }
- const profile = cleanSlug(item.profile, `${fieldName}.strategies[${index}].profile`).toLowerCase();
- if (seen.has(profile)) throw new Error(`${fieldName}.strategies contains duplicate profile`);
- seen.add(profile);
- return {
- profile,
- domain: cleanChoice(item.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.strategies[${index}].domain`),
- as_of: sanitizeStrategyHealthText(item.as_of, `${fieldName}.strategies[${index}].as_of`, 64, true),
- status: cleanChoice(item.status, STRATEGY_HEALTH_STATUSES, `${fieldName}.strategies[${index}].status`),
- score: normalizeStrategyHealthScore(item.score, `${fieldName}.strategies[${index}].score`),
- components: normalizeStrategyHealthComponents(item.components, `${fieldName}.strategies[${index}].components`),
- decision: normalizeStrategyHealthDecision(item.decision, `${fieldName}.strategies[${index}].decision`),
- review: normalizeStrategyHealthReview(item.review, `${fieldName}.strategies[${index}].review`),
- freshness: normalizeStrategyHealthFreshness(item.freshness, `${fieldName}.strategies[${index}].freshness`),
- source_revision: sanitizeStrategyHealthText(item.source_revision, `${fieldName}.strategies[${index}].source_revision`, 120, true),
- };
- });
-}
-
-function normalizeStrategyHealthSummary(value, strategies) {
- const counts = Object.fromEntries(STRATEGY_HEALTH_STATUSES.map((status) => [status, 0]));
- for (const item of strategies) counts[item.status] += 1;
- return { strategy_count: strategies.length, ...counts };
-}
-
-function normalizeStrategyHealthComponents(value, fieldName) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- performance: normalizeStrategyHealthScore(source.performance, `${fieldName}.performance`),
- risk: normalizeStrategyHealthScore(source.risk, `${fieldName}.risk`),
- decay: normalizeStrategyHealthScore(source.decay, `${fieldName}.decay`),
- stability: normalizeStrategyHealthScore(source.stability, `${fieldName}.stability`),
- operations: normalizeStrategyHealthScore(source.operations, `${fieldName}.operations`),
- };
-}
-
-function normalizeStrategyHealthDecision(value, fieldName) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- code: cleanSlug(source.code || "evidence_missing", `${fieldName}.code`).toLowerCase(),
- label: sanitizeStrategyHealthText(source.label, `${fieldName}.label`, 120, false, "证据不足,保持研究态"),
- reason: sanitizeStrategyHealthText(source.reason, `${fieldName}.reason`, 240, false, "没有可用的机器检查结果。"),
- };
-}
-
-function normalizeStrategyHealthReview(value, fieldName) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- requested_stage: sanitizeStrategyHealthText(source.requested_stage, `${fieldName}.requested_stage`, 80, true),
- evidence_package_id: sanitizeStrategyHealthText(source.evidence_package_id, `${fieldName}.evidence_package_id`, 120, true),
- validation: normalizeStrategyHealthSummaryObject(source.validation),
- risk: normalizeStrategyHealthSummaryObject(source.risk),
- kelly_readiness: normalizeStrategyHealthSummaryObject(source.kelly_readiness),
- };
-}
-
-function normalizeStrategyHealthSummaryObject(value) {
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
- const result = {};
- for (const [key, raw] of Object.entries(value).slice(0, 12)) {
- if (!/^[A-Za-z0-9_.-]{1,48}$/.test(key)) continue;
- if (/(token|secret|password|cookie|private|path|key)/i.test(key)) continue;
- if (typeof raw === "boolean") result[key] = raw;
- else if (typeof raw === "number" && Number.isFinite(raw)) result[key] = raw;
- else if (typeof raw === "string") {
- const safe = sanitizeStrategyHealthText(raw, "summary.value", 120, true);
- if (safe !== null) result[key] = safe;
- }
- }
- return result;
-}
-
-function normalizeStrategyHealthFreshness(value, fieldName) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- status: cleanChoice(source.status || "unknown", ["fresh", "stale", "unknown"], `${fieldName}.status`),
- age_seconds: normalizeStrategyHealthAge(source.age_seconds, `${fieldName}.age_seconds`),
- };
-}
-
-function normalizeStrategyHealthAge(value, fieldName) {
- if (value === null || value === undefined || value === "") return null;
- const number = Number(value);
- if (!Number.isFinite(number) || number < 0 || number > 315360000) throw new Error(`${fieldName} is invalid`);
- return Math.round(number);
-}
-
-function normalizeStrategyHealthScore(value, fieldName) {
- if (value === null || value === undefined || value === "") return null;
- const number = Number(value);
- if (!Number.isFinite(number) || number < 0 || number > 100) throw new Error(`${fieldName} must be between 0 and 100`);
- return number;
-}
-
-function normalizeStrategyHealthTimestamp(value, fieldName, nullable = false) {
- if ((value === null || value === undefined || value === "") && nullable) return null;
- const text = normalizeStrategyHealthText(value, fieldName, 64);
- if (!/^\d{4}-\d{2}-\d{2}T.+(?:Z|[+-]\d{2}:\d{2})$/.test(text) || Number.isNaN(Date.parse(text))) {
- throw new Error(`${fieldName} must be an ISO timestamp`);
- }
- return text;
-}
-
-function normalizeStrategyHealthText(value, fieldName, maxLength, nullable = false) {
- if ((value === null || value === undefined || value === "") && nullable) return null;
- const text = String(value || "").trim();
- if (
- !text ||
- text.length > maxLength ||
- /[<>\\]/.test(text) ||
- text.startsWith("/") ||
- /^[A-Za-z]:[\\/]/.test(text)
- ) throw new Error(`${fieldName} is invalid`);
- return text;
-}
-
-function sanitizeStrategyHealthText(value, fieldName, maxLength, nullable = false, fallback = null) {
- if (value === null || value === undefined || value === "") return nullable ? null : fallback;
- let text;
- try {
- text = normalizeStrategyHealthText(value, fieldName, maxLength);
- } catch {
- return nullable ? null : fallback;
- }
- if (
- /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/i.test(text) ||
- /\b(?:token|secret|password|api[_ -]?key|private[_ -]?key|cookie)\s*[:=]\s*[^\s,;]{8,}/i.test(text) ||
- /\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|sk-[A-Za-z0-9_-]{20,}|eyJ[A-Za-z0-9_-]{20,})\b/.test(text) ||
- /(?:^|[\s(])(?:\/Users\/|\/home\/|[A-Za-z]:[\\/])/.test(text)
- ) return nullable ? null : fallback;
- return text;
-}
-
-function normalizeStrategyHealthErrors(value) {
- if (!Array.isArray(value)) return [];
- return uniqueStrings(value.slice(0, 20).filter((item) => /^[a-z][a-z0-9_.-]{0,63}$/.test(String(item || ""))));
-}
-
-function normalizeStrategyHealthPolicy(value) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- const list = (raw) => Array.isArray(raw)
- ? raw.slice(0, 20).map((item) => sanitizeStrategyHealthText(item, "policy.item", 120, true)).filter(Boolean)
- : [];
- return {
- mode: sanitizeStrategyHealthText(source.mode, "policy.mode", 40, false, "read_only"),
- automatic_stages: list(source.automatic_stages),
- automatic_modes: list(source.automatic_modes),
- human_gate_stages: list(source.human_gate_stages),
- canary_requirements: list(source.canary_requirements),
- human_actions: list(source.human_actions),
- machine_checks: list(source.machine_checks),
- notice: sanitizeStrategyHealthText(source.notice, "policy.notice", 240, false, "健康不等于已批准 live。"),
- };
-}
-
-function emptyStrategyHealthPayload(errorCode) {
- return {
- schema_version: "strategy_health_dashboard.v1",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { strategy_count: 0, healthy: 0, watch: 0, review: 0, critical: 0 },
- strategies: [],
- policy: normalizeStrategyHealthPolicy({}),
- errors: [errorCode],
- };
-}
-
-function strategyHealthStaleTtlSeconds(env) {
- const configured = Number(env.STRATEGY_HEALTH_STALE_TTL_SECONDS);
- if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
- return STRATEGY_HEALTH_DEFAULT_STALE_TTL_SECONDS;
- }
- return Math.floor(configured);
-}
-
-function normalizeControlPlaneSnapshot(payload, fieldName = "control plane snapshot") {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- if (payload.schema_version !== "qsl_control_plane_dashboard.v1") {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- for (const required of ["generated_at", "computed_at", "data_status", "summary", "candidates", "policy", "errors"]) {
- if (!(required in payload)) throw new Error(`${fieldName}.${required} is required`);
- }
- if (!payload.summary || Array.isArray(payload.summary) || typeof payload.summary !== "object") {
- throw new Error(`${fieldName}.summary must be an object`);
- }
- const dataStatus = cleanChoice(payload.data_status || "unavailable", STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- const candidates = dataStatus === "unavailable" ? [] : normalizeControlPlaneCandidates(payload.candidates, fieldName);
- const errors = normalizeStrategyHealthErrors(payload.errors);
- return {
- schema_version: "qsl_control_plane_dashboard.v1",
- generated_at: normalizeStrategyHealthTimestamp(payload.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(payload.computed_at, `${fieldName}.computed_at`, true),
- data_status: dataStatus,
- summary: normalizeControlPlaneSummary(candidates),
- attention: normalizeControlPlaneAttention({ dataStatus, candidates, errors }),
- candidates,
- policy: normalizeControlPlanePolicy(payload.policy, fieldName),
- errors,
- };
-}
-
-function normalizeControlPlaneSourceSnapshot(payload, fieldName = "control plane source snapshot") {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- if (payload.schema_version !== CONTROL_PLANE_SOURCE_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- for (const required of ["source_id", "generated_at", "computed_at", "data_status", "candidates", "errors"]) {
- if (!(required in payload)) throw new Error(`${fieldName}.${required} is required`);
- }
- const dataStatus = cleanChoice(payload.data_status || "unavailable", STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- return {
- schema_version: CONTROL_PLANE_SOURCE_SCHEMA_VERSION,
- source_id: normalizeControlPlaneIdentifier(payload.source_id, `${fieldName}.source_id`, false),
- generated_at: normalizeStrategyHealthTimestamp(payload.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(payload.computed_at, `${fieldName}.computed_at`, true),
- data_status: dataStatus,
- candidates: dataStatus === "unavailable" ? [] : normalizeControlPlaneCandidates(payload.candidates, fieldName),
- errors: normalizeStrategyHealthErrors(payload.errors),
- };
-}
-
-function emptyControlPlaneSourceSnapshot(errorCode) {
- return {
- schema_version: CONTROL_PLANE_SOURCE_SCHEMA_VERSION,
- source_id: "unavailable",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- candidates: [],
- errors: [errorCode],
- };
-}
-
-function requireDedicatedM0ResearchSyncToken(request, env) {
- const expected = String(env.M0_RESEARCH_SYNC_TOKEN || "");
- if (!expected) throw new HttpError("M0 research sync token is not configured", 500);
- const header = request.headers.get("Authorization") || "";
- const token = header.match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (token !== expected) throw new HttpError("M0 research sync token is invalid", 401);
-}
-
-async function normalizeM0ResearchLedgerTransport(payload, fieldName = "M0 research ledger transport") {
- const source = assertExactFields(payload, [
- "schema_version", "producer", "source_artifact", "ledger_sha256", "ledger",
- ], fieldName);
- if (source.schema_version !== M0_RESEARCH_TRANSPORT_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const normalized = {
- schema_version: M0_RESEARCH_TRANSPORT_SCHEMA_VERSION,
- producer: normalizeM0ResearchProducer(source.producer, `${fieldName}.producer`),
- source_artifact: normalizeM0ResearchSourceArtifact(source.source_artifact, `${fieldName}.source_artifact`),
- ledger_sha256: normalizeResearchTaskDigest(source.ledger_sha256, `${fieldName}.ledger_sha256`),
- ledger: normalizeM0ResearchLedger(source.ledger, `${fieldName}.ledger`),
- };
- // The ledger digest binds the closed embedded ledger. source_artifact.sha256
- // intentionally remains a distinct immutable declaration about the QAR
- // source artifact; it is not a hash of this derived ledger.
- const recomputed = await calculateM0ResearchLedgerSha256(normalized.ledger);
- if (normalized.ledger_sha256 !== recomputed) {
- throw new Error(`${fieldName}.ledger_sha256 mismatch`);
- }
- const computedAt = Date.parse(normalized.ledger.computed_at);
- if (!Number.isFinite(computedAt) || computedAt > Date.now() + 5 * 60 * 1000) {
- throw new Error(`${fieldName}.ledger.computed_at is in the future`);
- }
- if (computedAt < Date.now() - M0_RESEARCH_RETENTION_SECONDS * 1000) {
- throw new Error(`${fieldName}.ledger is expired`);
- }
- return normalized;
-}
-
-async function normalizeM0ResearchLedgerStorageRecord(payload, fieldName) {
- const record = assertExactFields(payload, ["schema_version", "stored_at", "expires_at", "envelope"], fieldName);
- if (record.schema_version !== M0_RESEARCH_STORAGE_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const storedAt = normalizeM0ResearchTimestamp(record.stored_at, `${fieldName}.stored_at`);
- const expiresAt = normalizeM0ResearchTimestamp(record.expires_at, `${fieldName}.expires_at`);
- const storedMillis = Date.parse(storedAt);
- const expiresMillis = Date.parse(expiresAt);
- if (expiresMillis - storedMillis !== M0_RESEARCH_RETENTION_SECONDS * 1000 || expiresMillis <= Date.now()) {
- throw new Error(`${fieldName} is expired`);
- }
- return {
- schema_version: M0_RESEARCH_STORAGE_SCHEMA_VERSION,
- stored_at: storedAt,
- expires_at: expiresAt,
- envelope: await normalizeM0ResearchLedgerTransport(record.envelope, `${fieldName}.envelope`),
- };
-}
-
-function normalizeM0ResearchLedger(payload, fieldName) {
- const ledger = assertExactFields(payload, [
- "schema_version", "generated_at", "computed_at", "data_status", "summary", "subjects", "policy", "errors",
- ], fieldName);
- if (ledger.schema_version !== M0_RESEARCH_LEDGER_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const generatedAt = normalizeM0ResearchTimestamp(ledger.generated_at, `${fieldName}.generated_at`);
- const computedAt = normalizeM0ResearchTimestamp(ledger.computed_at, `${fieldName}.computed_at`);
- if (generatedAt !== computedAt || /\./.test(generatedAt)) {
- throw new Error(`${fieldName} timestamps must be the same canonical second`);
- }
- const dataStatus = cleanChoice(ledger.data_status, ["ready", "unavailable", "stale"], `${fieldName}.data_status`);
- if (!Array.isArray(ledger.subjects) || ledger.subjects.length > 50000) {
- throw new Error(`${fieldName}.subjects must be a bounded array`);
- }
- const subjects = ledger.subjects.map((subject, index) => normalizeM0ResearchSubject(
- subject, `${fieldName}.subjects[${index}]`, computedAt,
- ));
- assertM0ResearchSortedUnique(subjects, (subject) => `${subject.subject.kind}\u0000${subject.subject.identifier}`, `${fieldName}.subjects`);
- const summary = normalizeM0ResearchLedgerSummary(ledger.summary, `${fieldName}.summary`);
- const calculatedSummary = summarizeM0ResearchSubjects(subjects);
- if (!m0ResearchSummariesEqual(summary, calculatedSummary)) {
- throw new Error(`${fieldName}.summary does not match subjects`);
- }
- const expectedStatus = summary.fresh_observation_count > 0
- ? "ready"
- : (summary.observation_count > 0 ? "stale" : "unavailable");
- if (dataStatus !== expectedStatus) throw new Error(`${fieldName}.data_status does not match subjects`);
- if (dataStatus === "unavailable" && subjects.length) throw new Error(`${fieldName}.subjects must be empty when unavailable`);
- return {
- schema_version: M0_RESEARCH_LEDGER_SCHEMA_VERSION,
- generated_at: generatedAt,
- computed_at: computedAt,
- data_status: dataStatus,
- summary,
- subjects,
- policy: normalizeM0ResearchLedgerPolicy(ledger.policy, `${fieldName}.policy`),
- errors: normalizeM0ResearchErrorCodes(ledger.errors, `${fieldName}.errors`),
- };
-}
-
-function normalizeM0ResearchLedgerSummary(value, fieldName) {
- const summary = assertExactFields(value, M0_RESEARCH_SUMMARY_FIELDS, fieldName);
- const result = {};
- for (const key of M0_RESEARCH_SUMMARY_FIELDS) {
- result[key] = normalizeM0ResearchCount(summary[key], `${fieldName}.${key}`);
- }
- return result;
-}
-
-function m0ResearchSummariesEqual(left, right) {
- return M0_RESEARCH_SUMMARY_FIELDS.every((field) => left[field] === right[field]);
-}
-
-function normalizeM0ResearchLedgerPolicy(value, fieldName) {
- const policy = assertExactFields(value, ["authority", "no_order", "permitted_next_step", "notice"], fieldName);
- if (policy.authority !== "research_only" || policy.no_order !== true || policy.permitted_next_step !== "research_validation_only") {
- throw new Error(`${fieldName} must remain research-only and no-order`);
- }
- return {
- authority: "research_only",
- no_order: true,
- permitted_next_step: "research_validation_only",
- notice: normalizeM0ResearchText(policy.notice, `${fieldName}.notice`, 240),
- };
-}
-
-function normalizeM0ResearchSubject(value, fieldName, ledgerComputedAt) {
- const item = assertExactFields(value, ["subject", "observations", "horizon_conflict", "historical_stale_horizon_drift"], fieldName);
- const subject = assertExactFields(item.subject, ["kind", "identifier"], `${fieldName}.subject`);
- const normalizedSubject = {
- kind: cleanChoice(subject.kind, M0_RESEARCH_SUBJECT_KINDS, `${fieldName}.subject.kind`),
- identifier: normalizeM0ResearchIdentifier(subject.identifier, `${fieldName}.subject.identifier`),
- };
- if (!Array.isArray(item.observations) || !item.observations.length || item.observations.length > 100) {
- throw new Error(`${fieldName}.observations must be a non-empty bounded array`);
- }
- const observations = item.observations.map((observation, index) => normalizeM0ResearchObservation(
- observation, `${fieldName}.observations[${index}]`, ledgerComputedAt,
- ));
- assertM0ResearchSortedUnique(observations, (observation) => (
- `${observation.source_report_digest}\u0000${observation.source_entry_digest}`
- ), `${fieldName}.observations`);
- const expectedHorizonView = calculateM0ResearchHorizonViews(observations);
- const horizonConflict = normalizeM0ResearchHorizonView(
- item.horizon_conflict, `${fieldName}.horizon_conflict`, ["none", "conflict"], expectedHorizonView.horizon_conflict,
- );
- const historicalStaleHorizonDrift = normalizeM0ResearchHorizonView(
- item.historical_stale_horizon_drift, `${fieldName}.historical_stale_horizon_drift`,
- ["none", "drift", "unavailable"], expectedHorizonView.historical_stale_horizon_drift,
- );
- return {
- subject: normalizedSubject,
- observations,
- horizon_conflict: horizonConflict,
- historical_stale_horizon_drift: historicalStaleHorizonDrift,
- };
-}
-
-function normalizeM0ResearchObservation(value, fieldName, ledgerComputedAt) {
- const item = assertExactFields(value, [
- "source_ids", "source_report_digest", "source_entry_digest", "hypothesis_id", "as_of", "generated_at", "expires_at",
- "research_context", "freshness",
- ], fieldName);
- if (!Array.isArray(item.source_ids) || !item.source_ids.length || item.source_ids.length > 100) {
- throw new Error(`${fieldName}.source_ids must be a non-empty bounded array`);
- }
- const sourceIds = item.source_ids.map((sourceId, index) => normalizeM0ResearchIdentifier(sourceId, `${fieldName}.source_ids[${index}]`));
- assertM0ResearchSortedUnique(sourceIds, (sourceId) => sourceId, `${fieldName}.source_ids`);
- const generatedAt = normalizeM0ResearchTimestamp(item.generated_at, `${fieldName}.generated_at`);
- const expiresAt = normalizeM0ResearchTimestamp(item.expires_at, `${fieldName}.expires_at`);
- const generatedMillis = Date.parse(generatedAt);
- const expiresMillis = Date.parse(expiresAt);
- if (expiresMillis - generatedMillis !== 7 * 24 * 60 * 60 * 1000) {
- throw new Error(`${fieldName} must have the fixed seven-day M0 expiry`);
- }
- const asOf = normalizeM0ResearchDate(item.as_of, `${fieldName}.as_of`);
- if (asOf > generatedAt.slice(0, 10)) throw new Error(`${fieldName}.as_of cannot be after generated_at`);
- const context = normalizeM0ResearchContext(item.research_context, `${fieldName}.research_context`);
- const freshness = normalizeM0ResearchFreshness(
- item.freshness, `${fieldName}.freshness`, generatedMillis, expiresMillis, Date.parse(ledgerComputedAt),
- );
- return {
- source_ids: sourceIds,
- source_report_digest: normalizeResearchTaskDigest(item.source_report_digest, `${fieldName}.source_report_digest`),
- source_entry_digest: normalizeResearchTaskDigest(item.source_entry_digest, `${fieldName}.source_entry_digest`),
- hypothesis_id: normalizeM0ResearchIdentifier(item.hypothesis_id, `${fieldName}.hypothesis_id`),
- as_of: asOf,
- generated_at: generatedAt,
- expires_at: expiresAt,
- research_context: context,
- freshness,
- };
-}
-
-function normalizeM0ResearchContext(value, fieldName) {
- const context = assertExactFields(value, [
- "state", "primary_horizon", "suitable_horizons", "source_confidence", "source_style", "theme_ids",
- ], fieldName);
- const primaryHorizon = cleanChoice(context.primary_horizon, M0_RESEARCH_HORIZONS, `${fieldName}.primary_horizon`);
- if (!Array.isArray(context.suitable_horizons) || !context.suitable_horizons.length || context.suitable_horizons.length > 4) {
- throw new Error(`${fieldName}.suitable_horizons is invalid`);
- }
- const suitableHorizons = context.suitable_horizons.map((horizon, index) => cleanChoice(
- horizon, M0_RESEARCH_HORIZONS, `${fieldName}.suitable_horizons[${index}]`,
- ));
- if (!suitableHorizons.includes(primaryHorizon)) throw new Error(`${fieldName}.primary_horizon must be suitable`);
- assertM0ResearchUnique(suitableHorizons, `${fieldName}.suitable_horizons`);
- if (!Array.isArray(context.theme_ids) || context.theme_ids.length > 24) throw new Error(`${fieldName}.theme_ids is invalid`);
- const themeIds = context.theme_ids.map((themeId, index) => normalizeM0ResearchIdentifier(themeId, `${fieldName}.theme_ids[${index}]`));
- assertM0ResearchUnique(themeIds, `${fieldName}.theme_ids`);
- return {
- state: cleanChoice(context.state, M0_RESEARCH_STATES, `${fieldName}.state`),
- primary_horizon: primaryHorizon,
- suitable_horizons: suitableHorizons,
- source_confidence: cleanChoice(context.source_confidence, M0_RESEARCH_CONFIDENCE, `${fieldName}.source_confidence`),
- source_style: cleanChoice(context.source_style, M0_RESEARCH_STYLES, `${fieldName}.source_style`),
- theme_ids: themeIds,
- };
-}
-
-function normalizeM0ResearchFreshness(value, fieldName, generatedMillis, expiresMillis, ledgerComputedMillis) {
- const freshness = assertExactFields(value, ["status", "age_seconds"], fieldName);
- const status = cleanChoice(freshness.status, ["fresh", "stale", "unknown"], `${fieldName}.status`);
- const expectedAge = generatedMillis > ledgerComputedMillis
- ? null
- : Math.max(0, Math.floor((ledgerComputedMillis - generatedMillis) / 1000));
- const age = freshness.age_seconds === null ? null : normalizeM0ResearchCount(freshness.age_seconds, `${fieldName}.age_seconds`, 315360000);
- if (status === "unknown") {
- if (age !== null || generatedMillis <= ledgerComputedMillis) throw new Error(`${fieldName} unknown state is invalid`);
- return { status, age_seconds: null };
- }
- if (age !== expectedAge || generatedMillis > ledgerComputedMillis) throw new Error(`${fieldName}.age_seconds is invalid`);
- if (status === "fresh" && ledgerComputedMillis >= expiresMillis) throw new Error(`${fieldName} cannot be fresh after expiry`);
- return { status, age_seconds: age };
-}
-
-function calculateM0ResearchHorizonViews(observations) {
- const freshHorizons = [...new Set(observations
- .filter((observation) => observation.freshness.status === "fresh")
- .map((observation) => observation.research_context.primary_horizon))].sort();
- const staleHorizons = [...new Set(observations
- .filter((observation) => observation.freshness.status === "stale")
- .map((observation) => observation.research_context.primary_horizon))].sort();
- return {
- horizon_conflict: { status: freshHorizons.length > 1 ? "conflict" : "none", primary_horizons: freshHorizons },
- historical_stale_horizon_drift: {
- status: freshHorizons.length
- ? (staleHorizons.length && JSON.stringify(staleHorizons) !== JSON.stringify(freshHorizons) ? "drift" : "none")
- : (staleHorizons.length ? "unavailable" : "none"),
- primary_horizons: staleHorizons,
- },
- };
-}
-
-function projectM0ResearchDashboardForRead(ledger, sourceLedgerSha256, now = new Date()) {
- // The stored envelope remains the immutable, digest-bound publication
- // record. This is deliberately a different dashboard schema: changing
- // freshness at read time must never pretend to be a re-validatable ledger.
- const nowMillis = now instanceof Date ? now.getTime() : Date.parse(now);
- if (!Number.isFinite(nowMillis)) return emptyM0ResearchDashboardPayload("m0_research_ledger_unavailable");
- const subjects = ledger.subjects.map((entry) => {
- const observations = entry.observations.map((observation) => ({
- ...observation,
- freshness: projectM0ResearchObservationFreshness(observation, nowMillis),
- }));
- const horizonViews = calculateM0ResearchHorizonViews(observations);
- return {
- subject: { ...entry.subject },
- observations,
- horizon_conflict: horizonViews.horizon_conflict,
- historical_stale_horizon_drift: horizonViews.historical_stale_horizon_drift,
- };
- });
- const summary = summarizeM0ResearchSubjects(subjects);
- const dataStatus = summary.fresh_observation_count > 0
- ? "ready"
- : (summary.observation_count > 0 ? "stale" : "unavailable");
- return {
- schema_version: M0_RESEARCH_DASHBOARD_SCHEMA_VERSION,
- source_ledger_sha256: sourceLedgerSha256,
- source_generated_at: ledger.generated_at,
- source_computed_at: ledger.computed_at,
- viewed_at: utcTimestampSeconds(new Date(nowMillis)),
- data_status: dataStatus,
- summary,
- subjects,
- policy: { ...ledger.policy },
- errors: [...ledger.errors],
- };
-}
-
-function projectM0ResearchObservationFreshness(observation, nowMillis) {
- const generatedMillis = Date.parse(observation.generated_at);
- const expiresMillis = Date.parse(observation.expires_at);
- if (!Number.isFinite(generatedMillis) || !Number.isFinite(expiresMillis) || nowMillis < generatedMillis) {
- return { status: "unknown", age_seconds: null };
- }
- const ageSeconds = Math.max(0, Math.floor((nowMillis - generatedMillis) / 1000));
- // A stale source is never promoted by this projection. A former fresh
- // observation is demoted as soon as its own expiry is reached.
- const status = observation.freshness.status === "fresh" && nowMillis < expiresMillis
- ? "fresh"
- : "stale";
- return { status, age_seconds: ageSeconds };
-}
-
-function normalizeM0ResearchHorizonView(value, fieldName, allowedStatuses, expected) {
- const view = assertExactFields(value, ["status", "primary_horizons"], fieldName);
- const status = cleanChoice(view.status, allowedStatuses, `${fieldName}.status`);
- if (!Array.isArray(view.primary_horizons) || view.primary_horizons.length > 4) {
- throw new Error(`${fieldName}.primary_horizons is invalid`);
- }
- const horizons = view.primary_horizons.map((horizon, index) => cleanChoice(
- horizon, M0_RESEARCH_HORIZONS, `${fieldName}.primary_horizons[${index}]`,
- ));
- assertM0ResearchSortedUnique(horizons, (horizon) => horizon, `${fieldName}.primary_horizons`);
- if (status !== expected.status || JSON.stringify(horizons) !== JSON.stringify(expected.primary_horizons)) {
- throw new Error(`${fieldName} does not match observations`);
- }
- return { status, primary_horizons: horizons };
-}
-
-function summarizeM0ResearchSubjects(subjects) {
- const observations = subjects.flatMap((subject) => subject.observations);
- return {
- subject_count: subjects.length,
- observation_count: observations.length,
- fresh_observation_count: observations.filter((observation) => observation.freshness.status === "fresh").length,
- stale_observation_count: observations.filter((observation) => observation.freshness.status === "stale").length,
- unknown_observation_count: observations.filter((observation) => observation.freshness.status === "unknown").length,
- horizon_conflict_count: subjects.filter((subject) => subject.horizon_conflict.status === "conflict").length,
- historical_stale_horizon_drift_count: subjects.filter((subject) => subject.historical_stale_horizon_drift.status === "drift").length,
- };
-}
-
-function normalizeM0ResearchErrorCodes(value, fieldName) {
- if (!Array.isArray(value) || value.length > 20) throw new Error(`${fieldName} is invalid`);
- const errors = value.map((error, index) => {
- if (typeof error !== "string" || !/^[a-z][a-z0-9_.-]{0,63}$/.test(error)) {
- throw new Error(`${fieldName}[${index}] is invalid`);
- }
- return error;
- });
- assertM0ResearchSortedUnique(errors, (error) => error, fieldName);
- return errors;
-}
-
-function normalizeM0ResearchRepository(value, fieldName, allowedRepository) {
- const repository = normalizeResearchTaskRepository(value, fieldName);
- if (repository !== allowedRepository) throw new Error(`${fieldName} is not an approved M0 repository`);
- return repository;
-}
-
-function normalizeM0ResearchRevision(value, fieldName) {
- return normalizeResearchTaskRevision(value, fieldName);
-}
-
-function normalizeM0ResearchProducer(value, fieldName) {
- const producer = assertExactFields(value, ["repository", "revision"], fieldName);
- return {
- repository: normalizeM0ResearchRepository(
- producer.repository, `${fieldName}.repository`, M0_RESEARCH_ALLOWED_PRODUCER_REPOSITORY,
- ),
- revision: normalizeM0ResearchRevision(producer.revision, `${fieldName}.revision`),
- };
-}
-
-function normalizeM0ResearchSourceArtifact(value, fieldName) {
- const artifact = assertExactFields(value, ["repository", "revision", "run_id", "artifact_id", "sha256"], fieldName);
- return {
- repository: normalizeM0ResearchRepository(
- artifact.repository, `${fieldName}.repository`, M0_RESEARCH_ALLOWED_SOURCE_REPOSITORY,
- ),
- revision: normalizeM0ResearchRevision(artifact.revision, `${fieldName}.revision`),
- run_id: normalizeM0ResearchIdentifier(artifact.run_id, `${fieldName}.run_id`),
- artifact_id: normalizeM0ResearchArtifactId(artifact.artifact_id, `${fieldName}.artifact_id`),
- sha256: normalizeResearchTaskDigest(artifact.sha256, `${fieldName}.sha256`),
- };
-}
-
-function normalizeM0ResearchArtifactId(value, fieldName) {
- // Keep this exactly aligned with #309's generic identifier schema. Artifact
- // IDs are provenance labels, not strategy slugs, so uppercase and `:/` are
- // valid when they satisfy the closed source-artifact contract.
- return normalizeM0ResearchIdentifier(value, fieldName);
-}
-
-function normalizeM0ResearchIdentifier(value, fieldName) {
- if (typeof value !== "string" || !/^[A-Za-z0-9._:/-]{1,128}$/.test(value)) {
- throw new Error(`${fieldName} is invalid`);
- }
- return value;
-}
-
-function normalizeM0ResearchTimestamp(value, fieldName) {
- if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/.test(value) || Number.isNaN(Date.parse(value))) {
- throw new Error(`${fieldName} must be a UTC timestamp`);
- }
- if (new Date(value).toISOString().slice(0, 10) !== value.slice(0, 10)) {
- throw new Error(`${fieldName} must be a real UTC timestamp`);
- }
- return value;
-}
-
-function normalizeM0ResearchDate(value, fieldName) {
- if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value) || Number.isNaN(Date.parse(`${value}T00:00:00Z`))) {
- throw new Error(`${fieldName} must be an ISO date`);
- }
- if (new Date(`${value}T00:00:00Z`).toISOString().slice(0, 10) !== value) {
- throw new Error(`${fieldName} must be a real ISO date`);
- }
- return value;
-}
-
-function normalizeM0ResearchCount(value, fieldName, maximum = 50000) {
- if (!Number.isInteger(value) || value < 0 || value > maximum) throw new Error(`${fieldName} is invalid`);
- return value;
-}
-
-function normalizeM0ResearchText(value, fieldName, maximum) {
- if (typeof value !== "string" || !value || value.length > maximum || /[<>\\\u0000-\u001f]/.test(value)) {
- throw new Error(`${fieldName} is invalid`);
- }
- return value;
-}
-
-function assertM0ResearchUnique(values, fieldName) {
- if (new Set(values).size !== values.length) throw new Error(`${fieldName} contains duplicates`);
-}
-
-function assertM0ResearchSortedUnique(values, key, fieldName) {
- let previous = null;
- for (const value of values) {
- const current = key(value);
- if (previous !== null && current <= previous) throw new Error(`${fieldName} must be sorted and unique`);
- previous = current;
- }
-}
-
-function canonicalM0ResearchLedgerJson(value) {
- if (value === null) return "null";
- if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
- if (typeof value === "number") {
- if (!Number.isFinite(value)) throw new Error("M0 research ledger must use finite JSON values");
- return JSON.stringify(value);
- }
- if (Array.isArray(value)) return `[${value.map(canonicalM0ResearchLedgerJson).join(",")}]`;
- if (!value || typeof value !== "object") throw new Error("M0 research ledger must use JSON values");
- return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalM0ResearchLedgerJson(value[key])}`).join(",")}}`;
-}
-
-async function calculateM0ResearchLedgerSha256(ledger) {
- const raw = new TextEncoder().encode(canonicalM0ResearchLedgerJson(ledger));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-function emptyM0ResearchDashboardPayload(errorCode, now = new Date()) {
- return {
- schema_version: M0_RESEARCH_DASHBOARD_SCHEMA_VERSION,
- source_ledger_sha256: null,
- source_generated_at: null,
- source_computed_at: null,
- viewed_at: utcTimestampSeconds(now),
- data_status: "unavailable",
- summary: {
- subject_count: 0,
- observation_count: 0,
- fresh_observation_count: 0,
- stale_observation_count: 0,
- unknown_observation_count: 0,
- horizon_conflict_count: 0,
- historical_stale_horizon_drift_count: 0,
- },
- subjects: [],
- policy: {
- authority: "research_only",
- no_order: true,
- permitted_next_step: "research_validation_only",
- notice: "M0 研究台账不可用;不会推断策略、平台、运行状态或订单。",
- },
- errors: [errorCode],
- };
-}
-
-async function normalizeAdaptiveSelectionSourceSnapshot(payload, fieldName = "adaptive selection source snapshot") {
- const source = assertExactFields(payload, [
- "schema_version", "source_id", "generated_at", "computed_at", "data_status", "decision", "errors",
- ], fieldName);
- if (source.schema_version !== ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- const generatedAt = normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true);
- const computedAt = normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true);
- const decision = source.decision === null
- ? null
- : await normalizeAdaptiveSelectionDecision(source.decision, `${fieldName}.decision`);
- if (dataStatus === "unavailable" && decision !== null) {
- throw new Error(`${fieldName}.decision must be null when unavailable`);
- }
- if (dataStatus !== "unavailable" && (!decision || !generatedAt || !computedAt)) {
- throw new Error(`${fieldName} requires decision and timestamps when available`);
- }
- return {
- schema_version: ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION,
- source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
- generated_at: generatedAt,
- computed_at: computedAt,
- data_status: dataStatus,
- decision,
- errors: normalizeStrategyHealthErrors(source.errors),
- };
-}
-
-async function normalizeAdaptiveSelectionDecision(payload, fieldName) {
- const value = assertExactFields(payload, [
- "schema", "decision_id", "created_at", "authority", "no_order", "market_context", "policy_id",
- "recommended_strategy_profile", "recommended_platform_id", "candidates", "input_digest", "decision_digest",
- ], fieldName);
- if (value.schema !== ADAPTIVE_SELECTION_DECISION_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema is unsupported`);
- }
- if (value.authority !== ADAPTIVE_SELECTION_AUTHORITY || value.no_order !== true) {
- throw new Error(`${fieldName} must remain shadow-only and no-order`);
- }
- if (!Array.isArray(value.candidates) || value.candidates.length > 1000) {
- throw new Error(`${fieldName}.candidates must be a bounded array`);
- }
- const candidates = value.candidates.map((item, index) =>
- normalizeAdaptiveSelectionCandidate(item, `${fieldName}.candidates[${index}]`),
- );
- const candidateIds = new Set();
- for (const candidate of candidates) {
- if (candidateIds.has(candidate.strategy_profile)) {
- throw new Error(`${fieldName}.candidates contains duplicate strategy_profile`);
- }
- candidateIds.add(candidate.strategy_profile);
- }
- const recommendedStrategy = normalizeControlPlaneIdentifier(
- value.recommended_strategy_profile, `${fieldName}.recommended_strategy_profile`, true,
- );
- const recommendedPlatform = normalizeControlPlaneIdentifier(
- value.recommended_platform_id, `${fieldName}.recommended_platform_id`, true,
- );
- const recommendedCandidate = candidates.find((item) => item.strategy_profile === recommendedStrategy && item.accepted);
- if ((recommendedStrategy === null) !== (recommendedPlatform === null)) {
- throw new Error(`${fieldName}.recommended strategy and platform must be provided together`);
- }
- if (recommendedStrategy && (!recommendedCandidate || recommendedCandidate.selected_platform_id !== recommendedPlatform)) {
- throw new Error(`${fieldName}.recommended candidate is not accepted`);
- }
- const normalized = {
- schema: ADAPTIVE_SELECTION_DECISION_SCHEMA_VERSION,
- decision_id: normalizeControlPlaneIdentifier(value.decision_id, `${fieldName}.decision_id`, false),
- created_at: normalizeStrategyHealthTimestamp(value.created_at, `${fieldName}.created_at`),
- authority: ADAPTIVE_SELECTION_AUTHORITY,
- no_order: true,
- market_context: normalizeAdaptiveSelectionMarketContext(value.market_context, `${fieldName}.market_context`),
- policy_id: normalizeControlPlaneIdentifier(value.policy_id, `${fieldName}.policy_id`, false),
- recommended_strategy_profile: recommendedStrategy,
- recommended_platform_id: recommendedPlatform,
- candidates,
- input_digest: normalizeAdaptiveSelectionDigest(value.input_digest, `${fieldName}.input_digest`),
- decision_digest: normalizeAdaptiveSelectionDigest(value.decision_digest, `${fieldName}.decision_digest`),
- };
- // `input_digest` cannot be reconstructed from the display projection alone:
- // QPK calculates it from the private, immutable selection input. The QPK
- // decision digest binds that exact input digest to every decision field that
- // is displayed here, so a changed input digest cannot be silently accepted.
- if (normalized.decision_digest !== await calculateAdaptiveSelectionDecisionDigest(normalized)) {
- throw new Error(`${fieldName}.decision_digest mismatch`);
- }
- return normalized;
-}
-
-function normalizeAdaptiveSelectionMarketContext(value, fieldName) {
- const item = assertExactFields(value, [
- "schema", "as_of", "domain", "data_version", "data_freshness_days", "regime", "regime_confidence", "factors",
- ], fieldName);
- if (item.schema !== "qsl.market_context_snapshot.v1") {
- throw new Error(`${fieldName}.schema is unsupported`);
- }
- const asOf = String(item.as_of || "");
- if (!/^\d{4}-\d{2}-\d{2}$/.test(asOf) || Number.isNaN(Date.parse(`${asOf}T00:00:00Z`))) {
- throw new Error(`${fieldName}.as_of must be an ISO date`);
- }
- if (!Number.isInteger(item.data_freshness_days) || item.data_freshness_days < 0 || item.data_freshness_days > 366) {
- throw new Error(`${fieldName}.data_freshness_days is invalid`);
- }
- const confidence = Number(item.regime_confidence);
- if (!Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
- throw new Error(`${fieldName}.regime_confidence is invalid`);
- }
- if (!item.factors || Array.isArray(item.factors) || typeof item.factors !== "object" || Object.keys(item.factors).length > 100) {
- throw new Error(`${fieldName}.factors is invalid`);
- }
- const factors = {};
- for (const [key, raw] of Object.entries(item.factors)) {
- if (!/^[a-z][a-z0-9_.-]{0,63}$/.test(key)) throw new Error(`${fieldName}.factors key is invalid`);
- const numeric = Number(raw);
- if (!Number.isFinite(numeric) || Math.abs(numeric) > 1_000_000) {
- throw new Error(`${fieldName}.factors.${key} is invalid`);
- }
- factors[key] = numeric;
- }
- return {
- schema: "qsl.market_context_snapshot.v1",
- as_of: asOf,
- domain: cleanChoice(item.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.domain`),
- data_version: normalizeControlPlaneIdentifier(item.data_version, `${fieldName}.data_version`, false),
- data_freshness_days: item.data_freshness_days,
- regime: normalizeControlPlaneIdentifier(item.regime, `${fieldName}.regime`, false),
- regime_confidence: confidence,
- factors,
- };
-}
-
-function normalizeAdaptiveSelectionCandidate(value, fieldName) {
- const item = assertExactFields(value, [
- "strategy_profile", "release_digest", "selected_platform_id", "score", "risk_multiplier", "accepted", "reasons", "proposed_weight",
- ], fieldName);
- const score = item.score === null ? null : Number(item.score);
- const riskMultiplier = Number(item.risk_multiplier);
- if (score !== null && (!Number.isFinite(score) || Math.abs(score) > 1_000_000)) {
- throw new Error(`${fieldName}.score is invalid`);
- }
- if (!Number.isFinite(riskMultiplier) || riskMultiplier < 0 || riskMultiplier > 1) {
- throw new Error(`${fieldName}.risk_multiplier is invalid`);
- }
- if (typeof item.accepted !== "boolean") throw new Error(`${fieldName}.accepted must be boolean`);
- if (item.proposed_weight !== 0) throw new Error(`${fieldName}.proposed_weight must remain zero`);
- if (!Array.isArray(item.reasons) || item.reasons.length > 32) throw new Error(`${fieldName}.reasons is invalid`);
- const reasons = item.reasons.map((reason) => {
- const code = String(reason || "");
- if (!/^[a-z][a-z0-9_.:-]{0,127}$/.test(code)) throw new Error(`${fieldName}.reason is invalid`);
- return code;
- });
- return {
- strategy_profile: normalizeControlPlaneIdentifier(item.strategy_profile, `${fieldName}.strategy_profile`, false),
- release_digest: normalizeAdaptiveSelectionReleaseDigest(item.release_digest, `${fieldName}.release_digest`),
- selected_platform_id: normalizeControlPlaneIdentifier(item.selected_platform_id, `${fieldName}.selected_platform_id`, true),
- score,
- risk_multiplier: riskMultiplier,
- accepted: item.accepted,
- reasons,
- proposed_weight: 0,
- };
-}
-
-function normalizeAdaptiveSelectionReleaseDigest(value, fieldName) {
- const text = String(value || "").trim();
- if (!/^[A-Za-z0-9._:=+-]{1,160}$/.test(text) || /(token|secret|password|cookie|private|api[_-]?key)/i.test(text)) {
- throw new Error(`${fieldName} is invalid`);
- }
- return text;
-}
-
-function normalizeAdaptiveSelectionDigest(value, fieldName) {
- const text = String(value || "");
- if (!/^[a-f0-9]{64}$/.test(text)) throw new Error(`${fieldName} is invalid`);
- return text;
-}
-
-function isAdaptiveSelectionFloatPath(path) {
- if (path[0] === "market_context") {
- return path[1] === "regime_confidence" || path[1] === "factors";
- }
- return path[0] === "candidates"
- && ["score", "risk_multiplier", "proposed_weight"].includes(path[2]);
-}
-
-function canonicalAdaptiveSelectionNumber(value, forceFloat) {
- if (!Number.isFinite(value)) throw new Error("adaptive selection decision must use finite JSON values");
- if (Object.is(value, -0)) return forceFloat ? "-0.0" : "0";
- let text = String(value);
- const exponent = text.match(/^(.*)e([+-]?)(\d+)$/i);
- if (exponent) {
- const [, mantissa, sign, rawExponent] = exponent;
- // Python's json.dumps (used by QPK canonical_sha256) pads one-digit
- // negative exponents, while V8's Number#toString does not.
- text = `${mantissa}e${sign || "+"}${sign === "-" ? rawExponent.padStart(2, "0") : rawExponent}`;
- }
- if (forceFloat && !/[.eE]/.test(text)) return `${text}.0`;
- return text;
-}
-
-function canonicalAdaptiveSelectionDecisionJson(value, path = []) {
- if (value === null) return "null";
- if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
- if (typeof value === "number") return canonicalAdaptiveSelectionNumber(value, isAdaptiveSelectionFloatPath(path));
- if (Array.isArray(value)) {
- return `[${value.map((item) => canonicalAdaptiveSelectionDecisionJson(item, [...path, "*"])).join(",")}]`;
- }
- if (!value || typeof value !== "object") throw new Error("adaptive selection decision must use JSON values");
- return `{${Object.keys(value).sort().map((key) => (
- `${JSON.stringify(key)}:${canonicalAdaptiveSelectionDecisionJson(value[key], [...path, key])}`
- )).join(",")}}`;
-}
-
-async function calculateAdaptiveSelectionDecisionDigest(payload) {
- const material = { ...payload };
- delete material.decision_digest;
- const raw = new TextEncoder().encode(canonicalAdaptiveSelectionDecisionJson(material));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-function normalizeAdaptiveSelectionSummary(selections) {
- const entries = Array.isArray(selections) ? selections : [];
- const decisions = entries.map((item) => item.decision).filter(Boolean);
- const candidates = decisions.flatMap((item) => item.candidates);
- return {
- source_count: entries.length,
- decision_count: decisions.length,
- candidate_count: candidates.length,
- recommended_count: decisions.filter((item) => item.recommended_strategy_profile).length,
- rejected_candidate_count: candidates.filter((item) => !item.accepted).length,
- };
-}
-
-function emptyAdaptiveSelectionSourceSnapshot(errorCode) {
- return {
- schema_version: ADAPTIVE_SELECTION_SOURCE_SCHEMA_VERSION,
- source_id: "unavailable",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- decision: null,
- errors: [errorCode],
- };
-}
-
-function emptyAdaptiveSelectionPayload(errorCode) {
- return {
- schema_version: ADAPTIVE_SELECTION_DASHBOARD_SCHEMA_VERSION,
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { source_count: 0, decision_count: 0, candidate_count: 0, recommended_count: 0, rejected_candidate_count: 0 },
- selections: [],
- policy: {
- authority: ADAPTIVE_SELECTION_AUTHORITY,
- no_order: true,
- execution_authority_granted: false,
- notice: "M1 Shadow 建议尚不可用;控制台不会推断策略、平台或订单。",
- },
- errors: [errorCode],
- };
-}
-
-function adaptiveSelectionStaleTtlSeconds(env) {
- const configured = Number(env.ADAPTIVE_SELECTION_STALE_TTL_SECONDS);
- if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
- return ADAPTIVE_SELECTION_DEFAULT_STALE_TTL_SECONDS;
- }
- return Math.floor(configured);
-}
-
-function normalizeControlPlaneCandidates(value, fieldName) {
- if (!Array.isArray(value) || value.length > 1000) {
- throw new Error(`${fieldName}.candidates must be an array with at most 1000 items`);
- }
- const seen = new Set();
- return value.map((item, index) => {
- const prefix = `${fieldName}.candidates[${index}]`;
- if (!item || Array.isArray(item) || typeof item !== "object") throw new Error(`${prefix} must be an object`);
- const candidateId = normalizeControlPlaneIdentifier(item.candidate_id, `${prefix}.candidate_id`, false);
- if (seen.has(candidateId)) throw new Error(`${fieldName}.candidates contains duplicate candidate_id`);
- seen.add(candidateId);
- const lifecycle = normalizeControlPlaneLifecycle(item.lifecycle, prefix);
- const recommendation = normalizeControlPlaneRecommendation(item.recommendation, prefix);
- const isOwnerDecision = lifecycle.stage === "P6";
- if (isOwnerDecision && (lifecycle.status !== "owner_decision_required" || recommendation.code !== "owner_live_decision")) {
- throw new Error(`${prefix} P6 must be an owner_live_decision`);
- }
- if (!isOwnerDecision && (lifecycle.status === "owner_decision_required" || recommendation.code === "owner_live_decision")) {
- throw new Error(`${prefix} only P6 can require an owner_live_decision`);
- }
- const forwardObservation = item.forward_observation === undefined
- ? undefined
- : normalizeForwardObservation(item.forward_observation, lifecycle, prefix);
- return {
- candidate_id: candidateId,
- candidate_kind: cleanChoice(item.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${prefix}.candidate_kind`),
- domain: cleanChoice(item.domain, STRATEGY_HEALTH_DOMAINS, `${prefix}.domain`),
- lifecycle,
- evidence: normalizeControlPlaneEvidence(item.evidence, prefix),
- recommendation,
- freshness: normalizeStrategyHealthFreshness(item.freshness, `${prefix}.freshness`),
- ...(forwardObservation === undefined ? {} : { forward_observation: forwardObservation }),
- };
- });
-}
-
-function normalizeForwardObservation(value, lifecycle, prefix) {
- if (!FORWARD_OBSERVATION_RESEARCH_STAGES.has(lifecycle.stage)) {
- throw new Error(`${prefix}.forward_observation is only allowed for research stages`);
- }
- const observation = assertExactFields(value, [
- "state", "observations_completed", "required_trading_sessions", "last_observed_session", "observed_at", "no_order", "live_authority_granted",
- ], `${prefix}.forward_observation`);
- const completed = observation.observations_completed;
- const required = observation.required_trading_sessions;
- if (!Number.isSafeInteger(completed) || !Number.isSafeInteger(required) || completed < 0 || required < 1 || completed > required || required > 10000) {
- throw new Error(`${prefix}.forward_observation observation counts are invalid`);
- }
- if (observation.no_order !== true) throw new Error(`${prefix}.forward_observation.no_order must be true`);
- if (observation.live_authority_granted !== false) throw new Error(`${prefix}.forward_observation.live_authority_granted must be false`);
- return {
- state: cleanChoice(observation.state, FORWARD_OBSERVATION_STATES, `${prefix}.forward_observation.state`),
- observations_completed: completed,
- required_trading_sessions: required,
- last_observed_session: normalizeForwardObservationDate(observation.last_observed_session, `${prefix}.forward_observation.last_observed_session`),
- observed_at: normalizeStrategyHealthTimestamp(observation.observed_at, `${prefix}.forward_observation.observed_at`),
- no_order: true,
- live_authority_granted: false,
- };
-}
-
-function normalizeForwardObservationDate(value, fieldName) {
- const text = normalizeStrategyHealthText(value, fieldName, 10);
- if (!/^\d{4}-\d{2}-\d{2}$/.test(text) || Number.isNaN(Date.parse(`${text}T00:00:00.000Z`)) || new Date(`${text}T00:00:00.000Z`).toISOString().slice(0, 10) !== text) {
- throw new Error(`${fieldName} must be an ISO date`);
- }
- return text;
-}
-
-function normalizeControlPlaneIdentifier(value, fieldName, nullable = true) {
- if ((value === null || value === undefined || value === "") && nullable) return null;
- const text = String(value || "").trim();
- if (!/^[A-Za-z0-9._=-]{1,128}$/.test(text)) throw new Error(`${fieldName} is invalid`);
- if (/(token|secret|password|cookie|private|api[_-]?key)/i.test(text)) throw new Error(`${fieldName} is sensitive`);
- return text;
-}
-
-function normalizeControlPlaneLifecycle(value, prefix) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- stage: cleanChoice(source.stage, CONTROL_PLANE_STAGES, `${prefix}.lifecycle.stage`),
- status: cleanChoice(source.status, CONTROL_PLANE_LIFECYCLE_STATUSES, `${prefix}.lifecycle.status`),
- };
-}
-
-function normalizeControlPlaneEvidence(value, prefix) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- p1_input_digest: normalizeControlPlaneIdentifier(source.p1_input_digest, `${prefix}.evidence.p1_input_digest`),
- p2_config_digest: normalizeControlPlaneIdentifier(source.p2_config_digest, `${prefix}.evidence.p2_config_digest`),
- p3_evidence_id: normalizeControlPlaneIdentifier(source.p3_evidence_id, `${prefix}.evidence.p3_evidence_id`),
- source_revision: normalizeControlPlaneIdentifier(source.source_revision, `${prefix}.evidence.source_revision`),
- };
-}
-
-function normalizeControlPlaneRecommendation(value, prefix) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- return {
- code: cleanChoice(source.code || "none", CONTROL_PLANE_RECOMMENDATIONS, `${prefix}.recommendation.code`),
- reason: sanitizeStrategyHealthText(source.reason, `${prefix}.recommendation.reason`, 240, false, "没有可用的机器建议。"),
- };
-}
-
-function normalizeControlPlaneSummary(candidates) {
- return {
- candidate_count: candidates.length,
- deferred: candidates.filter((item) => item.lifecycle.status === "deferred").length,
- parked: candidates.filter((item) => item.lifecycle.status === "parked").length,
- owner_decision_required: candidates.filter((item) => item.lifecycle.status === "owner_decision_required").length,
- };
-}
-
-function normalizeControlPlaneAttention({ dataStatus, candidates, errors }) {
- const normalizedCandidates = Array.isArray(candidates) ? candidates : [];
- const normalizedErrors = uniqueStrings(Array.isArray(errors) ? errors : []);
- const reasonCodes = new Set(normalizedErrors);
- if (dataStatus !== "ready") reasonCodes.add("control_plane_source_unavailable");
- if (!normalizedCandidates.length && dataStatus === "ready") reasonCodes.add("control_plane_candidate_missing");
- if (normalizedCandidates.some((item) => item.lifecycle?.status === "deferred")) {
- reasonCodes.add("control_plane_candidate_deferred");
- }
- if (normalizedCandidates.some((item) => item.lifecycle?.status === "parked")) {
- reasonCodes.add("control_plane_candidate_parked");
- }
- const status = dataStatus !== "ready"
- ? "unavailable"
- : (reasonCodes.size ? "attention_required" : "research_only");
- return {
- status: cleanChoice(status, CONTROL_PLANE_ATTENTION_STATUSES, "control plane attention status"),
- reason_codes: [...reasonCodes].sort(),
- };
-}
-
-function normalizeControlPlanePolicy(value, fieldName) {
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
- if (source.p6_owner_decision_required !== true) {
- throw new Error(`${fieldName}.policy.p6_owner_decision_required must be true`);
- }
- return {
- p4_p5_automation: cleanChoice(
- source.p4_p5_automation || "not_configured",
- CONTROL_PLANE_AUTOMATION_STATES,
- `${fieldName}.policy.p4_p5_automation`,
- ),
- p6_owner_decision_required: true,
- notice: sanitizeStrategyHealthText(source.notice, `${fieldName}.policy.notice`, 240, false, "live 仍需所有者明确决定。"),
- };
-}
-
-function normalizeBinancePrivateScopeReport(payload, { requireIngestFreshness = false } = {}) {
- const report = assertExactFields(payload, [
- "platform",
- "observed_at",
- "source_run_id",
- "source_sha",
- "account_scope_sha256",
- "assets",
- "historical_difference_unresolved",
- "no_order",
- "execution_authority_granted",
- ], "Binance private scope report");
- if (report.platform !== "binance") throw new Error("Binance private scope report.platform must be binance");
- const observedAt = report.observed_at;
- if (typeof observedAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(observedAt)) {
- throw new Error("Binance private scope report.observed_at must be an ISO timestamp with timezone");
- }
- const observedAtMs = Date.parse(observedAt);
- if (!Number.isFinite(observedAtMs)) {
- throw new Error("Binance private scope report.observed_at must be valid");
- }
- if (requireIngestFreshness) {
- const ageMs = Date.now() - observedAtMs;
- if (ageMs > BINANCE_PRIVATE_SCOPE_INGEST_MAX_AGE_MS || ageMs < -BINANCE_PRIVATE_SCOPE_FUTURE_SKEW_MS) {
- throw new Error("Binance private scope report.observed_at is outside the ingestion window");
- }
- }
- const sourceRunId = report.source_run_id;
- if (typeof sourceRunId !== "string" || !/^[1-9]\d{0,19}$/.test(sourceRunId)) {
- throw new Error("Binance private scope report.source_run_id must be a decimal string");
- }
- const sourceSha = report.source_sha;
- if (typeof sourceSha !== "string" || !/^[0-9a-fA-F]{40}$/.test(sourceSha)) {
- throw new Error("Binance private scope report.source_sha must be a 40 character hex string");
- }
- const accountScopeSha256 = report.account_scope_sha256;
- if (typeof accountScopeSha256 !== "string" || !/^[0-9a-fA-F]{64}$/.test(accountScopeSha256)) {
- throw new Error("Binance private scope report.account_scope_sha256 must be a 64 character hex string");
- }
- if (!Array.isArray(report.assets) || report.assets.length > BINANCE_PRIVATE_SCOPE_MAX_ASSETS) {
- throw new Error(`Binance private scope report.assets must contain at most ${BINANCE_PRIVATE_SCOPE_MAX_ASSETS} items`);
- }
- const seenAssets = new Set();
- const assets = report.assets.map((value, index) => {
- const item = assertExactFields(value, ["asset", "free", "locked"], `Binance private scope report.assets[${index}]`);
- const asset = item.asset;
- if (typeof asset !== "string" || !/^[\p{L}\p{N}]{1,20}$/u.test(asset)) {
- throw new Error(`Binance private scope report.assets[${index}].asset is invalid`);
- }
- if (seenAssets.has(asset)) throw new Error("Binance private scope report.assets contains duplicate assets");
- seenAssets.add(asset);
- const free = normalizeBinancePrivateScopeDecimal(item.free, `Binance private scope report.assets[${index}].free`);
- const locked = normalizeBinancePrivateScopeDecimal(item.locked, `Binance private scope report.assets[${index}].locked`);
- if (binancePrivateScopeDecimalIsZero(free) && binancePrivateScopeDecimalIsZero(locked)) {
- throw new Error(`Binance private scope report.assets[${index}] must not be an all-zero row`);
- }
- return { asset, free, locked };
- });
- if (report.historical_difference_unresolved !== true) {
- throw new Error("Binance private scope report.historical_difference_unresolved must be true");
- }
- if (report.no_order !== true) throw new Error("Binance private scope report.no_order must be true");
- if (report.execution_authority_granted !== false) {
- throw new Error("Binance private scope report.execution_authority_granted must be false");
- }
- return {
- platform: "binance",
- observed_at: observedAt,
- source_run_id: sourceRunId,
- source_sha: sourceSha.toLowerCase(),
- account_scope_sha256: accountScopeSha256.toLowerCase(),
- assets,
- historical_difference_unresolved: true,
- no_order: true,
- execution_authority_granted: false,
- };
-}
-
-function normalizeBinancePrivateScopeDecimal(value, fieldName) {
- if (typeof value !== "string" || !/^\d+(?:\.\d+)?$/.test(value)) {
- throw new Error(`${fieldName} must be a non-negative finite decimal string`);
- }
- return value;
-}
-
-function binancePrivateScopeDecimalIsZero(value) {
- return /^0+(?:\.0+)?$/.test(value);
-}
-
-function normalizeReconciliationRecoverySourceSnapshot(payload, fieldName = "reconciliation recovery source snapshot") {
- const source = assertExactFields(payload, [
- "schema_version", "source_id", "generated_at", "computed_at", "data_status", "recoveries", "errors",
- ], fieldName);
- if (source.schema_version !== RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- if (!Array.isArray(source.recoveries) || source.recoveries.length > RECONCILIATION_RECOVERY_MAX_REQUESTS) {
- throw new Error(`${fieldName}.recoveries must be an array with at most ${RECONCILIATION_RECOVERY_MAX_REQUESTS} items`);
- }
- const recoveries = [];
- const seen = new Set();
- for (const [index, value] of source.recoveries.entries()) {
- const recovery = normalizeReconciliationRecoveryRequest(value, `${fieldName}.recoveries[${index}]`);
- if (seen.has(recovery.recovery_id)) {
- throw new Error(`${fieldName}.recoveries contains duplicate recovery_id`);
- }
- seen.add(recovery.recovery_id);
- recoveries.push(recovery);
- }
- if (dataStatus === "unavailable" && recoveries.length) {
- throw new Error(`${fieldName}.recoveries must be empty when unavailable`);
- }
- return {
- schema_version: RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION,
- source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
- generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
- data_status: dataStatus,
- recoveries,
- errors: normalizeStrategyHealthErrors(source.errors),
- };
-}
-
-function normalizeReconciliationRecoveryRequest(value, fieldName) {
- if (value?.mode === "initial_enrollment") {
- const item = assertExactFields(value, ["mode", "recovery_id", "target_id", "candidate", "facts"], fieldName);
- return { mode: "initial_enrollment", recovery_id: normalizeControlPlaneIdentifier(item.recovery_id, `${fieldName}.recovery_id`, false),
- target_id: normalizeControlPlaneIdentifier(item.target_id, `${fieldName}.target_id`, false), candidate: item.candidate, facts: item.facts };
- }
- const item = assertExactFields(value, [
- "recovery_id", "platform", "strategy_profile", "environment", "reconciliation_state", "readiness",
- "candidate_sha256", "evidence_sample_count", "first_observed_at", "last_observed_at", "dual_review", "blocker_codes",
- ], fieldName);
- const dualReview = assertExactFields(item.dual_review, [
- "outcome", "reviewer_count", "evidence_binding_sha256",
- ], `${fieldName}.dual_review`);
- const evidenceSampleCount = Number(item.evidence_sample_count);
- const reviewerCount = Number(dualReview.reviewer_count);
- if (!Number.isInteger(evidenceSampleCount) || evidenceSampleCount < 0 || evidenceSampleCount > 100) {
- throw new Error(`${fieldName}.evidence_sample_count must be a bounded integer`);
- }
- if (!Number.isInteger(reviewerCount) || reviewerCount < 0 || reviewerCount > 10) {
- throw new Error(`${fieldName}.dual_review.reviewer_count must be a bounded integer`);
- }
- const firstObservedAt = normalizeResearchTaskTimestamp(item.first_observed_at, `${fieldName}.first_observed_at`);
- const lastObservedAt = normalizeResearchTaskTimestamp(item.last_observed_at, `${fieldName}.last_observed_at`);
- const observationWindowMs = Date.parse(lastObservedAt) - Date.parse(firstObservedAt);
- if (observationWindowMs < 0) {
- throw new Error(`${fieldName}.first_observed_at must not be after last_observed_at`);
- }
- if (!Array.isArray(item.blocker_codes) || item.blocker_codes.length > 20) {
- throw new Error(`${fieldName}.blocker_codes must be an array with at most 20 items`);
- }
- const blockerCodes = normalizeStrategyHealthErrors(item.blocker_codes);
- if (blockerCodes.length !== item.blocker_codes.length) {
- throw new Error(`${fieldName}.blocker_codes must be unique stable codes`);
- }
- const recovery = {
- recovery_id: normalizeControlPlaneIdentifier(item.recovery_id, `${fieldName}.recovery_id`, false),
- platform: cleanChoice(item.platform, RECONCILIATION_RECOVERY_PLATFORMS, `${fieldName}.platform`),
- strategy_profile: normalizeResearchTaskIdentity(item.strategy_profile, `${fieldName}.strategy_profile`),
- environment: cleanChoice(item.environment, RECONCILIATION_RECOVERY_ENVIRONMENTS, `${fieldName}.environment`),
- reconciliation_state: cleanChoice(
- item.reconciliation_state,
- RECONCILIATION_RECOVERY_STATES,
- `${fieldName}.reconciliation_state`,
- ),
- readiness: cleanChoice(item.readiness, RECONCILIATION_RECOVERY_READINESS, `${fieldName}.readiness`),
- candidate_sha256: normalizeResearchTaskDigest(item.candidate_sha256, `${fieldName}.candidate_sha256`),
- evidence_sample_count: evidenceSampleCount,
- first_observed_at: firstObservedAt,
- last_observed_at: lastObservedAt,
- dual_review: {
- outcome: cleanChoice(
- dualReview.outcome,
- RECONCILIATION_RECOVERY_DUAL_REVIEW_OUTCOMES,
- `${fieldName}.dual_review.outcome`,
- ),
- reviewer_count: reviewerCount,
- evidence_binding_sha256: normalizeResearchTaskDigest(
- dualReview.evidence_binding_sha256,
- `${fieldName}.dual_review.evidence_binding_sha256`,
- ),
- },
- blocker_codes: blockerCodes,
- };
- if (recovery.readiness === "awaiting_human_confirmation") {
- if (
- recovery.evidence_sample_count < 1 ||
- observationWindowMs > RECONCILIATION_RECOVERY_MAX_SAMPLE_WINDOW_MS ||
- recovery.dual_review.evidence_binding_sha256 !== recovery.candidate_sha256 ||
- recovery.blocker_codes.length
- ) {
- throw new Error(`${fieldName}.readiness requires at least one observation within a 15-minute window, bound candidate, and no blockers`);
- }
- }
- return recovery;
-}
-
-function normalizeExecutionEvidenceSourceSnapshot(payload, fieldName = "execution evidence source snapshot") {
- const source = assertExactFields(payload, [
- "schema_version", "source_id", "generated_at", "computed_at", "data_status", "deployments", "errors",
- ], fieldName);
- if (source.schema_version !== EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- if (!Array.isArray(source.deployments) || source.deployments.length > 1000) {
- throw new Error(`${fieldName}.deployments must be an array with at most 1000 items`);
- }
- const deployments = [];
- const seen = new Set();
- for (const [index, item] of source.deployments.entries()) {
- const deployment = normalizeExecutionEvidenceDeployment(item, `${fieldName}.deployments[${index}]`);
- if (seen.has(deployment.deployment_id)) {
- throw new Error(`${fieldName}.deployments contains duplicate deployment_id`);
- }
- seen.add(deployment.deployment_id);
- deployments.push(deployment);
- }
- if (dataStatus === "unavailable" && deployments.length) {
- throw new Error(`${fieldName}.deployments must be empty when unavailable`);
- }
- return {
- schema_version: EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION,
- source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
- generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
- data_status: dataStatus,
- deployments,
- errors: normalizeStrategyHealthErrors(source.errors),
- };
-}
-
-function normalizeExecutionEvidenceDeployment(value, fieldName) {
- const item = assertRequiredAndOptionalFields(value, [
- "deployment_id", "strategy", "target", "capabilities", "evidence", "recommendation",
- ], ["execution_receipt"], fieldName);
- const strategy = assertExactFields(item.strategy, [
- "candidate_id", "candidate_kind", "domain", "strategy_revision",
- ], `${fieldName}.strategy`);
- const target = assertExactFields(item.target, ["platform", "environment"], `${fieldName}.target`);
- const capabilities = assertExactFields(item.capabilities, ["shadow", "paper"], `${fieldName}.capabilities`);
- const evidence = assertExactFields(item.evidence, [
- "strategy", "target_data", "target_execution",
- ], `${fieldName}.evidence`);
- const recommendation = assertExactFields(item.recommendation, ["code", "reason_code"], `${fieldName}.recommendation`);
- const executionReceipt = item.execution_receipt === undefined
- ? null
- : normalizeExecutionEvidenceReceipt(item.execution_receipt, `${fieldName}.execution_receipt`);
- const normalized = {
- deployment_id: normalizeControlPlaneIdentifier(item.deployment_id, `${fieldName}.deployment_id`, false),
- strategy: {
- candidate_id: normalizeControlPlaneIdentifier(strategy.candidate_id, `${fieldName}.strategy.candidate_id`, false),
- candidate_kind: cleanChoice(strategy.candidate_kind, CONTROL_PLANE_CANDIDATE_KINDS, `${fieldName}.strategy.candidate_kind`),
- domain: cleanChoice(strategy.domain, STRATEGY_HEALTH_DOMAINS, `${fieldName}.strategy.domain`),
- strategy_revision: normalizeResearchTaskRevision(strategy.strategy_revision, `${fieldName}.strategy.strategy_revision`),
- },
- target: {
- platform: cleanChoice(target.platform, EXECUTION_EVIDENCE_PLATFORMS, `${fieldName}.target.platform`),
- environment: cleanChoice(target.environment, EXECUTION_EVIDENCE_ENVIRONMENTS, `${fieldName}.target.environment`),
- },
- capabilities: {
- shadow: cleanChoice(capabilities.shadow, EXECUTION_EVIDENCE_CAPABILITIES, `${fieldName}.capabilities.shadow`),
- paper: cleanChoice(capabilities.paper, EXECUTION_EVIDENCE_CAPABILITIES, `${fieldName}.capabilities.paper`),
- },
- evidence: {
- strategy: cleanChoice(evidence.strategy, EXECUTION_EVIDENCE_STATUSES, `${fieldName}.evidence.strategy`),
- target_data: cleanChoice(evidence.target_data, EXECUTION_EVIDENCE_STATUSES, `${fieldName}.evidence.target_data`),
- target_execution: cleanChoice(evidence.target_execution, EXECUTION_EVIDENCE_STATUSES, `${fieldName}.evidence.target_execution`),
- },
- recommendation: {
- code: cleanChoice(recommendation.code, EXECUTION_EVIDENCE_RECOMMENDATIONS, `${fieldName}.recommendation.code`),
- reason_code: cleanChoice(recommendation.reason_code, EXECUTION_EVIDENCE_REASON_CODES, `${fieldName}.recommendation.reason_code`),
- },
- };
- if (normalized.recommendation.code === "continue_autonomous_shadow" && normalized.capabilities.shadow !== "available") {
- throw new Error(`${fieldName}.recommendation requires an available shadow capability`);
- }
- if (normalized.recommendation.code === "run_autonomous_paper" && normalized.capabilities.paper !== "available") {
- throw new Error(`${fieldName}.recommendation requires an available paper capability`);
- }
- if (normalized.recommendation.code === "owner_limited_live_canary_decision") {
- const statuses = Object.values(normalized.evidence);
- if (!statuses.every((status) => status === "verified")) {
- throw new Error(`${fieldName}.recommendation requires matching verified strategy, data, and execution evidence`);
- }
- }
- if (executionReceipt !== null) {
- const expectedExecutionStatus = ["failed", "reconciliation_required"].includes(executionReceipt.outcome)
- ? "unavailable"
- : (["no_signal", "no_rebalance"].includes(executionReceipt.outcome) ? "not_applicable" : "verified");
- if (normalized.evidence.target_execution !== expectedExecutionStatus) {
- throw new Error(`${fieldName}.execution_receipt does not match target_execution evidence`);
- }
- normalized.execution_receipt = executionReceipt;
- }
- return normalized;
-}
-
-function normalizeExecutionEvidenceReceipt(value, fieldName) {
- const receipt = assertExactFields(value, ["outcome", "broker_confirmation", "observed_at"], fieldName);
- const outcome = cleanChoice(receipt.outcome, EXECUTION_RECEIPT_OUTCOMES, `${fieldName}.outcome`);
- const confirmation = cleanChoice(
- receipt.broker_confirmation,
- EXECUTION_RECEIPT_CONFIRMATIONS,
- `${fieldName}.broker_confirmation`,
- );
- const allowedConfirmations = {
- not_due: ["not_applicable"],
- no_action: ["not_applicable"],
- no_signal: ["not_applicable"],
- no_rebalance: ["not_applicable"],
- risk_blocked: ["not_applicable"],
- submitted: ["not_observed"],
- broker_acknowledged: ["acknowledged"],
- partially_filled: ["partially_filled"],
- filled: ["filled"],
- reconciliation_required: ["reconciliation_required"],
- failed: ["not_applicable", "not_observed", "reconciliation_required"],
- };
- if (!allowedConfirmations[outcome].includes(confirmation)) {
- throw new Error(`${fieldName}.broker_confirmation does not match outcome`);
- }
- return {
- outcome,
- broker_confirmation: confirmation,
- observed_at: normalizeResearchTaskTimestamp(receipt.observed_at, `${fieldName}.observed_at`),
- };
-}
-
-function normalizeRuntimeTargetLifecycleSourceSnapshot(payload, fieldName = "runtime target lifecycle source snapshot") {
- const source = assertExactFields(payload, [
- "schema_version", "source_id", "generated_at", "computed_at", "data_status", "targets", "errors",
- ], fieldName);
- if (source.schema_version !== RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- const dataStatus = cleanChoice(source.data_status, STRATEGY_HEALTH_DATA_STATUSES, `${fieldName}.data_status`);
- if (!Array.isArray(source.targets) || source.targets.length > 1000) {
- throw new Error(`${fieldName}.targets must be an array with at most 1000 items`);
- }
- const targets = [];
- const seen = new Set();
- for (const [index, item] of source.targets.entries()) {
- const target = normalizeRuntimeTargetLifecycleTarget(item, `${fieldName}.targets[${index}]`);
- if (seen.has(target.target_id)) throw new Error(`${fieldName}.targets contains duplicate target_id`);
- seen.add(target.target_id);
- targets.push(target);
- }
- if (dataStatus === "unavailable" && targets.length) {
- throw new Error(`${fieldName}.targets must be empty when unavailable`);
- }
- return {
- schema_version: RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION,
- source_id: normalizeControlPlaneIdentifier(source.source_id, `${fieldName}.source_id`, false),
- generated_at: normalizeStrategyHealthTimestamp(source.generated_at, `${fieldName}.generated_at`, true),
- computed_at: normalizeStrategyHealthTimestamp(source.computed_at, `${fieldName}.computed_at`, true),
- data_status: dataStatus,
- targets,
- errors: normalizeStrategyHealthErrors(source.errors),
- };
-}
-
-function normalizeRuntimeTargetLifecycleTarget(value, fieldName) {
- const item = assertRequiredAndOptionalFields(value, ["target_id", "target", "monitoring", "disposition", "no_order"], ["deployment"], fieldName);
- const target = assertExactFields(item.target, ["platform", "configured_state", "execution_mode"], `${fieldName}.target`);
- const monitoring = assertExactFields(item.monitoring, ["runtime_guard", "execution_heartbeat"], `${fieldName}.monitoring`);
- const disposition = assertExactFields(item.disposition, ["code", "reason_code"], `${fieldName}.disposition`);
- if (item.no_order !== true) throw new Error(`${fieldName}.no_order must be true`);
- const normalized = {
- target_id: normalizeControlPlaneIdentifier(item.target_id, `${fieldName}.target_id`, false),
- target: {
- platform: cleanChoice(target.platform, EXECUTION_EVIDENCE_PLATFORMS, `${fieldName}.target.platform`),
- configured_state: cleanChoice(target.configured_state, RUNTIME_TARGET_LIFECYCLE_CONFIGURED_STATES, `${fieldName}.target.configured_state`),
- execution_mode: cleanChoice(target.execution_mode, RUNTIME_TARGET_LIFECYCLE_EXECUTION_MODES, `${fieldName}.target.execution_mode`),
- },
- monitoring: {
- runtime_guard: cleanChoice(monitoring.runtime_guard, RUNTIME_TARGET_LIFECYCLE_CHECK_STATUSES, `${fieldName}.monitoring.runtime_guard`),
- execution_heartbeat: cleanChoice(monitoring.execution_heartbeat, RUNTIME_TARGET_LIFECYCLE_CHECK_STATUSES, `${fieldName}.monitoring.execution_heartbeat`),
- },
- disposition: {
- code: cleanChoice(disposition.code, RUNTIME_TARGET_LIFECYCLE_DISPOSITIONS, `${fieldName}.disposition.code`),
- reason_code: cleanChoice(disposition.reason_code, RUNTIME_TARGET_LIFECYCLE_REASON_CODES, `${fieldName}.disposition.reason_code`),
- },
- no_order: true,
- };
- if (item.deployment !== undefined) {
- const observed = assertRequiredAndOptionalFields(item.deployment, ["runtime_enabled", "scheduler_state", "strategy_profile", "execution_mode"], ["observed_at"], `${fieldName}.deployment`);
- if (observed.runtime_enabled !== null && typeof observed.runtime_enabled !== "boolean") throw new Error("deployment switch must be boolean or null");
- normalized.deployment = {
- ...(observed.observed_at === undefined ? {} : {observed_at: normalizeM0ResearchTimestamp(observed.observed_at, "deployment.observed_at")}),
- runtime_enabled: observed.runtime_enabled,
- scheduler_state: cleanChoice(observed.scheduler_state, ["enabled", "paused", "mixed", "missing", "unknown", "not_applicable"], "deployment.scheduler_state"),
- strategy_profile: observed.strategy_profile === null ? null : cleanSlug(observed.strategy_profile, "deployment.strategy_profile"),
- execution_mode: observed.execution_mode === null ? null : cleanChoice(observed.execution_mode, RUNTIME_TARGET_LIFECYCLE_EXECUTION_MODES, "deployment.execution_mode"),
- };
- }
- const guardUnavailable = normalized.monitoring.runtime_guard === "unavailable";
- const heartbeatUnavailable = normalized.monitoring.execution_heartbeat === "unavailable";
- const hasAttention = normalized.monitoring.runtime_guard === "attention" || normalized.monitoring.execution_heartbeat === "attention";
- if (normalized.target.configured_state === "disabled") {
- if (normalized.monitoring.execution_heartbeat !== "not_applicable") {
- throw new Error(`${fieldName}.disabled target must not claim an execution heartbeat`);
- }
- if (!hasAttention && !guardUnavailable && normalized.disposition.code !== "continue_disabled_validation") {
- throw new Error(`${fieldName}.disabled target requires continue_disabled_validation`);
- }
- } else if (!hasAttention && !guardUnavailable && !heartbeatUnavailable && normalized.disposition.code !== "continue_enabled_monitoring") {
- throw new Error(`${fieldName}.enabled healthy target requires continue_enabled_monitoring`);
- }
- if (hasAttention || guardUnavailable || heartbeatUnavailable) {
- if (normalized.disposition.code !== "parked") throw new Error(`${fieldName}.unhealthy monitoring requires parked`);
- }
- return normalized;
-}
-
-function normalizeExecutionEvidenceSummary(deployments) {
- return {
- deployment_count: deployments.length,
- autonomous_shadow: deployments.filter((item) => item.recommendation.code === "continue_autonomous_shadow").length,
- autonomous_paper: deployments.filter((item) => item.recommendation.code === "run_autonomous_paper").length,
- owner_canary_decision: deployments.filter((item) => item.recommendation.code === "owner_limited_live_canary_decision").length,
- parked: deployments.filter((item) => item.recommendation.code === "parked").length,
- };
-}
-
-function emptyExecutionEvidenceSourceSnapshot(errorCode) {
- return {
- schema_version: EXECUTION_EVIDENCE_SOURCE_SCHEMA_VERSION,
- source_id: "unavailable",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- deployments: [],
- errors: [errorCode],
- };
-}
-
-function emptyRuntimeTargetLifecycleSourceSnapshot(errorCode) {
- return {
- schema_version: RUNTIME_TARGET_LIFECYCLE_SOURCE_SCHEMA_VERSION,
- source_id: "unavailable",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- targets: [],
- errors: [errorCode],
- };
-}
-
-function emptyRuntimeTargetLifecyclePayload(errorCode) {
- return {
- schema_version: RUNTIME_TARGET_LIFECYCLE_DASHBOARD_SCHEMA_VERSION,
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { target_count: 0, enabled: 0, disabled: 0, attention: 0 },
- targets: [],
- policy: {
- lifecycle_status_read_only: true,
- execution_observation_read_only: true,
- no_order: true,
- order_or_fill_evidence: "not_collected",
- notice: "运行目标生命周期快照尚不可用;页面不会推断目标已启用或存在订单/成交。",
- },
- errors: [errorCode],
- };
-}
-
-function emptyExecutionEvidencePayload(errorCode) {
- return {
- schema_version: EXECUTION_EVIDENCE_DASHBOARD_SCHEMA_VERSION,
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { deployment_count: 0, autonomous_shadow: 0, autonomous_paper: 0, owner_canary_decision: 0, parked: 0 },
- deployments: [],
- policy: {
- execution_evidence_read_only: true,
- p6_owner_decision_required: true,
- limited_live_canary_active: false,
- notice: "执行证据尚不可用;控制台不会推断 paper 或 live 状态。",
- },
- errors: [errorCode],
- };
-}
-
-function emptyReconciliationRecoverySourceSnapshot(errorCode) {
- return {
- schema_version: RECONCILIATION_RECOVERY_SOURCE_SCHEMA_VERSION,
- source_id: "unavailable",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- recoveries: [],
- errors: [errorCode],
- };
-}
-
-function emptyReconciliationRecoveryPayload(errorCode) {
- return {
- schema_version: RECONCILIATION_RECOVERY_DASHBOARD_SCHEMA_VERSION,
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { recovery_count: 0, awaiting_human_confirmation: 0, blocked: 0, confirmed: 0 },
- recoveries: [],
- current_reconciliation_observation: currentReconciliationObservationPresentation(),
- policy: {
- human_confirmation_required: true,
- current_evidence_required: true,
- no_order: true,
- execution_authority_granted: false,
- notice: "恢复核验尚不可用;控制台不会推断已恢复或已启用。",
- },
- errors: [errorCode],
- };
-}
-
-function reconciliationRecoveryStaleTtlSeconds(env) {
- const configured = Number(env.RECONCILIATION_RECOVERY_STALE_TTL_SECONDS);
- if (!Number.isFinite(configured) || configured < 300 || configured > 3600) {
- return RECONCILIATION_RECOVERY_DEFAULT_STALE_TTL_SECONDS;
- }
- return Math.floor(configured);
-}
-
-function executionEvidenceStaleTtlSeconds(env) {
- const configured = Number(env.EXECUTION_EVIDENCE_STALE_TTL_SECONDS);
- if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
- return EXECUTION_EVIDENCE_DEFAULT_STALE_TTL_SECONDS;
- }
- return Math.floor(configured);
-}
-
-function emptyControlPlanePayload(errorCode) {
- return {
- schema_version: "qsl_control_plane_dashboard.v1",
- generated_at: null,
- computed_at: null,
- data_status: "unavailable",
- summary: { candidate_count: 0, deferred: 0, parked: 0, owner_decision_required: 0 },
- attention: { status: "unavailable", reason_codes: ["control_plane_source_unavailable", errorCode] },
- candidates: [],
- policy: { p4_p5_automation: "not_configured", p6_owner_decision_required: true, notice: "live 仍需所有者明确决定。" },
- errors: [errorCode],
- };
-}
-
-function controlPlaneStaleTtlSeconds(env) {
- const configured = Number(env.CONTROL_PLANE_STALE_TTL_SECONDS);
- if (!Number.isFinite(configured) || configured < 300 || configured > 604800) {
- return CONTROL_PLANE_DEFAULT_STALE_TTL_SECONDS;
- }
- return Math.floor(configured);
-}
-
-async function syncStrategyProfilesConfig(env, session) {
- const profiles = normalizeStrategyProfilesPayload(DEFAULT_STRATEGY_PROFILES, "DEFAULT_STRATEGY_PROFILES");
- if (!hasConfigStore(env)) return { synced: false, reason: "kv_not_bound", count: profiles.length };
- let changed = true;
- try {
- const current = await readConfigJson(env, STRATEGY_PROFILES_KEY);
- if (current) {
- const normalizedCurrent = normalizeStrategyProfilesPayload(current, STRATEGY_PROFILES_KEY);
- changed = JSON.stringify(normalizedCurrent) !== JSON.stringify(profiles);
- }
- } catch {
- changed = true;
- }
- let auditLogged = false;
- if (changed) {
- await writeConfigJson(env, STRATEGY_PROFILES_KEY, profiles);
- try {
- await appendAuditLog(env, {
- ts: new Date().toISOString(),
- login: session?.login || "",
- action: "sync_strategy_profiles",
- count: profiles.length,
- });
- auditLogged = true;
- } catch {
- auditLogged = false;
- }
- }
- return { synced: true, changed, count: profiles.length, audit_logged: auditLogged };
-}
-
-function updateAccountOptionsDefaultStrategy(accountOptions, inputs) {
- const options = normalizeAccountOptionsPayload(accountOptions || {}, ACCOUNT_OPTIONS_KEY);
- const platformOptions = options[inputs.platform] || [];
- const rawPlatformOptions = Array.isArray(accountOptions?.[inputs.platform]) ? accountOptions[inputs.platform] : [];
- let matched = false;
- let changed = false;
- const updatedPlatformOptions = platformOptions.map((option, index) => {
- if (!accountOptionMatchesInputs(option, inputs)) return option;
- matched = true;
- const rawOption = rawPlatformOptions[index] && typeof rawPlatformOptions[index] === "object"
- ? rawPlatformOptions[index]
- : {};
- const nextOption = { ...option };
- let optionChanged = false;
- if ("ibit_zscore_exit_mode" in rawOption) optionChanged = true;
- if (inputs.plugin_mode === "none") {
- const currentPluginMode = nextOption.plugin_mode || "none";
- if (currentPluginMode !== inputs.plugin_mode) {
- nextOption.plugin_mode = inputs.plugin_mode;
- optionChanged = true;
- }
- }
- if (inputs.option_overlay_mode === "enabled" || inputs.option_overlay_mode === "disabled") {
- if (nextOption.option_overlay_mode !== inputs.option_overlay_mode) {
- nextOption.option_overlay_mode = inputs.option_overlay_mode;
- optionChanged = true;
- }
- }
- const cashOnlyExecutionMode = cashOnlyExecutionModeFromInputs(inputs);
- if (cashOnlyExecutionMode === "enabled" || cashOnlyExecutionMode === "disabled") {
- if (nextOption.cash_only_execution_mode !== cashOnlyExecutionMode) {
- nextOption.cash_only_execution_mode = cashOnlyExecutionMode;
- optionChanged = true;
- }
- }
- const dcaControls = dcaControlsFromInputs(inputs);
- if (isDcaProfile(inputs.strategy_profile)) {
- if (dcaControls.dca_mode && nextOption.dca_mode !== dcaControls.dca_mode) {
- nextOption.dca_mode = dcaControls.dca_mode;
- optionChanged = true;
- }
- if (
- dcaControls.dca_base_investment_usd &&
- nextOption.dca_base_investment_usd !== dcaControls.dca_base_investment_usd
- ) {
- nextOption.dca_base_investment_usd = dcaControls.dca_base_investment_usd;
- optionChanged = true;
- }
- } else {
- for (const field of ["dca_mode", "dca_base_investment_usd"]) {
- if (field in nextOption) {
- delete nextOption[field];
- optionChanged = true;
- }
- }
- }
- if ("ibit_zscore_exit_mode" in nextOption) {
- delete nextOption.ibit_zscore_exit_mode;
- optionChanged = true;
- }
- changed = changed || optionChanged;
- if (!optionChanged) return option;
- return nextOption;
- });
- if (!matched) throw new Error("switch inputs do not match configured account options");
- return {
- options: { ...options, [inputs.platform]: updatedPlatformOptions },
- changed,
- };
-}
-
-function normalizeSwitchInputs(raw) {
- const platform = cleanChoice(raw.platform, SUPPORTED_PLATFORMS, "platform");
- const targetName = cleanSlug(raw.target_name, "target_name");
- const strategyProfile = cleanSlug(raw.strategy_profile, "strategy_profile").toLowerCase();
- assertDcaPlatform(platform, strategyProfile);
- const executionMode = cleanExecutionMode(raw.execution_mode || "live");
- if (!supportedExecutionModesForPlatform(platform).includes(executionMode)) {
- throw new Error(`${platform} does not support ${executionMode} control execution`);
- }
- const liveContinuity = normalizeLiveContinuityInputs(raw, executionMode);
- // "current" is used only by internal deployment reconciliation to retain
- // a service's existing plugin mount. It is deliberately not exposed as a
- // console editing mode, where operators can still select only "none".
- const requestedPluginMode = cleanChoice(raw.plugin_mode || "none", ["auto", "none", "current"], "plugin_mode");
- const pluginMode = requestedPluginMode === "auto" ? "none" : requestedPluginMode;
- if (String(raw.custom_plugin_mounts_json || "").trim()) {
- throw new Error("legacy custom plugin mounts are retired pending a P1/P2/P3-bound signal.v2 adapter");
- }
- const optionOverlayMode = cleanChoice(raw.option_overlay_mode || "current", OPTION_OVERLAY_MODES, "option_overlay_mode");
- if (optionOverlayMode === "enabled") {
- throw new Error("option overlay is retired; migrate existing option settings and obligations explicitly");
- }
- const cashOnlyExecutionMode = cleanChoice(
- raw.cash_only_execution_mode || "enabled",
- CASH_ONLY_EXECUTION_MODES,
- "cash_only_execution_mode",
- );
- const variableScope = cleanChoice(
- raw.variable_scope || "default",
- ["default", "repository", "environment"],
- "variable_scope",
- );
- const apply = cleanBoolean(raw.apply);
- const triggerPlatformSync = cleanBoolean(raw.trigger_platform_sync) && apply;
- const extraVariablesJson = cleanOptionalJsonObject(raw.extra_variables_json || "", "extra_variables_json");
- const extraVariables = extraVariablesJson ? JSON.parse(extraVariablesJson) : {};
- const directDcaVariables = [DCA_MODE_VARIABLE, DCA_BASE_INVESTMENT_VARIABLE].filter((name) =>
- extraVariables[name] !== undefined && String(extraVariables[name] || "").trim() !== "",
- );
- if (directDcaVariables.length) {
- throw new Error("use dca_mode and dca_base_investment_usd control fields instead of DCA_MODE variables");
- }
- const directIbitZscoreVariables = [
- IBIT_ZSCORE_EXIT_ENABLED_VARIABLE,
- IBIT_ZSCORE_EXIT_MODE_VARIABLE,
- IBIT_ZSCORE_EXIT_PARKING_SYMBOL_VARIABLE,
- "IBIT_ZSCORE_EXIT_RISK_REDUCED_EXPOSURE",
- "IBIT_ZSCORE_EXIT_RISK_OFF_EXPOSURE",
- "IBIT_ZSCORE_EXIT_ALLOW_OUTSIDE_EXECUTION_WINDOW",
- ].filter((name) => extraVariables[name] !== undefined && String(extraVariables[name] || "").trim() !== "");
- if (directIbitZscoreVariables.length) {
- throw new Error(
- "IBIT_ZSCORE_EXIT variables are derived from ibit_smart_dca smart DCA mode; do not set them directly",
- );
- }
- rejectResearchOnlyExtraVariables(extraVariables);
- const directCashOnlyVariables = [
- LEGACY_CASH_ONLY_EXECUTION_VARIABLE,
- ...Object.values(PLATFORM_CASH_ONLY_EXECUTION_VARIABLES),
- ].filter((name) => extraVariables[name] !== undefined && String(extraVariables[name] || "").trim() !== "");
- if (directCashOnlyVariables.length) {
- throw new Error("use cash_only_execution_mode instead of CASH_ONLY_EXECUTION variables");
- }
- const dcaExtraControls = dcaPayloadFromObject(extraVariables);
- stripLegacyIbitZscoreExitControls(extraVariables);
-
- const inputs = {
- platform,
- target_name: targetName,
- strategy_profile: strategyProfile,
- execution_mode: executionMode,
- live_continuity_state: liveContinuity.state,
- variable_scope: variableScope,
- plugin_mode: pluginMode,
- option_overlay_mode: optionOverlayMode,
- service_targets_mode: "auto",
- apply: apply ? "true" : "false",
- trigger_platform_sync: triggerPlatformSync ? "true" : "false",
- confirm_apply: apply ? (triggerPlatformSync ? "APPLY_AND_SYNC" : "APPLY") : "",
- platform_sync_workflow: "sync-cloud-run-env.yml",
- };
-
- if (liveContinuity.state !== "NONE") {
- inputs.live_continuity_baseline_id = liveContinuity.baseline_id;
- inputs.live_continuity_captured_at = liveContinuity.captured_at;
- }
-
- addOptional(inputs, "github_environment", raw.github_environment, cleanSlug);
- addOptional(inputs, "deployment_selector", raw.deployment_selector, cleanSlug);
- addOptional(inputs, "account_selector", raw.account_selector, cleanCsv);
- addOptional(inputs, "account_scope", raw.account_scope, cleanSlug);
- addOptional(inputs, "service_name", raw.service_name, cleanSlug);
- addOptional(inputs, "reserved_cash_ratio", raw.reserved_cash_ratio, cleanRatio);
- addOptional(inputs, "min_reserved_cash_usd", raw.min_reserved_cash_usd, cleanNonNegativeNumber);
- addOptional(inputs, "income_layer_start_usd", raw.income_layer_start_usd, cleanNonNegativeNumber);
- addOptional(inputs, "income_layer_max_ratio", raw.income_layer_max_ratio, cleanRatio);
- const rawHasDcaMode = raw.dca_mode !== undefined && raw.dca_mode !== null && String(raw.dca_mode).trim() !== "";
- const rawHasDcaBase = raw.dca_base_investment_usd !== undefined &&
- raw.dca_base_investment_usd !== null &&
- String(raw.dca_base_investment_usd).trim() !== "";
- const dcaModeValue = rawHasDcaMode ? raw.dca_mode : dcaExtraControls.dca_mode;
- const dcaBaseInvestmentValue = rawHasDcaBase
- ? raw.dca_base_investment_usd
- : dcaExtraControls.dca_base_investment_usd;
- const hasDcaMode = Boolean(String(dcaModeValue || "").trim());
- const hasDcaBase = Boolean(String(dcaBaseInvestmentValue || "").trim());
- if (!isDcaProfile(strategyProfile) && (hasDcaMode || hasDcaBase)) {
- throw new Error("DCA settings are only supported for DCA strategy profiles");
- }
- if (isDcaProfile(strategyProfile)) {
- if (hasDcaMode) extraVariables.dca_mode = cleanDcaMode(dcaModeValue);
- if (hasDcaBase) extraVariables.dca_base_investment_usd = cleanPositiveNumber(
- dcaBaseInvestmentValue,
- "dca_base_investment_usd",
- );
- }
- const cashOnlyMode = cleanChoice(
- raw.cash_only_execution_mode || extraVariables.cash_only_execution_mode || "enabled",
- CASH_ONLY_EXECUTION_MODES,
- "cash_only_execution_mode",
- );
- if (cashOnlyMode !== "current") {
- extraVariables.cash_only_execution_mode = cashOnlyMode;
- }
- if (Object.keys(extraVariables).length) inputs.extra_variables_json = JSON.stringify(extraVariables);
- return inputs;
-}
-
-function normalizeLiveContinuityInputs(raw, executionMode) {
- const state = String(raw.live_continuity_state || "NONE").trim().toUpperCase();
- if (!LIVE_CONTINUITY_STATES.includes(state)) {
- throw new Error(`live_continuity_state must be one of ${LIVE_CONTINUITY_STATES.join(", ")}`);
- }
- const rawBaselineId = String(raw.live_continuity_baseline_id || "").trim();
- const rawCapturedAt = String(raw.live_continuity_captured_at || "").trim();
- if (state === "NONE") {
- if (rawBaselineId || rawCapturedAt) {
- throw new Error("live continuity baseline fields require a non-NONE live_continuity_state");
- }
- return { state };
- }
- if (executionMode !== "live") {
- throw new Error("live continuity is only valid for live execution_mode");
- }
- return {
- state,
- baseline_id: cleanSlug(rawBaselineId, "live_continuity_baseline_id"),
- captured_at: normalizeM0ResearchDate(rawCapturedAt, "live_continuity_captured_at"),
- };
-}
-
-function assertSwitchIntent(inputs) {
- if (
- inputs.apply !== "true" ||
- inputs.trigger_platform_sync !== "true" ||
- inputs.confirm_apply !== "APPLY_AND_SYNC"
- ) {
- throw new Error("switch endpoint requires apply=true and APPLY_AND_SYNC");
- }
-}
-
-function assertConfiguredAccount(inputs, accountOptions) {
- if (!accountOptions) throw new Error("account options are not configured");
- const matched = configuredAccountForInputs(inputs, accountOptions);
- if (!matched) throw new Error("switch inputs do not match configured account options");
- return matched;
-}
-
-function configuredAccountForInputs(inputs, accountOptions) {
- if (!accountOptions) return null;
- const options = accountOptions[inputs.platform] || [];
- return options.find((option) => accountOptionMatchesInputs(option, inputs)) || null;
-}
-
-function registerLegacyContinuityAccount(env, accountOptions, inputs, strategy) {
- if (!hasConfigStore(env)) {
- throw new Error("switch inputs do not match configured account options");
- }
- if (!isEligibleLegacyContinuityInput(inputs, strategy)) {
- throw new Error("switch inputs do not match configured account options");
- }
- const platformOptions = accountOptions[inputs.platform] || [];
- if (platformOptions.some((option) => option.target_name === inputs.target_name)) {
- throw new Error("legacy continuity account target conflicts with configured account options");
- }
- if (platformOptions.some((option) => option.service_name
- && option.service_name === inputs.service_name
- && accountOptionMatchesInputs(option, { ...inputs, target_name: option.target_name }))) {
- throw new HttpError("deployment already has a configured account; use its existing target", 400);
- }
- if (platformOptions.length >= 20) {
- throw new Error(`account options for ${inputs.platform} have reached the maximum`);
- }
-
- const account = cleanAccountOption(
- {
- key: inputs.target_name,
- label: `Legacy continuity ${inputs.target_name}`,
- target_name: inputs.target_name,
- account_selector: inputs.account_selector,
- deployment_selector: inputs.deployment_selector,
- account_scope: inputs.account_scope,
- service_name: inputs.service_name,
- github_environment: inputs.github_environment,
- variable_scope: resolvedVariableScope(inputs.variable_scope, inputs),
- supported_domains: [strategy.domain],
- },
- inputs.platform,
- platformOptions.length,
- );
- const options = normalizeAccountOptionsPayload(
- { ...accountOptions, [inputs.platform]: [...platformOptions, account] },
- ACCOUNT_OPTIONS_KEY,
- );
- return { options, account: options[inputs.platform].at(-1), registered: true };
-}
-
-function assertStrategyAllowedForAccount(inputs, accountOption, strategyProfiles) {
- const strategy = strategyProfiles.find((item) => sameStrategyProfile(item.profile, inputs.strategy_profile));
- if (!strategy) {
- throw new Error(`strategy ${inputs.strategy_profile} is not configured`);
- }
- const supportedDomains = supportedDomainsForAccount(inputs.platform, accountOption);
- if (!supportedDomains.includes(strategy.domain)) {
- throw new Error(
- `strategy domain ${strategy.domain} is not supported by ${inputs.platform}/${accountOption.key}`,
- );
- }
- const executionMode = cleanExecutionMode(inputs.execution_mode);
- if (!supportedExecutionModesForPlatform(inputs.platform).includes(executionMode)) {
- throw new Error(`${inputs.platform} does not support ${executionMode} control execution`);
- }
- const allowedModes = strategy.allowed_execution_modes || [];
- if (isFrozenStrategyProfile(strategy) && !(
- ["RECONCILE_ONLY", "RISK_REDUCTION_ONLY"].includes(inputs.live_continuity_state)
- && isEligibleLegacyContinuityInput(inputs, strategy)
- )) {
- throw new HttpError(`strategy ${inputs.strategy_profile} is frozen for new selection`, 409);
- }
- if (executionMode === "live") {
- if (isEligibleLegacyContinuityInput(inputs, strategy)) {
- assertDcaPlatform(inputs.platform, inputs.strategy_profile);
- return;
- }
- assertLiveSwitchAllowed(strategy, inputs.strategy_profile);
- const lifecycleStage = cleanLifecycleStage(strategy.lifecycle_stage || "research_active");
- if (!["live_enabled", "runtime_enabled"].includes(lifecycleStage)) {
- throw new Error(`strategy ${inputs.strategy_profile} is not live-enabled`);
- }
- if (!allowedModes.includes(executionMode)) {
- throw new Error(`strategy ${inputs.strategy_profile} is not live-enabled`);
- }
- if (strategy.blocked_live_reason) {
- throw new Error(`strategy ${inputs.strategy_profile} is blocked for live: ${strategy.blocked_live_reason}`);
- }
- } else if (allowedModes.length && !allowedModes.includes(executionMode)) {
- throw new Error(`strategy ${inputs.strategy_profile} does not allow ${executionMode} execution`);
- }
- if (inputs.option_overlay_mode === "enabled" && strategy.option_overlay_enabled !== true) {
- throw new Error(`strategy ${inputs.strategy_profile} does not define an option overlay`);
- }
- assertDcaPlatform(inputs.platform, inputs.strategy_profile);
-}
-
-function isEligibleLegacyContinuityInput(inputs, strategy) {
- if (
- inputs.execution_mode !== "live" ||
- !inputs.live_continuity_state ||
- inputs.live_continuity_state === "NONE" ||
- !inputs.live_continuity_baseline_id ||
- !inputs.live_continuity_captured_at ||
- inputs.plugin_mode !== "current" ||
- inputs.option_overlay_mode !== "current" ||
- inputs.reserved_cash_ratio ||
- inputs.min_reserved_cash_usd ||
- inputs.income_layer_start_usd ||
- inputs.income_layer_max_ratio
- ) {
- return false;
- }
- const extraVariables = inputs.extra_variables_json ? JSON.parse(inputs.extra_variables_json) : {};
- const extraVariableNames = Object.keys(extraVariables);
- if (
- extraVariableNames.length > 1 ||
- (extraVariableNames.length === 1 && (
- extraVariableNames[0] !== "RUNTIME_TARGET_ENABLED" ||
- extraVariables.RUNTIME_TARGET_ENABLED !== "true"
- ))
- ) {
- return false;
- }
- const policy = strategy?.live_continuity;
- return policy?.eligible === true && Array.isArray(policy.allowed_platforms) && policy.allowed_platforms.includes(inputs.platform);
-}
-
-function resolvedVariableScope(value, inputs) {
- const text = String(value || "").trim();
- if (!text || text === "default") return defaultInputValue("variable_scope", inputs);
- return text;
-}
-
-function accountOptionMatchesInputs(option, inputs) {
- if (option.target_name !== inputs.target_name) return false;
- const fields = [
- "account_selector",
- "deployment_selector",
- "account_scope",
- "service_name",
- "github_environment",
- "variable_scope",
- ];
- for (const field of fields) {
- if (field === "variable_scope") {
- if (resolvedVariableScope(option[field], inputs) !== resolvedVariableScope(inputs[field], inputs)) {
- return false;
- }
- continue;
- }
- const expected = option[field] || "";
- const actual = inputs[field] || "";
- if (expected && actual !== expected) return false;
- if (!expected && actual && !["default", "auto", defaultInputValue(field, inputs)].includes(actual)) return false;
- }
- return true;
-}
-
-function defaultInputValue(field, inputs) {
- const platform = inputs.platform;
- const targetName = inputs.target_name;
- if (field === "variable_scope") return DEFAULT_VARIABLE_SCOPE[platform] || "repository";
- if (field === "plugin_mode") return "none";
- if (field === "deployment_selector") {
- if (platform === "firstrade") return "firstrade";
- if (platform === "qmt") return "qmt";
- return ["sg", "hk", "paper"].includes(targetName.toLowerCase()) ? targetName.toUpperCase() : targetName;
- }
- if (field === "account_scope") {
- if (platform === "firstrade") return "US";
- if (platform === "qmt") return "CN";
- return inputs.deployment_selector || defaultInputValue("deployment_selector", inputs);
- }
- if (field === "account_selector") {
- if (platform === "firstrade") return "firstrade";
- if (platform === "qmt") return "qmt";
- return inputs.account_scope || defaultInputValue("account_scope", inputs);
- }
- if (field === "github_environment") {
- const variableScope = inputs.variable_scope === "default"
- ? defaultInputValue("variable_scope", inputs)
- : inputs.variable_scope;
- if (variableScope !== "environment") return "";
- return platform === "longbridge" ? `longbridge-${targetName.toLowerCase()}` : targetName;
- }
- if (field === "service_name") {
- if (platform === "schwab") return "charles-schwab-quant-service";
- if (platform === "firstrade") return "firstrade-quant-service";
- if (platform === "qmt") return "qmt-quant-service";
- if (platform === "longbridge") return `longbridge-quant-${targetName.toLowerCase()}-service`;
- if (platform === "ibkr") return `interactive-brokers-${targetName.toLowerCase()}-service`;
- }
- return "";
-}
-
-function parseAccountOptions(raw, fieldName = "account options") {
- const text = String(raw || "").trim();
- if (!text) return null;
- let payload;
- try {
- payload = JSON.parse(text);
- } catch (error) {
- throw new Error(`${fieldName} must be valid JSON`);
- }
- return normalizeAccountOptionsPayload(payload, fieldName);
-}
-
-function normalizeAccountOptionsInput(value, fieldName) {
- if (typeof value === "string") return parseAccountOptions(value, fieldName) || {};
- return normalizeAccountOptionsPayload(value, fieldName);
-}
-
-function parseStrategyProfiles(raw, fieldName = "strategy profiles") {
- const text = String(raw || "").trim();
- if (!text) return null;
- let payload;
- try {
- payload = JSON.parse(text);
- } catch (error) {
- throw new Error(`${fieldName} must be valid JSON`);
- }
- return normalizeStrategyProfilesPayload(payload, fieldName);
-}
-
-function isFrozenStrategyProfile(strategy) {
- const profile = canonicalStrategyProfile(strategy?.profile);
- // Normalize only the policy lookup; retain the original profile in payloads.
- return strategy?.frozen === true || DEFAULT_STRATEGY_PROFILES.some((item) => item.profile === profile && item.frozen === true);
-}
-
-function normalizeStrategyProfilesPayload(payload, fieldName = "strategy profiles") {
- if (!Array.isArray(payload) || payload.length > 100) {
- throw new Error(`${fieldName} must be an array with at most 100 items`);
- }
-
- const result = [];
- const seen = new Set();
- for (const [index, item] of payload.entries()) {
- if (!item || Array.isArray(item) || typeof item !== "object") {
- throw new Error(`${fieldName}[${index}] must be an object`);
- }
- const profile = cleanCurrentStrategy(item.profile || item.strategy_profile);
- if (!profile) throw new Error(`${fieldName}[${index}].profile is invalid`);
- if (seen.has(profile)) continue;
- seen.add(profile);
- const entry = {
- profile,
- label: cleanLabel(item.label || item.display_name || profile, `${fieldName}[${index}].label`),
- runtime_enabled: cleanProfileBoolean(item.runtime_enabled ?? false),
- };
- addConfigOptional(
- entry,
- "label_en",
- item.label_en || item.display_name_en || item.label,
- cleanLabel,
- );
- addConfigOptional(
- entry,
- "label_zh",
- item.label_zh || item.display_name_zh,
- cleanLabel,
- );
- const rawDomain = typeof item.domain === "string" ? item.domain.trim() : "";
- entry.domain = cleanStrategyDomain(rawDomain || "us_equity", `${fieldName}[${index}].domain`);
- Object.defineProperty(entry, "domain_explicit", { value: rawDomain !== "", enumerable: false });
- if (isFrozenStrategyProfile(item)) entry.frozen = true;
- const sourceLifecycleStage = item.lifecycle_stage || item.lifecycleStage;
- const canSwitchLive = cleanOptionalBoolean(item.can_switch_live);
- if (canSwitchLive !== null) entry.can_switch_live = canSwitchLive;
- const allowedExecutionModes = cleanAllowedExecutionModes(item.allowed_execution_modes);
- if (allowedExecutionModes.length) entry.allowed_execution_modes = allowedExecutionModes;
- if (sourceLifecycleStage) {
- entry.lifecycle_stage = canonicalLifecycleStage(sourceLifecycleStage, {
- runtimeEnabled: entry.runtime_enabled === true,
- canSwitchLive: canSwitchLive === true,
- allowedExecutionModes,
- });
- }
- addConfigOptional(entry, "blocked_live_reason", item.blocked_live_reason, cleanLabel);
- if (item.live_continuity !== undefined && item.live_continuity !== null) {
- entry.live_continuity = normalizeLiveContinuityPolicy(
- item.live_continuity,
- `${fieldName}[${index}].live_continuity`,
- );
- }
- if (item.research_candidate_identity !== undefined && item.research_candidate_identity !== null) {
- entry.research_candidate_identity = normalizeResearchCandidateIdentity(
- item.research_candidate_identity,
- `${fieldName}[${index}].research_candidate_identity`,
- profile,
- );
- }
- addConfigOptional(entry, "latest_evidence_status", item.latest_evidence_status, cleanLifecycleStage);
- addConfigOptional(entry, "plugin_gate_status", item.plugin_gate_status, cleanLifecycleStage);
- // DCA detection: accept from item payload OR hardcoded DCA_PROFILE_CONFIG
- const dcaEnabled = item.dca_enabled === true || Boolean(DCA_PROFILE_CONFIG[profile]);
- if (dcaEnabled) {
- const dcaDefaults = DCA_PROFILE_CONFIG[profile] || null;
- entry.dca_enabled = true;
- entry.dca_default_mode = cleanDcaMode(item.dca_default_mode || item.default_dca_mode || dcaDefaults?.default_mode || "fixed");
- entry.dca_default_base_investment_usd = cleanPositiveNumber(
- item.dca_default_base_investment_usd ||
- item.default_dca_base_investment_usd ||
- dcaDefaults?.default_base_investment_usd ||
- "1000",
- `${fieldName}[${index}].dca_default_base_investment_usd`,
- );
- }
- // Pass through combo_enabled and combo_mode from item payload
- if (item.combo_enabled === true) {
- entry.combo_enabled = true;
- entry.combo_mode = String(item.combo_mode || "dynamic").trim() || "dynamic";
- }
- const incomeLayerConfig = incomeLayerConfigFromProfileItem(item, `${fieldName}[${index}]`);
- if (incomeLayerConfig) Object.assign(entry, incomeLayerConfig);
- const optionOverlayConfig = optionOverlayConfigFromProfileItem(item, `${fieldName}[${index}]`);
- if (optionOverlayConfig) Object.assign(entry, optionOverlayConfig);
- result.push(entry);
- }
- return result;
-}
-
-function normalizeResearchCandidateIdentity(value, fieldName, profile) {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- assertExactFields(value, ["candidate_id", "config_sha256"], fieldName);
- const candidateId = cleanCurrentStrategy(value.candidate_id);
- if (!candidateId || candidateId !== profile) {
- throw new Error(`${fieldName}.candidate_id must match profile`);
- }
- const configSha256 = String(value.config_sha256 || "").trim().toLowerCase();
- if (!/^[0-9a-f]{64}$/.test(configSha256)) {
- throw new Error(`${fieldName}.config_sha256 must be a 64-character sha256`);
- }
- return { candidate_id: candidateId, config_sha256: configSha256 };
-}
-
-function normalizeLiveContinuityPolicy(value, fieldName) {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- const unsupported = Object.keys(value).filter((key) => !["eligible", "allowed_platforms"].includes(key));
- if (unsupported.length) {
- throw new Error(`${fieldName} contains unsupported fields: ${unsupported.sort().join(", ")}`);
- }
- if (typeof value.eligible !== "boolean") {
- throw new Error(`${fieldName}.eligible must be boolean`);
- }
- if (!Array.isArray(value.allowed_platforms)) {
- throw new Error(`${fieldName}.allowed_platforms must be an array`);
- }
- const allowedPlatforms = value.allowed_platforms.map((platform) =>
- cleanChoice(platform, SUPPORTED_PLATFORMS, `${fieldName}.allowed_platforms`),
- );
- if (new Set(allowedPlatforms).size !== allowedPlatforms.length) {
- throw new Error(`${fieldName}.allowed_platforms must not contain duplicates`);
- }
- if (value.eligible && !allowedPlatforms.length) {
- throw new Error(`${fieldName}.eligible requires allowed_platforms`);
- }
- return { eligible: value.eligible, allowed_platforms: allowedPlatforms };
-}
-
-function rejectResearchOnlyExtraVariables(extraVariables) {
- const blocked = [
- ...LEGACY_INCOME_LAYER_CONTROL_FIELDS,
- ...LEGACY_INCOME_LAYER_VARIABLES,
- ...OPTION_OVERLAY_CONTROL_FIELDS,
- ...OPTION_OVERLAY_VARIABLES,
- ].filter((name) => extraVariables[name] !== undefined);
- if (blocked.length) {
- throw new Error(
- `direct option overlay settings and legacy income controls are research-only: ${blocked.join(", ")}`,
- );
- }
-}
-
-function incomeLayerConfigFromProfileItem(item, fieldName) {
- const hasIncomeLayerConfig = [
- "income_layer_enabled",
- "income_layer_start_usd",
- "income_layer_max_ratio",
- "income_layer_allocations",
- ].some((field) => item[field] !== undefined && item[field] !== null && String(item[field]).trim() !== "");
- if (!hasIncomeLayerConfig) return null;
- const enabled = item.income_layer_enabled === undefined || item.income_layer_enabled === null
- ? true
- : cleanProfileBoolean(item.income_layer_enabled);
- if (!enabled) return { income_layer_enabled: false };
- return {
- income_layer_enabled: true,
- income_layer_start_usd: cleanNonNegativeNumber(
- item.income_layer_start_usd,
- `${fieldName}.income_layer_start_usd`,
- ),
- income_layer_max_ratio: cleanRatio(item.income_layer_max_ratio, `${fieldName}.income_layer_max_ratio`),
- income_layer_allocations: cleanIncomeLayerAllocations(
- item.income_layer_allocations,
- `${fieldName}.income_layer_allocations`,
- ),
- };
-}
-
-function optionOverlayConfigFromProfileItem(item, fieldName) {
- const hasOptionOverlayConfig = OPTION_OVERLAY_PROFILE_FIELDS.some((field) =>
- item[field] !== undefined && item[field] !== null && String(item[field]).trim() !== "",
- );
- if (!hasOptionOverlayConfig) return null;
- const enabled = item.option_overlay_enabled === undefined || item.option_overlay_enabled === null
- ? true
- : cleanProfileBoolean(item.option_overlay_enabled);
- const result = { option_overlay_enabled: enabled };
- addConfigOptional(result, "option_overlay_live_gate", item.option_overlay_live_gate || (enabled ? "promotion_required" : "disabled"), (value, field) =>
- cleanChoice(value, ["promotion_required", "live_allowed", "disabled"], field),
- );
- addConfigOptional(result, "option_overlay_live_status", item.option_overlay_live_status || (enabled ? "research_only" : "disabled"), (value, field) =>
- cleanChoice(value, ["research_only", "live_allowed", "disabled"], field),
- );
- if (!enabled) return result;
-
- addOptionalOptionFamilyConfig(result, item, "growth", fieldName);
- addOptionalOptionFamilyConfig(result, item, "income", fieldName);
- return result;
-}
-
-function addOptionalOptionFamilyConfig(target, item, family, fieldName) {
- const prefix = `option_${family}_overlay`;
- const enabledField = `${prefix}_enabled`;
- if (item[enabledField] === undefined || item[enabledField] === null || String(item[enabledField]).trim() === "") {
- return;
- }
- const enabled = cleanProfileBoolean(item[enabledField]);
- target[enabledField] = enabled;
- if (!enabled) return;
-
- target[`${prefix}_recipe`] = cleanSlug(item[`${prefix}_recipe`], `${fieldName}.${prefix}_recipe`);
- target[`${prefix}_start_usd`] = cleanNonNegativeNumber(
- item[`${prefix}_start_usd`],
- `${fieldName}.${prefix}_start_usd`,
- );
- if (family === "growth") {
- target.option_growth_overlay_nav_budget_ratio = cleanRatio(
- item.option_growth_overlay_nav_budget_ratio,
- `${fieldName}.option_growth_overlay_nav_budget_ratio`,
- );
- } else {
- target.option_income_overlay_nav_risk_ratio = cleanRatio(
- item.option_income_overlay_nav_risk_ratio,
- `${fieldName}.option_income_overlay_nav_risk_ratio`,
- );
- }
-}
-
-function cleanIncomeLayerAllocations(value, fieldName) {
- if (!value || Array.isArray(value) || typeof value !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- const result = {};
- let total = 0;
- for (const [rawSymbol, rawWeight] of Object.entries(value)) {
- const symbol = String(rawSymbol || "").trim().toUpperCase();
- if (!/^[A-Z0-9.-]{1,12}$/.test(symbol)) throw new Error(`${fieldName} contains an invalid symbol`);
- const weight = Number(cleanPositiveNumber(rawWeight, `${fieldName}.${symbol}`));
- total += weight;
- result[symbol] = weight;
- }
- if (!Object.keys(result).length || total <= 0) throw new Error(`${fieldName} must contain positive allocations`);
- return result;
-}
-
-function cleanProfileBoolean(value) {
- if (value === true || value === "true" || value === "1" || value === 1) return true;
- if (value === false || value === "false" || value === "0" || value === 0) return false;
- throw new Error("runtime_enabled must be boolean");
-}
-
-function normalizeAccountOptionsPayload(payload, fieldName = "account options") {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
-
- // Structural gate from account_options_schema.js; cleanAccountOption keeps
- // console-specific enrichment (domain inference, mode defaults, length caps).
- validateAccountOptionsSchemaOrThrow(payload, fieldName);
-
- const result = {};
- for (const platform of SUPPORTED_PLATFORMS) {
- const items = payload[platform];
- if (items === undefined) continue;
- if (!Array.isArray(items) || items.length > 20) {
- throw new Error(`${fieldName}.${platform} must be an array with at most 20 items`);
- }
- result[platform] = items.map((item, index) => cleanAccountOption(item, platform, index));
- }
- return result;
-}
-
-function cleanAccountOption(item, platform, index) {
- if (!item || Array.isArray(item) || typeof item !== "object") {
- throw new Error(`account option ${platform}[${index}] must be an object`);
- }
- const key = cleanSlug(item.key || item.target_name || `${platform}-${index}`, "account key");
- const label = cleanLabel(item.label || item.target_name || key, "account label");
- const option = {
- key,
- label,
- target_name: cleanSlug(item.target_name || key, "target_name"),
- };
- addConfigOptional(option, "account_selector", item.account_selector, cleanCsv);
- addConfigOptional(option, "deployment_selector", item.deployment_selector, cleanSlug);
- addConfigOptional(option, "account_scope", item.account_scope, cleanSlug);
- addConfigOptional(option, "service_name", item.service_name, cleanSlug);
- addConfigOptional(option, "runtime_status_target_id", item.runtime_status_target_id, cleanSlug);
- addConfigOptional(option, "broker_environment", item.broker_environment, normalizeBrokerEnvironment);
- addConfigOptional(option, "default_execution_mode", item.default_execution_mode, cleanExecutionMode);
- addConfigOptional(option, "default_strategy_profile", item.default_strategy_profile, cleanSlug);
- addConfigOptional(
- option,
- "cash_currency",
- item.cash_currency || item.market_currency || item.trading_currency,
- cleanCashCurrency,
- );
- addConfigOptional(option, "github_environment", item.github_environment, cleanSlug);
- addConfigOptional(option, "variable_scope", item.variable_scope, (value, field) =>
- cleanChoice(value || "default", ["default", "repository", "environment"], field),
- );
- addConfigOptional(option, "plugin_mode", item.plugin_mode, (value, field) =>
- cleanChoice(value || "auto", ["auto", "none"], field),
- );
- addConfigOptional(option, "option_overlay_mode", item.option_overlay_mode, (value, field) =>
- cleanChoice(value || "enabled", OPTION_OVERLAY_MODES, field),
- );
- addConfigOptional(option, "cash_only_execution_mode", item.cash_only_execution_mode, (value, field) =>
- cleanChoice(value || "enabled", CASH_ONLY_EXECUTION_MODES, field),
- );
- addConfigOptional(option, "dca_mode", item.dca_mode, cleanDcaMode);
- addConfigOptional(option, "dca_base_investment_usd", item.dca_base_investment_usd, cleanPositiveNumber);
- option.supported_domains = shouldInferSupportedDomains(item.supported_domains)
- ? inferAccountSupportedDomains(platform, option)
- : normalizeSupportedDomains(item.supported_domains, `account option ${platform}[${index}].supported_domains`);
- return option;
-}
-
-function shouldInferSupportedDomains(value) {
- if (value === undefined || value === null) return true;
- if (Array.isArray(value)) return value.length === 0;
- return String(value).trim() === "";
-}
-
-function supportedDomainsForAccount(platform, option) {
- const platformDomains = inferAccountSupportedDomains(platform, option || {});
- if (Array.isArray(option?.supported_domains) && option.supported_domains.length) {
- return normalizeSupportedDomains(option.supported_domains, "supported_domains")
- .filter((domain) => platformDomains.includes(domain));
- }
- return platformDomains;
-}
-
-function inferAccountSupportedDomains(platform, option) {
- void option;
- const domains = PLATFORM_CONFIG[platform]?.supported_domains;
- return Array.isArray(domains) ? [...domains] : [];
-}
-
-function platformRepositories(env) {
- return resolvePlatformRepositories(env);
-}
-
-function normalizeSupportedDomains(value, fieldName) {
- const items = Array.isArray(value)
- ? value
- : String(value || "").split(/[\s,;]+/);
- if (!items.length || items.length > SUPPORTED_STRATEGY_DOMAINS.length) {
- throw new Error(`${fieldName} must list one or more strategy domains`);
- }
- const result = [];
- for (const item of items) {
- const domain = cleanStrategyDomain(item, fieldName);
- if (!result.includes(domain)) result.push(domain);
- }
- if (!result.length) throw new Error(`${fieldName} must list one or more strategy domains`);
- return result;
-}
-
-function cleanStrategyDomain(value, fieldName) {
- return cleanChoice(value, SUPPORTED_STRATEGY_DOMAINS, fieldName);
-}
-
-function cleanCashCurrency(value, fieldName) {
- return cleanChoice(String(value || "").trim().toUpperCase(), ["USD", "HKD", "CNY"], fieldName);
-}
-
-function addConfigOptional(target, key, value, cleaner) {
- if (value === undefined || value === null || String(value).trim() === "") return;
- target[key] = cleaner(value, key);
-}
-
-function addOptional(target, key, value, cleaner) {
- if (value === undefined || value === null || String(value).trim() === "") return;
- target[key] = cleaner(value, key);
-}
-
-function cleanChoice(value, allowed, field) {
- const text = String(value || "").trim();
- if (!allowed.includes(text)) throw new Error(`${field} is invalid`);
- return text;
-}
-
-function isDcaProfile(profile) {
- return Boolean(DCA_PROFILE_CONFIG[canonicalStrategyProfile(profile)]);
-}
-
-function assertDcaPlatform(platform, strategyProfile) {
- if (isDcaProfile(strategyProfile) && !DCA_SUPPORTED_PLATFORMS.has(platform)) {
- throw new Error(
- `DCA strategy profiles are not supported on ${platform}; got strategy_profile=${strategyProfile}`,
- );
- }
-}
-
-function cleanDcaMode(value, field = "dca_mode") {
- const mode = String(value || "").trim().toLowerCase();
- const aliases = {
- ordinary: "fixed",
- ordinary_dca: "fixed",
- fixed_dca: "fixed",
- smart_dca: "smart",
- };
- const normalized = aliases[mode] || mode;
- return cleanChoice(normalized, ["fixed", "smart"], field);
-}
-
-function cleanBoolean(value) {
- if (value === true || value === "true") return true;
- if (value === false || value === "false" || value === "" || value === undefined || value === null) return false;
- throw new Error("boolean input is invalid");
-}
-
-function cleanRatio(value, field) {
- const text = cleanNumberText(value, field);
- const numeric = Number(text);
- if (numeric < 0 || numeric > 1) throw new Error(`${field} must be between 0 and 1`);
- return text;
-}
-
-function cleanNonNegativeNumber(value, field) {
- const text = cleanNumberText(value, field);
- if (Number(text) < 0) throw new Error(`${field} must be non-negative`);
- return text;
-}
-
-function cleanPositiveNumber(value, field) {
- const text = cleanNumberText(value, field);
- if (Number(text) <= 0) throw new Error(`${field} must be greater than 0`);
- return text;
-}
-
-function cleanNumberText(value, field) {
- const text = String(value || "").trim();
- if (!text || text.length > 32 || !/^(?:\d+|\d*\.\d+)$/.test(text)) {
- throw new Error(`${field} must be a finite decimal number`);
- }
- const numeric = Number(text);
- if (!Number.isFinite(numeric)) throw new Error(`${field} must be finite`);
- return text;
-}
-
-function cleanSlug(value, field) {
- const text = String(value || "").trim();
- if (!text || text.length > 120 || !/^[A-Za-z0-9._=-]+$/.test(text)) {
- throw new Error(`${field} must use letters, numbers, dot, underscore, dash, or equals`);
- }
- return text;
-}
-
-function cleanRepositoryName(value, field) {
- const text = String(value || "").trim();
- if (!text || text.length > 160 || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(text)) {
- throw new Error(`${field} must be owner/repo`);
- }
- return text;
-}
-
-function cleanLabel(value, field) {
- const text = String(value || "").trim();
- if (!text || text.length > 80 || /[<>{}]/.test(text)) {
- throw new Error(`${field} is invalid`);
- }
- return text;
-}
-
-function cleanLifecycleStage(value, field = "lifecycle_stage") {
- const text = String(value || "").trim().toLowerCase();
- if (!text || text.length > 80 || !/^[a-z0-9._-]+$/.test(text)) {
- throw new Error(`${field} is invalid`);
- }
- return text;
-}
-
-function canonicalLifecycleStage(value, deployment = {}) {
- const stage = cleanLifecycleStage(value);
- // Keep runtime_enabled as a first-class catalog stage so bundled SSOT and
- // /api/strategy-profiles readback stay bit-identical for deploy verification.
- if (["research_active", "shadow_active", "paper_active", "live_candidate", "live_enabled", "runtime_enabled"].includes(stage)) {
- return stage;
- }
- if (["research", "research_backtest_only", "ai_monitored_candidate"].includes(stage)) return "research_active";
- if (stage === "shadow_candidate") return "shadow_active";
- void deployment;
- throw new Error(`lifecycle_stage ${stage} is unsupported`);
-}
-
-function cleanAllowedExecutionModes(value) {
- const items = Array.isArray(value)
- ? value
- : String(value || "").split(/[,\s/|]+/);
- const modes = [];
- for (const item of items) {
- const mode = String(item || "").trim().toLowerCase();
- if (!mode) continue;
- if (!["live", "paper", "dry_run"].includes(mode)) {
- throw new Error(`allowed_execution_modes contains unsupported mode ${mode}`);
- }
- if (!modes.includes(mode)) modes.push(mode);
- }
- return modes;
-}
-
-function cleanExecutionMode(value) {
- const mode = cleanChoice(value || "live", ["live", "paper", "dry_run"], "execution_mode");
- return mode === "paper" ? "dry_run" : mode;
-}
-
-function supportedExecutionModesForPlatform(platform) {
- const modes = PLATFORM_CONFIG[platform]?.supported_execution_modes;
- if (!Array.isArray(modes)) return [];
- return modes.filter((mode) => mode === "live" || mode === "dry_run");
-}
-
-function requireSameOrigin(request, options = {}) {
- const origin = request.headers.get("Origin");
- if (!origin) {
- if (options.requireOrigin) throw new HttpError("Origin header is required", 403);
- return;
- }
- if (origin !== new URL(request.url).origin) throw new HttpError("cross-origin request rejected", 403);
-}
-
-async function fetchGithubVariables(token, repository, scope, githubEnvironment, { reportReadErrors = false, onReadFailure = () => {} } = {}) {
- const apiUrl = githubVariablesUrl(repository, scope, githubEnvironment);
- const values = new Map();
- // Evidence-aware readers opt in. Other callers retain their existing fallback.
- const failed = (reason = "read_failed") => { onReadFailure(reason); return reportReadErrors ? null : new Map(); };
- if (!apiUrl) return failed();
- try {
- // Follow the variable-list pages, never arbitrary URLs returned by an upstream.
- for (let page = 1; ; page += 1) {
- const response = await fetchWithTimeout(`${apiUrl}?per_page=100&page=${page}`, {
- headers: githubHeaders(token),
- });
- if (!response.ok) return failed([401, 403].includes(response.status) ? "permission_denied" : "read_failed");
- const payload = await response.json();
- if (!Array.isArray(payload?.variables)) return failed();
- for (const item of payload.variables) {
- if (typeof item.name === "string" && typeof item.value === "string") values.set(item.name, item.value);
- }
- if (!response.headers.get("Link")?.includes('rel="next"')) return values;
- }
- } catch {
- return failed();
- }
-}
-
-
-function githubVariablesUrl(repository, scope, githubEnvironment) {
- const [owner, repo] = String(repository || "").split("/");
- if (!owner || !repo) return "";
- const base = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
- if (scope === "environment") {
- if (!githubEnvironment) return "";
- return `${base}/environments/${encodeURIComponent(githubEnvironment)}/variables`;
- }
- return `${base}/actions/variables`;
-}
-
-function resolveVariableScope(platform, option) {
- const configured = String(option?.variable_scope || "").trim();
- if (configured && configured !== "default") return configured;
- return DEFAULT_VARIABLE_SCOPE[platform] || "repository";
-}
-
-function resolveGithubEnvironment(platform, option, variableScope) {
- if (variableScope !== "environment") return "";
- const configured = String(option?.github_environment || "").trim();
- if (configured) return configured;
- const targetName = String(option?.target_name || option?.key || "").trim();
- if (!targetName) return "";
- if (platform === "longbridge") return `longbridge-${targetName.toLowerCase()}`;
- return targetName;
-}
-
-function runtimeTargetFromServiceTargets(rawValue, platform, option) {
- const payload = parseJsonValue(rawValue);
- const targets = Array.isArray(payload)
- ? payload
- : (Array.isArray(payload?.targets) ? payload.targets : []);
- const matches = [];
- for (const entry of targets) {
- if (!entry || Array.isArray(entry) || typeof entry !== "object") continue;
- const runtimeTarget = entry.runtime_target && typeof entry.runtime_target === "object"
- ? entry.runtime_target
- : {};
- if (!runtimeTargetMatchesAccount(runtimeTarget, platform, option, entry)) continue;
- // Match deployment identity before reading overrides. The deploy planner
- // supports nested env values and gives explicit top-level values precedence.
- const nestedEnv = entry.env && typeof entry.env === "object" && !Array.isArray(entry.env)
- ? entry.env : {};
- const settings = { ...nestedEnv, ...entry };
- matches.push({
- ...runtimeTarget,
- strategy_profile: runtimeTarget.strategy_profile || entry.strategy_profile,
- ...reservedCashPayloadFromObject(platform, settings),
- ...incomeLayerPayloadFromObject(settings),
- ...optionOverlayPayloadFromObject(settings),
- ...runtimeTargetEnabledPayloadFromObject(settings),
- ...dcaPayloadFromObject(settings),
- ...cashOnlyPayloadFromObject(platform, settings),
- });
- }
- return matches.length === 1 ? matches[0] : null;
-}
-
-async function readCashOnlyVariables({ platform, repository, variableScope, githubEnvironment, readVariable }) {
- const platformVariable = PLATFORM_CASH_ONLY_EXECUTION_VARIABLES[platform];
- const [platformValue, legacyValue] = await Promise.all([
- readVariable(repository, variableScope, githubEnvironment, platformVariable),
- readVariable(repository, variableScope, githubEnvironment, LEGACY_CASH_ONLY_EXECUTION_VARIABLE),
- ]);
- return cashOnlyPayloadFromValues(platformValue ?? legacyValue);
-}
-
-function cashOnlyPayloadFromObject(platform, payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
- return cashOnlyPayloadFromValues(
- payload[PLATFORM_CASH_ONLY_EXECUTION_VARIABLES[platform]] ??
- payload[LEGACY_CASH_ONLY_EXECUTION_VARIABLE] ??
- payload.cash_only_execution,
- );
-}
-
-function cashOnlyPayloadFromValues(value) {
- const enabled = cleanOptionalBoolean(value);
- if (enabled === null) return {};
- return { cash_only_execution: enabled };
-}
-
-async function readReservedCashVariables({ platform, repository, variableScope, githubEnvironment, readVariable }) {
- const [floorValue, ratioValue] = await Promise.all([
- readVariable(repository, variableScope, githubEnvironment, PLATFORM_MIN_RESERVED_CASH_VARIABLES[platform]),
- readVariable(repository, variableScope, githubEnvironment, PLATFORM_RESERVED_CASH_RATIO_VARIABLES[platform]),
- ]);
- return reservedCashPayloadFromValues(floorValue, ratioValue);
-}
-
-async function readIncomeLayerVariables({ repository, variableScope, githubEnvironment, readVariable }) {
- const [enabledValue, startUsdValue, maxRatioValue] = await Promise.all([
- readVariable(repository, variableScope, githubEnvironment, INCOME_LAYER_ENABLED_VARIABLE),
- readVariable(repository, variableScope, githubEnvironment, INCOME_LAYER_START_USD_VARIABLE),
- readVariable(repository, variableScope, githubEnvironment, INCOME_LAYER_MAX_RATIO_VARIABLE),
- ]);
- return incomeLayerPayloadFromValues(enabledValue, startUsdValue, maxRatioValue);
-}
-
-async function readOptionOverlayVariables({ repository, variableScope, githubEnvironment, readVariable }) {
- const enabledValue = await readVariable(repository, variableScope, githubEnvironment, OPTION_OVERLAY_ENABLED_VARIABLE);
- return optionOverlayPayloadFromValue(enabledValue);
-}
-
-async function readRuntimeTargetEnabledVariable({ repository, variableScope, githubEnvironment, readVariable }) {
- const value = await readVariable(repository, variableScope, githubEnvironment, RUNTIME_TARGET_ENABLED_VARIABLE);
- return runtimeTargetEnabledPayloadFromValue(value);
-}
-
-async function readDcaVariables({ repository, variableScope, githubEnvironment, readVariable }) {
- const [modeValue, baseInvestmentValue] = await Promise.all([
- readVariable(repository, variableScope, githubEnvironment, DCA_MODE_VARIABLE),
- readVariable(repository, variableScope, githubEnvironment, DCA_BASE_INVESTMENT_VARIABLE),
- ]);
- return dcaPayloadFromValues(modeValue, baseInvestmentValue);
-}
-
-function reservedCashPayloadFromObject(platform, payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
- return reservedCashPayloadFromValues(
- payload[PLATFORM_MIN_RESERVED_CASH_VARIABLES[platform]] ??
- payload.min_reserved_cash_usd ??
- payload.reserved_cash_floor_usd,
- payload[PLATFORM_RESERVED_CASH_RATIO_VARIABLES[platform]] ??
- payload.reserved_cash_ratio,
- );
-}
-
-function reservedCashPayloadFromValues(floorValue, ratioValue) {
- const result = {};
- const floor = cleanCurrentNonNegativeNumber(floorValue);
- const ratio = cleanCurrentRatio(ratioValue);
- if (floor) result.min_reserved_cash_usd = floor;
- if (ratio) result.reserved_cash_ratio = ratio;
- return result;
-}
-
-function incomeLayerPayloadFromObject(payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
- return incomeLayerPayloadFromValues(
- payload[INCOME_LAYER_ENABLED_VARIABLE] ?? payload.income_layer_enabled,
- payload[INCOME_LAYER_START_USD_VARIABLE] ?? payload.income_layer_start_usd,
- payload[INCOME_LAYER_MAX_RATIO_VARIABLE] ?? payload.income_layer_max_ratio,
- );
-}
-
-function incomeLayerPayloadFromValues(enabledValue, startUsdValue, maxRatioValue) {
- const result = {};
- const enabled = cleanOptionalBoolean(enabledValue);
- const startUsd = cleanCurrentNonNegativeNumber(startUsdValue);
- const maxRatio = cleanCurrentRatio(maxRatioValue);
- if (enabled !== null) result.income_layer_enabled = enabled;
- if (startUsd) result.income_layer_start_usd = startUsd;
- if (maxRatio) result.income_layer_max_ratio = maxRatio;
- return result;
-}
-
-function optionOverlayPayloadFromObject(payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
- return optionOverlayPayloadFromValue(
- payload[OPTION_OVERLAY_ENABLED_VARIABLE] ?? payload.option_overlay_enabled,
- );
-}
-
-function optionOverlayPayloadFromValue(value) {
- const enabled = cleanOptionalBoolean(value);
- return enabled === null ? {} : { option_overlay_enabled: enabled };
-}
-
-function runtimeTargetEnabledPayloadFromObject(payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
- return runtimeTargetEnabledPayloadFromValue(
- payload[RUNTIME_TARGET_ENABLED_VARIABLE] ?? payload.runtime_target_enabled,
- );
-}
-
-function runtimeTargetEnabledPayloadFromValue(value) {
- const enabled = cleanOptionalBoolean(value);
- return enabled === null ? {} : { runtime_target_enabled: enabled };
-}
-
-function dcaPayloadFromObject(payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return {};
- return dcaPayloadFromValues(
- payload[DCA_MODE_VARIABLE] ?? payload.dca_mode,
- payload[DCA_BASE_INVESTMENT_VARIABLE] ??
- payload.dca_base_investment_usd ??
- payload.base_investment_usd,
- );
-}
-
-function stripLegacyIbitZscoreExitControls(payload) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") return;
- for (const field of [
- "ibit_zscore_exit_mode",
- "ibit_zscore_exit_enabled",
- "ibit_zscore_exit_parking_symbol",
- "ibit_zscore_exit_risk_reduced_exposure",
- "ibit_zscore_exit_risk_off_exposure",
- "ibit_zscore_exit_allow_outside_execution_window",
- ]) {
- delete payload[field];
- }
-}
-
-function dcaPayloadFromValues(modeValue, baseInvestmentValue) {
- const result = {};
- const mode = cleanCurrentDcaMode(modeValue);
- const baseInvestmentUsd = cleanCurrentPositiveNumber(baseInvestmentValue);
- if (mode) result.dca_mode = mode;
- if (baseInvestmentUsd) result.dca_base_investment_usd = baseInvestmentUsd;
- return result;
-}
-
-function dcaControlsFromInputs(inputs) {
- const payload = inputs?.extra_variables_json ? JSON.parse(inputs.extra_variables_json) : {};
- return {
- ...dcaPayloadFromObject(payload),
- ...dcaPayloadFromObject(inputs),
- };
-}
-
-function cashOnlyExecutionModeFromInputs(inputs) {
- const direct = String(inputs?.cash_only_execution_mode || "").trim().toLowerCase();
- if (direct === "enabled" || direct === "disabled") return direct;
- try {
- const payload = inputs?.extra_variables_json ? JSON.parse(inputs.extra_variables_json) : {};
- const mode = String(payload.cash_only_execution_mode || "").trim().toLowerCase();
- return mode === "enabled" || mode === "disabled" ? mode : "";
- } catch {
- return "";
- }
-}
-
-function dcaPayloadForProfile(profile, payload) {
- return isDcaProfile(profile) ? payload : {};
-}
-
-function runtimeModePayload(runtimeTarget) {
- const executionMode = normalizeRuntimeExecutionMode(runtimeTarget?.execution_mode, runtimeTarget?.dry_run_only);
- const payload = {};
- if (executionMode) payload.execution_mode = executionMode;
- const dryRunOnly = cleanOptionalBoolean(runtimeTarget?.dry_run_only);
- if (dryRunOnly !== null) payload.dry_run_only = dryRunOnly;
- return payload;
-}
-
-function normalizeRuntimeExecutionMode(value, dryRunOnly) {
- const mode = String(value || "").trim().toLowerCase();
- if (mode === "live" || mode === "dry_run") return mode;
- if (mode === "paper" && cleanOptionalBoolean(dryRunOnly) !== true) return mode;
- const dryRun = cleanOptionalBoolean(dryRunOnly);
- if (dryRun === true) return "dry_run";
- if (dryRun === false) return "live";
- return "";
-}
-
-function cleanOptionalBoolean(value) {
- if (value === true || value === 1) return true;
- if (value === false || value === 0) return false;
- if (typeof value === "string") {
- const text = value.trim().toLowerCase();
- if (text === "true" || text === "1") return true;
- if (text === "false" || text === "0") return false;
- }
- return null;
-}
-
-function cleanCurrentNonNegativeNumber(value) {
- const text = String(value ?? "").trim();
- if (!text || text.length > 32 || !/^(?:\d+|\d*\.\d+)$/.test(text)) return "";
- const numeric = Number(text);
- if (!Number.isFinite(numeric) || numeric < 0) return "";
- return text;
-}
-
-function cleanCurrentRatio(value) {
- const text = cleanCurrentNonNegativeNumber(value);
- if (!text) return "";
- const numeric = Number(text);
- if (numeric < 0 || numeric > 1) return "";
- return text;
-}
-
-function cleanCurrentPositiveNumber(value) {
- const text = cleanCurrentNonNegativeNumber(value);
- if (!text || Number(text) <= 0) return "";
- return text;
-}
-
-function cleanCurrentDcaMode(value) {
- try {
- return cleanDcaMode(value || "");
- } catch {
- return "";
- }
-}
-
-function runtimeTargetMatchesAccount(runtimeTarget, platform, option, entry = {}) {
- const runtimePlatform = String(runtimeTarget?.platform_id || "").trim().toLowerCase();
- if (runtimePlatform && runtimePlatform !== platform) return false;
-
- const serviceName = String(option?.service_name || defaultCurrentServiceName(platform, option?.target_name || option?.key) || "");
- const serviceCandidates = [
- runtimeTarget?.service_name,
- entry?.service,
- entry?.service_name,
- ].filter((value) => normalizeMatchValue(value));
- if (serviceName && serviceCandidates.length) {
- return hasCandidate(serviceName, serviceCandidates);
- }
-
- if (hasCandidate(option?.account_scope, [
- runtimeTarget?.account_scope,
- entry?.ACCOUNT_GROUP,
- entry?.account_scope,
- ])) return true;
-
- if (hasCandidate(option?.deployment_selector, [
- runtimeTarget?.deployment_selector,
- entry?.deployment_selector,
- ])) return true;
-
- const optionSelectors = splitSelectorValues(option?.account_selector);
- const runtimeSelectors = splitSelectorValues(runtimeTarget?.account_selector || entry?.account_selector);
- if (optionSelectors.some((value) => runtimeSelectors.includes(value))) return true;
-
- const targetName = String(option?.target_name || option?.key || "").trim();
- return Boolean(targetName && hasCandidate(targetName, [
- runtimeTarget?.target_name,
- runtimeTarget?.deployment_selector,
- runtimeTarget?.account_scope,
- entry?.target_name,
- ]));
-}
-
-function defaultCurrentServiceName(platform, targetName) {
- const normalized = String(targetName || "").trim().toLowerCase();
- if (!normalized) return "";
- if (platform === "longbridge") return `longbridge-quant-${normalized}-service`;
- if (platform === "ibkr") return `interactive-brokers-${normalized}-service`;
- if (platform === "schwab") return "charles-schwab-quant-service";
- if (platform === "firstrade") return "firstrade-quant-service";
- if (platform === "qmt") return "qmt-quant-service";
- return "";
-}
-
-function hasCandidate(expected, candidates) {
- const normalizedExpected = normalizeMatchValue(expected);
- if (!normalizedExpected) return false;
- return candidates.some((candidate) => normalizeMatchValue(candidate) === normalizedExpected);
-}
-
-function splitSelectorValues(value) {
- if (Array.isArray(value)) return value.map(normalizeMatchValue).filter(Boolean);
- return String(value || "")
- .split(/[,\s]+/)
- .map(normalizeMatchValue)
- .filter(Boolean);
-}
-
-function normalizeMatchValue(value) {
- return String(value || "").trim().toLowerCase();
-}
-
-function parseJsonObject(value) {
- const text = String(value || "").trim();
- if (!text) return null;
- for (const candidate of [text, text.replaceAll("\\n", "\n")]) {
- try {
- const payload = JSON.parse(candidate);
- return payload && !Array.isArray(payload) && typeof payload === "object" ? payload : null;
- } catch {
- // Try the next representation.
- }
- }
- return null;
-}
-
-function parseJsonValue(value) {
- const text = String(value || "").trim();
- if (!text) return null;
- for (const candidate of [text, text.replaceAll("\\n", "\n")]) {
- try {
- return JSON.parse(candidate);
- } catch {
- // Try the next representation.
- }
- }
- return null;
-}
-
-function cleanCurrentStrategy(value) {
- const text = String(value || "").trim().toLowerCase();
- if (!text || text.length > 120 || !/^[a-z0-9._=-]+$/.test(text)) return "";
- return text;
-}
-
-function cleanCsv(value, field) {
- const text = String(value || "").trim();
- if (text.length > 300 || !/^[A-Za-z0-9._=,\-\s]+$/.test(text)) {
- throw new Error(`${field} is invalid`);
- }
- return text;
-}
-
-function cleanJson(value, field) {
- const text = String(value || "").trim();
- if (!text) return "";
- if (text.length > 8000) throw new Error(`${field} is too long`);
- JSON.parse(text);
- return text;
-}
-
-function cleanOptionalJsonObject(value, field) {
- const text = cleanJson(value, field);
- if (!text) return "";
- const payload = JSON.parse(text);
- if (!payload || Array.isArray(payload) || typeof payload !== "object") {
- throw new Error(`${field} must be a JSON object`);
- }
- for (const name of Object.keys(payload)) {
- if (looksLikeSecretName(name)) {
- throw new Error(`${field}.${name} looks like a secret and must not be stored here`);
- }
- }
- return text;
-}
-
-function looksLikeSecretName(name) {
- const upperName = String(name || "").toUpperCase();
- if (/_SECRET_(ID|NAME|REF|RESOURCE|RESOURCE_NAME|VERSION)$/.test(upperName)) return false;
- return /PASSWORD|PRIVATE_KEY|TOKEN|API_KEY|ACCESS_KEY|CLIENT_SECRET|SECRET/.test(upperName);
-}
-
-function githubHeaders(token) {
- return {
- Authorization: `Bearer ${token}`,
- Accept: "application/vnd.github+json",
- "Content-Type": "application/json",
- "User-Agent": "QuantRuntimeSettings-StrategySwitchConsole",
- "X-GitHub-Api-Version": "2022-11-28",
- };
-}
-
-async function fetchGithubOrgLogins(token, timeoutMs = GITHUB_API_TIMEOUT_MS) {
- const orgs = [];
- for (let page = 1; page <= 5; page += 1) {
- const response = await fetchWithTimeout(`https://api.github.com/user/orgs?per_page=100&page=${page}`, {
- headers: githubHeaders(token),
- }, timeoutMs);
- if (!response.ok) return orgs;
- const payload = await response.json();
- if (!Array.isArray(payload) || !payload.length) break;
- for (const org of payload) {
- const login = cleanGithubOrg(org?.login || "", "github org");
- if (login) orgs.push(login);
- }
- if (payload.length < 100) break;
- }
- return uniqueStrings(orgs);
-}
-
-function requireEnv(env, name) {
- if (!env[name]) throw new Error(`${name} is not configured`);
-}
-
-async function loadAuthConfig(env) {
- const bootstrapAdmins = parseLoginList(env.STRATEGY_SWITCH_ADMIN_LOGINS || "", "STRATEGY_SWITCH_ADMIN_LOGINS");
- const bootstrapAdminOrgs = parseOrgList(env.STRATEGY_SWITCH_ADMIN_ORGS || "", "STRATEGY_SWITCH_ADMIN_ORGS");
- const envAllowed = parseLoginList(
- env.ALLOWED_GITHUB_LOGINS || env.ALLOWED_GITHUB_LOGIN || "",
- "ALLOWED_GITHUB_LOGINS",
- );
- const envAllowedOrgs = parseOrgList(
- env.ALLOWED_GITHUB_ORGS || env.ALLOWED_GITHUB_ORG || "",
- "ALLOWED_GITHUB_ORGS",
- );
- let storedAllowed = [];
- let storedAllowedOrgs = [];
- let storedAdmins = [];
- let storedAdminOrgs = [];
- let source = "secret";
- if (hasConfigStore(env)) {
- const stored = await readConfigJson(env, AUTH_CONFIG_KEY);
- if (stored) {
- const normalized = normalizeAuthConfigPayload(stored, AUTH_CONFIG_KEY);
- storedAllowed = normalized.allowed_logins;
- storedAllowedOrgs = normalized.allowed_orgs;
- storedAdmins = normalized.admin_logins;
- storedAdminOrgs = normalized.admin_orgs;
- source = "kv";
- }
- }
- const adminLogins = uniqueStrings([...bootstrapAdmins, ...storedAdmins]);
- const adminOrgs = uniqueStrings([...bootstrapAdminOrgs, ...storedAdminOrgs]);
- const allowedLogins = uniqueStrings([...envAllowed, ...storedAllowed, ...adminLogins]);
- const allowedOrgs = uniqueStrings([...envAllowedOrgs, ...storedAllowedOrgs]);
- return {
- allowed_logins: allowedLogins,
- allowed_orgs: allowedOrgs,
- admin_logins: adminLogins,
- admin_orgs: adminOrgs,
- bootstrap_admin_logins: bootstrapAdmins,
- bootstrap_admin_orgs: bootstrapAdminOrgs,
- env_allowed_logins: envAllowed,
- env_allowed_orgs: envAllowedOrgs,
- source,
- kv_available: hasConfigStore(env),
- };
-}
-
-function normalizeAuthConfigPayload(payload, fieldName) {
- if (!payload || Array.isArray(payload) || typeof payload !== "object") {
- throw new Error(`${fieldName} must be an object`);
- }
- return {
- allowed_logins: normalizeLoginList(payload.allowed_logins || [], `${fieldName}.allowed_logins`),
- allowed_orgs: normalizeOrgList(payload.allowed_orgs || [], `${fieldName}.allowed_orgs`),
- admin_logins: normalizeLoginList(payload.admin_logins || [], `${fieldName}.admin_logins`),
- admin_orgs: normalizeOrgList(payload.admin_orgs || [], `${fieldName}.admin_orgs`),
- };
-}
-
-function parseLoginList(value, fieldName) {
- return normalizeLoginList(value, fieldName);
-}
-
-function normalizeLoginList(value, fieldName) {
- const items = Array.isArray(value) ? value : String(value || "").split(/[\s,]+/);
- if (items.length > 80) throw new Error(`${fieldName} supports at most 80 logins`);
- return uniqueStrings(items.map((item) => cleanGithubLogin(item, fieldName)).filter(Boolean));
-}
-
-function parseOrgList(value, fieldName) {
- return normalizeOrgList(value, fieldName);
-}
-
-function normalizeOrgList(value, fieldName) {
- const items = Array.isArray(value) ? value : String(value || "").split(/[\s,]+/);
- if (items.length > 80) throw new Error(`${fieldName} supports at most 80 orgs`);
- return uniqueStrings(items.map((item) => cleanGithubOrg(item, fieldName)).filter(Boolean));
-}
-
-function cleanGithubLogin(value, fieldName) {
- const login = String(value || "").trim().toLowerCase();
- if (!login) return "";
- if (
- login.length > 39 ||
- !/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(login) ||
- login.includes("--")
- ) {
- throw new Error(`${fieldName} contains an invalid GitHub login`);
- }
- return login;
-}
-
-function cleanGithubOrg(value, fieldName) {
- return cleanGithubLogin(value, fieldName);
-}
-
-function isAdminLogin(login, orgLogins, authConfig) {
- return authConfig.admin_logins.includes(String(login || "").toLowerCase());
-}
-
-function isAdminPrincipal(login, orgLogins, authConfig) {
- return isAdminLogin(login, orgLogins, authConfig) || hasOrgMatch(orgLogins, authConfig.admin_orgs);
-}
-
-function isAllowedPrincipal(login, orgLogins, authConfig) {
- const normalizedLogin = String(login || "").toLowerCase();
- return (
- authConfig.allowed_logins.includes(normalizedLogin) ||
- hasOrgMatch(orgLogins, authConfig.allowed_orgs) ||
- isAdminPrincipal(normalizedLogin, orgLogins, authConfig)
- );
-}
-
-function authorizedOrgLogins(orgLogins, authConfig) {
- const authorized = new Set([...authConfig.allowed_orgs, ...authConfig.admin_orgs]);
- return uniqueStrings(orgLogins).filter((org) => authorized.has(org));
-}
-
-function hasOrgMatch(orgLogins, configuredOrgs) {
- const orgs = new Set(uniqueStrings(orgLogins));
- return configuredOrgs.some((org) => orgs.has(String(org || "").toLowerCase()));
-}
-
-async function loadAccountOptionsConfig(env) {
- if (hasRuntimeInstanceStore(env)) {
- const state = await runtimeInstanceCommand(env);
- if (state.initialized) return { options: state.account_options, source: "durable_object", revision: state.revision };
- // Existing execution can read the frozen legacy configuration during import;
- // every instance writer rejects this uninitialized state.
- }
- return loadLegacyAccountOptionsConfig(env);
-}
-
-async function loadLegacyAccountOptionsConfig(env) {
- if (hasConfigStore(env)) {
- const stored = await readConfigJson(env, ACCOUNT_OPTIONS_KEY);
- if (stored) {
- return {
- options: normalizeAccountOptionsPayload(stored, ACCOUNT_OPTIONS_KEY),
- source: "kv",
- };
- }
- }
- return {
- options: parseAccountOptions(env.STRATEGY_SWITCH_ACCOUNT_OPTIONS_JSON || "", "STRATEGY_SWITCH_ACCOUNT_OPTIONS_JSON"),
- source: env.STRATEGY_SWITCH_ACCOUNT_OPTIONS_JSON ? "secret" : "none",
- };
-}
-
-async function loadStrategyProfilesConfig(env) {
- if (hasConfigStore(env)) {
- const stored = await readConfigJson(env, STRATEGY_PROFILES_KEY);
- if (stored) return normalizeStrategyProfilesPayload(stored, STRATEGY_PROFILES_KEY);
- }
- const configured = parseStrategyProfiles(
- env.STRATEGY_SWITCH_STRATEGY_PROFILES_JSON || "",
- "STRATEGY_SWITCH_STRATEGY_PROFILES_JSON",
- );
- if (configured) return configured;
- return normalizeStrategyProfilesPayload(DEFAULT_STRATEGY_PROFILES, "DEFAULT_STRATEGY_PROFILES");
-}
-
-function riskProfileScopeId(platform, targetName) {
- return `${platform}--${targetName}`;
-}
-
-function riskProfileBindingTargets(accountOptions) {
- const targets = [];
- for (const platform of SUPPORTED_PLATFORMS) {
- const options = Array.isArray(accountOptions?.[platform]) ? accountOptions[platform] : [];
- for (const option of options) {
- targets.push({
- scope_id: riskProfileScopeId(platform, option.target_name),
- platform,
- target_name: option.target_name,
- });
- }
- }
- return targets.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
-}
-
-function utcTimestampSeconds(now = new Date()) {
- return now.toISOString().replace(/\.\d{3}Z$/, "Z");
-}
-
-async function calculateRiskProfileSelectionSha256(payload) {
- const material = { ...payload };
- delete material.selection_sha256;
- const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function normalizeRiskProfileSelection(payload, fieldName) {
- const value = assertExactFields(payload, ["schema", "profile_id", "risk_preference", "selection_sha256"], fieldName);
- const riskPreference = cleanChoice(value.risk_preference, RISK_PROFILE_PREFERENCES, `${fieldName}.risk_preference`);
- const normalized = {
- schema: RISK_PROFILE_SELECTION_SCHEMA_VERSION,
- profile_id: RISK_PROFILE_IDS[riskPreference],
- risk_preference: riskPreference,
- selection_sha256: normalizeResearchTaskDigest(value.selection_sha256, `${fieldName}.selection_sha256`),
- };
- if (value.schema !== RISK_PROFILE_SELECTION_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema is unsupported`);
- }
- if (value.profile_id !== normalized.profile_id) {
- throw new Error(`${fieldName}.profile_id does not match risk_preference`);
- }
- if (normalized.selection_sha256 !== await calculateRiskProfileSelectionSha256(normalized)) {
- throw new Error(`${fieldName}.selection_sha256 mismatch`);
- }
- return normalized;
-}
-
-async function calculateRiskProfileBindingSha256(payload) {
- const material = { ...payload };
- delete material.binding_sha256;
- const raw = new TextEncoder().encode(canonicalResearchTaskJson(material));
- const digest = await crypto.subtle.digest("SHA-256", raw);
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
-}
-
-async function normalizeRiskProfileBinding(payload, fieldName) {
- const value = assertExactFields(payload, [
- "schema_version", "scope_id", "platform", "target_name", "profile_selection", "updated_at", "updated_by",
- "no_order", "execution_authority_granted", "binding_sha256",
- ], fieldName);
- const platform = cleanChoice(value.platform, SUPPORTED_PLATFORMS, `${fieldName}.platform`);
- const targetName = cleanSlug(value.target_name, `${fieldName}.target_name`);
- const normalized = {
- schema_version: RISK_PROFILE_BINDING_SCHEMA_VERSION,
- scope_id: riskProfileScopeId(platform, targetName),
- platform,
- target_name: targetName,
- profile_selection: await normalizeRiskProfileSelection(value.profile_selection, `${fieldName}.profile_selection`),
- updated_at: normalizeResearchTaskTimestamp(value.updated_at, `${fieldName}.updated_at`),
- updated_by: cleanGithubLogin(value.updated_by, `${fieldName}.updated_by`),
- no_order: value.no_order,
- execution_authority_granted: value.execution_authority_granted,
- binding_sha256: normalizeResearchTaskDigest(value.binding_sha256, `${fieldName}.binding_sha256`),
- };
- if (value.schema_version !== RISK_PROFILE_BINDING_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- if (value.scope_id !== normalized.scope_id) {
- throw new Error(`${fieldName}.scope_id does not match platform and target_name`);
- }
- if (normalized.no_order !== true || normalized.execution_authority_granted !== false) {
- throw new Error(`${fieldName} must remain no-order and non-executable`);
- }
- if (normalized.binding_sha256 !== await calculateRiskProfileBindingSha256(normalized)) {
- throw new Error(`${fieldName}.binding_sha256 mismatch`);
- }
- return normalized;
-}
-
-async function normalizeRiskProfileBindingRegistry(payload, fieldName = RISK_PROFILE_BINDINGS_KEY) {
- const value = assertExactFields(payload, ["schema_version", "bindings"], fieldName);
- if (value.schema_version !== RISK_PROFILE_BINDING_REGISTRY_SCHEMA_VERSION) {
- throw new Error(`${fieldName}.schema_version is unsupported`);
- }
- if (!Array.isArray(value.bindings) || value.bindings.length > SUPPORTED_PLATFORMS.length * 20) {
- throw new Error(`${fieldName}.bindings must be a bounded array`);
- }
- const bindings = [];
- const scopes = new Set();
- for (const [index, item] of value.bindings.entries()) {
- const binding = await normalizeRiskProfileBinding(item, `${fieldName}.bindings[${index}]`);
- if (scopes.has(binding.scope_id)) throw new Error(`${fieldName}.bindings contains duplicate scope_id`);
- scopes.add(binding.scope_id);
- bindings.push(binding);
- }
- return bindings.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
-}
-
-async function buildRiskProfileBindings(payload, accountOptions, updatedBy) {
- const value = assertExactFields(payload, ["bindings"], "risk profile bindings request");
- if (!Array.isArray(value.bindings) || value.bindings.length > SUPPORTED_PLATFORMS.length * 20) {
- throw new Error("risk profile bindings request.bindings must be a bounded array");
- }
- const bindings = [];
- const scopes = new Set();
- const updatedAt = utcTimestampSeconds();
- for (const [index, item] of value.bindings.entries()) {
- const itemValue = assertExactFields(item, ["platform", "target_name", "risk_preference"], `risk profile bindings request.bindings[${index}]`);
- const platform = cleanChoice(itemValue.platform, SUPPORTED_PLATFORMS, `risk profile bindings request.bindings[${index}].platform`);
- const targetName = cleanSlug(itemValue.target_name, `risk profile bindings request.bindings[${index}].target_name`);
- if (!riskProfileBindingTargets(accountOptions).some((target) => target.platform === platform && target.target_name === targetName)) {
- throw new Error(`risk profile binding target is not configured: ${platform}/${targetName}`);
- }
- const scopeId = riskProfileScopeId(platform, targetName);
- if (scopes.has(scopeId)) throw new Error("risk profile bindings request contains duplicate target");
- scopes.add(scopeId);
- const riskPreference = cleanChoice(
- itemValue.risk_preference,
- RISK_PROFILE_PREFERENCES,
- `risk profile bindings request.bindings[${index}].risk_preference`,
- );
- const profileSelection = {
- schema: RISK_PROFILE_SELECTION_SCHEMA_VERSION,
- profile_id: RISK_PROFILE_IDS[riskPreference],
- risk_preference: riskPreference,
- selection_sha256: "",
- };
- profileSelection.selection_sha256 = await calculateRiskProfileSelectionSha256(profileSelection);
- const binding = {
- schema_version: RISK_PROFILE_BINDING_SCHEMA_VERSION,
- scope_id: scopeId,
- platform,
- target_name: targetName,
- profile_selection: profileSelection,
- updated_at: updatedAt,
- updated_by: cleanGithubLogin(updatedBy, "risk profile binding.updated_by"),
- no_order: true,
- execution_authority_granted: false,
- binding_sha256: "",
- };
- binding.binding_sha256 = await calculateRiskProfileBindingSha256(binding);
- bindings.push(await normalizeRiskProfileBinding(binding, `risk profile bindings request.bindings[${index}]`));
- }
- return bindings.sort((left, right) => left.scope_id.localeCompare(right.scope_id));
-}
-
-function accountSettingsIdentity(instance) {
- const config = instance?.config || {};
- const broker = config.broker_environment;
- return {
- platform: instance.platform,
- key: instance.key,
- target_name: typeof config.target_name === "string" ? config.target_name : "",
- broker_environment: broker === "live" || broker === "paper" ? broker : null,
- account_selector: typeof config.account_selector === "string" ? config.account_selector : "",
- deployment_selector: typeof config.deployment_selector === "string" ? config.deployment_selector : "",
- account_scope: typeof config.account_scope === "string" ? config.account_scope : "",
- service_name: typeof config.service_name === "string" ? config.service_name : "",
- };
-}
-
-function accountSettingsIdentityIsComplete(identity) {
- if (!identity || Array.isArray(identity) || typeof identity !== "object"
- || !SUPPORTED_PLATFORMS.includes(identity.platform)
- || (identity.broker_environment !== "paper" && identity.broker_environment !== "live")) return false;
- return ["key", "target_name", "account_selector", "deployment_selector", "account_scope", "service_name"]
- .every((field) => typeof identity[field] === "string" && identity[field].trim() !== "");
-}
-
-function runtimeControlIdentityIsComplete(identity) {
- return Boolean(identity && SUPPORTED_PLATFORMS.includes(identity.platform)
- && [null, "live", "paper"].includes(identity.broker_environment)
- && ["key", "target_name", "account_selector", "deployment_selector", "account_scope", "service_name"]
- .every((field) => typeof identity[field] === "string" && identity[field].trim() !== ""));
-}
-
-function accountSettingsProfileName(value) {
- if (typeof value !== "string" || value.length > 128 || value !== value.trim()
- || !/^[a-z0-9][a-z0-9._-]*$/.test(value)) return "";
- return value;
-}
-
-function accountSettingPositiveAmount(value) {
- if (typeof value !== "string" || value.length > 32 || !/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value)) return false;
- const numeric = Number(value);
- return Number.isFinite(numeric) && numeric > 0;
-}
-
-function accountSettingRatio(value) {
- if (typeof value !== "string" || value.length > 32 || !/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value)) return null;
- const [whole, frac = ""] = value.split(".");
- if (whole === "0") return value;
- if (whole === "1" && (frac === "" || /^0+$/.test(frac))) return value;
- return null;
-}
-
-function applyAccountSettingOverrides(current, patch) {
- if (!patch || Array.isArray(patch) || typeof patch !== "object") throw new HttpError("invalid_account_setting_overrides", 400);
- const next = current && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
- for (const key of Object.keys(patch)) {
- if (!ACCOUNT_SETTING_OVERRIDE_FIELDS.includes(key)) throw new HttpError("invalid_account_setting_overrides", 400);
- const value = patch[key];
- if (value === null) {
- delete next[key];
- continue;
- }
- if (typeof value === "number") throw new HttpError("invalid_account_setting_overrides", 400);
- if (key === "income_layer_enabled" || key === "option_overlay_enabled") {
- if (typeof value !== "boolean") throw new HttpError("invalid_account_setting_overrides", 400);
- next[key] = value;
- } else if (key === "reserved_cash_floor") {
- if (typeof value !== "string" || value.length > 32 || !/^\d+(?:\.\d+)?$/.test(value) || !Number.isFinite(Number(value))) {
- throw new HttpError("invalid_account_setting_overrides", 400);
- }
- next[key] = value;
- } else if (key === "reserved_cash_ratio") {
- const ratio = accountSettingRatio(value);
- if (ratio === null) throw new HttpError("invalid_account_setting_overrides", 400);
- next[key] = ratio;
- } else if (key === "dca_mode") {
- if (value !== "fixed" && value !== "smart") throw new HttpError("invalid_account_setting_overrides", 400);
- next[key] = value;
- } else if (key === "dca_base_investment_usd") {
- if (!accountSettingPositiveAmount(value)) throw new HttpError("invalid_account_setting_overrides", 400);
- next[key] = value;
- } else if (typeof value !== "string" || value.trim() === "" || value !== value.trim()) {
- throw new HttpError("invalid_account_setting_overrides", 400);
- } else {
- next[key] = value;
- }
- }
- return next;
-}
-
-async function readRiskProfileLegacy(env) {
- if (!hasConfigStore(env)) return { state: "absent" };
- try {
- const stored = await readConfigJson(env, RISK_PROFILE_BINDINGS_KEY);
- if (!stored) return { state: "absent" };
- return { state: "valid", bindings: await normalizeRiskProfileBindingRegistry(stored) };
- } catch {
- return { state: "blocked" };
- }
-}
-
-async function loadRiskProfileBindings(env) {
- if (!hasRuntimeInstanceStore(env)) {
- return { bindings: [], revision: null, account_options: null, error: "runtime_instances_not_bound", status: 503 };
- }
- const legacy = await readRiskProfileLegacy(env);
- try {
- const state = await runtimeInstanceCommand(env, { action: "risk_profile_read", actor: "risk-profile-read", legacy });
- return { bindings: state.bindings, revision: state.revision, account_options: state.account_options, error: null, status: 200 };
- } catch (error) {
- const status = error instanceof HttpError ? error.status : 503;
- return {
- bindings: [],
- revision: null,
- account_options: null,
- error: error instanceof HttpError ? error.message : "runtime_instances_unavailable",
- status,
- };
- }
-}
-
-// Desk reads deliberately bypass the current-strategies memory/KV cache. Raw
-// variable maps stay local; only explicit resolver fields enter the projection.
-async function deskTargetReadback(env, target, actor, suppliedObserved = undefined) {
- let observed = suppliedObserved;
- if (observed === undefined) {
- try {
- observed = await runtimeInstanceCommand(env, { action: "account_settings_read", actor,
- platform: target.platform, key: target.key, legacy: await readRiskProfileLegacy(env) });
- } catch { observed = null; }
- }
- if (observed && observed.config?.target_name !== target.config.target_name) throw new DeskError("not_found", 404);
- const config = observed?.config || target.config;
- const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
- const repository = platformRepositories(env)?.[target.platform];
- let platform = {}, platformReason = "source_unavailable";
- if (token && repository && config) {
- const cache = new Map();
- let failed = false;
- const readVariable = async (repo, scope, environment, name) => {
- const key = JSON.stringify([repo, scope, environment]);
- if (!cache.has(key)) cache.set(key, fetchGithubVariables(token, repo, scope, environment, { reportReadErrors: true }));
- const variables = await cache.get(key);
- if (variables === null) failed = true;
- return variables?.get(name) || "";
- };
- try {
- const options = observed?.account_options?.[target.platform] || [];
- const current = await resolveCurrentStrategyForAccount({ platform: target.platform, option: config,
- optionsCount: options.length || target.optionsCount || 1, repository, readVariable });
- if (failed) throw new Error("read_failed");
- const scope = resolveVariableScope(target.platform, config);
- const environment = resolveGithubEnvironment(target.platform, config, scope);
- // Identity must come from a uniquely matched runtime record, never config.
- const service = current?.source === "CLOUD_RUN_SERVICE_TARGETS_JSON"
- ? runtimeTargetFromServiceTargets(await readVariable(repository, "repository", "", "CLOUD_RUN_SERVICE_TARGETS_JSON"), target.platform, config) : null;
- const runtime = current?.source === "RUNTIME_TARGET_JSON"
- ? parseJsonObject(await readVariable(repository, scope, environment, "RUNTIME_TARGET_JSON")) : null;
- if (failed) throw new Error("read_failed");
- const identity = current?.source === "CLOUD_RUN_SERVICE_TARGETS_JSON" ? service
- : runtime && runtimeTargetMatchesAccount(runtime, target.platform, config) ? runtime : null;
- platform = { strategy_profile: current?.strategy_profile, enabled: current?.runtime_target_enabled,
- income_layer_enabled: current?.income_layer_enabled, option_overlay_enabled: current?.option_overlay_enabled,
- reserved_cash_floor: current?.min_reserved_cash_usd, reserved_cash_ratio: current?.reserved_cash_ratio,
- dca_mode: current?.dca_mode, dca_base_investment_usd: current?.dca_base_investment_usd,
- broker_environment: identity?.broker_environment, account_selector: identity?.account_selector,
- cash_currency: identity?.cash_currency, runtime_status_target_id: identity?.runtime_status_target_id };
- platformReason = "never_read";
- } catch { platform = {}; platformReason = "read_failed"; }
- }
- return buildReadback({ target, observed, platform, platformReason, now: Date.now(), cleanRatio: cleanCurrentRatio, splitSelectorValues });
-}
-
-async function effectiveAccountSettings(env, observed) {
- const broker = observed.identity?.broker_environment === "live" || observed.identity?.broker_environment === "paper"
- ? { status: "known", value: observed.identity.broker_environment }
- : { status: "unknown" };
- // Keep the legacy value shape: non-DCA settings remain absent for old clients.
- const effective = {
- strategy_profile: { status: "unknown" },
- broker_environment: broker,
- income_layer_enabled: { status: "unknown" },
- option_overlay_enabled: { status: "unknown" },
- reserved_cash_floor: { status: "unknown" },
- reserved_cash_ratio: { status: "unknown" },
- };
- const fields = ["strategy_profile", "dca_mode", "dca_base_investment_usd", "income_layer_enabled",
- "option_overlay_enabled", "reserved_cash_floor", "reserved_cash_ratio"];
- // This names the resolver path, not a particular variable, deployment or broker readback.
- const finish = (reason = "runtime_setting_unresolved", dcaReason = reason) => ({
- effective,
- effectiveRead: Object.fromEntries(fields.map(field => [field, {
- status: effective[field]?.status === "known" ? "known" : "unknown",
- source: "github_runtime_configuration",
- source_as_of: null,
- reason: effective[field]?.status === "known" ? null : field.startsWith("dca_") ? dcaReason : reason,
- }])),
- });
- const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
- const repository = platformRepositories(env)?.[observed.platform];
- if (!token) return finish("reader_not_configured");
- if (!repository) return finish("repository_not_configured");
- if (!observed.config) return finish("account_config_unavailable");
- const options = Array.isArray(observed.account_options?.[observed.platform]) ? observed.account_options[observed.platform] : [];
- const variableCache = new Map();
- let readFailed = false;
- const readVariable = async (repo, scope, githubEnvironment, name) => {
- const cacheKey = [repo, scope, githubEnvironment || ""].join("|");
- if (!variableCache.has(cacheKey)) variableCache.set(cacheKey, fetchGithubVariables(token, repo, scope, githubEnvironment, { reportReadErrors: true }));
- const values = await variableCache.get(cacheKey);
- if (values === null) readFailed = true;
- return values?.get(name) || "";
- };
- let current = null;
- try {
- current = await resolveCurrentStrategyForAccount({
- platform: observed.platform,
- option: observed.config,
- optionsCount: options.length || 1,
- repository,
- readVariable,
- });
- } catch {
- return finish("runtime_configuration_read_failed");
- }
- // A failed later page must discard earlier values, never certify missing settings.
- if (readFailed) return finish("runtime_configuration_read_failed");
- if (!current || typeof current !== "object") current = {};
- if (typeof current.strategy_profile === "string" && current.strategy_profile) {
- effective.strategy_profile = { status: "known", value: current.strategy_profile };
- }
- if (typeof current.income_layer_enabled === "boolean") effective.income_layer_enabled = { status: "known", value: current.income_layer_enabled };
- if (typeof current.option_overlay_enabled === "boolean") effective.option_overlay_enabled = { status: "known", value: current.option_overlay_enabled };
- if (typeof current.min_reserved_cash_usd === "string" && current.min_reserved_cash_usd) {
- effective.reserved_cash_floor = { status: "known", value: current.min_reserved_cash_usd };
- }
- if (typeof current.reserved_cash_ratio === "string") {
- const ratio = cleanCurrentRatio(current.reserved_cash_ratio);
- if (ratio) effective.reserved_cash_ratio = { status: "known", value: ratio };
- }
- const profile = effective.strategy_profile.status === "known" ? effective.strategy_profile.value : "";
- if (isDcaProfile(profile) && DCA_SUPPORTED_PLATFORMS.has(observed.platform)) {
- const mode = current.dca_mode === "fixed" || current.dca_mode === "smart" ? current.dca_mode : "";
- const amount = typeof current.dca_base_investment_usd === "string" ? current.dca_base_investment_usd : "";
- effective.dca_mode = mode ? { status: "known", value: mode } : { status: "unknown" };
- effective.dca_base_investment_usd = amount ? { status: "known", value: amount } : { status: "unknown" };
- return finish();
- }
- return finish("runtime_setting_unresolved", !DCA_SUPPORTED_PLATFORMS.has(observed.platform) || profile
- ? "dca_not_applicable" : "strategy_profile_unresolved");
-}
-
-async function accountSettingsProfileRuntimeReadback(env, observed, resolved = null) {
- const token = env.RUNTIME_SETTINGS_DISPATCH_TOKEN;
- const repository = resolved?.repository ?? platformRepositories(env)?.[observed.platform];
- if (!token || !repository || !observed.config) return null;
- const options = Array.isArray(observed.account_options?.[observed.platform])
- ? observed.account_options[observed.platform] : [];
- const variableCache = new Map();
- const readVariable = async (repo, scope, githubEnvironment, name) => {
- const cacheKey = [repo, scope, githubEnvironment || ""].join("|");
- if (!variableCache.has(cacheKey)) {
- variableCache.set(cacheKey, fetchGithubVariables(token, repo, scope, githubEnvironment));
- }
- return (await variableCache.get(cacheKey)).get(name) || "";
- };
- try {
- const current = await resolveCurrentStrategyForAccount({
- platform: observed.platform,
- option: observed.config,
- optionsCount: options.length || 1,
- repository,
- readVariable,
- });
- if (!current) return null;
- const variableScope = resolved?.variableScope ?? resolveVariableScope(observed.platform, observed.config);
- const githubEnvironment = resolved?.githubEnvironment ?? resolveGithubEnvironment(observed.platform, observed.config, variableScope);
- const variables = await variableCache.get([repository, variableScope, githubEnvironment || ""].join("|"));
- return {
- strategy_profile: current.strategy_profile || null,
- runtime_target_enabled: variables?.get(RUNTIME_TARGET_ENABLED_VARIABLE) || null,
- };
- } catch {
- return null;
- }
-}
-
-function hasConfigStore(env) {
- return Boolean(configStore(env));
-}
-
-function configStore(env) {
- const store = env.STRATEGY_SWITCH_CONFIG;
- if (!store || typeof store.get !== "function" || typeof store.put !== "function") return null;
- return store;
-}
-
-async function readConfigJson(env, key) {
- const store = configStore(env);
- if (!store) return null;
- const text = await store.get(key);
- if (!text) return null;
- try {
- return JSON.parse(text);
- } catch (error) {
- throw new Error(`STRATEGY_SWITCH_CONFIG.${key} must be valid JSON`);
- }
-}
-
-async function writeConfigJson(env, key, value) {
- const store = configStore(env);
- if (!store) throw new Error("STRATEGY_SWITCH_CONFIG KV binding is required");
- const text = JSON.stringify(value, null, 2);
- if (indexedKey(key)) await directoryCommand(env, { action: "put", key, value: text });
- else await store.put(key, text);
-}
-
-async function loadAuditLog(env) {
- if (!hasConfigStore(env)) return [];
- const payload = await readConfigJson(env, AUDIT_LOG_KEY);
- if (!Array.isArray(payload)) return [];
- return payload
- .filter((entry) => entry && !Array.isArray(entry) && typeof entry === "object")
- .slice(0, AUDIT_LOG_LIMIT);
-}
-
-async function appendAuditLog(env, entry) {
- if (!hasConfigStore(env)) return;
- let current = [];
- try {
- current = await loadAuditLog(env);
- } catch (error) {
- current = [];
- }
- await writeConfigJson(env, AUDIT_LOG_KEY, [entry, ...current].slice(0, AUDIT_LOG_LIMIT));
-}
-
-function accountCounts(accountOptions) {
- const counts = {};
- for (const platform of SUPPORTED_PLATFORMS) {
- counts[platform] = Array.isArray(accountOptions[platform]) ? accountOptions[platform].length : 0;
- }
- return counts;
-}
-
-function uniqueStrings(items) {
- const result = [];
- const seen = new Set();
- for (const item of items) {
- const text = String(item || "").trim().toLowerCase();
- if (!text || seen.has(text)) continue;
- seen.add(text);
- result.push(text);
- }
- return result;
-}
-
-async function makeSession(login, orgs, env) {
- const payload = base64UrlEncodeJson({
- login,
- orgs: uniqueStrings(orgs),
- exp: Math.floor(Date.now() / 1000) + SESSION_TTL_SECONDS,
- });
- const signature = await hmac(payload, env.SESSION_SECRET);
- return `${payload}.${signature}`;
-}
-
-async function readSession(request, env) {
- if (!env.SESSION_SECRET) return null;
- const cookies = parseCookies(request.headers.get("Cookie") || "");
- const token = cookies[SESSION_COOKIE];
- if (!token || !token.includes(".")) return null;
- const [payload, signature] = token.split(".", 2);
- const expected = await hmac(payload, env.SESSION_SECRET);
- if (signature !== expected) return null;
- const session = JSON.parse(base64UrlDecode(payload));
- if (!session.exp || session.exp < Math.floor(Date.now() / 1000)) return null;
- const login = String(session.login || "").toLowerCase();
- const orgs = normalizeOrgList(session.orgs || [], "session.orgs");
- const authConfig = await loadAuthConfig(env);
- const admin = isAdminPrincipal(login, orgs, authConfig);
- return { login, orgs, allowed: isAllowedPrincipal(login, orgs, authConfig), admin };
-}
-
-async function hmac(value, secret) {
- const key = await crypto.subtle.importKey(
- "raw",
- new TextEncoder().encode(secret),
- { name: "HMAC", hash: "SHA-256" },
- false,
- ["sign"],
- );
- const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(value));
- return base64UrlEncodeBytes(new Uint8Array(signature));
-}
-
-function randomToken() {
- const bytes = new Uint8Array(24);
- crypto.getRandomValues(bytes);
- return base64UrlEncodeBytes(bytes);
-}
-
-function base64UrlEncodeJson(value) {
- return base64UrlEncodeBytes(new TextEncoder().encode(JSON.stringify(value)));
-}
-
-function base64UrlEncodeBytes(bytes) {
- let binary = "";
- for (const byte of bytes) binary += String.fromCharCode(byte);
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
-}
-
-function base64UrlDecode(value) {
- const base64 = value.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
- const binary = atob(base64);
- const bytes = new Uint8Array(binary.length);
- for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
- return new TextDecoder().decode(bytes);
-}
-
-function parseCookies(header) {
- const result = {};
- for (const part of header.split(";")) {
- const [name, ...rest] = part.trim().split("=");
- if (!name) continue;
- result[name] = decodeURIComponent(rest.join("="));
- }
- return result;
-}
-
-function cookie(name, value, maxAge) {
- return `${name}=${encodeURIComponent(value)}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=${maxAge}`;
-}
-
-function clearCookie(name) {
- return `${name}=; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=0`;
-}
-
-function clearOAuthCookie() {
- return { "Set-Cookie": clearCookie(OAUTH_STATE_COOKIE) };
-}
-
-
-function requireMarketBenchmarkSyncToken(request, env) {
- const expected = String(env.MARKET_BENCHMARK_SYNC_TOKEN || env.STRATEGY_SWITCH_SYNC_TOKEN || env.RUNTIME_SETTINGS_DISPATCH_TOKEN || "");
- if (!expected) throw new HttpError("market_benchmark_sync_token_missing", 503);
- const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (!token || token !== expected) throw new HttpError("unauthorized", 401);
- // Fail closed if the bearer equals another dedicated sync token family when those are set differently.
- const forbidden = [
- env.ACCOUNT_FACTS_SYNC_TOKEN,
- env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN,
- env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN,
- env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN,
- env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
- env.EXECUTION_EVIDENCE_SYNC_TOKEN,
- ].filter((value) => typeof value === "string" && value && value !== expected);
- if (forbidden.includes(token)) throw new HttpError("unauthorized", 401);
-}
-
-async function marketBenchmarkResponse(request, env) {
- if (request.method !== "GET" && request.method !== "HEAD") {
- return json({ ok: false, error: "method_not_allowed" }, 405);
- }
- if (!hasRuntimeInstanceStore(env)) {
- return json({ ok: false, error: "market_benchmark_store_unavailable" }, 503);
- }
- try {
- const stored = await runtimeInstanceCommand(env, {
- action: "market_benchmark_read",
- });
- const body = {
- ok: true,
- schema_version: MARKET_BENCHMARK_SCHEMA,
- inception_date: stored.inception_date ?? null,
- timezone: stored.timezone || "Asia/Shanghai",
- points: Array.isArray(stored.points) ? stored.points : [],
- };
- const headers = responseHeaders({ "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
- return new Response(request.method === "HEAD" ? null : JSON.stringify(body), { status: 200, headers });
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 500);
- return json({ ok: false, error: "market_benchmark_unavailable" }, 503);
- }
-}
-
-
-function requireMarketBenchmarkRevisionToken(request, env) {
- // Dedicated secret only — never fall back to sync/dispatch tokens.
- const expected = String(env.MARKET_BENCHMARK_REVISION_TOKEN || "");
- if (!expected) throw new HttpError("market_benchmark_revision_token_missing", 503);
- const token = (request.headers.get("Authorization") || "").match(/^Bearer\s+(.+)$/i)?.[1] || "";
- if (!token || token !== expected) throw new HttpError("unauthorized", 401);
- const forbidden = [
- env.MARKET_BENCHMARK_SYNC_TOKEN,
- env.STRATEGY_SWITCH_SYNC_TOKEN,
- env.RUNTIME_SETTINGS_DISPATCH_TOKEN,
- env.ACCOUNT_FACTS_SYNC_TOKEN,
- env.IBKR_ACCOUNT_FACTS_SYNC_TOKEN,
- env.SCHWAB_ACCOUNT_FACTS_SYNC_TOKEN,
- env.FIRSTRADE_ACCOUNT_FACTS_SYNC_TOKEN,
- env.BINANCE_ACCOUNT_FACTS_SYNC_TOKEN,
- env.EXECUTION_EVIDENCE_SYNC_TOKEN,
- ].filter((value) => typeof value === "string" && value && value !== expected);
- if (forbidden.includes(token)) throw new HttpError("unauthorized", 401);
-}
-
-async function reviseMarketBenchmarkResponse(request, env) {
- try {
- requireMarketBenchmarkRevisionToken(request, env);
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 401);
- return json({ ok: false, error: "unauthorized" }, 401);
- }
- if (!hasRuntimeInstanceStore(env)) {
- return json({ ok: false, error: "market_benchmark_store_unavailable" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, 64 * 1024);
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 400);
- return json({ ok: false, error: "invalid_market_benchmark_revision_payload" }, 400);
- }
- try {
- const stored = await runtimeInstanceCommand(env, {
- action: "market_benchmark_read",
- });
- const appliedAt = typeof raw.applied_at === "string" && !Number.isNaN(Date.parse(raw.applied_at))
- ? raw.applied_at
- : new Date().toISOString();
- const digestHex = async (value) => sha256Hex(String(value));
- // planRevisionApply expects sync digest; pre-hash with Web Crypto then use a map.
- const strings = new Set();
- const proposal = raw.proposal;
- if (proposal && Array.isArray(proposal.entries)) {
- strings.add(JSON.stringify(proposal.entries));
- for (const entry of proposal.entries) {
- if (entry && typeof entry.series_id_sha256 === "string") strings.add(entry.series_id_sha256);
- }
- }
- for (const point of (raw.replacements || [])) {
- if (point?.seriesId) strings.add(point.seriesId);
- if (point?.close) strings.add(point.close);
- }
- for (const point of (Array.isArray(stored.points) ? stored.points : [])) {
- if (point?.close) strings.add(point.close);
- if (point?.seriesId) strings.add(point.seriesId);
- }
- const cache = new Map();
- for (const value of strings) cache.set(value, await digestHex(value));
- // Also hash every seriesId/close used by planRevisionApply via digest()
- const digest = (value) => {
- const text = String(value);
- if (cache.has(text)) return cache.get(text);
- throw new HttpError("benchmark_revision_digest_cache_miss", 500);
- };
- // Ensure proposal.entries JSON and all replacement/stored closes/seriesIds are cached —
- // re-walk after building any missing by computing individually.
- async function ensure(value) {
- const text = String(value);
- if (!cache.has(text)) cache.set(text, await digestHex(text));
- return cache.get(text);
- }
- await ensure(JSON.stringify(proposal?.entries || []));
- for (const point of (raw.replacements || [])) {
- await ensure(point.seriesId);
- await ensure(point.close);
- }
- for (const point of (Array.isArray(stored.points) ? stored.points : [])) {
- await ensure(point.seriesId);
- await ensure(point.close);
- }
- const plan = planRevisionApply({
- proposal: raw.proposal,
- approvedProposalSha256: raw.approved_proposal_sha256,
- replacements: raw.replacements || [],
- storedPoints: Array.isArray(stored.points) ? stored.points : [],
- digest: (value) => cache.get(String(value)) || (() => { throw new HttpError("benchmark_revision_digest_cache_miss", 500); })(),
- appliedAt,
- previouslyAppliedProposalSha256s: [],
- });
- const result = await runtimeInstanceCommand(env, {
- action: "market_benchmark_revise",
- plan: {
- proposal_sha256: plan.proposal_sha256,
- overwrites: plan.overwrites,
- deletes: plan.deletes,
- updates: plan.updates,
- ledger_entries: plan.ledger_entries,
- },
- applied_at: appliedAt,
- });
- return json({
- ok: true,
- applied: true,
- proposal_sha256: result.proposal_sha256 || plan.proposal_sha256,
- overwrites: result.overwrites || plan.overwrites,
- deletes: 0,
- ledger_entries: result.ledger_entries || plan.ledger_entries.length,
- log: revisionApplyLogSummary(plan),
- });
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 500);
- if (error instanceof MarketBenchmarkRevisionError) return json({ ok: false, error: error.code }, error.status || 400);
- if (error instanceof MarketBenchmarkError) return json({ ok: false, error: error.code }, error.status || 400);
- return json({ ok: false, error: "market_benchmark_revision_failed" }, 502);
- }
-}
-
-async function syncMarketBenchmarkResponse(request, env) {
- try {
- requireMarketBenchmarkSyncToken(request, env);
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 401);
- return json({ ok: false, error: "unauthorized" }, 401);
- }
- if (!hasRuntimeInstanceStore(env)) {
- return json({ ok: false, error: "market_benchmark_store_unavailable" }, 503);
- }
- let raw;
- try {
- raw = await readBoundedJson(request, 64 * 1024);
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 400);
- return json({ ok: false, error: "invalid_market_benchmark_payload" }, 400);
- }
- try {
- const result = await runtimeInstanceCommand(env, {
- action: "market_benchmark_put",
- payload: raw,
- });
- return json({
- ok: true,
- stored: true,
- schema_version: MARKET_BENCHMARK_SCHEMA,
- inception_date: result.inception_date ?? null,
- written: result.written || 0,
- unchanged: result.unchanged || 0,
- points: result.points || 0,
- });
- } catch (error) {
- if (error instanceof HttpError) return json({ ok: false, error: error.message }, error.status || 500);
- if (error instanceof MarketBenchmarkError) return json({ ok: false, error: error.code }, error.status || 400);
- return json({ ok: false, error: "market_benchmark_sync_failed" }, 502);
- }
-}
-
-async function overviewFxResponse(request, fetchImpl = fetch) {
- return overviewFxResponseImpl(request, {
- fetchImpl,
- fetchWithTimeout,
- json,
- responseHeaders,
- });
-}
-
-function json(payload, status = 200, headers = {}) {
- return new Response(JSON.stringify(payload, null, 2), {
- status,
- headers: responseHeaders({
- "Content-Type": "application/json; charset=utf-8",
- "Cache-Control": "no-store",
- }, headers),
- });
-}
-
-function html(body, status = 200, headers = {}) {
- return new Response(body, {
- status,
- headers: responseHeaders({
- "Content-Type": "text/html; charset=utf-8",
- "Cache-Control": "no-store",
- }, headers),
- });
-}
-
-function redirect(location, headers = {}) {
- return new Response(null, {
- status: 302,
- headers: responseHeaders({ Location: location }, headers),
- });
-}
-
-function responseHeaders(base = {}, extra = {}) {
- const headers = new Headers(SECURITY_HEADERS);
- appendHeaderEntries(headers, base);
- appendHeaderEntries(headers, extra);
- return headers;
-}
-
-function appendHeaderEntries(headers, values) {
- for (const [name, value] of Object.entries(values)) {
- if (Array.isArray(value)) {
- for (const item of value) headers.append(name, item);
- } else {
- headers.set(name, value);
- }
- }
-}
-
-function renderMessage(title, message) {
- return `${escapeHtml(title)}
-
-${escapeHtml(title)}
${escapeHtml(message)}
返回控制台
`;
-}
-
-function escapeHtml(value) {
- return String(value)
- .replaceAll("&", "&")
- .replaceAll("<", "<")
- .replaceAll(">", ">")
- .replaceAll('"', """);
-}
-
export const __test = {
splitSelectorValues,
deskAuth,