diff --git a/src/Web/autopilot-monitor-web/app/admin/AdminConfigContext.tsx b/src/Web/autopilot-monitor-web/app/admin/AdminConfigContext.tsx index 6c3faf82..0508af5d 100644 --- a/src/Web/autopilot-monitor-web/app/admin/AdminConfigContext.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/AdminConfigContext.tsx @@ -34,6 +34,8 @@ interface AdminConfigContextValue { setAllowAgentDowngrade: (value: boolean) => void; modernDeploymentHarmlessEventIds: string; setModernDeploymentHarmlessEventIds: (value: string) => void; + enableIndexDualWrite: boolean; + setEnableIndexDualWrite: (value: boolean) => void; // Diagnostics log paths globalDiagPaths: DiagnosticsLogPath[]; @@ -110,6 +112,7 @@ export function AdminConfigProvider({ children }: { children: React.ReactNode }) const [opsEventRetentionDays, setOpsEventRetentionDays] = useState(90); const [allowAgentDowngrade, setAllowAgentDowngrade] = useState(false); const [modernDeploymentHarmlessEventIds, setModernDeploymentHarmlessEventIds] = useState("100, 1005"); + const [enableIndexDualWrite, setEnableIndexDualWrite] = useState(false); // Diagnostics Log Paths state const [globalDiagPaths, setGlobalDiagPaths] = useState([]); @@ -162,6 +165,7 @@ export function AdminConfigProvider({ children }: { children: React.ReactNode }) setOpsEventRetentionDays(data.opsEventRetentionDays ?? 90); setAllowAgentDowngrade(data.allowAgentDowngrade ?? false); setModernDeploymentHarmlessEventIds(parseHarmlessEventIdsJson(data.modernDeploymentHarmlessEventIdsJson)); + setEnableIndexDualWrite(data.enableIndexDualWrite ?? false); try { setGlobalDiagPaths(data.diagnosticsGlobalLogPathsJson ? JSON.parse(data.diagnosticsGlobalLogPathsJson) : []); } catch { @@ -255,6 +259,7 @@ export function AdminConfigProvider({ children }: { children: React.ReactNode }) opsEventRetentionDays, allowAgentDowngrade, modernDeploymentHarmlessEventIdsJson: serializeHarmlessEventIds(modernDeploymentHarmlessEventIds), + enableIndexDualWrite, }; const response = await authenticatedFetch(api.globalConfig.get(), getAccessToken, { @@ -281,7 +286,7 @@ export function AdminConfigProvider({ children }: { children: React.ReactNode }) } finally { setSavingConfig(false); } - }, [adminConfig, globalRateLimit, platformStatsBlobSasUrl, collectorIdleTimeoutMinutes, maxSessionWindowHours, maintenanceBlockDurationHours, opsEventRetentionDays, allowAgentDowngrade, modernDeploymentHarmlessEventIds, getAccessToken]); + }, [adminConfig, globalRateLimit, platformStatsBlobSasUrl, collectorIdleTimeoutMinutes, maxSessionWindowHours, maintenanceBlockDurationHours, opsEventRetentionDays, allowAgentDowngrade, modernDeploymentHarmlessEventIds, enableIndexDualWrite, getAccessToken]); // Reset admin config const handleResetAdminConfig = useCallback(() => { @@ -294,6 +299,7 @@ export function AdminConfigProvider({ children }: { children: React.ReactNode }) setOpsEventRetentionDays(adminConfig.opsEventRetentionDays ?? 90); setAllowAgentDowngrade(adminConfig.allowAgentDowngrade ?? false); setModernDeploymentHarmlessEventIds(parseHarmlessEventIdsJson(adminConfig.modernDeploymentHarmlessEventIdsJson)); + setEnableIndexDualWrite(adminConfig.enableIndexDualWrite ?? false); try { setGlobalDiagPaths(adminConfig.diagnosticsGlobalLogPathsJson ? JSON.parse(adminConfig.diagnosticsGlobalLogPathsJson) : []); } catch { @@ -418,6 +424,7 @@ export function AdminConfigProvider({ children }: { children: React.ReactNode }) opsEventRetentionDays, setOpsEventRetentionDays, allowAgentDowngrade, setAllowAgentDowngrade, modernDeploymentHarmlessEventIds, setModernDeploymentHarmlessEventIds, + enableIndexDualWrite, setEnableIndexDualWrite, globalDiagPaths, setGlobalDiagPaths, savingDiagPaths, opsAlertRules, setOpsAlertRules, opsAlertTelegramEnabled, setOpsAlertTelegramEnabled, diff --git a/src/Web/autopilot-monitor-web/app/admin/components/AdminConfigSettingsSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/AdminConfigSettingsSection.tsx index 218522b8..cc68e884 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/AdminConfigSettingsSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/AdminConfigSettingsSection.tsx @@ -16,6 +16,8 @@ interface AdminConfigSettingsSectionProps { setAllowAgentDowngrade: (value: boolean) => void; modernDeploymentHarmlessEventIds: string; setModernDeploymentHarmlessEventIds: (value: string) => void; + enableIndexDualWrite: boolean; + setEnableIndexDualWrite: (value: boolean) => void; onSave: () => Promise; onReset: () => void; } @@ -34,6 +36,8 @@ export function AdminConfigSettingsSection({ setAllowAgentDowngrade, modernDeploymentHarmlessEventIds, setModernDeploymentHarmlessEventIds, + enableIndexDualWrite, + setEnableIndexDualWrite, onSave, onReset, }: AdminConfigSettingsSectionProps) { @@ -152,6 +156,34 @@ export function AdminConfigSettingsSection({ +
+ +
+ {adminConfig && (
diff --git a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionGlobalSettings.tsx b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionGlobalSettings.tsx index 30add519..bc4cff07 100644 --- a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionGlobalSettings.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionGlobalSettings.tsx @@ -12,6 +12,7 @@ export function SectionGlobalSettings() { collectorIdleTimeoutMinutes, setCollectorIdleTimeoutMinutes, allowAgentDowngrade, setAllowAgentDowngrade, modernDeploymentHarmlessEventIds, setModernDeploymentHarmlessEventIds, + enableIndexDualWrite, setEnableIndexDualWrite, handleSaveAdminConfig, handleResetAdminConfig, } = useAdminConfig(); @@ -32,6 +33,8 @@ export function SectionGlobalSettings() { setAllowAgentDowngrade={setAllowAgentDowngrade} modernDeploymentHarmlessEventIds={modernDeploymentHarmlessEventIds} setModernDeploymentHarmlessEventIds={setModernDeploymentHarmlessEventIds} + enableIndexDualWrite={enableIndexDualWrite} + setEnableIndexDualWrite={setEnableIndexDualWrite} onSave={handleSaveAdminConfig} onReset={handleResetAdminConfig} /> diff --git a/src/Web/autopilot-monitor-web/types/adminConfig.ts b/src/Web/autopilot-monitor-web/types/adminConfig.ts index f5305ece..0f2e6475 100644 --- a/src/Web/autopilot-monitor-web/types/adminConfig.ts +++ b/src/Web/autopilot-monitor-web/types/adminConfig.ts @@ -24,6 +24,13 @@ export interface AdminConfiguration { opsAlertSlackWebhookUrl?: string; allowAgentDowngrade?: boolean; modernDeploymentHarmlessEventIdsJson?: string; + /** + * Feature flag for the V2 Decision Engine index-table dual-write (Plan §M5.d). + * When true, IngestTelemetryFunction enqueues telemetry-index-reconcile envelopes after + * committing each primary row, and the 2h IndexReconcileTimer re-scans the last 4h as + * a safety net. Default false — keeps pre-M5.d behaviour bit-exact until explicitly flipped. + */ + enableIndexDualWrite?: boolean; } export interface OpsAlertRule {