/** * PFLK cycle tracking — Problem, Feedback, Loophole, Knowledge. * * Tracks the full lifecycle of a PFLK cycle with specific queries * for analyzing loophole success rates and knowledge extraction. */ import type { Database } from "bun:sqlite" import { createPFLKCycle, updatePFLKPhase, listPFLKCycles } from "../db/index.ts" export interface PFLKTracker { id: string projectId: string workspaceId: string } /** * Start tracking a new PFLK cycle. */ export function startPFLK(db: Database, projectId: string, workspaceId: string, problem?: string): PFLKTracker { const id = createPFLKCycle(db, { project_id: projectId, workspace_id: workspaceId, problem }) return { id, projectId, workspaceId } } /** * Record the feedback phase results. */ export function recordFeedback(db: Database, pflkId: string, feedback: string): void { updatePFLKPhase(db, pflkId, "feedback", feedback) } /** * Record the loophole phase — all parallel experiment sandbox IDs. */ export function recordLoopholes(db: Database, pflkId: string, sandboxIds: string[]): void { updatePFLKPhase(db, pflkId, "loopholes", JSON.stringify(sandboxIds)) } /** * Record the knowledge phase — codified learning from the winning experiment. */ export function recordKnowledge(db: Database, pflkId: string, knowledge: string, winningExperimentId?: string): void { updatePFLKPhase(db, pflkId, "knowledge", knowledge) if (winningExperimentId) { db.run("UPDATE pflk_cycles SET winning_experiment_id = ? WHERE id = ?", [winningExperimentId, pflkId]) } } /** * Get PFLK history for a project. */ export function getPFLKHistory(db: Database, projectId: string) { return (listPFLKCycles(db, projectId) as Record[]).map((row) => ({ id: row.id as string, problem: row.problem as string, feedback: row.feedback as string, loopholes: JSON.parse((row.loopholes as string) ?? "[]") as string[], knowledge: row.knowledge as string | null, winningExperimentId: row.winning_experiment_id as string | null, createdAt: row.created_at as string, })) } /** * Calculate loophole success rate — what % of PFLK cycles found a winner. */ export function getLoopholeSuccessRate(db: Database, projectId?: string): { total: number; withWinner: number; rate: number } { let sql = "SELECT COUNT(*) as total, COUNT(winning_experiment_id) as with_winner FROM pflk_cycles" const params: string[] = [] if (projectId) { sql += " WHERE project_id = ?" params.push(projectId) } const row = db.query(sql).get(...params) as { total: number; with_winner: number } return { total: row.total, withWinner: row.with_winner, rate: row.total > 0 ? row.with_winner / row.total : 0, } } /** * Get all knowledge entries generated by PFLK cycles for a project. */ export function getKnowledgeFromPFLK(db: Database, projectId: string): string[] { const rows = db .query("SELECT knowledge FROM pflk_cycles WHERE project_id = ? AND knowledge IS NOT NULL AND knowledge != ''") .all(projectId) as { knowledge: string }[] return rows.map((r) => r.knowledge) }