/**
 * Skill Signals v2 — discriminated-union schema for .specweave/state/skill-signals.json
 *
 * v1 (legacy) was a generation-only store produced by SignalCollector
 * (see src/core/skill-gen/types.ts). v2 adds refinement signals emitted by
 * closure gates (judge-llm, rubric, code-reviewer) and keeps generation
 * signals bit-identical except for an added `type: "generation"` discriminator.
 *
 * Migration is lazy: the reader detects a v1 file and returns a v2 view in
 * memory; the next writer call persists v2 to disk.
 *
 * @module types/skill-signals
 */
import { z } from 'zod';
export const SIGNAL_SOURCES = [
    'judge-llm',
    'rubric',
    'code-reviewer',
];
export const SIGNAL_SEVERITIES = ['low', 'medium', 'high'];
export const GenerationSignalSchema = z.object({
    type: z.literal('generation'),
    id: z.string(),
    pattern: z.string(),
    category: z.string(),
    description: z.string(),
    incrementIds: z.array(z.string()),
    firstSeen: z.string(),
    lastSeen: z.string(),
    confidence: z.number(),
    evidence: z.array(z.string()),
    suggested: z.boolean(),
    declined: z.boolean(),
    generated: z.boolean(),
    uniqueSourceFiles: z.array(z.string()).optional(),
});
export const RefinementSignalSchema = z.object({
    type: z.literal('refinement'),
    id: z.string(),
    source: z.enum(['judge-llm', 'rubric', 'code-reviewer']),
    targetSkill: z.string(),
    severity: z.enum(['low', 'medium', 'high']),
    incrementId: z.string(),
    evidence: z.string(),
    detectedAt: z.string(),
    consumedBy: z.string().nullable(),
});
export const SkillSignalSchema = z.discriminatedUnion('type', [
    GenerationSignalSchema,
    RefinementSignalSchema,
]);
export const SignalFileSchema = z.object({
    schemaVersion: z.literal(2),
    signals: z.array(SkillSignalSchema),
});
export const EMPTY_SIGNAL_FILE = {
    schemaVersion: 2,
    signals: [],
};
const V1SignalEntrySchema = z.object({
    id: z.string(),
    pattern: z.string(),
    category: z.string(),
    description: z.string(),
    incrementIds: z.array(z.string()),
    firstSeen: z.string(),
    lastSeen: z.string(),
    confidence: z.number(),
    evidence: z.array(z.string()),
    suggested: z.boolean(),
    declined: z.boolean(),
    generated: z.boolean(),
    uniqueSourceFiles: z.array(z.string()).optional(),
});
const V1SignalStoreSchema = z.object({
    version: z.string(),
    signals: z.array(V1SignalEntrySchema),
});
// ── Migration ────────────────────────────────────────────────────────
/**
 * Returns true when `raw` conforms to the v1 on-disk shape.
 * v1 is identified by a string `version` field (e.g. "1.0") and absent
 * `schemaVersion`. v2 uses a numeric `schemaVersion: 2`.
 */
export function isV1(raw) {
    return V1SignalStoreSchema.safeParse(raw).success;
}
/**
 * Migrate a v1 store to v2 without data loss. Adds `type: "generation"`
 * to every existing entry; all other fields are preserved verbatim.
 */
export function migrateV1toV2(v1) {
    return {
        schemaVersion: 2,
        signals: v1.signals.map((entry) => ({
            type: 'generation',
            id: entry.id,
            pattern: entry.pattern,
            category: entry.category,
            description: entry.description,
            incrementIds: [...entry.incrementIds],
            firstSeen: entry.firstSeen,
            lastSeen: entry.lastSeen,
            confidence: entry.confidence,
            evidence: [...entry.evidence],
            suggested: entry.suggested,
            declined: entry.declined,
            generated: entry.generated,
            ...(entry.uniqueSourceFiles !== undefined
                ? { uniqueSourceFiles: [...entry.uniqueSourceFiles] }
                : {}),
        })),
    };
}
//# sourceMappingURL=skill-signals.js.map