// engine/migration/feature-flag-generator.ts — Feature flag spec generator (SPEC-028b)
// Generates feature flag specs for traffic shifting during migrations
// --- Traffic shifting stages ---
const DEFAULT_TRAFFIC_STAGES = [
    {
        percentage: 1,
        observationPeriodMinutes: 60,
        advanceCondition: 'Error rate < 2x baseline for 60min',
    },
    {
        percentage: 5,
        observationPeriodMinutes: 120,
        advanceCondition: 'Error rate < 2x baseline for 2h',
    },
    {
        percentage: 25,
        observationPeriodMinutes: 240,
        advanceCondition: 'Error rate < 2x baseline for 4h',
    },
    {
        percentage: 50,
        observationPeriodMinutes: 480,
        advanceCondition: 'Error rate < 2x baseline for 8h',
    },
    {
        percentage: 100,
        observationPeriodMinutes: 1440,
        advanceCondition: 'All parity checks verified for 24h',
    },
];
// --- Provider adapters ---
const PROVIDER_ADAPTERS = {
    launchdarkly: {
        provider: 'launchdarkly',
        implementation: `import * as ld from 'launchdarkly-node-server-sdk';
const client = ld.init(process.env.LAUNCHDARKLY_SDK_KEY!);
export async function isEnabled(flagKey: string, userKey: string): Promise<boolean> {
  return client.variation(flagKey, { key: userKey }, false) as Promise<boolean>;
}`,
        configExample: `LAUNCHDARKLY_SDK_KEY=sdk-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
    },
    unleash: {
        provider: 'unleash',
        implementation: `import { initialize } from 'unleash-client';
const unleash = initialize({ url: process.env.UNLEASH_URL!, appName: 'migration', instanceId: 'instance-1' });
export function isEnabled(flagKey: string, context?: object): boolean {
  return unleash.isEnabled(flagKey, context);
}`,
        configExample: `UNLEASH_URL=http://unleash.internal/api`,
    },
    flagsmith: {
        provider: 'flagsmith',
        implementation: `import Flagsmith from 'flagsmith-nodejs';
const flagsmith = new Flagsmith({ environmentKey: process.env.FLAGSMITH_ENV_KEY! });
export async function isEnabled(flagKey: string, identifier?: string): Promise<boolean> {
  const flags = identifier ? await flagsmith.getIdentityFlags(identifier) : await flagsmith.getEnvironmentFlags();
  return flags.isFeatureEnabled(flagKey);
}`,
        configExample: `FLAGSMITH_ENV_KEY=ser.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`,
    },
    'custom-json': {
        provider: 'custom-json',
        implementation: `import { readFileSync } from 'fs';
interface FlagConfig { enabled: boolean; percentage: number; }
function loadFlags(): Record<string, FlagConfig> {
  try { return JSON.parse(readFileSync('./flags.json', 'utf-8')) as Record<string, FlagConfig>; }
  catch { return {}; }
}
export function isEnabled(flagKey: string): boolean {
  const flags = loadFlags();
  const flag = flags[flagKey];
  if (!flag?.enabled) return false;
  return Math.random() * 100 < (flag.percentage ?? 100);
}`,
        configExample: `// flags.json\n{ "migration_new_service": { "enabled": true, "percentage": 5 } }`,
    },
};
// --- Router generation ---
function buildRouter(migratedModules, flagName) {
    return {
        description: 'Strangler-fig router: reads the migration flag and routes each request to new or old system based on migrated modules',
        pseudocode: `function route(request, module) {
  const isMigrated = [${migratedModules.map((m) => JSON.stringify(m)).join(', ')}].includes(module);
  const useNew = isMigrated && featureFlags.isEnabled('${flagName}');
  return useNew ? newSystem.handle(request) : oldSystem.handle(request);
}`,
        modules: migratedModules,
    };
}
// --- Test scenarios ---
function buildFlagTests(flagName, modules) {
    return [
        {
            scenario: `Flag ${flagName} is OFF — all traffic goes to old system`,
            flagState: 'off',
            expectedBehavior: `All modules [${modules.join(', ')}] route to old system; no errors from new system`,
        },
        {
            scenario: `Flag ${flagName} is ON at 100% — all traffic goes to new system`,
            flagState: 'on',
            expectedBehavior: `All modules route to new system; parity with old system verified`,
        },
        {
            scenario: `Flag ${flagName} is PARTIAL (1-99%) — traffic splits correctly`,
            flagState: 'partial',
            expectedBehavior: `Percentage of requests route to new system; no data inconsistency on split requests`,
        },
    ];
}
// --- Auto-rollback criteria ---
function buildAutoRollbackCriteria(hasBaselineMetrics) {
    if (!hasBaselineMetrics) {
        return {
            errorRateMultiplier: 0, // 0 means disabled
            windowMinutes: 0,
            description: 'Auto-rollback DISABLED — source system has no metrics baseline. Manual decision required for rollback.',
        };
    }
    return {
        errorRateMultiplier: 2,
        windowMinutes: 5,
        description: 'If error rate of new system exceeds 2x the baseline error rate for 5 minutes, flag automatically reverts to 0%',
    };
}
// --- Expiration policy ---
function buildExpirationPolicy() {
    return {
        suggestedDaysAfterMigration: 14,
        techDebtWarningDays: 90,
        rationale: 'Flag should be removed 14 days after 100% migration is stable. Flag is flagged as tech debt if still active at 90 days.',
    };
}
// --- Public API ---
export function generateFeatureFlagSpec(params) {
    const { migrationName, migratedComponents, hasBaselineMetrics, strategy } = params;
    const flagName = `migration_${migrationName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
    const moduleNames = migratedComponents.map((c) => c.name);
    const allProviders = Object.keys(PROVIDER_ADAPTERS);
    const adapters = allProviders.map((p) => PROVIDER_ADAPTERS[p]);
    const router = strategy === 'strangler-fig' ? buildRouter(moduleNames, flagName) : undefined;
    return {
        flagName,
        description: `Controls traffic shifting for migration: ${migrationName}. Enables progressive cutover from old to new system.`,
        trafficStages: DEFAULT_TRAFFIC_STAGES,
        autoRollback: buildAutoRollbackCriteria(hasBaselineMetrics),
        adapters,
        router,
        expirationPolicy: buildExpirationPolicy(),
        tests: buildFlagTests(flagName, moduleNames),
        generatedAt: new Date().toISOString(),
    };
}
//# sourceMappingURL=feature-flag-generator.js.map