/**
 * Phase 2 Pipeline -- Stage 4: ADR Generator
 *
 * Generates Architecture Decision Records as markdown documents driven by
 * the SPARC specification and research dossier. ADRs are derived from actual
 * architectural decisions implied by the SPARC output.
 *
 * Primary output: ADR markdown files (one per decision)
 * Compat output: adr-index.json for downstream consumers
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import { createSpan, endSpan, emitSpan } from '../telemetry.js';
import { createClaudeCodeRunner, isClaudeCodeRunnerAvailable } from '../../../runtime/claude-code-runner.js';
import { detectTechnologyStack, writeTechStack, formatERPContextForPrompt } from './tech-stack-detector.js';
const DIR_MODE = 0o700;
const FILE_MODE = 0o600;
const ADR_SUBDIR = 'adrs';
/**
 * Load agentics fleet report from phase2Dir and format for LLM context.
 */
function loadAgenticsFleetContextForADR(phase2Dir) {
    try {
        // Check phase dir first, then .pre-phaseN (written before phase command runs)
        let reportPath = path.join(phase2Dir, 'agentics-agents-report.json');
        if (!fs.existsSync(reportPath)) {
            const prePhaseDir = path.join(path.dirname(phase2Dir), `.pre-${path.basename(phase2Dir)}`);
            reportPath = path.join(prePhaseDir, 'agentics-agents-report.json');
        }
        if (!fs.existsSync(reportPath))
            return '';
        const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
        if (!report.results || report.results.length === 0)
            return '';
        const successResults = report.results.filter(r => r.status === 200);
        if (successResults.length === 0)
            return '';
        const summaries = successResults.slice(0, 12).map(r => {
            const resp = r.response;
            const data = resp?.['data'];
            let finding = '';
            if (data) {
                const vals = Object.values(data).filter(v => typeof v === 'string').slice(0, 2);
                finding = vals.map(v => String(v).slice(0, 100)).join('; ');
            }
            return `- [${r.domain}/${r.agent}] ${r.role}: ${finding || 'completed'}`;
        }).join('\n');
        return `\nAGENTICS FLEET ANALYSIS (${successResults.length} agents):\n${summaries}\n`;
    }
    catch {
        return '';
    }
}
function slugify(text) {
    return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
}
function pad3(n) {
    return String(n).padStart(3, '0');
}
function findDossierRefs(dossier, keywords) {
    const refs = [];
    for (const item of dossier.items) {
        const text = `${item.title} ${item.content}`.toLowerCase();
        if (keywords.some(kw => text.includes(kw.toLowerCase()))) {
            refs.push(item.id);
        }
    }
    return refs;
}
// ============================================================================
// ADR Markdown Renderer
// ============================================================================
function renderADRMarkdown(adr) {
    const lines = [];
    lines.push(`# ${adr.id}: ${adr.title}`);
    lines.push('');
    lines.push(`**Status:** ${adr.status}`);
    lines.push(`**Date:** ${adr.date}`);
    lines.push('');
    lines.push('## Context');
    lines.push(adr.context);
    lines.push('');
    lines.push('## Decision');
    lines.push(adr.decision);
    lines.push('');
    if (adr.alternatives.length > 0) {
        lines.push('## Alternatives Considered');
        for (const alt of adr.alternatives) {
            const status = alt.rejected ? '(rejected)' : '(selected)';
            lines.push(`- **${alt.option}** ${status}: ${alt.rationale}`);
        }
        lines.push('');
    }
    if (adr.consequences.length > 0) {
        lines.push('## Consequences');
        for (const c of adr.consequences) {
            const icon = c.type === 'positive' ? '+' : c.type === 'negative' ? '-' : '~';
            lines.push(`- [${icon}] ${c.description}`);
        }
        lines.push('');
    }
    if (adr.researchDossierItemRefs.length > 0) {
        lines.push('## References');
        lines.push(`Dossier items: ${adr.researchDossierItemRefs.join(', ')}`);
        lines.push('');
    }
    return lines.join('\n');
}
// ============================================================================
// ADR Builder — derived from SPARC + dossier
// ============================================================================
function makeAlt(option, rationale, rejected) {
    return { option, rationale, rejected };
}
function makeCons(description, type) {
    return { description, type };
}
/**
 * Normalize a loosely-typed SPARC object (e.g. loaded from disk with unknown
 * key shapes) into the arrays that ADR generation needs.
 */
function normalizeSPARCForADR(sparc) {
    // Services: may be on architecture.services or architecture.components or top-level services
    const raw = sparc;
    const arch = (raw.architecture ?? {});
    let services = [];
    const candidateServices = arch.services ?? arch.components ?? arch.modules ?? raw.services;
    if (Array.isArray(candidateServices)) {
        services = candidateServices.map((s, i) => ({
            id: String(s.id ?? `SVC-${String(i + 1).padStart(3, '0')}`),
            name: String(s.name ?? s.label ?? `Service${i + 1}`),
            responsibility: String(s.responsibility ?? s.description ?? s.purpose ?? ''),
            api: Array.isArray(s.api) ? s.api.map(String) : Array.isArray(s.endpoints) ? s.endpoints.map(String) : [],
            dependencies: Array.isArray(s.dependencies) ? s.dependencies.map(String) : Array.isArray(s.deps) ? s.deps.map(String) : [],
            dossierItemRefs: Array.isArray(s.dossierItemRefs) ? s.dossierItemRefs.map(String) : [],
        }));
    }
    // Security: may be array of objects or array of strings
    const ref = (raw.refinement ?? {});
    let securityItems = [];
    const rawSec = ref.securityConsiderations ?? ref.security ?? [];
    if (Array.isArray(rawSec)) {
        securityItems = rawSec.map((item, i) => {
            if (typeof item === 'string')
                return { id: `sec-${i + 1}`, text: item, dossierItemRefs: [] };
            const obj = item;
            return { id: String(obj.id ?? `sec-${i + 1}`), text: String(obj.text ?? obj.description ?? obj.name ?? ''), dossierItemRefs: [] };
        });
    }
    // Performance: may be array of objects or array of strings
    let perfItems = [];
    const rawPerf = ref.performanceTargets ?? ref.performance ?? [];
    if (Array.isArray(rawPerf)) {
        perfItems = rawPerf.map((item, i) => {
            if (typeof item === 'string')
                return { id: `perf-${i + 1}`, text: item, dossierItemRefs: [] };
            const obj = item;
            return { id: String(obj.id ?? `perf-${i + 1}`), text: String(obj.text ?? obj.description ?? obj.target ?? ''), dossierItemRefs: [] };
        });
    }
    const comp = (raw.completion ?? {});
    const integrationPlan = typeof comp.integrationPlan === 'string' ? comp.integrationPlan : '';
    return { services, securityItems, perfItems, integrationPlan };
}
function buildADRsFromSPARC(sparc, dossier, scenarioQuery) {
    const adrs = [];
    let idx = 1;
    const today = new Date().toISOString().slice(0, 10);
    const { services, securityItems, perfItems } = normalizeSPARCForADR(sparc);
    // 1. Service implementation ADRs — describe WHAT each service builds, not just "use adapter pattern"
    const svcForADRs = services.slice(0, 6);
    for (const svc of svcForADRs) {
        const depsText = svc.dependencies.length > 0
            ? ` It integrates with: ${svc.dependencies.join(', ')}.`
            : '';
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: `Implement ${svc.name}${svc.responsibility ? ': ' + svc.responsibility.slice(0, 60) : ''}`,
            status: 'proposed',
            date: today,
            context: `The platform requires a ${svc.name} component that handles ${svc.responsibility || 'core domain logic'}.${depsText} This is a key part of the solution described in the project requirements.`,
            decision: `Build ${svc.name} as a modular service with clear interfaces. ${svc.responsibility ? 'Implement: ' + svc.responsibility + '.' : ''} ${svc.dependencies.length > 0 ? 'Use adapter interfaces for each dependency (' + svc.dependencies.join(', ') + ') to enable testing and future replacement.' : 'Expose a clean API surface for other services to consume.'}`,
            alternatives: [
                makeAlt(`Dedicated ${svc.name} module`, `Clear ownership, testable in isolation`, false),
                makeAlt('Inline in monolith', 'Simpler initially but harder to test and scale', true),
                makeAlt('Third-party service', 'Faster to deploy but less control over domain logic', true),
            ],
            consequences: [
                makeCons(`${svc.name} logic is encapsulated with clear boundaries`, 'positive'),
                makeCons(`Enables independent testing of ${svc.name} business rules`, 'positive'),
                makeCons('Requires well-defined interfaces between services', 'negative'),
            ],
            sparcSectionRefs: [`architecture.services.${svc.name}`],
            researchDossierItemRefs: findDossierRefs(dossier, [svc.name, ...svc.dependencies]),
        });
    }
    // 2. Security ADR — domain-specific, not "defense-in-depth" boilerplate
    if (securityItems.length > 0) {
        const securityContext = securityItems.slice(0, 3).map(s => typeof s === 'string' ? s : (s && typeof s === 'object' ? (s['text'] ?? s['description'] ?? JSON.stringify(s)) : String(s))).join('; ');
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: `Security: ${securityContext.slice(0, 80) || 'Access Control and Data Protection'}`,
            status: 'proposed',
            date: today,
            context: `The project has specific security requirements: ${securityContext}. ${scenarioQuery ? 'The system handles sensitive ' + (scenarioQuery.match(/financial|compliance|regulatory|audit|trading|clinical|patient|confidential/i)?.[0] ?? 'business') + ' data.' : ''}`,
            decision: `Implement role-based access control with domain-specific permissions. ${securityItems.length > 1 ? 'Apply ' + securityItems.slice(0, 2).map(s => typeof s === 'string' ? s : s?.['text'] ?? JSON.stringify(s)).join(' and ') + ' at the service layer.' : ''} All sensitive operations must produce audit trail entries.`,
            alternatives: [
                makeAlt('Role-based with audit trail', 'Meets domain compliance needs', false),
                makeAlt('Simple API key', 'Insufficient for multi-user sensitive data', true),
            ],
            consequences: [
                makeCons('Meets domain-specific compliance and audit requirements', 'positive'),
                makeCons('Requires role definition and permission matrix per service', 'negative'),
            ],
            sparcSectionRefs: ['refinement.securityConsiderations'],
            researchDossierItemRefs: findDossierRefs(dossier, ['security', 'auth', 'access', 'encryption']),
        });
    }
    // 3. Performance ADR — tied to specific domain operations
    if (perfItems.length > 0) {
        const perfContext = perfItems.slice(0, 3).map(s => typeof s === 'string' ? s : (s && typeof s === 'object' ? (s['text'] ?? s['description'] ?? JSON.stringify(s)) : String(s))).join('; ');
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: `Performance: ${perfContext.slice(0, 80) || 'Optimize Critical Path Operations'}`,
            status: 'proposed',
            date: today,
            context: `Performance targets: ${perfContext}. ${scenarioQuery?.includes('simulation') || scenarioQuery?.includes('real-time') ? 'The system includes computationally intensive operations that need optimization.' : ''}`,
            decision: `Optimize the critical data paths identified in the SPARC specification. Use caching for read-heavy queries, async processing for non-blocking operations, and connection pooling for database access. ${scenarioQuery?.includes('Rust') ? 'Use Rust for compute-intensive modules as specified in requirements.' : ''}`,
            alternatives: [
                makeAlt('Targeted optimization', 'Focuses effort on actual bottlenecks', false),
                makeAlt('Premature optimization everywhere', 'Wastes effort on non-critical paths', true),
            ],
            consequences: [
                makeCons('Critical operations meet performance targets', 'positive'),
                makeCons('Requires profiling to validate improvements', 'negative'),
            ],
            sparcSectionRefs: ['refinement.performanceTargets'],
            researchDossierItemRefs: findDossierRefs(dossier, ['performance', 'latency', 'throughput']),
        });
    }
    // 4. High-severity risk ADRs — use actual risk content, not generic "mitigate through redundancy"
    const highRisks = dossier.items.filter(i => i.category === 'risk' && i.severity && /high|critical/i.test(i.severity));
    for (const risk of highRisks.slice(0, 3)) {
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: `Address Risk: ${risk.title.slice(0, 70)}`,
            status: 'proposed',
            date: today,
            context: risk.content,
            decision: `Address this risk by: implementing validation at the boundary where this risk originates, adding monitoring/alerting for early detection, and designing a fallback path for degraded operation. Specific controls should be documented in the implementation.`,
            alternatives: [
                makeAlt('Active controls at boundary', 'Prevents impact before it occurs', false),
                makeAlt('Accept and monitor', 'Lower effort but reactive', true),
            ],
            consequences: [
                makeCons(`Risk "${risk.title.slice(0, 40)}" mitigated with domain-specific controls`, 'positive'),
                makeCons('Requires validation logic in the affected service', 'negative'),
            ],
            sparcSectionRefs: [],
            researchDossierItemRefs: [risk.id],
        });
    }
    // 5. Compliance ADR — reference the specific compliance requirements
    const complianceRefs = findDossierRefs(dossier, ['compliance', 'regulatory', 'gdpr', 'hipaa', 'pci', 'privacy', 'audit', 'governance']);
    if (complianceRefs.length > 0) {
        const complianceContext = scenarioQuery
            ? (scenarioQuery.match(/audit|compliance|regulatory|governance|disclosure|reporting/gi) ?? []).join(', ')
            : '';
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: `Compliance: ${complianceContext.slice(0, 60) || 'Audit Trail and Regulatory Requirements'}`,
            status: 'proposed',
            date: today,
            context: `${complianceRefs.length} compliance-related items identified. ${complianceContext ? 'The project specifically requires: ' + complianceContext + '.' : ''}`,
            decision: `Implement immutable audit logging for all state-changing operations. Each service must record who, what, when, and why for every domain action. ${complianceContext.includes('governance') ? 'Include human-in-the-loop approval workflows for high-impact decisions.' : ''}`,
            alternatives: [
                makeAlt('Immutable audit log per service', 'Complete traceability', false),
                makeAlt('Centralized logging only', 'Gaps in coverage', true),
            ],
            consequences: [
                makeCons('Full audit trail for compliance and regulatory review', 'positive'),
                makeCons('Storage and query overhead for audit data', 'negative'),
            ],
            sparcSectionRefs: [],
            researchDossierItemRefs: complianceRefs,
        });
    }
    // 6. Data persistence ADR
    const dataRefs = findDossierRefs(dossier, ['data', 'database', 'storage', 'persistence']);
    if (dataRefs.length > 0) {
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: 'Data Persistence Strategy',
            status: 'proposed',
            date: today,
            context: `${dataRefs.length} data-related items. Services need isolated data stores.`,
            decision: 'Each bounded context owns its data store. Event sourcing for audit-critical domains.',
            alternatives: [
                makeAlt('Context-owned stores', 'Strong isolation', false),
                makeAlt('Shared database', 'Simpler but coupling risk', true),
            ],
            consequences: [
                makeCons('Data isolation per bounded context', 'positive'),
                makeCons('Cross-context queries need API/events', 'negative'),
            ],
            sparcSectionRefs: ['architecture.services'],
            researchDossierItemRefs: dataRefs,
        });
    }
    // 7. Inter-service communication
    if (services.length > 1) {
        adrs.push({
            id: `ADR-P2-${pad3(idx++)}`,
            title: 'Inter-Service Communication Pattern',
            status: 'proposed',
            date: today,
            context: `${services.length} services need communication pattern.`,
            decision: 'Sync REST/gRPC for queries, async events for commands and domain events.',
            alternatives: [
                makeAlt('Hybrid sync+async', 'Balanced approach', false),
                makeAlt('All synchronous', 'Simple but cascading failures', true),
                makeAlt('All async', 'Loose coupling but complex debugging', true),
            ],
            consequences: [
                makeCons('Sync for reads, async for writes — balanced', 'positive'),
                makeCons('Need both REST and messaging infrastructure', 'negative'),
            ],
            sparcSectionRefs: ['architecture.dataFlow'],
            researchDossierItemRefs: [],
        });
    }
    // Fallback: at least one ADR
    if (adrs.length === 0) {
        adrs.push({
            id: 'ADR-P2-001',
            title: 'System Architecture Approach',
            status: 'proposed',
            date: today,
            context: 'Initial architecture decision based on SPARC specification.',
            decision: 'Build modular system with clear service boundaries, TDD, and iterative refinement.',
            alternatives: [
                makeAlt('Modular architecture', 'Follows SPARC methodology', false),
                makeAlt('Monolithic', 'Simpler but harder to scale', true),
            ],
            consequences: [makeCons('Clean architecture', 'positive')],
            sparcSectionRefs: [],
            researchDossierItemRefs: [],
        });
    }
    return adrs;
}
export function buildPhase2ADRs(sparc, dossier) {
    return buildADRsFromSPARC(sparc, dossier);
}
// ============================================================================
// ADR-027: LLM-Generated Architecture Decision Records
// ============================================================================
/**
 * Generate domain-specific ADRs using Claude instead of generic boilerplate.
 * Returns enriched ADR array, or null if LLM is unavailable.
 */
function tryGenerateLLMADRs(sparc, dossier, query, phase2Dir = '') {
    if (!isClaudeCodeRunnerAvailable())
        return null;
    try {
        const runner = createClaudeCodeRunner();
        const services = sparc.architecture?.services ?? [];
        const serviceList = services.map(s => `- ${s.name}: ${s.responsibility.slice(0, 100)} (deps: ${s.dependencies.join(', ') || 'none'})`).join('\n');
        const dossierContext = dossier.items
            .filter(i => ['requirement', 'constraint', 'risk', 'decision-rationale'].includes(i.category))
            .slice(0, 20)
            .map(i => `- [${i.category}] ${i.title}: ${i.content.slice(0, 120)}`)
            .join('\n');
        // ADR-027: Include agentics fleet analysis from 110 agents
        const agentContext = phase2Dir ? loadAgenticsFleetContextForADR(phase2Dir) : '';
        // ADR-029: Use shared tech stack detector instead of inline patterns
        const dossierText = dossier.items.map(i => i.content).join(' ');
        const techStack = detectTechnologyStack(query, dossierText);
        const techMentions = [];
        if (techStack.erp)
            techMentions.push(techStack.erp.name);
        if (techStack.cloud)
            techMentions.push(techStack.cloud.toUpperCase());
        if (techStack.database)
            techMentions.push(techStack.database);
        if (techStack.messageQueue)
            techMentions.push(techStack.messageQueue);
        if (techStack.searchEngine)
            techMentions.push(techStack.searchEngine);
        if (techStack.cacheLayer)
            techMentions.push(techStack.cacheLayer);
        // Build ERP-specific API context for the prompt
        const erpPromptContext = techStack.erp
            ? `\nERP API DETAILS (use these EXACT paths):\n${formatERPContextForPrompt(techStack.erp)}\n`
            : '';
        const prompt = `You are a senior solution architect writing Architecture Decision Records. Read the FULL project requirements below and write ADRs that guide a developer on HOW to build this specific system.\n\n` +
            `## Project Requirements\n\n${query}\n\n` +
            `## Services Identified\n${serviceList}\n` +
            `\nRESEARCH FINDINGS:\n${dossierContext}\n` +
            (agentContext ? agentContext + '\n' : '') +
            `\nDETECTED TECHNOLOGIES: ${techMentions.join(', ') || 'not specified'}\n` +
            erpPromptContext +
            `\nWrite 8-12 ADRs as a JSON array. Each ADR must be an IMPLEMENTATION DECISION that tells a developer what to build and how.\n` +
            `\nIMPORTANT: ADRs must cover TWO categories:\n` +
            `\nA) DOMAIN-SPECIFIC DECISIONS (at least 5) — these guide implementation of the actual business logic:\n` +
            `   - How to model the core domain concepts (e.g., "Model emissions as facility-level time series with BU rollup")\n` +
            `   - How to implement the key algorithms/calculations the user described\n` +
            `   - How to structure the decision/simulation/optimization logic\n` +
            `   - How domain entities relate and what business rules constrain them\n` +
            `   - How to handle the specific workflows the user described\n` +
            `\nB) INFRASTRUCTURE DECISIONS (3-5) — technology choices that support the domain:\n` +
            `   - Data persistence: which database(s) and why\n` +
            `   - ERP integration approach for ${techMentions[0] || 'the ERP system'}\n` +
            `   - Deployment and cloud platform specifics\n` +
            `   - Security and compliance requirements\n` +
            `\nEach ADR title should describe a SPECIFIC decision, not a category. Example:\n` +
            `  GOOD: "Use Monte Carlo simulation for carbon price forecasting with configurable volatility"\n` +
            `  BAD: "Performance Architecture"\n` +
            `  GOOD: "Model emissions baseline as facility-level time series with business unit rollup"\n` +
            `  BAD: "Data persistence strategy"\n` +
            `\nReturn JSON array:\n` +
            `[\n` +
            `  {\n` +
            `    "title": "Specific decision title that tells a developer what to build",\n` +
            `    "context": "Why this decision matters — reference the specific business problem from the requirements",\n` +
            `    "decision": "The specific approach — include enough detail that a developer can implement it",\n` +
            `    "alternatives": [{"option": "Name", "rationale": "Why considered", "rejected": true/false}],\n` +
            `    "consequences": [{"description": "Impact on the system", "type": "positive|negative|neutral"}]\n` +
            `  }\n` +
            `]\n` +
            `\nCRITICAL RULES:\n` +
            `- NO generic titles like "Security Architecture", "Performance Architecture", "Service Boundary"\n` +
            `- Every ADR must contain enough implementation detail that a developer can build from it\n` +
            `- The "decision" field should be 2-4 sentences describing the specific approach, not one vague sentence\n` +
            `- Reference actual domain concepts from the requirements (not generic "entities" or "services")\n` +
            `- If the user specified technologies (${techMentions.join(', ')}), reference them in relevant ADRs`;
        const result = runner.invoke(prompt, {
            runId: `adr-llm-${Date.now()}`,
            timeoutMs: 60_000, // 60s — LLM ADRs are much better than fallback templates, worth waiting for
        });
        const data = result.data;
        let rawAdrs;
        if (Array.isArray(data)) {
            rawAdrs = data;
        }
        else if (typeof data.content === 'string') {
            try {
                const parsed = JSON.parse(data.content);
                if (Array.isArray(parsed))
                    rawAdrs = parsed;
            }
            catch { /* not JSON */ }
        }
        if (!rawAdrs || rawAdrs.length === 0) {
            process.stderr.write('[adr-generator] LLM ADRs: no decisions in response\n');
            return null;
        }
        const today = new Date().toISOString().slice(0, 10);
        const adrs = rawAdrs.map((raw, idx) => {
            const alts = Array.isArray(raw.alternatives)
                ? raw.alternatives.map(a => makeAlt(String(a.option || ''), String(a.rationale || ''), !!a.rejected))
                : [makeAlt('Selected approach', String(raw.decision || ''), false)];
            const cons = Array.isArray(raw.consequences)
                ? raw.consequences.map(c => makeCons(String(c.description || ''), (c.type || 'neutral')))
                : [makeCons('Decision applied', 'neutral')];
            return {
                id: `ADR-P2-${pad3(idx + 1)}`,
                title: String(raw.title || `Decision ${idx + 1}`),
                status: 'proposed',
                date: today,
                context: String(raw.context || ''),
                decision: String(raw.decision || ''),
                alternatives: alts,
                consequences: cons,
                sparcSectionRefs: [],
                researchDossierItemRefs: findDossierRefs(dossier, [
                    String(raw.title || '').toLowerCase(),
                ]),
            };
        });
        process.stderr.write(`[adr-generator] LLM-generated ${adrs.length} domain-specific ADRs in ${result.durationMs}ms\n`);
        return adrs;
    }
    catch (err) {
        process.stderr.write(`[adr-generator] LLM ADR generation failed: ${err instanceof Error ? err.message : String(err)}\n`);
        return null;
    }
}
// ============================================================================
// Public: Main Stage Function
// ============================================================================
export async function generateADRs(context) {
    const rootSpan = createSpan('adr-generation', 'generate-adrs', { phase2Dir: context.phase2Dir });
    try {
        const sparcStage = context.stageOutputs.get('sparc-specification');
        if (!sparcStage || sparcStage.status !== 'completed') {
            throw new Error('ECLI-P2-020: SPARC output not available.');
        }
        const sparc = sparcStage.data;
        const dossierStage = context.stageOutputs.get('research-dossier');
        if (!dossierStage || dossierStage.status !== 'completed') {
            throw new Error('ECLI-P2-020: Research dossier not available.');
        }
        const dossier = dossierStage.data;
        // ADR-027: Try LLM-generated domain-specific ADRs first, fall back to template
        const query = context.phase1Artifacts?.scenario?.query
            ?? context.phase1Artifacts?.manifest?.['query']
            ?? '';
        // ADR-029: Detect and persist tech stack so downstream phases use the same ERP
        const dossierText = dossier.items.map(i => i.content).join(' ');
        const techStack = detectTechnologyStack(query, dossierText);
        writeTechStack(techStack, context.phase2Dir);
        if (techStack.erp) {
            process.stderr.write(`[adr-generator] Detected ERP: ${techStack.erp.name} (${techStack.erp.slug})\n`);
        }
        const adrs = (query ? tryGenerateLLMADRs(sparc, dossier, query, context.phase2Dir) : null)
            ?? buildADRsFromSPARC(sparc, dossier, query);
        const adrDir = path.join(context.phase2Dir, ADR_SUBDIR);
        fs.mkdirSync(adrDir, { recursive: true, mode: DIR_MODE });
        const writtenPaths = [];
        for (const adr of adrs) {
            const slug = slugify(adr.title);
            const filename = `${adr.id}-${slug}.md`;
            const filePath = path.join(adrDir, filename);
            const markdown = renderADRMarkdown(adr);
            fs.writeFileSync(filePath, markdown, { encoding: 'utf-8', mode: FILE_MODE });
            writtenPaths.push(filePath);
        }
        const indexPath = path.join(adrDir, 'adr-index.json');
        fs.writeFileSync(indexPath, JSON.stringify(adrs, null, 2) + '\n', { encoding: 'utf-8', mode: FILE_MODE });
        writtenPaths.push(indexPath);
        endSpan(rootSpan, 'ok', { adrCount: adrs.length });
        emitSpan(rootSpan);
        const timing = rootSpan.durationMs ?? 0;
        const output = {
            stage: 'adr-generation',
            status: 'completed',
            data: adrs,
            artifacts: writtenPaths,
            timing,
            summary: `     ADRs: ${adrs.length} decisions (${writtenPaths.length - 1} markdown + 1 JSON index)`,
        };
        context.stageOutputs.set('adr-generation', output);
        return output;
    }
    catch (err) {
        const errorMessage = err instanceof Error ? err.message : String(err);
        endSpan(rootSpan, 'error', { error: errorMessage });
        emitSpan(rootSpan);
        const output = {
            stage: 'adr-generation',
            status: 'failed',
            data: { error: errorMessage },
            artifacts: [],
            timing: rootSpan.durationMs ?? 0,
            summary: `ADR generation failed: ${errorMessage}`,
        };
        context.stageOutputs.set('adr-generation', output);
        return output;
    }
}
//# sourceMappingURL=adr-generator.js.map